diff options
author | Dennis Tang <dtang@gitlab.com> | 2018-05-25 23:56:17 +0200 |
---|---|---|
committer | Dennis Tang <dtang@gitlab.com> | 2018-05-25 23:56:17 +0200 |
commit | 95a63a881673533e3fd44243297d1a81e19396b6 (patch) | |
tree | 9a3190b813e2d599043394b30afaa5a5c8f8e565 /app/assets/javascripts | |
parent | 48e46f959716c8915f5b59d1314b5e5781f3cd8d (diff) | |
parent | 50c8ed2bf498c69d3d52ba1451274e3fbf438429 (diff) | |
download | gitlab-ce-95a63a881673533e3fd44243297d1a81e19396b6.tar.gz |
Merge remote-tracking branch 'origin/master' into 38759-fetch-available-parameters-directly-from-gke-when-creating-a-cluster
Diffstat (limited to 'app/assets/javascripts')
164 files changed, 1041 insertions, 559 deletions
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index 8ad3d18b302..ce1069276ab 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -21,8 +21,11 @@ const Api = { issuableTemplatePath: '/:namespace_path/:project_path/templates/:type/:key', usersPath: '/api/:version/users.json', commitPath: '/api/:version/projects/:id/repository/commits', + commitPipelinesPath: '/:project_id/commit/:sha/pipelines', branchSinglePath: '/api/:version/projects/:id/repository/branches/:branch', createBranchPath: '/api/:version/projects/:id/repository/branches', + pipelinesPath: '/api/:version/projects/:id/pipelines', + pipelineJobsPath: '/api/:version/projects/:id/pipelines/:pipeline_id/jobs', group(groupId, callback) { const url = Api.buildUrl(Api.groupPath).replace(':id', groupId); @@ -164,6 +167,19 @@ const Api = { }); }, + commitPipelines(projectId, sha) { + const encodedProjectId = projectId + .split('/') + .map(fragment => encodeURIComponent(fragment)) + .join('/'); + + const url = Api.buildUrl(Api.commitPipelinesPath) + .replace(':project_id', encodedProjectId) + .replace(':sha', encodeURIComponent(sha)); + + return axios.get(url); + }, + branchSingle(id, branch) { const url = Api.buildUrl(Api.branchSinglePath) .replace(':id', encodeURIComponent(id)) @@ -222,6 +238,20 @@ const Api = { }); }, + pipelines(projectPath, params = {}) { + const url = Api.buildUrl(this.pipelinesPath).replace(':id', encodeURIComponent(projectPath)); + + return axios.get(url, { params }); + }, + + pipelineJobs(projectPath, pipelineId, params = {}) { + const url = Api.buildUrl(this.pipelineJobsPath) + .replace(':id', encodeURIComponent(projectPath)) + .replace(':pipeline_id', pipelineId); + + return axios.get(url, { params }); + }, + buildUrl(url) { let urlRoot = ''; if (gon.relative_url_root != null) { diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js index 976d32abe9b..eb0f06efab4 100644 --- a/app/assets/javascripts/awards_handler.js +++ b/app/assets/javascripts/awards_handler.js @@ -345,7 +345,7 @@ class AwardsHandler { counter.text(counterNumber - 1); this.removeYouFromUserList($emojiButton); } else if (emoji === 'thumbsup' || emoji === 'thumbsdown') { - $emojiButton.tooltip('destroy'); + $emojiButton.tooltip('dispose'); counter.text('0'); this.removeYouFromUserList($emojiButton); if ($emojiButton.parents('.note').length) { @@ -358,7 +358,7 @@ class AwardsHandler { } removeEmoji($emojiButton) { - $emojiButton.tooltip('destroy'); + $emojiButton.tooltip('dispose'); $emojiButton.remove(); const $votesBlock = this.getVotesBlock(); if ($votesBlock.find('.js-emoji-btn').length === 0) { @@ -392,7 +392,7 @@ class AwardsHandler { .removeAttr('data-title') .removeAttr('data-original-title') .attr('title', this.toSentence(authors)) - .tooltip('fixTitle'); + .tooltip('_fixTitle'); } addYouToUserList(votesBlock, emoji) { @@ -405,7 +405,7 @@ class AwardsHandler { users.unshift('You'); return awardBlock .attr('title', this.toSentence(users)) - .tooltip('fixTitle'); + .tooltip('_fixTitle'); } createAwardButtonForVotesBlock(votesBlock, emojiName) { diff --git a/app/assets/javascripts/badges/components/badge.vue b/app/assets/javascripts/badges/components/badge.vue index 6e6cb31e3ac..d0f60e1d4cb 100644 --- a/app/assets/javascripts/badges/components/badge.vue +++ b/app/assets/javascripts/badges/components/badge.vue @@ -89,7 +89,7 @@ export default { v-show="hasError" class="btn-group" > - <div class="btn btn-default btn-xs disabled"> + <div class="btn btn-default btn-sm disabled"> <icon class="prepend-left-8 append-right-8" name="doc_image" @@ -98,7 +98,7 @@ export default { /> </div> <div - class="btn btn-default btn-xs disabled" + class="btn btn-default btn-sm disabled" > <span class="prepend-left-8 append-right-8">{{ s__('Badges|No badge image') }}</span> </div> @@ -106,7 +106,7 @@ export default { <button v-show="hasError" - class="btn btn-transparent btn-xs text-primary" + class="btn btn-transparent btn-sm text-primary" type="button" v-tooltip :title="s__('Badges|Reload badge image')" diff --git a/app/assets/javascripts/badges/components/badge_list.vue b/app/assets/javascripts/badges/components/badge_list.vue index ca7197e1e0f..268968b63b3 100644 --- a/app/assets/javascripts/badges/components/badge_list.vue +++ b/app/assets/javascripts/badges/components/badge_list.vue @@ -23,8 +23,8 @@ export default { </script> <template> - <div class="panel panel-default"> - <div class="panel-heading"> + <div class="card"> + <div class="card-header"> {{ s__('Badges|Your badges') }} <span v-show="!isLoading" @@ -33,19 +33,19 @@ export default { </div> <loading-icon v-show="isLoading" - class="panel-body" + class="card-body" size="2" /> <div v-if="hasNoBadges" - class="panel-body" + class="card-body" > <span v-if="isGroupBadge">{{ s__('Badges|This group has no badges') }}</span> <span v-else>{{ s__('Badges|This project has no badges') }}</span> </div> <div v-else - class="panel-body" + class="card-body" > <badge-list-row v-for="badge in badges" diff --git a/app/assets/javascripts/behaviors/copy_to_clipboard.js b/app/assets/javascripts/behaviors/copy_to_clipboard.js index e2a73a1797c..75834ba351d 100644 --- a/app/assets/javascripts/behaviors/copy_to_clipboard.js +++ b/app/assets/javascripts/behaviors/copy_to_clipboard.js @@ -8,10 +8,10 @@ function showTooltip(target, title) { if (!$target.data('hideTooltip')) { $target .attr('title', title) - .tooltip('fixTitle') + .tooltip('_fixTitle') .tooltip('show') .attr('title', originalTitle) - .tooltip('fixTitle'); + .tooltip('_fixTitle'); } } diff --git a/app/assets/javascripts/behaviors/quick_submit.js b/app/assets/javascripts/behaviors/quick_submit.js index 3ec932bdb73..b6e2781773c 100644 --- a/app/assets/javascripts/behaviors/quick_submit.js +++ b/app/assets/javascripts/behaviors/quick_submit.js @@ -69,7 +69,7 @@ $(document).on('keyup.quick_submit', '.js-quick-submit input[type=submit], .js-q $this.tooltip({ container: 'body', html: 'true', - placement: 'auto top', + placement: 'top', title, trigger: 'manual', }); diff --git a/app/assets/javascripts/behaviors/requires_input.js b/app/assets/javascripts/behaviors/requires_input.js index ffff4ddb71a..a8b6dbf0948 100644 --- a/app/assets/javascripts/behaviors/requires_input.js +++ b/app/assets/javascripts/behaviors/requires_input.js @@ -42,9 +42,9 @@ $.fn.requiresInput = function requiresInput() { function hideOrShowHelpBlock(form) { const selected = $('.js-select-namespace option:selected'); if (selected.length && selected.data('optionsParent') === 'groups') { - form.find('.help-block').hide(); + form.find('.form-text.text-muted').hide(); } else if (selected.length) { - form.find('.help-block').show(); + form.find('.form-text.text-muted').show(); } } diff --git a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js index c17877a276d..766039404ce 100644 --- a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js +++ b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js @@ -2,9 +2,9 @@ import sqljs from 'sql.js'; import { template as _template } from 'underscore'; const PREVIEW_TEMPLATE = _template(` - <div class="panel panel-default"> - <div class="panel-heading"><%- name %></div> - <div class="panel-body"> + <div class="card"> + <div class="card-header"><%- name %></div> + <div class="card-body"> <img class="img-thumbnail" src="data:image/png;base64,<%- image %>"/> </div> </div> diff --git a/app/assets/javascripts/blob/sketch/index.js b/app/assets/javascripts/blob/sketch/index.js index 0799991aa40..13318c58006 100644 --- a/app/assets/javascripts/blob/sketch/index.js +++ b/app/assets/javascripts/blob/sketch/index.js @@ -44,7 +44,7 @@ export default class SketchLoader { previewLink.href = previewUrl; previewLink.target = '_blank'; previewImage.src = previewUrl; - previewImage.className = 'img-responsive'; + previewImage.className = 'img-fluid'; previewLink.appendChild(previewImage); this.container.appendChild(previewLink); diff --git a/app/assets/javascripts/blob/viewer/index.js b/app/assets/javascripts/blob/viewer/index.js index 137e1f5a099..f61c0be9230 100644 --- a/app/assets/javascripts/blob/viewer/index.js +++ b/app/assets/javascripts/blob/viewer/index.js @@ -116,7 +116,7 @@ export default class BlobViewer { this.copySourceBtn.classList.add('disabled'); } - $(this.copySourceBtn).tooltip('fixTitle'); + $(this.copySourceBtn).tooltip('_fixTitle'); } switchToViewer(name) { diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue index 84885ca9306..33e3369b971 100644 --- a/app/assets/javascripts/boards/components/board_card.vue +++ b/app/assets/javascripts/boards/components/board_card.vue @@ -77,7 +77,7 @@ export default { <template> <li - class="card" + class="board-card" :class="{ 'user-can-drag': !disabled && issue.id, 'is-disabled': disabled || !issue.id, diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue index 8d84c1735b8..e8dfd95f7ae 100644 --- a/app/assets/javascripts/boards/components/board_new_issue.vue +++ b/app/assets/javascripts/boards/components/board_new_issue.vue @@ -92,7 +92,7 @@ export default { <template> <div class="board-new-issue-form"> - <div class="card"> + <div class="board-card"> <form @submit="submit($event)"> <div class="flash-container" @@ -122,7 +122,7 @@ export default { /> <div class="clearfix prepend-top-10"> <button - class="btn btn-success pull-left" + class="btn btn-success float-left" type="submit" :disabled="disabled" ref="submit-button" @@ -130,7 +130,7 @@ export default { Submit issue </button> <button - class="btn btn-default pull-right" + class="btn btn-default float-right" type="button" @click="cancel" > diff --git a/app/assets/javascripts/boards/components/issue_card_inner.js b/app/assets/javascripts/boards/components/issue_card_inner.js index 84fe9b1288a..dcc07810d01 100644 --- a/app/assets/javascripts/boards/components/issue_card_inner.js +++ b/app/assets/javascripts/boards/components/issue_card_inner.js @@ -135,8 +135,8 @@ gl.issueBoards.IssueCardInner = Vue.extend({ }, template: ` <div> - <div class="card-header"> - <h4 class="card-title"> + <div class="board-card-header"> + <h4 class="board-card-title"> <i class="fa fa-eye-slash confidential-icon" v-if="issue.confidential" @@ -147,13 +147,13 @@ gl.issueBoards.IssueCardInner = Vue.extend({ :href="issue.path" :title="issue.title">{{ issue.title }}</a> <span - class="card-number" + class="board-card-number" v-if="issueId" > {{ issue.referencePath }} </span> </h4> - <div class="card-assignee"> + <div class="board-card-assignee"> <user-avatar-link v-for="(assignee, index) in issue.assignees" :key="assignee.id" @@ -175,11 +175,11 @@ gl.issueBoards.IssueCardInner = Vue.extend({ </div> </div> <div - class="card-footer" + class="board-card-footer" v-if="showLabelFooter" > <button - class="label color-label has-tooltip" + class="badge color-label has-tooltip" v-for="label in issue.labels" type="button" v-if="showLabel(label)" diff --git a/app/assets/javascripts/boards/components/modal/empty_state.js b/app/assets/javascripts/boards/components/modal/empty_state.js index 9e37f95cdd6..eb8a66975ee 100644 --- a/app/assets/javascripts/boards/components/modal/empty_state.js +++ b/app/assets/javascripts/boards/components/modal/empty_state.js @@ -41,10 +41,10 @@ gl.issueBoards.ModalEmptyState = Vue.extend({ template: ` <section class="empty-state"> <div class="row"> - <div class="col-xs-12 col-sm-6 col-sm-push-6"> + <div class="col-xs-12 col-sm-6 order-sm-last"> <aside class="svg-content"><img :src="emptyStateSvg"/></aside> </div> - <div class="col-xs-12 col-sm-6 col-sm-pull-6"> + <div class="col-xs-12 col-sm-6 order-sm-first"> <div class="text-content"> <h4>{{ contents.title }}</h4> <p v-html="contents.content"></p> diff --git a/app/assets/javascripts/boards/components/modal/footer.js b/app/assets/javascripts/boards/components/modal/footer.js index 9735e0ddacc..11bb3e98334 100644 --- a/app/assets/javascripts/boards/components/modal/footer.js +++ b/app/assets/javascripts/boards/components/modal/footer.js @@ -58,7 +58,7 @@ gl.issueBoards.ModalFooter = Vue.extend({ template: ` <footer class="form-actions add-issues-footer"> - <div class="pull-left"> + <div class="float-left"> <button class="btn btn-success" type="button" @@ -72,7 +72,7 @@ gl.issueBoards.ModalFooter = Vue.extend({ <lists-dropdown></lists-dropdown> </div> <button - class="btn btn-default pull-right" + class="btn btn-default float-right" type="button" @click="toggleModal(false)"> Cancel diff --git a/app/assets/javascripts/boards/components/modal/list.js b/app/assets/javascripts/boards/components/modal/list.js index 6b04a6c7a6c..6c662432037 100644 --- a/app/assets/javascripts/boards/components/modal/list.js +++ b/app/assets/javascripts/boards/components/modal/list.js @@ -133,9 +133,9 @@ gl.issueBoards.ModalList = Vue.extend({ <div v-for="issue in group" v-if="showIssue(issue)" - class="card-parent"> + class="board-card-parent"> <div - class="card" + class="board-card" :class="{ 'is-active': issue.selected }" @click="toggleIssue($event, issue)"> <issue-card-inner diff --git a/app/assets/javascripts/boards/components/modal/tabs.js b/app/assets/javascripts/boards/components/modal/tabs.js index b6465a88e5e..9d331de8e22 100644 --- a/app/assets/javascripts/boards/components/modal/tabs.js +++ b/app/assets/javascripts/boards/components/modal/tabs.js @@ -24,7 +24,7 @@ gl.issueBoards.ModalTabs = Vue.extend({ role="button" @click.prevent="changeTab('all')"> Open issues - <span class="badge"> + <span class="badge badge-pill"> {{ issuesCount }} </span> </a> @@ -35,7 +35,7 @@ gl.issueBoards.ModalTabs = Vue.extend({ role="button" @click.prevent="changeTab('selected')"> Selected issues - <span class="badge"> + <span class="badge badge-pill"> {{ selectedCount }} </span> </a> diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index a6f8681cfac..29ab13b8e0b 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -214,7 +214,7 @@ export default () => { if (this.disabled) { $tooltip.tooltip(); } else { - $tooltip.tooltip('destroy'); + $tooltip.tooltip('dispose'); } }); }, diff --git a/app/assets/javascripts/ci_variable_list/ci_variable_list.js b/app/assets/javascripts/ci_variable_list/ci_variable_list.js index e177a3bfdc7..47efb3a8cee 100644 --- a/app/assets/javascripts/ci_variable_list/ci_variable_list.js +++ b/app/assets/javascripts/ci_variable_list/ci_variable_list.js @@ -141,6 +141,11 @@ export default class VariableList { $rowClone.find(entry.selector).val(entry.default); }); + // Close any dropdowns + $rowClone.find('.dropdown-menu.show').each((index, $dropdown) => { + $dropdown.classList.remove('show'); + }); + this.initRow($rowClone); $row.after($rowClone); diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue index c2a35341eb2..fae580c091b 100644 --- a/app/assets/javascripts/clusters/components/application_row.vue +++ b/app/assets/javascripts/clusters/components/application_row.vue @@ -179,7 +179,7 @@ role="row" > <div - class="alert alert-danger alert-block append-bottom-0 table-section section-100" + class="alert alert-danger alert-block append-bottom-0" role="gridcell" > <div> diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index 9c12b89240c..bb5fcea648d 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -191,11 +191,11 @@ export default { :value="ingressExternalIp" readonly /> - <span class="input-group-btn"> + <span class="input-group-append"> <clipboard-button :text="ingressExternalIp" :title="s__('ClusterIntegration|Copy Ingress IP Address to clipboard')" - class="js-clipboard-btn" + class="input-group-text js-clipboard-btn" /> </span> </div> diff --git a/app/assets/javascripts/commons/bootstrap.js b/app/assets/javascripts/commons/bootstrap.js index db96da4ccba..50e2949ab55 100644 --- a/app/assets/javascripts/commons/bootstrap.js +++ b/app/assets/javascripts/commons/bootstrap.js @@ -1,15 +1,7 @@ import $ from 'jquery'; // bootstrap jQuery plugins -import 'bootstrap-sass/assets/javascripts/bootstrap/affix'; -import 'bootstrap-sass/assets/javascripts/bootstrap/alert'; -import 'bootstrap-sass/assets/javascripts/bootstrap/button'; -import 'bootstrap-sass/assets/javascripts/bootstrap/dropdown'; -import 'bootstrap-sass/assets/javascripts/bootstrap/modal'; -import 'bootstrap-sass/assets/javascripts/bootstrap/tab'; -import 'bootstrap-sass/assets/javascripts/bootstrap/transition'; -import 'bootstrap-sass/assets/javascripts/bootstrap/tooltip'; -import 'bootstrap-sass/assets/javascripts/bootstrap/popover'; +import 'bootstrap'; // custom jQuery functions $.fn.extend({ diff --git a/app/assets/javascripts/compare_autocomplete.js b/app/assets/javascripts/compare_autocomplete.js index 9c88466e576..ffe15f02f2e 100644 --- a/app/assets/javascripts/compare_autocomplete.js +++ b/app/assets/javascripts/compare_autocomplete.js @@ -54,7 +54,7 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = ( .attr('href', '#') .addClass(ref === selected ? 'is-active' : '') .text(ref) - .attr('data-ref', escape(ref)); + .attr('data-ref', ref); return $('<li />').append(link); } }, @@ -78,7 +78,7 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = ( $dropdownContainer.on('click', '.dropdown-content a', e => { $dropdown.prop('title', e.target.text.replace(/_+?/g, '-')); if ($dropdown.hasClass('has-tooltip')) { - $dropdown.tooltip('fixTitle'); + $dropdown.tooltip('_fixTitle'); } }); }); diff --git a/app/assets/javascripts/create_merge_request_dropdown.js b/app/assets/javascripts/create_merge_request_dropdown.js index a88b6971f90..09d490106df 100644 --- a/app/assets/javascripts/create_merge_request_dropdown.js +++ b/app/assets/javascripts/create_merge_request_dropdown.js @@ -61,8 +61,8 @@ export default class CreateMergeRequestDropdown { } available() { - this.availableButton.classList.remove('hide'); - this.unavailableButton.classList.add('hide'); + this.availableButton.classList.remove('hidden'); + this.unavailableButton.classList.add('hidden'); } bindEvents() { @@ -232,7 +232,7 @@ export default class CreateMergeRequestDropdown { } hide() { - this.wrapperEl.classList.add('hide'); + this.wrapperEl.classList.add('hidden'); } init() { @@ -406,8 +406,8 @@ export default class CreateMergeRequestDropdown { } unavailable() { - this.availableButton.classList.add('hide'); - this.unavailableButton.classList.remove('hide'); + this.availableButton.classList.add('hidden'); + this.unavailableButton.classList.remove('hidden'); } updateBranchName(suggestedBranchName) { diff --git a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue index 32ae0cc1476..5be17081b58 100644 --- a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue +++ b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue @@ -16,7 +16,7 @@ <template> <span v-if="count === 50" - class="events-info pull-right" + class="events-info float-right" > <i class="fa fa-warning" diff --git a/app/assets/javascripts/diff_notes/components/diff_note_avatars.js b/app/assets/javascripts/diff_notes/components/diff_note_avatars.js index 180a6bd67e7..fe9b0795609 100644 --- a/app/assets/javascripts/diff_notes/components/diff_note_avatars.js +++ b/app/assets/javascripts/diff_notes/components/diff_note_avatars.js @@ -79,7 +79,7 @@ const DiffNoteAvatars = Vue.extend({ storeState: { handler() { this.$nextTick(() => { - $('.has-tooltip', this.$el).tooltip('fixTitle'); + $('.has-tooltip', this.$el).tooltip('_fixTitle'); // We need to add/remove a class to an element that is outside the Vue instance this.addNoCommentClass(); @@ -138,7 +138,7 @@ const DiffNoteAvatars = Vue.extend({ this.$nextTick(() => { this.setDiscussionVisible(); - $('.has-tooltip', this.$el).tooltip('fixTitle'); + $('.has-tooltip', this.$el).tooltip('_fixTitle'); $('.has-tooltip', this.$el).tooltip('hide'); }); }, diff --git a/app/assets/javascripts/diff_notes/components/resolve_btn.js b/app/assets/javascripts/diff_notes/components/resolve_btn.js index df4c72ba0ed..8d66417abac 100644 --- a/app/assets/javascripts/diff_notes/components/resolve_btn.js +++ b/app/assets/javascripts/diff_notes/components/resolve_btn.js @@ -61,7 +61,7 @@ const ResolveBtn = Vue.extend({ this.$nextTick(() => { $(this.$refs.button) .tooltip('hide') - .tooltip('fixTitle'); + .tooltip('_fixTitle'); }); }, resolve: function () { diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue index ab9e22037d0..0b3fef9fcca 100644 --- a/app/assets/javascripts/environments/components/environment_actions.vue +++ b/app/assets/javascripts/environments/components/environment_actions.vue @@ -74,7 +74,7 @@ </span> </button> - <ul class="dropdown-menu dropdown-menu-align-right"> + <ul class="dropdown-menu dropdown-menu-right"> <li v-for="(action, i) in actions" :key="i"> diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index 79326ca3487..23aaab2c441 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -486,14 +486,14 @@ {{ model.folderName }} </span> - <span class="badge"> + <span class="badge badge-pill"> {{ model.size }} </span> </span> </div> <div - class="table-section section-10 deployment-column hidden-xs hidden-sm" + class="table-section section-10 deployment-column d-none d-sm-none d-md-block" role="gridcell" > <span v-if="shouldRenderDeploymentID"> @@ -513,7 +513,7 @@ </div> <div - class="table-section section-15 hidden-xs hidden-sm" + class="table-section section-15 d-none d-sm-none d-md-block" role="gridcell" > <a diff --git a/app/assets/javascripts/environments/components/environment_monitoring.vue b/app/assets/javascripts/environments/components/environment_monitoring.vue index deada134b27..8df1b6317e3 100644 --- a/app/assets/javascripts/environments/components/environment_monitoring.vue +++ b/app/assets/javascripts/environments/components/environment_monitoring.vue @@ -28,7 +28,7 @@ <template> <a v-tooltip - class="btn monitoring-url hidden-xs hidden-sm" + class="btn monitoring-url d-none d-sm-none d-md-block" data-container="body" rel="noopener noreferrer nofollow" :href="monitoringUrl" diff --git a/app/assets/javascripts/environments/components/environment_rollback.vue b/app/assets/javascripts/environments/components/environment_rollback.vue index c822fb1574c..7515d711c50 100644 --- a/app/assets/javascripts/environments/components/environment_rollback.vue +++ b/app/assets/javascripts/environments/components/environment_rollback.vue @@ -40,7 +40,7 @@ <template> <button type="button" - class="btn hidden-xs hidden-sm" + class="btn d-none d-sm-none d-md-block" @click="onClick" :disabled="isLoading" > diff --git a/app/assets/javascripts/environments/components/environment_stop.vue b/app/assets/javascripts/environments/components/environment_stop.vue index dda7429a726..7055f208451 100644 --- a/app/assets/javascripts/environments/components/environment_stop.vue +++ b/app/assets/javascripts/environments/components/environment_stop.vue @@ -43,7 +43,7 @@ if (confirm('Are you sure you want to stop this environment?')) { this.isLoading = true; - $(this.$el).tooltip('destroy'); + $(this.$el).tooltip('dispose'); eventHub.$emit('postAction', this.stopUrl); } @@ -55,7 +55,7 @@ <button v-tooltip type="button" - class="btn stop-env-link hidden-xs hidden-sm" + class="btn stop-env-link d-none d-sm-none d-md-block" data-container="body" @click="onClick" :disabled="isLoading" diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.vue b/app/assets/javascripts/environments/components/environment_terminal_button.vue index e8469d088ef..0dbbbb75e07 100644 --- a/app/assets/javascripts/environments/components/environment_terminal_button.vue +++ b/app/assets/javascripts/environments/components/environment_terminal_button.vue @@ -30,7 +30,7 @@ <template> <a v-tooltip - class="btn terminal-button hidden-xs hidden-sm" + class="btn terminal-button d-none d-sm-none d-md-block" data-container="body" :title="title" :aria-label="title" diff --git a/app/assets/javascripts/environments/components/environments_app.vue b/app/assets/javascripts/environments/components/environments_app.vue index c0be72f7401..3da762446c9 100644 --- a/app/assets/javascripts/environments/components/environments_app.vue +++ b/app/assets/javascripts/environments/components/environments_app.vue @@ -68,8 +68,7 @@ this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', showLoader); this.service.getFolderContent(folder.folder_path) - .then(resp => resp.json()) - .then(response => this.store.setfolderContent(folder, response.environments)) + .then(response => this.store.setfolderContent(folder, response.data.environments)) .then(() => this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false)) .catch(() => { Flash(s__('Environments|An error occurred while fetching the environments.')); diff --git a/app/assets/javascripts/environments/mixins/environments_mixin.js b/app/assets/javascripts/environments/mixins/environments_mixin.js index 34d18d55120..a7a79dbca70 100644 --- a/app/assets/javascripts/environments/mixins/environments_mixin.js +++ b/app/assets/javascripts/environments/mixins/environments_mixin.js @@ -6,7 +6,6 @@ import Visibility from 'visibilityjs'; import Poll from '../../lib/utils/poll'; import { getParameterByName, - parseQueryStringIntoObject, } from '../../lib/utils/common_utils'; import { s__ } from '../../locale'; import Flash from '../../flash'; @@ -46,17 +45,14 @@ export default { methods: { saveData(resp) { - const headers = resp.headers; - return resp.json().then((response) => { - this.isLoading = false; - - if (_.isEqual(parseQueryStringIntoObject(resp.url.split('?')[1]), this.requestData)) { - this.store.storeAvailableCount(response.available_count); - this.store.storeStoppedCount(response.stopped_count); - this.store.storeEnvironments(response.environments); - this.store.setPagination(headers); - } - }); + this.isLoading = false; + + if (_.isEqual(resp.config.params, this.requestData)) { + this.store.storeAvailableCount(resp.data.available_count); + this.store.storeStoppedCount(resp.data.stopped_count); + this.store.storeEnvironments(resp.data.environments); + this.store.setPagination(resp.headers); + } }, /** @@ -70,7 +66,7 @@ export default { updateContent(parameters) { this.updateInternalState(parameters); // fetch new data - return this.service.get(this.requestData) + return this.service.fetchEnvironments(this.requestData) .then(response => this.successCallback(response)) .then(() => { // restart polling @@ -105,7 +101,7 @@ export default { fetchEnvironments() { this.isLoading = true; - return this.service.get(this.requestData) + return this.service.fetchEnvironments(this.requestData) .then(this.successCallback) .catch(this.errorCallback); }, @@ -141,7 +137,7 @@ export default { this.poll = new Poll({ resource: this.service, - method: 'get', + method: 'fetchEnvironments', data: this.requestData, successCallback: this.successCallback, errorCallback: this.errorCallback, diff --git a/app/assets/javascripts/environments/services/environments_service.js b/app/assets/javascripts/environments/services/environments_service.js index 03ab74b3338..3b121551aca 100644 --- a/app/assets/javascripts/environments/services/environments_service.js +++ b/app/assets/javascripts/environments/services/environments_service.js @@ -1,25 +1,22 @@ -/* eslint-disable class-methods-use-this */ -import Vue from 'vue'; -import VueResource from 'vue-resource'; - -Vue.use(VueResource); +import axios from '~/lib/utils/axios_utils'; export default class EnvironmentsService { constructor(endpoint) { - this.environments = Vue.resource(endpoint); + this.environmentsEndpoint = endpoint; this.folderResults = 3; } - get(options = {}) { + fetchEnvironments(options = {}) { const { scope, page } = options; - return this.environments.get({ scope, page }); + return axios.get(this.environmentsEndpoint, { params: { scope, page } }); } + // eslint-disable-next-line class-methods-use-this postAction(endpoint) { - return Vue.http.post(endpoint, {}, { emulateJSON: true }); + return axios.post(endpoint, {}, { emulateJSON: true }); } getFolderContent(folderUrl) { - return Vue.http.get(`${folderUrl}.json?per_page=${this.folderResults}`); + return axios.get(`${folderUrl}.json?per_page=${this.folderResults}`); } } diff --git a/app/assets/javascripts/feature_highlight/feature_highlight.js b/app/assets/javascripts/feature_highlight/feature_highlight.js index 2d5bae9a9c4..2f27c9351bc 100644 --- a/app/assets/javascripts/feature_highlight/feature_highlight.js +++ b/app/assets/javascripts/feature_highlight/feature_highlight.js @@ -24,7 +24,7 @@ export function setupFeatureHighlightPopover(id, debounceTimeout = 300) { template: ` <div class="popover feature-highlight-popover" role="tooltip"> <div class="arrow"></div> - <div class="popover-content"></div> + <div class="popover-body"></div> </div> `, }) diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index fa48d7d1915..746a06b7c4f 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -374,7 +374,7 @@ GitLabDropdown = (function() { $relatedTarget = $(e.relatedTarget); $dropdownMenu = $relatedTarget.closest('.dropdown-menu'); if ($dropdownMenu.length === 0) { - return _this.dropdown.removeClass('open'); + return _this.dropdown.removeClass('show'); } } }; @@ -801,7 +801,7 @@ GitLabDropdown = (function() { if (this.options.filterable) { const initialScrollTop = $(window).scrollTop(); - if (this.dropdown.is('.open')) { + if (this.dropdown.is('.show') && !this.filterInput.is(':focus')) { this.filterInput.focus(); } diff --git a/app/assets/javascripts/gl_field_error.js b/app/assets/javascripts/gl_field_error.js index 972b2252acb..87c6e37b9fb 100644 --- a/app/assets/javascripts/gl_field_error.js +++ b/app/assets/javascripts/gl_field_error.js @@ -62,7 +62,7 @@ export default class GlFieldError { this.inputDomElement = this.inputElement.get(0); this.form = formErrors; this.errorMessage = this.inputElement.attr('title') || 'This field is required.'; - this.fieldErrorElement = $(`<p class='${errorMessageClass} hide'>${this.errorMessage}</p>`); + this.fieldErrorElement = $(`<p class='${errorMessageClass} hidden'>${this.errorMessage}</p>`); this.state = { valid: false, @@ -146,8 +146,8 @@ export default class GlFieldError { renderInvalid() { this.inputElement.addClass(inputErrorClass); - this.scopedSiblings.hide(); - return this.fieldErrorElement.show(); + this.scopedSiblings.addClass('hidden'); + return this.fieldErrorElement.removeClass('hidden'); } renderClear() { @@ -157,7 +157,7 @@ export default class GlFieldError { this.accessCurrentValue(trimmedInput); } this.inputElement.removeClass(inputErrorClass); - this.scopedSiblings.hide(); - this.fieldErrorElement.hide(); + this.scopedSiblings.addClass('hidden'); + this.fieldErrorElement.addClass('hidden'); } } diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue index 764b130fdb8..7f64a9bd741 100644 --- a/app/assets/javascripts/groups/components/group_item.vue +++ b/app/assets/javascripts/groups/components/group_item.vue @@ -99,7 +99,7 @@ export default { /> </div> <div - class="avatar-container prepend-top-8 prepend-left-5 s24 hidden-xs" + class="avatar-container prepend-top-8 prepend-left-5 s24 d-none d-sm-block" :class="{ 'content-loading': group.isChildrenLoading }" > <a diff --git a/app/assets/javascripts/ide/components/commit_sidebar/form.vue b/app/assets/javascripts/ide/components/commit_sidebar/form.vue index 4a645c827ad..81961fe3c57 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/form.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/form.vue @@ -5,7 +5,7 @@ import LoadingButton from '~/vue_shared/components/loading_button.vue'; import CommitMessageField from './message_field.vue'; import Actions from './actions.vue'; import SuccessMessage from './success_message.vue'; -import { activityBarViews, MAX_WINDOW_HEIGHT_COMPACT, COMMIT_ITEM_PADDING } from '../../constants'; +import { activityBarViews, MAX_WINDOW_HEIGHT_COMPACT } from '../../constants'; export default { components: { @@ -70,7 +70,7 @@ export default { ? this.$refs.formEl && this.$refs.formEl.offsetHeight : this.$refs.compactEl && this.$refs.compactEl.offsetHeight; - this.componentHeight = elHeight + COMMIT_ITEM_PADDING; + this.componentHeight = elHeight; }, enterTransition() { this.$nextTick(() => { @@ -78,7 +78,7 @@ export default { ? this.$refs.compactEl && this.$refs.compactEl.offsetHeight : this.$refs.formEl && this.$refs.formEl.offsetHeight; - this.componentHeight = elHeight + COMMIT_ITEM_PADDING; + this.componentHeight = elHeight; }); }, afterEndTransition() { diff --git a/app/assets/javascripts/ide/components/file_finder/index.vue b/app/assets/javascripts/ide/components/file_finder/index.vue index ea2b13a8b21..cabb3f59b17 100644 --- a/app/assets/javascripts/ide/components/file_finder/index.vue +++ b/app/assets/javascripts/ide/components/file_finder/index.vue @@ -39,12 +39,10 @@ export default { return this.allBlobs.slice(0, MAX_FILE_FINDER_RESULTS); } - return fuzzaldrinPlus - .filter(this.allBlobs, searchText, { - key: 'path', - maxResults: MAX_FILE_FINDER_RESULTS, - }) - .sort((a, b) => b.lastOpenedAt - a.lastOpenedAt); + return fuzzaldrinPlus.filter(this.allBlobs, searchText, { + key: 'path', + maxResults: MAX_FILE_FINDER_RESULTS, + }); }, filteredBlobsLength() { return this.filteredBlobs.length; diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue index 6c373a92776..2c184ea726c 100644 --- a/app/assets/javascripts/ide/components/ide.vue +++ b/app/assets/javascripts/ide/components/ide.vue @@ -52,7 +52,10 @@ export default { methods: { ...mapActions(['toggleFileFinder']), mousetrapStopCallback(e, el, combo) { - if (combo === 't' && el.classList.contains('dropdown-input-field')) { + if ( + (combo === 't' && el.classList.contains('dropdown-input-field')) || + el.classList.contains('inputarea') + ) { return true; } else if (combo === 'command+p' || combo === 'ctrl+p') { return false; @@ -99,12 +102,12 @@ export default { class="ide-empty-state" > <div class="row js-empty-state"> - <div class="col-xs-12"> + <div class="col-12"> <div class="svg-content svg-250"> <img :src="emptyStateSvgPath" /> </div> </div> - <div class="col-xs-12"> + <div class="col-12"> <div class="text-content text-center"> <h4> Welcome to the GitLab IDE @@ -120,8 +123,6 @@ export default { </template> </div> </div> - <ide-status-bar - :file="activeFile" - /> + <ide-status-bar :file="activeFile"/> </article> </template> diff --git a/app/assets/javascripts/ide/components/ide_file_buttons.vue b/app/assets/javascripts/ide/components/ide_file_buttons.vue index a6c6f46a144..30b00abf6ed 100644 --- a/app/assets/javascripts/ide/components/ide_file_buttons.vue +++ b/app/assets/javascripts/ide/components/ide_file_buttons.vue @@ -32,14 +32,14 @@ export default { <template> <div v-if="showButtons" - class="pull-right ide-btn-group" + class="float-right ide-btn-group" > <a v-tooltip v-if="!file.binary" :href="file.blamePath" :title="__('Blame')" - class="btn btn-xs btn-transparent blame" + class="btn btn-sm btn-transparent blame" > <icon name="blame" @@ -50,7 +50,7 @@ export default { v-tooltip :href="file.commitsPath" :title="__('History')" - class="btn btn-xs btn-transparent history" + class="btn btn-sm btn-transparent history" > <icon name="history" @@ -61,7 +61,7 @@ export default { v-tooltip :href="file.permalink" :title="__('Permalink')" - class="btn btn-xs btn-transparent permalink" + class="btn btn-sm btn-transparent permalink" > <icon name="link" @@ -72,7 +72,7 @@ export default { v-tooltip :href="file.rawPath" target="_blank" - class="btn btn-xs btn-transparent prepend-left-10 raw" + class="btn btn-sm btn-transparent prepend-left-10 raw" rel="noopener noreferrer" :title="rawDownloadButtonLabel"> <icon diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue index 70c6d53c3ab..6f60cfbf184 100644 --- a/app/assets/javascripts/ide/components/ide_status_bar.vue +++ b/app/assets/javascripts/ide/components/ide_status_bar.vue @@ -1,14 +1,16 @@ <script> -import { mapGetters } from 'vuex'; +import { mapActions, mapState, mapGetters } from 'vuex'; import icon from '~/vue_shared/components/icon.vue'; import tooltip from '~/vue_shared/directives/tooltip'; import timeAgoMixin from '~/vue_shared/mixins/timeago'; +import CiIcon from '../../vue_shared/components/ci_icon.vue'; import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; export default { components: { icon, userAvatarImage, + CiIcon, }, directives: { tooltip, @@ -27,8 +29,16 @@ export default { }; }, computed: { + ...mapState(['currentBranchId', 'currentProjectId']), ...mapGetters(['currentProject', 'lastCommit']), }, + watch: { + lastCommit() { + if (!this.isPollingInitialized) { + this.initPipelinePolling(); + } + }, + }, mounted() { this.startTimer(); }, @@ -36,13 +46,21 @@ export default { if (this.intervalId) { clearInterval(this.intervalId); } + if (this.isPollingInitialized) { + this.stopPipelinePolling(); + } }, methods: { + ...mapActions(['pipelinePoll', 'stopPipelinePolling']), startTimer() { this.intervalId = setInterval(() => { this.commitAgeUpdate(); }, 1000); }, + initPipelinePolling() { + this.pipelinePoll(); + this.isPollingInitialized = true; + }, commitAgeUpdate() { if (this.lastCommit) { this.lastCommitFormatedAge = this.timeFormated(this.lastCommit.committed_date); @@ -61,6 +79,23 @@ export default { class="ide-status-branch" v-if="lastCommit && lastCommitFormatedAge" > + <span + class="ide-status-pipeline" + v-if="lastCommit.pipeline && lastCommit.pipeline.details" + > + <ci-icon + :status="lastCommit.pipeline.details.status" + v-tooltip + :title="lastCommit.pipeline.details.status.text" + /> + Pipeline + <a + class="monospace" + :href="lastCommit.pipeline.details.status.details_path">#{{ lastCommit.pipeline.id }}</a> + {{ lastCommit.pipeline.details.status.text }} + for + </span> + <icon name="commit" /> diff --git a/app/assets/javascripts/ide/components/new_dropdown/index.vue b/app/assets/javascripts/ide/components/new_dropdown/index.vue index a0ce1c9dac7..f0b29702497 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/index.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/index.vue @@ -57,7 +57,7 @@ export default { <div class="dropdown" :class="{ - open: dropdownOpen, + show: dropdownOpen, }" > <button @@ -69,12 +69,12 @@ export default { <icon name="plus" :size="12" - css-classes="pull-left" + css-classes="float-left" /> <icon name="arrow-down" :size="12" - css-classes="pull-left" + css-classes="float-left" /> </button> <ul diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue index a95a0225950..d83a90f71e1 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue @@ -70,12 +70,12 @@ export default { @submit="createEntryInStore" > <form - class="form-horizontal" slot="body" @submit.prevent="createEntryInStore" + class="form-group row append-bottom-0" > <fieldset class="form-group append-bottom-0"> - <label class="label-light col-sm-3 ide-new-modal-label"> + <label class="label-light col-form-label col-sm-3 ide-new-modal-label"> {{ __('Name') }} </label> <div class="col-sm-9"> diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index f8678b602ac..a281ecb95c8 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -43,9 +43,13 @@ export default { }, }, watch: { - file(oldVal, newVal) { + file(newVal, oldVal) { + if (oldVal.pending) { + this.removePendingTab(oldVal); + } + // Compare key to allow for files opened in review mode to be cached differently - if (newVal.key !== this.file.key) { + if (oldVal.key !== this.file.key) { this.initMonaco(); if (this.currentActivityView !== activityBarViews.edit) { @@ -99,6 +103,7 @@ export default { 'setFileViewMode', 'setFileEOL', 'updateViewer', + 'removePendingTab', ]), initMonaco() { if (this.shouldHideEditor) return; @@ -192,7 +197,7 @@ export default { > <div class="ide-mode-tabs clearfix" > <ul - class="nav-links pull-left" + class="nav-links float-left" v-if="!shouldHideEditor && isEditModeActive" > <li :class="editTabCSS"> diff --git a/app/assets/javascripts/ide/components/repo_file.vue b/app/assets/javascripts/ide/components/repo_file.vue index 14946f8c9fa..442697e1c80 100644 --- a/app/assets/javascripts/ide/components/repo_file.vue +++ b/app/assets/javascripts/ide/components/repo_file.vue @@ -122,11 +122,11 @@ export default { <div class="file" :class="fileClass" + @click="clickFile" + role="button" > <div class="file-name" - @click="clickFile" - role="button" > <span class="ide-file-name str-truncated" @@ -144,7 +144,7 @@ export default { :file="file" /> </span> - <span class="pull-right ide-file-icon-holder"> + <span class="float-right ide-file-icon-holder"> <mr-file-icon v-if="file.mrChange" /> @@ -177,7 +177,7 @@ export default { :project-id="file.projectId" :branch="file.branchId" :path="file.path" - class="pull-right prepend-left-8" + class="float-right prepend-left-8" /> </div> </div> diff --git a/app/assets/javascripts/ide/components/repo_loading_file.vue b/app/assets/javascripts/ide/components/repo_loading_file.vue index 79af8c0b0c7..3e47da88050 100644 --- a/app/assets/javascripts/ide/components/repo_loading_file.vue +++ b/app/assets/javascripts/ide/components/repo_loading_file.vue @@ -25,13 +25,13 @@ /> </td> <template v-if="!leftPanelCollapsed"> - <td class="hidden-sm hidden-xs"> + <td class="d-none d-sm-none d-md-block"> <skeleton-loading-container :small="true" /> </td> - <td class="hidden-xs"> + <td class="d-none d-sm-block"> <skeleton-loading-container class="animation-container-right" :small="true" diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js index 48d4cc43198..83fe22f40a4 100644 --- a/app/assets/javascripts/ide/constants.js +++ b/app/assets/javascripts/ide/constants.js @@ -5,8 +5,6 @@ export const FILE_FINDER_EMPTY_ROW_HEIGHT = 33; export const MAX_WINDOW_HEIGHT_COMPACT = 750; -export const COMMIT_ITEM_PADDING = 32; - // Commit message textarea export const MAX_TITLE_LENGTH = 50; export const MAX_BODY_LENGTH = 72; diff --git a/app/assets/javascripts/ide/ide_router.js b/app/assets/javascripts/ide/ide_router.js index adca85dc65b..a21cec4e8d8 100644 --- a/app/assets/javascripts/ide/ide_router.js +++ b/app/assets/javascripts/ide/ide_router.js @@ -41,7 +41,7 @@ const router = new VueRouter({ component: EmptyRouterComponent, children: [ { - path: ':targetmode(edit|tree|blob)/:branch/*', + path: ':targetmode(edit|tree|blob)/*', component: EmptyRouterComponent, }, { @@ -63,23 +63,27 @@ router.beforeEach((to, from, next) => { .then(() => { const fullProjectId = `${to.params.namespace}/${to.params.project}`; - if (to.params.branch) { - store.dispatch('setCurrentBranchId', to.params.branch); + const baseSplit = to.params[0].split('/-/'); + const branchId = baseSplit[0].slice(-1) === '/' ? baseSplit[0].slice(0, -1) : baseSplit[0]; + + if (branchId) { + const basePath = baseSplit.length > 1 ? baseSplit[1] : ''; + + store.dispatch('setCurrentBranchId', branchId); store.dispatch('getBranchData', { projectId: fullProjectId, - branchId: to.params.branch, + branchId, }); store .dispatch('getFiles', { projectId: fullProjectId, - branchId: to.params.branch, + branchId, }) .then(() => { - if (to.params[0]) { - const path = - to.params[0].slice(-1) === '/' ? to.params[0].slice(0, -1) : to.params[0]; + if (basePath) { + const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath; const treeEntryKey = Object.keys(store.state.entries).find( key => key === path && !store.state.entries[key].pending, ); diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js index a12e637616a..e8b51f2b516 100644 --- a/app/assets/javascripts/ide/services/index.js +++ b/app/assets/javascripts/ide/services/index.js @@ -75,4 +75,8 @@ export default { }, }); }, + lastCommitPipelines({ getters }) { + const commitSha = getters.lastCommit.id; + return Api.commitPipelines(getters.currentProject.path_with_namespace, commitSha); + }, }; diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js index b6baa693104..13aea91d8ba 100644 --- a/app/assets/javascripts/ide/stores/actions/file.js +++ b/app/assets/javascripts/ide/stores/actions/file.js @@ -63,7 +63,9 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive const file = state.entries[path]; commit(types.TOGGLE_LOADING, { entry: file }); return service - .getFileData(`${gon.relative_url_root ? gon.relative_url_root : ''}${file.url}`) + .getFileData( + `${gon.relative_url_root ? gon.relative_url_root : ''}${file.url.replace('/-/', '/')}`, + ) .then(res => { const pageTitle = decodeURI(normalizeHeaders(res.headers)['PAGE-TITLE']); setPageTitle(pageTitle); diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js index eff9bc03651..cece9154c82 100644 --- a/app/assets/javascripts/ide/stores/actions/project.js +++ b/app/assets/javascripts/ide/stores/actions/project.js @@ -1,6 +1,11 @@ +import Visibility from 'visibilityjs'; import flash from '~/flash'; +import { __ } from '~/locale'; import service from '../../services'; import * as types from '../mutation_types'; +import Poll from '../../../lib/utils/poll'; + +let eTagPoll; export const getProjectData = ( { commit, state, dispatch }, @@ -21,7 +26,7 @@ export const getProjectData = ( }) .catch(() => { flash( - 'Error loading project data. Please try again.', + __('Error loading project data. Please try again.'), 'alert', document, null, @@ -59,7 +64,7 @@ export const getBranchData = ( }) .catch(() => { flash( - 'Error loading branch data. Please try again.', + __('Error loading branch data. Please try again.'), 'alert', document, null, @@ -73,25 +78,74 @@ export const getBranchData = ( } }); -export const refreshLastCommitData = ( - { commit, state, dispatch }, - { projectId, branchId } = {}, -) => service - .getBranchData(projectId, branchId) - .then(({ data }) => { - commit(types.SET_BRANCH_COMMIT, { - projectId, - branchId, - commit: data.commit, +export const refreshLastCommitData = ({ commit, state, dispatch }, { projectId, branchId } = {}) => + service + .getBranchData(projectId, branchId) + .then(({ data }) => { + commit(types.SET_BRANCH_COMMIT, { + projectId, + branchId, + commit: data.commit, + }); + }) + .catch(() => { + flash(__('Error loading last commit.'), 'alert', document, null, false, true); }); - }) - .catch(() => { - flash( - 'Error loading last commit.', - 'alert', - document, - null, - false, - true, + +export const pollSuccessCallBack = ({ commit, state, dispatch }, { data }) => { + if (data.pipelines && data.pipelines.length) { + const lastCommitHash = + state.projects[state.currentProjectId].branches[state.currentBranchId].commit.id; + const lastCommitPipeline = data.pipelines.find( + pipeline => pipeline.commit.id === lastCommitHash, ); + commit(types.SET_LAST_COMMIT_PIPELINE, { + projectId: state.currentProjectId, + branchId: state.currentBranchId, + pipeline: lastCommitPipeline || {}, + }); + } + + return data; +}; + +export const pipelinePoll = ({ getters, dispatch }) => { + eTagPoll = new Poll({ + resource: service, + method: 'lastCommitPipelines', + data: { + getters, + }, + successCallback: ({ data }) => dispatch('pollSuccessCallBack', { data }), + errorCallback: () => { + flash( + __('Something went wrong while fetching the latest pipeline status.'), + 'alert', + document, + null, + false, + true, + ); + }, }); + + if (!Visibility.hidden()) { + eTagPoll.makeRequest(); + } + + Visibility.change(() => { + if (!Visibility.hidden()) { + eTagPoll.restart(); + } else { + eTagPoll.stop(); + } + }); +}; + +export const stopPipelinePolling = () => { + eTagPoll.stop(); +}; + +export const restartPipelinePolling = () => { + eTagPoll.restart(); +}; diff --git a/app/assets/javascripts/ide/stores/index.js b/app/assets/javascripts/ide/stores/index.js index 7c82ce7976b..699710055e3 100644 --- a/app/assets/javascripts/ide/stores/index.js +++ b/app/assets/javascripts/ide/stores/index.js @@ -5,6 +5,7 @@ import * as actions from './actions'; import * as getters from './getters'; import mutations from './mutations'; import commitModule from './modules/commit'; +import pipelines from './modules/pipelines'; Vue.use(Vuex); @@ -15,5 +16,6 @@ export default new Vuex.Store({ getters, modules: { commit: commitModule, + pipelines, }, }); diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js index b85246b2502..cd25c3060f2 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/actions.js +++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js @@ -204,17 +204,23 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo dispatch('updateViewer', 'editor', { root: true }); router.push( - `/project/${rootState.currentProjectId}/blob/${getters.branchName}/${ + `/project/${rootState.currentProjectId}/blob/${getters.branchName}/-/${ rootGetters.activeFile.path }`, ); } }) .then(() => dispatch('updateCommitAction', consts.COMMIT_TO_CURRENT_BRANCH)) - .then(() => dispatch('refreshLastCommitData', { - projectId: rootState.currentProjectId, - branchId: rootState.currentBranchId, - }, { root: true })); + .then(() => + dispatch( + 'refreshLastCommitData', + { + projectId: rootState.currentProjectId, + branchId: rootState.currentBranchId, + }, + { root: true }, + ), + ); }) .catch(err => { let errMsg = __('Error committing changes. Please try again.'); diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js new file mode 100644 index 00000000000..07f7b201f2e --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js @@ -0,0 +1,49 @@ +import { __ } from '../../../../locale'; +import Api from '../../../../api'; +import flash from '../../../../flash'; +import * as types from './mutation_types'; + +export const requestLatestPipeline = ({ commit }) => commit(types.REQUEST_LATEST_PIPELINE); +export const receiveLatestPipelineError = ({ commit }) => { + flash(__('There was an error loading latest pipeline')); + commit(types.RECEIVE_LASTEST_PIPELINE_ERROR); +}; +export const receiveLatestPipelineSuccess = ({ commit }, pipeline) => + commit(types.RECEIVE_LASTEST_PIPELINE_SUCCESS, pipeline); + +export const fetchLatestPipeline = ({ dispatch, rootState }, sha) => { + dispatch('requestLatestPipeline'); + + return Api.pipelines(rootState.currentProjectId, { sha, per_page: '1' }) + .then(({ data }) => { + dispatch('receiveLatestPipelineSuccess', data.pop()); + }) + .catch(() => dispatch('receiveLatestPipelineError')); +}; + +export const requestJobs = ({ commit }) => commit(types.REQUEST_JOBS); +export const receiveJobsError = ({ commit }) => { + flash(__('There was an error loading jobs')); + commit(types.RECEIVE_JOBS_ERROR); +}; +export const receiveJobsSuccess = ({ commit }, data) => commit(types.RECEIVE_JOBS_SUCCESS, data); + +export const fetchJobs = ({ dispatch, state, rootState }, page = '1') => { + dispatch('requestJobs'); + + Api.pipelineJobs(rootState.currentProjectId, state.latestPipeline.id, { + page, + }) + .then(({ data, headers }) => { + const nextPage = headers && headers['x-next-page']; + + dispatch('receiveJobsSuccess', data); + + if (nextPage) { + dispatch('fetchJobs', nextPage); + } + }) + .catch(() => dispatch('receiveJobsError')); +}; + +export default () => {}; diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/getters.js b/app/assets/javascripts/ide/stores/modules/pipelines/getters.js new file mode 100644 index 00000000000..d6c91f5b64d --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pipelines/getters.js @@ -0,0 +1,7 @@ +export const hasLatestPipeline = state => !state.isLoadingPipeline && !!state.latestPipeline; + +export const failedJobs = state => + state.stages.reduce( + (acc, stage) => acc.concat(stage.jobs.filter(job => job.status === 'failed')), + [], + ); diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/index.js b/app/assets/javascripts/ide/stores/modules/pipelines/index.js new file mode 100644 index 00000000000..b44c3141b81 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pipelines/index.js @@ -0,0 +1,12 @@ +import state from './state'; +import * as actions from './actions'; +import mutations from './mutations'; +import * as getters from './getters'; + +export default { + namespaced: true, + state: state(), + actions, + mutations, + getters, +}; diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js b/app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js new file mode 100644 index 00000000000..6b5701670a6 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js @@ -0,0 +1,7 @@ +export const REQUEST_LATEST_PIPELINE = 'REQUEST_LATEST_PIPELINE'; +export const RECEIVE_LASTEST_PIPELINE_ERROR = 'RECEIVE_LASTEST_PIPELINE_ERROR'; +export const RECEIVE_LASTEST_PIPELINE_SUCCESS = 'RECEIVE_LASTEST_PIPELINE_SUCCESS'; + +export const REQUEST_JOBS = 'REQUEST_JOBS'; +export const RECEIVE_JOBS_ERROR = 'RECEIVE_JOBS_ERROR'; +export const RECEIVE_JOBS_SUCCESS = 'RECEIVE_JOBS_SUCCESS'; diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js b/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js new file mode 100644 index 00000000000..2b16e57b386 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pipelines/mutations.js @@ -0,0 +1,53 @@ +/* eslint-disable no-param-reassign */ +import * as types from './mutation_types'; + +export default { + [types.REQUEST_LATEST_PIPELINE](state) { + state.isLoadingPipeline = true; + }, + [types.RECEIVE_LASTEST_PIPELINE_ERROR](state) { + state.isLoadingPipeline = false; + }, + [types.RECEIVE_LASTEST_PIPELINE_SUCCESS](state, pipeline) { + state.isLoadingPipeline = false; + + if (pipeline) { + state.latestPipeline = { + id: pipeline.id, + status: pipeline.status, + }; + } + }, + [types.REQUEST_JOBS](state) { + state.isLoadingJobs = true; + }, + [types.RECEIVE_JOBS_ERROR](state) { + state.isLoadingJobs = false; + }, + [types.RECEIVE_JOBS_SUCCESS](state, jobs) { + state.isLoadingJobs = false; + + state.stages = jobs.reduce((acc, job) => { + let stage = acc.find(s => s.title === job.stage); + + if (!stage) { + stage = { + title: job.stage, + jobs: [], + }; + + acc.push(stage); + } + + stage.jobs = stage.jobs.concat({ + id: job.id, + name: job.name, + status: job.status, + stage: job.stage, + duration: job.duration, + }); + + return acc; + }, state.stages); + }, +}; diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/state.js b/app/assets/javascripts/ide/stores/modules/pipelines/state.js new file mode 100644 index 00000000000..6f22542aaea --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pipelines/state.js @@ -0,0 +1,6 @@ +export default () => ({ + isLoadingPipeline: false, + isLoadingJobs: false, + latestPipeline: null, + stages: [], +}); diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js index a3fb3232f1d..0a3f8d031c4 100644 --- a/app/assets/javascripts/ide/stores/mutation_types.js +++ b/app/assets/javascripts/ide/stores/mutation_types.js @@ -23,6 +23,7 @@ export const SET_BRANCH = 'SET_BRANCH'; export const SET_BRANCH_COMMIT = 'SET_BRANCH_COMMIT'; export const SET_BRANCH_WORKING_REFERENCE = 'SET_BRANCH_WORKING_REFERENCE'; export const TOGGLE_BRANCH_OPEN = 'TOGGLE_BRANCH_OPEN'; +export const SET_LAST_COMMIT_PIPELINE = 'SET_LAST_COMMIT_PIPELINE'; // Tree mutation types export const SET_DIRECTORY_DATA = 'SET_DIRECTORY_DATA'; diff --git a/app/assets/javascripts/ide/stores/mutations/branch.js b/app/assets/javascripts/ide/stores/mutations/branch.js index e09f88878f4..f17ec4da308 100644 --- a/app/assets/javascripts/ide/stores/mutations/branch.js +++ b/app/assets/javascripts/ide/stores/mutations/branch.js @@ -14,6 +14,10 @@ export default { treeId: `${projectPath}/${branchName}`, active: true, workingReference: '', + commit: { + ...branch.commit, + pipeline: {}, + }, }, }, }); @@ -28,4 +32,9 @@ export default { commit, }); }, + [types.SET_LAST_COMMIT_PIPELINE](state, { projectId, branchId, pipeline }) { + Object.assign(state.projects[projectId].branches[branchId].commit, { + pipeline, + }); + }, }; diff --git a/app/assets/javascripts/ide/stores/workers/files_decorator_worker.js b/app/assets/javascripts/ide/stores/workers/files_decorator_worker.js index d249b05f47c..0a1c253c637 100644 --- a/app/assets/javascripts/ide/stores/workers/files_decorator_worker.js +++ b/app/assets/javascripts/ide/stores/workers/files_decorator_worker.js @@ -26,7 +26,7 @@ self.addEventListener('message', e => { id: folderPath, name: folderName, path: folderPath, - url: `/${projectId}/tree/${branchId}/${folderPath}/`, + url: `/${projectId}/tree/${branchId}/-/${folderPath}/`, type: 'tree', parentTreeUrl: parentFolder ? parentFolder.url : `/${projectId}/tree/${branchId}/`, tempFile, @@ -64,7 +64,7 @@ self.addEventListener('message', e => { id: path, name: blobName, path, - url: `/${projectId}/blob/${branchId}/${path}`, + url: `/${projectId}/blob/${branchId}/-/${path}`, type: 'blob', parentTreeUrl: fileFolder ? fileFolder.url : `/${projectId}/blob/${branchId}`, tempFile, diff --git a/app/assets/javascripts/issue_show/components/edit_actions.vue b/app/assets/javascripts/issue_show/components/edit_actions.vue index a539506bce2..7ef5e679881 100644 --- a/app/assets/javascripts/issue_show/components/edit_actions.vue +++ b/app/assets/javascripts/issue_show/components/edit_actions.vue @@ -51,7 +51,7 @@ <template> <div class="prepend-top-default append-bottom-default clearfix"> <button - class="btn btn-save pull-left" + class="btn btn-save float-left" :class="{ disabled: formState.updateLoading || !isSubmitEnabled }" type="submit" :disabled="formState.updateLoading || !isSubmitEnabled" @@ -64,14 +64,14 @@ </i> </button> <button - class="btn btn-default pull-right" + class="btn btn-default float-right" type="button" @click="closeForm"> Cancel </button> <button v-if="shouldShowDeleteButton" - class="btn btn-danger pull-right append-right-default" + class="btn btn-danger float-right append-right-default" :class="{ disabled: deleteLoading }" type="button" :disabled="deleteLoading" diff --git a/app/assets/javascripts/issue_show/components/form.vue b/app/assets/javascripts/issue_show/components/form.vue index 779705e19ac..ab8bd34762f 100644 --- a/app/assets/javascripts/issue_show/components/form.vue +++ b/app/assets/javascripts/issue_show/components/form.vue @@ -84,7 +84,7 @@ <div :class="{ 'col-sm-8 col-lg-9': hasIssuableTemplates, - 'col-xs-12': !hasIssuableTemplates, + 'col-12': !hasIssuableTemplates, }" > <title-field diff --git a/app/assets/javascripts/job.js b/app/assets/javascripts/job.js index ace45e9dd29..c67bd7fb0c6 100644 --- a/app/assets/javascripts/job.js +++ b/app/assets/javascripts/job.js @@ -1,5 +1,6 @@ import $ from 'jquery'; import _ from 'underscore'; +import StickyFill from 'stickyfilljs'; import axios from './lib/utils/axios_utils'; import { visitUrl } from './lib/utils/url_utility'; import bp from './breakpoints'; @@ -82,17 +83,11 @@ export default class Job { /** If the browser does not support position sticky, it returns the position as static. If the browser does support sticky, then we allow the browser to handle it, if not - then we default back to Bootstraps affix + then we use a polyfill **/ if (this.$topBar.css('position') !== 'static') return; - const offsetTop = this.$buildTrace.offset().top; - - this.$topBar.affix({ - offset: { - top: offsetTop, - }, - }); + StickyFill.add(this.$topBar); } // eslint-disable-next-line class-methods-use-this diff --git a/app/assets/javascripts/jobs/components/header.vue b/app/assets/javascripts/jobs/components/header.vue index 21b545d6cab..c1044f4cd42 100644 --- a/app/assets/javascripts/jobs/components/header.vue +++ b/app/assets/javascripts/jobs/components/header.vue @@ -56,7 +56,7 @@ export default { actions.push({ label: 'New issue', path: this.job.new_issue_path, - cssClass: 'js-new-issue btn btn-new btn-inverted visible-md-block visible-lg-block', + cssClass: 'js-new-issue btn btn-new btn-inverted d-none d-md-block d-lg-block d-xl-block', type: 'link', }); } diff --git a/app/assets/javascripts/jobs/components/sidebar_detail_row.vue b/app/assets/javascripts/jobs/components/sidebar_detail_row.vue index dfe87d89a39..83560a8ff0e 100644 --- a/app/assets/javascripts/jobs/components/sidebar_detail_row.vue +++ b/app/assets/javascripts/jobs/components/sidebar_detail_row.vue @@ -39,7 +39,7 @@ <span v-if="hasHelpURL" - class="help-button pull-right" + class="help-button float-right" > <a :href="helpUrl" diff --git a/app/assets/javascripts/jobs/components/sidebar_details_block.vue b/app/assets/javascripts/jobs/components/sidebar_details_block.vue index db19dc9b238..82fec7e936b 100644 --- a/app/assets/javascripts/jobs/components/sidebar_details_block.vue +++ b/app/assets/javascripts/jobs/components/sidebar_details_block.vue @@ -48,7 +48,7 @@ export default { return `${this.job.runner.description} (#${this.job.runner.id})`; }, retryButtonClass() { - let className = 'js-retry-button pull-right btn btn-retry visible-md-block visible-lg-block'; + let className = 'js-retry-button pull-right btn btn-retry d-none d-md-block d-lg-block d-xl-block'; className += this.job.status && this.job.recoverable ? ' btn-primary' @@ -105,7 +105,7 @@ export default { type="button" :aria-label="__('Toggle Sidebar')" class="btn btn-blank gutter-toggle pull-right - visible-xs-block visible-sm-block js-sidebar-build-toggle" + d-block d-sm-block d-md-none js-sidebar-build-toggle" > <i aria-hidden="true" diff --git a/app/assets/javascripts/label_manager.js b/app/assets/javascripts/label_manager.js index e230dbbd4ac..6af22ecc990 100644 --- a/app/assets/javascripts/label_manager.js +++ b/app/assets/javascripts/label_manager.js @@ -35,7 +35,7 @@ export default class LabelManager { const $label = $(`#${$btn.data('domId')}`); const action = $btn.parents('.js-prioritized-labels').length ? 'remove' : 'add'; const $tooltip = $(`#${$btn.find('.has-tooltip:visible').attr('aria-describedby')}`); - $tooltip.tooltip('destroy'); + $tooltip.tooltip('dispose'); _this.toggleLabelPriority($label, action); _this.toggleEmptyState($label, $btn, action); } diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js index 9b62cfb8206..eafdaf4a672 100644 --- a/app/assets/javascripts/labels_select.js +++ b/app/assets/javascripts/labels_select.js @@ -120,7 +120,7 @@ export default class LabelsSelect { $sidebarLabelTooltip .attr('title', labelTooltipTitle) - .tooltip('fixTitle'); + .tooltip('_fixTitle'); $('.has-tooltip', $value).tooltip({ container: 'body' diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 9ff2042475b..8b5445d012b 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -51,7 +51,7 @@ export const rstrip = (val) => { return val; }; -export const updateTooltipTitle = ($tooltipEl, newTitle) => $tooltipEl.attr('title', newTitle).tooltip('fixTitle'); +export const updateTooltipTitle = ($tooltipEl, newTitle) => $tooltipEl.attr('title', newTitle).tooltip('_fixTitle'); export const disableButtonIfEmptyField = (fieldSelector, buttonSelector, eventName = 'input') => { const field = $(fieldSelector); diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index c3d94d63c13..0ff23bbb061 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -2,10 +2,7 @@ import $ from 'jquery'; import timeago from 'timeago.js'; import dateFormat from 'vendor/date.format'; import { pluralize } from './text_utility'; -import { - languageCode, - s__, -} from '../../locale'; +import { languageCode, s__ } from '../../locale'; window.timeago = timeago; window.dateFormat = dateFormat; @@ -17,11 +14,37 @@ window.dateFormat = dateFormat; * * @param {Boolean} abbreviated */ -const getMonthNames = (abbreviated) => { +const getMonthNames = abbreviated => { if (abbreviated) { - return [s__('Jan'), s__('Feb'), s__('Mar'), s__('Apr'), s__('May'), s__('Jun'), s__('Jul'), s__('Aug'), s__('Sep'), s__('Oct'), s__('Nov'), s__('Dec')]; + return [ + s__('Jan'), + s__('Feb'), + s__('Mar'), + s__('Apr'), + s__('May'), + s__('Jun'), + s__('Jul'), + s__('Aug'), + s__('Sep'), + s__('Oct'), + s__('Nov'), + s__('Dec'), + ]; } - return [s__('January'), s__('February'), s__('March'), s__('April'), s__('May'), s__('June'), s__('July'), s__('August'), s__('September'), s__('October'), s__('November'), s__('December')]; + return [ + s__('January'), + s__('February'), + s__('March'), + s__('April'), + s__('May'), + s__('June'), + s__('July'), + s__('August'), + s__('September'), + s__('October'), + s__('November'), + s__('December'), + ]; }; /** @@ -29,7 +52,8 @@ const getMonthNames = (abbreviated) => { * @param {date} date * @returns {String} */ -export const getDayName = date => ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][date.getDay()]; +export const getDayName = date => + ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][date.getDay()]; /** * @example @@ -55,7 +79,7 @@ export function getTimeago() { if (!timeagoInstance) { const localeRemaining = function getLocaleRemaining(number, index) { return [ - [s__('Timeago|less than a minute ago'), s__('Timeago|in a while')], + [s__('Timeago|less than a minute ago'), s__('Timeago|right now')], [s__('Timeago|less than a minute ago'), s__('Timeago|%s seconds remaining')], [s__('Timeago|about a minute ago'), s__('Timeago|1 minute remaining')], [s__('Timeago|%s minutes ago'), s__('Timeago|%s minutes remaining')], @@ -73,7 +97,7 @@ export function getTimeago() { }; const locale = function getLocale(number, index) { return [ - [s__('Timeago|less than a minute ago'), s__('Timeago|in a while')], + [s__('Timeago|less than a minute ago'), s__('Timeago|right now')], [s__('Timeago|less than a minute ago'), s__('Timeago|in %s seconds')], [s__('Timeago|about a minute ago'), s__('Timeago|in 1 minute')], [s__('Timeago|%s minutes ago'), s__('Timeago|in %s minutes')], @@ -102,7 +126,7 @@ export function getTimeago() { * For the given element, renders a timeago instance. * @param {jQuery} $els */ -export const renderTimeago = ($els) => { +export const renderTimeago = $els => { const timeagoEls = $els || document.querySelectorAll('.js-timeago-render'); // timeago.js sets timeouts internally for each timeago value to be updated in real time @@ -119,7 +143,7 @@ export const localTimeAgo = ($timeagoEls, setTimeago = true) => { if (setTimeago) { // Recreate with custom template $(el).tooltip({ - template: '<div class="tooltip local-timeago" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', + template: '<div class="tooltip local-timeago" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>', }); } @@ -141,7 +165,9 @@ export const timeFor = (time, expiredLabel) => { if (new Date(time) < new Date()) { return expiredLabel || s__('Timeago|Past due'); } - return getTimeago().format(time, `${timeagoLanguageCode}-remaining`).trim(); + return getTimeago() + .format(time, `${timeagoLanguageCode}-remaining`) + .trim(); }; export const getDayDifference = (a, b) => { @@ -161,7 +187,7 @@ export const getDayDifference = (a, b) => { export function timeIntervalInWords(intervalInSeconds) { const secondsInteger = parseInt(intervalInSeconds, 10); const minutes = Math.floor(secondsInteger / 60); - const seconds = secondsInteger - (minutes * 60); + const seconds = secondsInteger - minutes * 60; let text = ''; if (minutes >= 1) { @@ -178,8 +204,34 @@ export function dateInWords(date, abbreviated = false, hideYear = false) { const month = date.getMonth(); const year = date.getFullYear(); - const monthNames = [s__('January'), s__('February'), s__('March'), s__('April'), s__('May'), s__('June'), s__('July'), s__('August'), s__('September'), s__('October'), s__('November'), s__('December')]; - const monthNamesAbbr = [s__('Jan'), s__('Feb'), s__('Mar'), s__('Apr'), s__('May'), s__('Jun'), s__('Jul'), s__('Aug'), s__('Sep'), s__('Oct'), s__('Nov'), s__('Dec')]; + const monthNames = [ + s__('January'), + s__('February'), + s__('March'), + s__('April'), + s__('May'), + s__('June'), + s__('July'), + s__('August'), + s__('September'), + s__('October'), + s__('November'), + s__('December'), + ]; + const monthNamesAbbr = [ + s__('Jan'), + s__('Feb'), + s__('Mar'), + s__('Apr'), + s__('May'), + s__('Jun'), + s__('Jul'), + s__('Aug'), + s__('Sep'), + s__('Oct'), + s__('Nov'), + s__('Dec'), + ]; const monthName = abbreviated ? monthNamesAbbr[month] : monthNames[month]; @@ -210,7 +262,7 @@ export const monthInWords = (date, abbreviated = false) => { * * @param {Date} date */ -export const totalDaysInMonth = (date) => { +export const totalDaysInMonth = date => { if (!date) { return 0; } @@ -223,12 +275,20 @@ export const totalDaysInMonth = (date) => { * * @param {Date} date */ -export const getSundays = (date) => { +export const getSundays = date => { if (!date) { return []; } - const daysToSunday = ['Saturday', 'Friday', 'Thursday', 'Wednesday', 'Tuesday', 'Monday', 'Sunday']; + const daysToSunday = [ + 'Saturday', + 'Friday', + 'Thursday', + 'Wednesday', + 'Tuesday', + 'Monday', + 'Sunday', + ]; const month = date.getMonth(); const year = date.getFullYear(); diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 247aeb481c6..9803bebfd10 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -46,9 +46,9 @@ document.addEventListener('beforeunload', () => { // Unbind scroll events $(document).off('scroll'); // Close any open tooltips - $('.has-tooltip, [data-toggle="tooltip"]').tooltip('destroy'); + $('.has-tooltip, [data-toggle="tooltip"]').tooltip('dispose'); // Close any open popover - $('[data-toggle="popover"]').popover('destroy'); + $('[data-toggle="popover"]').popover('dispose'); }); window.addEventListener('hashchange', handleLocationHash); @@ -111,7 +111,7 @@ document.addEventListener('DOMContentLoaded', () => { $('.remove-row').on('ajax:success', function removeRowAjaxSuccessCallback() { $(this) - .tooltip('destroy') + .tooltip('dispose') .closest('li') .fadeOut(); }); @@ -141,9 +141,9 @@ document.addEventListener('DOMContentLoaded', () => { }); // Initialize tooltips - $.fn.tooltip.Constructor.DEFAULTS.trigger = 'hover'; $body.tooltip({ selector: '.has-tooltip, [data-toggle="tooltip"]', + trigger: 'hover', placement(tip, el) { return $(el).data('placement') || 'bottom'; }, @@ -196,7 +196,7 @@ document.addEventListener('DOMContentLoaded', () => { $container.remove(); }); - $('.navbar-toggle').on('click', () => { + $('.navbar-toggler').on('click', () => { $('.header-content').toggleClass('menu-expanded'); gl.lazyLoader.loadCheck(); }); diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js index db1d09eb2f2..70f185e3656 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js +++ b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js @@ -351,7 +351,7 @@ import Cookies from 'js-cookie'; }, getCommitButtonText() { - const initial = 'Commit conflict resolution'; + const initial = 'Commit to source branch'; const inProgress = 'Committing...'; return this.state ? this.state.isSubmitting ? inProgress : initial : initial; diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index 3f84f4b9499..3548c07aea8 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -362,7 +362,7 @@ export default class MergeRequestTabs { // // status - Boolean, true to show, false to hide toggleLoading(status) { - $('.mr-loading-status .loading').toggle(status); + $('.mr-loading-status .loading').toggleClass('hidden', status); } diffViewType() { diff --git a/app/assets/javascripts/monitoring/components/graph_group.vue b/app/assets/javascripts/monitoring/components/graph_group.vue index a6dbe42a8f0..241627f9790 100644 --- a/app/assets/javascripts/monitoring/components/graph_group.vue +++ b/app/assets/javascripts/monitoring/components/graph_group.vue @@ -17,12 +17,12 @@ export default { <template> <div v-if="showPanels" - class="panel panel-default prometheus-panel" + class="card prometheus-panel" > - <div class="panel-heading"> + <div class="card-header"> <h4>{{ name }}</h4> </div> - <div class="panel-body prometheus-graph-group"> + <div class="card-body prometheus-graph-group"> <slot></slot> </div> </div> diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 96f2b3eac98..b2c1a26bbae 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -1231,8 +1231,8 @@ export default class Notes { const isForced = forceShow === true || forceShow === false; const showNow = forceShow === true || (!isCurrentlyShown && !isForced); - targetRow.toggle(showNow); - notesContent.toggle(showNow); + targetRow.toggleClass('hide', !showNow); + notesContent.toggleClass('hide', !showNow); } if (addForm) { @@ -1675,7 +1675,7 @@ export default class Notes { <div class="note-header"> <div class="note-header-info"> <a href="/${_.escape(currentUsername)}"> - <span class="hidden-xs">${_.escape( + <span class="d-none d-sm-block">${_.escape( currentUsername, )}</span> <span class="note-headline-light">${_.escape( @@ -1694,7 +1694,7 @@ export default class Notes { </li>`, ); - $tempNote.find('.hidden-xs').text(_.escape(currentUserFullname)); + $tempNote.find('.d-none.d-sm-block').text(_.escape(currentUserFullname)); $tempNote .find('.note-headline-light') .text(`@${_.escape(currentUsername)}`); diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue index 48642c4a086..72d7e22fba0 100644 --- a/app/assets/javascripts/notes/components/comment_form.vue +++ b/app/assets/javascripts/notes/components/comment_form.vue @@ -321,7 +321,7 @@ Please check your network connection and try again.`; <li class="timeline-entry"> <div class="timeline-entry-inner"> <div class="flash-container error-alert timeline-content"></div> - <div class="timeline-icon hidden-xs hidden-sm"> + <div class="timeline-icon d-none d-sm-none d-md-block"> <user-avatar-link v-if="author" :link-href="author.path" @@ -369,7 +369,7 @@ js-gfm-input js-autosize markdown-area js-vue-textarea" </markdown-field> <div class="note-form-actions"> <div - class="pull-left btn-group + class="float-left btn-group append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"> <button @click.prevent="handleSave()" @@ -383,6 +383,7 @@ append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown" name="button" type="button" class="btn comment-btn note-type-toggle js-note-new-discussion dropdown-toggle" + data-display="static" data-toggle="dropdown" aria-label="Open comment type dropdown"> <i diff --git a/app/assets/javascripts/notes/components/note_edited_text.vue b/app/assets/javascripts/notes/components/note_edited_text.vue index 4ddca918495..2dc39d1a186 100644 --- a/app/assets/javascripts/notes/components/note_edited_text.vue +++ b/app/assets/javascripts/notes/components/note_edited_text.vue @@ -32,17 +32,17 @@ export default { <template> <div :class="className"> {{ actionText }} - <time-ago-tooltip - :time="editedAt" - tooltip-placement="bottom" - /> <template v-if="editedBy"> - by + {{ s__('ByAuthor|by') }} <a :href="editedBy.path" class="js-vue-author author_link"> {{ editedBy.name }} </a> </template> + <time-ago-tooltip + :time="editedAt" + tooltip-placement="bottom" + /> </div> </template> diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue index c3d1ef1fcc6..a4081957207 100644 --- a/app/assets/javascripts/notes/components/note_header.vue +++ b/app/assets/javascripts/notes/components/note_header.vue @@ -62,6 +62,21 @@ export default { <template> <div class="note-header-info"> + <div + v-if="includeToggle" + class="discussion-actions"> + <button + @click="handleToggle" + class="note-action-button discussion-toggle-button js-vue-toggle-button" + type="button"> + <i + :class="toggleChevronClass" + class="fa" + aria-hidden="true"> + </i> + {{ __('Toggle discussion') }} + </button> + </div> <a :href="author.path"> <span class="note-header-author-name">{{ author.name }}</span> <span class="note-headline-light"> @@ -78,10 +93,13 @@ export default { v-html="actionTextHtml" class="system-note-message"> </span> + <span class="system-note-separator"> + · + </span> <a :href="noteTimestampLink" @click="updateTargetNoteHash" - class="note-timestamp"> + class="note-timestamp system-note-separator"> <time-ago-tooltip :time="createdAt" tooltip-placement="bottom" @@ -95,20 +113,5 @@ export default { </i> </span> </span> - <div - v-if="includeToggle" - class="discussion-actions"> - <button - @click="handleToggle" - class="note-action-button discussion-toggle-button js-vue-toggle-button" - type="button"> - <i - :class="toggleChevronClass" - class="fa" - aria-hidden="true"> - </i> - Toggle discussion - </button> - </div> </div> </template> diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index e0f883a8e08..7f5aacaa3a2 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -100,7 +100,7 @@ export default { : 'div'; }, wrapperClass() { - return this.isDiffDiscussion ? '' : 'panel panel-default'; + return this.isDiffDiscussion ? '' : 'card'; }, }, mounted() { @@ -263,7 +263,7 @@ Please check your network connection and try again.`; class="discussion-reply-holder"> <template v-if="!isReplying && canReply"> <div - class="btn-group-justified discussion-with-resolve-btn" + class="btn-group d-flex discussion-with-resolve-btn" role="group"> <div class="btn-group" diff --git a/app/assets/javascripts/notifications_form.js b/app/assets/javascripts/notifications_form.js index 9e6cf67dff0..00e27ca0e70 100644 --- a/app/assets/javascripts/notifications_form.js +++ b/app/assets/javascripts/notifications_form.js @@ -15,7 +15,7 @@ export default class NotificationsForm { toggleCheckbox(e) { const $checkbox = $(e.currentTarget); - const $parent = $checkbox.closest('.checkbox'); + const $parent = $checkbox.closest('.form-check'); this.saveEvent($checkbox, $parent); } diff --git a/app/assets/javascripts/pages/admin/admin.js b/app/assets/javascripts/pages/admin/admin.js index 91f154b7ecd..ff4d6ab15f9 100644 --- a/app/assets/javascripts/pages/admin/admin.js +++ b/app/assets/javascripts/pages/admin/admin.js @@ -25,7 +25,7 @@ export default function adminInit() { $('body').on('click', '.js-toggle-colors-link', (e) => { e.preventDefault(); - $('.js-toggle-colors-container').toggle(); + $('.js-toggle-colors-container').toggleClass('hide'); }); $('.log-tabs a').on('click', function logTabsClick(e) { diff --git a/app/assets/javascripts/pages/ldap/omniauth_callbacks/index.js b/app/assets/javascripts/pages/ldap/omniauth_callbacks/index.js new file mode 100644 index 00000000000..edd7e38471b --- /dev/null +++ b/app/assets/javascripts/pages/ldap/omniauth_callbacks/index.js @@ -0,0 +1,3 @@ +import initU2F from '../../../shared/sessions/u2f'; + +document.addEventListener('DOMContentLoaded', initU2F); diff --git a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js index fbdef329ab2..8e8f47c21d8 100644 --- a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js +++ b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js @@ -5,7 +5,7 @@ document.addEventListener('DOMContentLoaded', () => { const twoFactorNode = document.querySelector('.js-two-factor-auth'); const skippable = twoFactorNode.dataset.twoFactorSkippable === 'true'; if (skippable) { - const button = `<a class="btn btn-xs btn-warning pull-right" data-method="patch" href="${twoFactorNode.dataset.two_factor_skip_url}">Configure it later</a>`; + const button = `<a class="btn btn-sm btn-warning float-right" data-method="patch" href="${twoFactorNode.dataset.two_factor_skip_url}">Configure it later</a>`; const flashAlert = document.querySelector('.flash-alert .container-fluid'); if (flashAlert) flashAlert.insertAdjacentHTML('beforeend', button); } diff --git a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js index a99ce0f1c36..5316d3e9f3c 100644 --- a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js +++ b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js @@ -1,4 +1,4 @@ -/* 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 */ +/* eslint-disable func-names, space-before-function-paren, 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 $ from 'jquery'; import _ from 'underscore'; @@ -13,17 +13,17 @@ import { dateTickFormat } from '~/lib/utils/tick_formats'; const d3 = { extent, max, select, scaleTime, scaleLinear, axisLeft, axisBottom, area, brushX, timeParse }; -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; +const extend = function(child, parent) { for (const 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; }; export const ContributorsGraph = (function() { function ContributorsGraph() {} ContributorsGraph.prototype.MARGIN = { top: 20, - right: 20, + right: 10, bottom: 30, - left: 50 + left: 40 }; ContributorsGraph.prototype.x_domain = null; @@ -32,6 +32,12 @@ export const ContributorsGraph = (function() { ContributorsGraph.prototype.dates = []; + ContributorsGraph.prototype.determine_width = function(baseWidth, $parentElement) { + const parentPaddingWidth = parseFloat($parentElement.css('padding-left')) + parseFloat($parentElement.css('padding-right')); + const marginWidth = this.MARGIN.left + this.MARGIN.right; + return baseWidth - parentPaddingWidth - marginWidth; + }; + ContributorsGraph.set_x_domain = function(data) { return ContributorsGraph.prototype.x_domain = data; }; @@ -105,11 +111,10 @@ export const ContributorsMasterGraph = (function(superClass) { function ContributorsMasterGraph(data1) { const $parentElement = $('#contributors-master'); - const parentPadding = parseFloat($parentElement.css('padding-left')) + parseFloat($parentElement.css('padding-right')); this.data = data1; this.update_content = this.update_content.bind(this); - this.width = $('.content').width() - parentPadding - (this.MARGIN.left + this.MARGIN.right); + this.width = this.determine_width($('.js-graphs-show').width(), $parentElement); this.height = 200; this.x = null; this.y = null; @@ -122,8 +127,7 @@ export const ContributorsMasterGraph = (function(superClass) { } ContributorsMasterGraph.prototype.process_dates = function(data) { - var dates; - dates = this.get_dates(data); + const dates = this.get_dates(data); this.parse_dates(data); return ContributorsGraph.set_dates(dates); }; @@ -133,8 +137,7 @@ export const ContributorsMasterGraph = (function(superClass) { }; ContributorsMasterGraph.prototype.parse_dates = function(data) { - var parseDate; - parseDate = d3.timeParse("%Y-%m-%d"); + const parseDate = d3.timeParse("%Y-%m-%d"); return data.forEach(function(d) { return d.date = parseDate(d.date); }); @@ -152,7 +155,14 @@ export const ContributorsMasterGraph = (function(superClass) { }; 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 + ")"); + 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 + ")"); + return this.svg; }; ContributorsMasterGraph.prototype.create_area = function(x, y) { @@ -218,12 +228,14 @@ export const ContributorsAuthorGraph = (function(superClass) { extend(ContributorsAuthorGraph, superClass); function ContributorsAuthorGraph(data1) { + const $parentElements = $('.person'); + this.data = data1; // Don't split graph size in half for mobile devices. - if ($(window).width() < 768) { - this.width = $('.content').width() - 80; + if ($(window).width() < 790) { + this.width = this.determine_width($('.js-graphs-show').width(), $parentElements); } else { - this.width = ($('.content').width() / 2) - 100; + this.width = this.determine_width($('.js-graphs-show').width() / 2, $parentElements); } this.height = 200; this.x = null; @@ -249,8 +261,7 @@ export const ContributorsAuthorGraph = (function(superClass) { ContributorsAuthorGraph.prototype.create_area = function(x, y) { return this.area = d3.area().x(function(d) { - var parseDate; - parseDate = d3.timeParse("%Y-%m-%d"); + const parseDate = d3.timeParse("%Y-%m-%d"); return x(parseDate(d)); }).y0(this.height).y1((function(_this) { return function(d) { @@ -264,9 +275,16 @@ export const ContributorsAuthorGraph = (function(superClass) { }; ContributorsAuthorGraph.prototype.create_svg = function() { - var persons = document.querySelectorAll('.person'); + const persons = document.querySelectorAll('.person'); this.list_item = persons[persons.length - 1]; - 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 + ")"); + 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 + ")"); + return this.svg; }; ContributorsAuthorGraph.prototype.draw_path = function(data) { diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue index 25a88f846eb..17b91479ea5 100644 --- a/app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue +++ b/app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue @@ -42,7 +42,7 @@ </label> <span v-if="helpText" - class="help-block" + class="form-text text-muted" > {{ helpText }} </span> diff --git a/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue new file mode 100644 index 00000000000..df21e2f8771 --- /dev/null +++ b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue @@ -0,0 +1,77 @@ +<script> +import _ from 'underscore'; +import GlModal from '~/vue_shared/components/gl_modal.vue'; +import { s__, sprintf } from '~/locale'; + +export default { + components: { + GlModal, + }, + props: { + deleteWikiUrl: { + type: String, + required: true, + default: '', + }, + pageTitle: { + type: String, + required: true, + default: '', + }, + csrfToken: { + type: String, + required: true, + default: '', + }, + }, + computed: { + message() { + return s__('WikiPageConfirmDelete|Are you sure you want to delete this page?'); + }, + title() { + return sprintf( + s__('WikiPageConfirmDelete|Delete page %{pageTitle}?'), + { + pageTitle: _.escape(this.pageTitle), + }, + false, + ); + }, + }, + methods: { + onSubmit() { + this.$refs.form.submit(); + }, + }, +}; +</script> + +<template> + <gl-modal + id="delete-wiki-modal" + :header-title-text="title" + footer-primary-button-variant="danger" + :footer-primary-button-text="s__('WikiPageConfirmDelete|Delete page')" + @submit="onSubmit" + > + {{ message }} + <form + ref="form" + :action="deleteWikiUrl" + method="post" + class="form-horizontal js-requires-input" + > + <input + ref="method" + type="hidden" + name="_method" + value="delete" + /> + <input + type="hidden" + name="authenticity_token" + :value="csrfToken" + /> + </form> + </gl-modal> +</template> diff --git a/app/assets/javascripts/pages/projects/wikis/index.js b/app/assets/javascripts/pages/projects/wikis/index.js index ec01c66ffda..0295653cb29 100644 --- a/app/assets/javascripts/pages/projects/wikis/index.js +++ b/app/assets/javascripts/pages/projects/wikis/index.js @@ -1,12 +1,40 @@ import $ from 'jquery'; +import Vue from 'vue'; +import Translate from '~/vue_shared/translate'; +import csrf from '~/lib/utils/csrf'; import Wikis from './wikis'; import ShortcutsWiki from '../../../shortcuts_wiki'; import ZenMode from '../../../zen_mode'; import GLForm from '../../../gl_form'; +import deleteWikiModal from './components/delete_wiki_modal.vue'; document.addEventListener('DOMContentLoaded', () => { new Wikis(); // eslint-disable-line no-new new ShortcutsWiki(); // eslint-disable-line no-new new ZenMode(); // eslint-disable-line no-new new GLForm($('.wiki-form'), true); // eslint-disable-line no-new + + const deleteWikiButton = document.getElementById('delete-wiki-button'); + + if (deleteWikiButton) { + Vue.use(Translate); + + const { deleteWikiUrl, pageTitle } = deleteWikiButton.dataset; + const deleteWikiModalEl = document.getElementById('delete-wiki-modal'); + const deleteModal = new Vue({ // eslint-disable-line + el: deleteWikiModalEl, + data: { + deleteWikiUrl: '', + }, + render(createElement) { + return createElement(deleteWikiModal, { + props: { + pageTitle, + deleteWikiUrl, + csrfToken: csrf.token, + }, + }); + }, + }); + } }); diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js index 124bc2ba710..ca375007ec5 100644 --- a/app/assets/javascripts/pages/users/user_tabs.js +++ b/app/assets/javascripts/pages/users/user_tabs.js @@ -181,7 +181,7 @@ export default class UserTabs { toggleLoading(status) { return this.$parentEl.find('.loading-status .loading') - .toggle(status); + .toggleClass('hidden', status); } setCurrentAction(source) { @@ -195,6 +195,6 @@ export default class UserTabs { } getCurrentAction() { - return this.$parentEl.find('.nav-links .active a').data('action'); + return this.$parentEl.find('.nav-links a.active').data('action'); } } diff --git a/app/assets/javascripts/performance_bar/components/request_selector.vue b/app/assets/javascripts/performance_bar/components/request_selector.vue index 3ed07a4a47d..dd9578a6c7f 100644 --- a/app/assets/javascripts/performance_bar/components/request_selector.vue +++ b/app/assets/javascripts/performance_bar/components/request_selector.vue @@ -37,7 +37,7 @@ export default { <template> <div id="peek-request-selector" - class="pull-right" + class="float-right" > <select v-model="currentRequestId"> <option diff --git a/app/assets/javascripts/pipelines/components/blank_state.vue b/app/assets/javascripts/pipelines/components/blank_state.vue index 8d3d6223d7b..f3219b8291c 100644 --- a/app/assets/javascripts/pipelines/components/blank_state.vue +++ b/app/assets/javascripts/pipelines/components/blank_state.vue @@ -17,13 +17,13 @@ <template> <div class="row empty-state"> - <div class="col-xs-12"> + <div class="col-12"> <div class="svg-content"> <img :src="svgPath" /> </div> </div> - <div class="col-xs-12 text-center"> + <div class="col-12 text-center"> <div class="text-content"> <h4>{{ message }}</h4> </div> diff --git a/app/assets/javascripts/pipelines/components/empty_state.vue b/app/assets/javascripts/pipelines/components/empty_state.vue index 10ac8c08bed..50c27bed9fd 100644 --- a/app/assets/javascripts/pipelines/components/empty_state.vue +++ b/app/assets/javascripts/pipelines/components/empty_state.vue @@ -19,13 +19,13 @@ </script> <template> <div class="row empty-state js-empty-state"> - <div class="col-xs-12"> + <div class="col-12"> <div class="svg-content svg-250"> <img :src="emptyStateSvgPath" /> </div> </div> - <div class="col-xs-12"> + <div class="col-12"> <div class="text-content"> <template v-if="canSetCi"> @@ -34,7 +34,7 @@ </h4> <p> - {{ s__(`Pipelines|Continous Integration can help + {{ s__(`Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment.`) }} diff --git a/app/assets/javascripts/pipelines/components/graph/action_component.vue b/app/assets/javascripts/pipelines/components/graph/action_component.vue index fd3491c7fe0..82b4ce083fb 100644 --- a/app/assets/javascripts/pipelines/components/graph/action_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/action_component.vue @@ -1,11 +1,21 @@ <script> import $ from 'jquery'; -import tooltip from '../../../vue_shared/directives/tooltip'; -import Icon from '../../../vue_shared/components/icon.vue'; -import { dasherize } from '../../../lib/utils/text_utility'; -import eventHub from '../../event_hub'; +import axios from '~/lib/utils/axios_utils'; +import { dasherize } from '~/lib/utils/text_utility'; +import { __ } from '~/locale'; +import createFlash from '~/flash'; +import tooltip from '~/vue_shared/directives/tooltip'; +import Icon from '~/vue_shared/components/icon.vue'; + /** - * Renders either a cancel, retry or play icon pointing to the given path. + * Renders either a cancel, retry or play icon button and handles the post request + * + * Used in: + * - mr widget mini pipeline graph: `mr_widget_pipeline.vue` + * - pipelines table + * - pipelines table in merge request page + * - pipelines table in commit page + * - pipelines detail page in big graph */ export default { components: { @@ -32,16 +42,10 @@ export default { required: true, }, - requestFinishedFor: { - type: String, - required: false, - default: '', - }, }, data() { return { isDisabled: false, - linkRequested: '', }; }, @@ -51,19 +55,28 @@ export default { return `${actionIconDash} js-icon-${actionIconDash}`; }, }, - watch: { - requestFinishedFor() { - if (this.requestFinishedFor === this.linkRequested) { - this.isDisabled = false; - } - }, - }, methods: { + /** + * The request should not be handled here. + * However due to this component being used in several + * different apps it avoids repetition & complexity. + * + */ onClickAction() { $(this.$el).tooltip('hide'); - eventHub.$emit('postAction', this.link); - this.linkRequested = this.link; + this.isDisabled = true; + + axios.post(`${this.link}.json`) + .then(() => { + this.isDisabled = false; + this.$emit('pipelineActionRequestComplete'); + }) + .catch(() => { + this.isDisabled = false; + + createFlash(__('An error occurred while making the request.')); + }); }, }, }; @@ -80,6 +93,6 @@ btn-transparent ci-action-icon-container ci-action-icon-wrapper" data-container="body" :disabled="isDisabled" > - <icon :name="actionIcon" /> + <icon :name="actionIcon"/> </button> </template> diff --git a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue index 4027d26098f..7bfe11ab8cd 100644 --- a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue @@ -42,11 +42,6 @@ export default { type: Object, required: true, }, - requestFinishedFor: { - type: String, - required: false, - default: '', - }, }, computed: { @@ -76,11 +71,15 @@ export default { e.stopPropagation(); }); }, + + pipelineActionRequestComplete() { + this.$emit('pipelineActionRequestComplete'); + }, }, }; </script> <template> - <div class="ci-job-dropdown-container"> + <div class="ci-job-dropdown-container dropdown"> <button v-tooltip type="button" @@ -110,7 +109,7 @@ export default { <job-component :job="item" css-class-job-name="mini-pipeline-graph-dropdown-item" - :request-finished-for="requestFinishedFor" + @pipelineActionRequestComplete="pipelineActionRequestComplete" /> </li> </ul> diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue index 7b8a5edcbff..4ec67f6c01b 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue @@ -16,11 +16,6 @@ export default { type: Object, required: true, }, - requestFinishedFor: { - type: String, - required: false, - default: '', - }, }, computed: { @@ -51,6 +46,10 @@ export default { return className; }, + + refreshPipelineGraph() { + this.$emit('refreshPipelineGraph'); + }, }, }; </script> @@ -74,7 +73,7 @@ export default { :key="stage.name" :stage-connector-class="stageConnectorClass(index, stage)" :is-first-column="isFirstColumn(index)" - :request-finished-for="requestFinishedFor" + @refreshPipelineGraph="refreshPipelineGraph" /> </ul> </div> diff --git a/app/assets/javascripts/pipelines/components/graph/job_component.vue b/app/assets/javascripts/pipelines/components/graph/job_component.vue index c1f0f051b63..dc16d395bcb 100644 --- a/app/assets/javascripts/pipelines/components/graph/job_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/job_component.vue @@ -46,11 +46,6 @@ export default { required: false, default: '', }, - requestFinishedFor: { - type: String, - required: false, - default: '', - }, }, computed: { status() { @@ -84,6 +79,11 @@ export default { return this.job.status && this.job.status.action && this.job.status.action.path; }, }, + methods: { + pipelineActionRequestComplete() { + this.$emit('pipelineActionRequestComplete'); + }, + }, }; </script> <template> @@ -96,6 +96,7 @@ export default { :class="cssClassJobName" data-container="body" data-html="true" + data-boundary="viewport" class="js-pipeline-graph-job-link" > @@ -126,7 +127,7 @@ export default { :tooltip-text="status.action.title" :link="status.action.path" :action-icon="status.action.icon" - :request-finished-for="requestFinishedFor" + @pipelineActionRequestComplete="pipelineActionRequestComplete" /> </div> </template> diff --git a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue index 5461fdbbadd..f32368947e8 100644 --- a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue @@ -29,12 +29,6 @@ export default { required: false, default: '', }, - - requestFinishedFor: { - type: String, - required: false, - default: '', - }, }, methods: { @@ -49,6 +43,10 @@ export default { buildConnnectorClass(index) { return index === 0 && !this.isFirstColumn ? 'left-connector' : ''; }, + + pipelineActionRequestComplete() { + this.$emit('refreshPipelineGraph'); + }, }, }; </script> @@ -75,12 +73,13 @@ export default { v-if="job.size === 1" :job="job" css-class-job-name="build-content" + @pipelineActionRequestComplete="pipelineActionRequestComplete" /> <dropdown-job-component v-if="job.size > 1" :job="job" - :request-finished-for="requestFinishedFor" + @pipelineActionRequestComplete="pipelineActionRequestComplete" /> </li> diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue index ceb4d9ca604..4d965733f95 100644 --- a/app/assets/javascripts/pipelines/components/pipeline_url.vue +++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue @@ -46,7 +46,7 @@ }; </script> <template> - <div class="table-section section-15 hidden-xs hidden-sm pipeline-tags"> + <div class="table-section section-15 d-none d-sm-none d-md-block pipeline-tags"> <a :href="pipeline.path" class="js-pipeline-url-link"> @@ -69,35 +69,35 @@ <span v-if="pipeline.flags.latest" v-tooltip - class="js-pipeline-url-latest label label-success" + class="js-pipeline-url-latest badge badge-success" title="Latest pipeline for this branch"> latest </span> <span v-if="pipeline.flags.yaml_errors" v-tooltip - class="js-pipeline-url-yaml label label-danger" + class="js-pipeline-url-yaml badge badge-danger" :title="pipeline.yaml_errors"> yaml invalid </span> <span v-if="pipeline.flags.failure_reason" v-tooltip - class="js-pipeline-url-failure label label-danger" + class="js-pipeline-url-failure badge badge-danger" :title="pipeline.failure_reason"> error </span> <a v-if="pipeline.flags.auto_devops" tabindex="0" - class="js-pipeline-url-autodevops label label-info autodevops-badge" + class="js-pipeline-url-autodevops badge badge-info autodevops-badge" v-popover="popoverOptions" role="button"> Auto DevOps </a> <span v-if="pipeline.flags.stuck" - class="js-pipeline-url-stuck label label-warning"> + class="js-pipeline-url-stuck badge badge-warning"> stuck </span> </div> diff --git a/app/assets/javascripts/pipelines/components/pipelines_actions.vue b/app/assets/javascripts/pipelines/components/pipelines_actions.vue index 3297af7bde4..e9bc3cf14ca 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_actions.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_actions.vue @@ -63,7 +63,7 @@ <loading-icon v-if="isLoading" /> </button> - <ul class="dropdown-menu dropdown-menu-align-right"> + <ul class="dropdown-menu dropdown-menu-right"> <li v-for="(action, i) in actions" :key="i" diff --git a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue index 1b9e0f917a4..31fcc9dd412 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue @@ -37,7 +37,7 @@ > </i> </button> - <ul class="dropdown-menu dropdown-menu-align-right"> + <ul class="dropdown-menu dropdown-menu-right"> <li v-for="(artifact, i) in artifacts" :key="i"> diff --git a/app/assets/javascripts/pipelines/components/pipelines_table.vue b/app/assets/javascripts/pipelines/components/pipelines_table.vue index 41986b827cd..4318abe97e0 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_table.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_table.vue @@ -37,6 +37,7 @@ return { pipelineId: '', endpoint: '', + cancelingPipeline: null, }; }, computed: { @@ -64,6 +65,7 @@ }, onSubmit() { eventHub.$emit('postAction', this.endpoint); + this.cancelingPipeline = this.pipelineId; }, }, }; @@ -106,6 +108,7 @@ :update-graph-dropdown="updateGraphDropdown" :auto-devops-help-path="autoDevopsHelpPath" :view-type="viewType" + :canceling-pipeline="cancelingPipeline" /> <modal diff --git a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue index 498a97851fa..a3c17479e6f 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue @@ -9,6 +9,7 @@ import CommitComponent from '../../vue_shared/components/commit.vue'; import LoadingButton from '../../vue_shared/components/loading_button.vue'; import Icon from '../../vue_shared/components/icon.vue'; + import { PIPELINES_TABLE } from '../constants'; /** * Pipeline table row. @@ -45,11 +46,16 @@ type: String, required: true, }, + cancelingPipeline: { + type: String, + required: false, + default: null, + }, }, + pipelinesTable: PIPELINES_TABLE, data() { return { isRetrying: false, - isCancelling: false, }; }, computed: { @@ -225,12 +231,14 @@ isChildView() { return this.viewType === 'child'; }, + + isCancelling() { + return this.cancelingPipeline === this.pipeline.id; + }, }, methods: { handleCancelClick() { - this.isCancelling = true; - eventHub.$emit('openConfirmationModal', { pipelineId: this.pipeline.id, endpoint: this.pipeline.cancel_path, @@ -297,6 +305,7 @@ v-for="(stage, index) in pipeline.details.stages" :key="index"> <pipeline-stage + :type="$options.pipelinesTable" :stage="stage" :update-dropdown="updateGraphDropdown" /> @@ -322,7 +331,7 @@ <pipelines-artifacts-component v-if="pipeline.details.artifacts.length" - class="hidden-xs hidden-sm" + class="d-none d-sm-none d-md-block" :artifacts="pipeline.details.artifacts" /> diff --git a/app/assets/javascripts/pipelines/components/stage.vue b/app/assets/javascripts/pipelines/components/stage.vue index a65485c05eb..f9769815796 100644 --- a/app/assets/javascripts/pipelines/components/stage.vue +++ b/app/assets/javascripts/pipelines/components/stage.vue @@ -21,6 +21,7 @@ import Icon from '../../vue_shared/components/icon.vue'; import LoadingIcon from '../../vue_shared/components/loading_icon.vue'; import JobComponent from './graph/job_component.vue'; import tooltip from '../../vue_shared/directives/tooltip'; +import { PIPELINES_TABLE } from '../constants'; export default { components: { @@ -44,6 +45,12 @@ export default { required: false, default: false, }, + + type: { + type: String, + required: false, + default: '', + }, }, data() { @@ -133,6 +140,16 @@ export default { isDropdownOpen() { return this.$el.classList.contains('open'); }, + + pipelineActionRequestComplete() { + if (this.type === PIPELINES_TABLE) { + // warn the table to update + eventHub.$emit('refreshPipelinesTable'); + } else { + // close the dropdown in mr widget + $(this.$refs.dropdown).dropdown('toggle'); + } + }, }, }; </script> @@ -151,6 +168,7 @@ export default { id="stageDropdown" aria-haspopup="true" aria-expanded="false" + ref="dropdown" > <span @@ -188,6 +206,7 @@ export default { <job-component :job="job" css-class-job-name="mini-pipeline-graph-dropdown-item" + @pipelineActionRequestComplete="pipelineActionRequestComplete" /> </li> </ul> diff --git a/app/assets/javascripts/pipelines/components/time_ago.vue b/app/assets/javascripts/pipelines/components/time_ago.vue index cd54d26c9d3..79dbdca4010 100644 --- a/app/assets/javascripts/pipelines/components/time_ago.vue +++ b/app/assets/javascripts/pipelines/components/time_ago.vue @@ -75,7 +75,7 @@ </p> <p - class="finished-at hidden-xs hidden-sm" + class="finished-at d-none d-sm-none d-md-block" v-if="hasFinishedTime" > diff --git a/app/assets/javascripts/pipelines/constants.js b/app/assets/javascripts/pipelines/constants.js index b384c7500e7..eaa11a84cb9 100644 --- a/app/assets/javascripts/pipelines/constants.js +++ b/app/assets/javascripts/pipelines/constants.js @@ -1,2 +1,2 @@ -// eslint-disable-next-line import/prefer-default-export export const CANCEL_REQUEST = 'CANCEL_REQUEST'; +export const PIPELINES_TABLE = 'PIPELINES_TABLE'; diff --git a/app/assets/javascripts/pipelines/mixins/pipelines.js b/app/assets/javascripts/pipelines/mixins/pipelines.js index de0faf181e5..30b1eee186d 100644 --- a/app/assets/javascripts/pipelines/mixins/pipelines.js +++ b/app/assets/javascripts/pipelines/mixins/pipelines.js @@ -55,11 +55,13 @@ export default { eventHub.$on('postAction', this.postAction); eventHub.$on('retryPipeline', this.postAction); eventHub.$on('clickedDropdown', this.updateTable); + eventHub.$on('refreshPipelinesTable', this.fetchPipelines); }, beforeDestroy() { eventHub.$off('postAction', this.postAction); eventHub.$off('retryPipeline', this.postAction); eventHub.$off('clickedDropdown', this.updateTable); + eventHub.$off('refreshPipelinesTable', this.fetchPipelines); }, destroyed() { this.poll.stop(); diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js index 04fe7958fe6..b49a16a87e6 100644 --- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js +++ b/app/assets/javascripts/pipelines/pipeline_details_bundle.js @@ -25,30 +25,14 @@ export default () => { data() { return { mediator, - requestFinishedFor: null, }; }, - created() { - eventHub.$on('postAction', this.postAction); - }, - beforeDestroy() { - eventHub.$off('postAction', this.postAction); - }, methods: { - postAction(action) { - // Click was made, reset this variable - this.requestFinishedFor = null; - - this.mediator.service - .postAction(action) - .then(() => { - this.mediator.refreshPipeline(); - this.requestFinishedFor = action; - }) - .catch(() => { - this.requestFinishedFor = action; - Flash(__('An error occurred while making the request.')); - }); + requestRefreshPipelineGraph() { + // When an action is clicked + // (wether in the dropdown or in the main nodes, we refresh the big graph) + this.mediator.refreshPipeline() + .catch(() => Flash(__('An error occurred while making the request.'))); }, }, render(createElement) { @@ -56,7 +40,9 @@ export default () => { props: { isLoading: this.mediator.state.isLoading, pipeline: this.mediator.store.state.pipeline, - requestFinishedFor: this.requestFinishedFor, + }, + on: { + refreshPipelineGraph: this.requestRefreshPipelineGraph, }, }); }, diff --git a/app/assets/javascripts/profile/account/components/update_username.vue b/app/assets/javascripts/profile/account/components/update_username.vue index e5de3f69b01..a7a2a7235fd 100644 --- a/app/assets/javascripts/profile/account/components/update_username.vue +++ b/app/assets/javascripts/profile/account/components/update_username.vue @@ -86,7 +86,11 @@ Please update your Git repository remotes as soon as possible.`), <div class="form-group"> <label :for="$options.inputId">{{ s__('Profiles|Path') }}</label> <div class="input-group"> - <div class="input-group-addon">{{ rootUrl }}</div> + <div class="input-group-prepend"> + <div class="input-group-text"> + {{ rootUrl }} + </div> + </div> <input :id="$options.inputId" class="form-control" diff --git a/app/assets/javascripts/project_fork.js b/app/assets/javascripts/project_fork.js index 6fedd94a6a9..f5cd1c3cc3e 100644 --- a/app/assets/javascripts/project_fork.js +++ b/app/assets/javascripts/project_fork.js @@ -4,6 +4,6 @@ export default () => { $('.js-fork-thumbnail').on('click', function forkThumbnailClicked() { if ($(this).hasClass('disabled')) return false; - return $('.js-fork-content').toggle(); + return $('.js-fork-content').toggleClass('hidden'); }); }; diff --git a/app/assets/javascripts/project_label_subscription.js b/app/assets/javascripts/project_label_subscription.js index f31beb4dc78..6f06944ebb6 100644 --- a/app/assets/javascripts/project_label_subscription.js +++ b/app/assets/javascripts/project_label_subscription.js @@ -42,7 +42,7 @@ export default class ProjectLabelSubscription { const $button = $(button); if ($button.attr('data-original-title')) { - $button.tooltip('hide').attr('data-original-title', newAction).tooltip('fixTitle'); + $button.tooltip('hide').attr('data-original-title', newAction).tooltip('_fixTitle'); } return button; diff --git a/app/assets/javascripts/project_visibility.js b/app/assets/javascripts/project_visibility.js index 7c95c71e239..a52ac768e57 100644 --- a/app/assets/javascripts/project_visibility.js +++ b/app/assets/javascripts/project_visibility.js @@ -7,7 +7,7 @@ function setVisibilityOptions(namespaceSelector) { const selectedNamespace = namespaceSelector.options[namespaceSelector.selectedIndex]; const { name, visibility, visibilityLevel, showPath, editPath } = selectedNamespace.dataset; - document.querySelectorAll('.visibility-level-setting .radio').forEach((option) => { + document.querySelectorAll('.visibility-level-setting .form-check').forEach((option) => { const optionInput = option.querySelector('input[type=radio]'); const optionValue = optionInput ? optionInput.value : 0; const optionTitle = option.querySelector('.option-title'); diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js index 93603dfc14d..888b1d6ce33 100644 --- a/app/assets/javascripts/projects/project_new.js +++ b/app/assets/javascripts/projects/project_new.js @@ -66,8 +66,8 @@ const bindEvents = () => { .on('click', (e) => { e.preventDefault(); }) .popover({ title: $pushNewProjectTipTrigger.data('title'), - placement: 'auto bottom', - html: 'true', + placement: 'bottom', + html: true, content: $('.push-new-project-tip-template').html(), }) .on('shown.bs.popover', () => { diff --git a/app/assets/javascripts/projects_dropdown/components/search.vue b/app/assets/javascripts/projects_dropdown/components/search.vue index 0c46ed184be..7fcd62dcdb8 100644 --- a/app/assets/javascripts/projects_dropdown/components/search.vue +++ b/app/assets/javascripts/projects_dropdown/components/search.vue @@ -46,7 +46,7 @@ <template> <div - class="search-input-container hidden-xs" + class="search-input-container d-none d-sm-block" > <input type="search" diff --git a/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js b/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js index 0a60f4845b2..1a75fdd75db 100644 --- a/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js +++ b/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js @@ -31,7 +31,7 @@ export default class PrometheusMetrics { /* eslint-disable class-methods-use-this */ handlePanelToggle(e) { const $toggleBtn = $(e.currentTarget); - const $currentPanelBody = $toggleBtn.closest('.panel').find('.panel-body'); + const $currentPanelBody = $toggleBtn.closest('.card').find('.card-body'); $currentPanelBody.toggleClass('hidden'); if ($toggleBtn.hasClass('fa-caret-down')) { $toggleBtn.removeClass('fa-caret-down').addClass('fa-caret-right'); diff --git a/app/assets/javascripts/registry/components/collapsible_container.vue b/app/assets/javascripts/registry/components/collapsible_container.vue index a03180e80e6..2fc3778820b 100644 --- a/app/assets/javascripts/registry/components/collapsible_container.vue +++ b/app/assets/javascripts/registry/components/collapsible_container.vue @@ -28,11 +28,6 @@ isOpen: false, }; }, - computed: { - clipboardText() { - return `docker pull ${this.repo.location}`; - }, - }, methods: { ...mapActions([ 'fetchRepos', @@ -84,12 +79,12 @@ <clipboard-button v-if="repo.location" - :text="clipboardText" + :text="repo.location" :title="repo.location" css-class="btn-default btn-transparent btn-clipboard" /> - <div class="controls hidden-xs pull-right"> + <div class="controls d-none d-sm-block float-right"> <button v-if="repo.canDelete" type="button" diff --git a/app/assets/javascripts/registry/components/table_registry.vue b/app/assets/javascripts/registry/components/table_registry.vue index a2227b2f554..e4a4b3bb129 100644 --- a/app/assets/javascripts/registry/components/table_registry.vue +++ b/app/assets/javascripts/registry/components/table_registry.vue @@ -56,10 +56,6 @@ .catch(() => this.showError(errorMessagesTypes.FETCH_REGISTRY)); }, - clipboardText(text) { - return `docker pull ${text}`; - }, - showError(message) { Flash(errorMessages[message]); }, @@ -89,7 +85,7 @@ <clipboard-button v-if="item.location" :title="item.location" - :text="clipboardText(item.location)" + :text="item.location" css-class="btn-default btn-transparent btn-clipboard" /> </td> @@ -124,7 +120,7 @@ <button v-if="item.canDelete" type="button" - class="js-delete-registry btn btn-danger hidden-xs pull-right" + class="js-delete-registry btn btn-danger d-none d-sm-block float-right" :title="s__('ContainerRegistry|Remove tag')" :aria-label="s__('ContainerRegistry|Remove tag')" data-container="body" diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js index 6eb0b62fa1c..2afcf4626b8 100644 --- a/app/assets/javascripts/right_sidebar.js +++ b/app/assets/javascripts/right_sidebar.js @@ -108,7 +108,7 @@ Sidebar.prototype.todoUpdateDone = function(data) { .attr('title', $el.data(`${attrPrefix}Text`)); if ($el.hasClass('has-tooltip')) { - $el.tooltip('fixTitle'); + $el.tooltip('_fixTitle'); } if ($el.data(`${attrPrefix}Icon`)) { diff --git a/app/assets/javascripts/shortcuts_navigation.js b/app/assets/javascripts/shortcuts_navigation.js index a4d10850471..78f7353eb0d 100644 --- a/app/assets/javascripts/shortcuts_navigation.js +++ b/app/assets/javascripts/shortcuts_navigation.js @@ -7,7 +7,7 @@ export default class ShortcutsNavigation extends Shortcuts { super(); Mousetrap.bind('g p', () => findAndFollowLink('.shortcuts-project')); - Mousetrap.bind('g e', () => findAndFollowLink('.shortcuts-project-activity')); + Mousetrap.bind('g v', () => findAndFollowLink('.shortcuts-project-activity')); Mousetrap.bind('g f', () => findAndFollowLink('.shortcuts-tree')); Mousetrap.bind('g c', () => findAndFollowLink('.shortcuts-commits')); Mousetrap.bind('g j', () => findAndFollowLink('.shortcuts-builds')); @@ -16,9 +16,10 @@ export default class ShortcutsNavigation extends Shortcuts { Mousetrap.bind('g i', () => findAndFollowLink('.shortcuts-issues')); Mousetrap.bind('g b', () => findAndFollowLink('.shortcuts-issue-boards')); Mousetrap.bind('g m', () => findAndFollowLink('.shortcuts-merge_requests')); - Mousetrap.bind('g t', () => findAndFollowLink('.shortcuts-todos')); Mousetrap.bind('g w', () => findAndFollowLink('.shortcuts-wiki')); Mousetrap.bind('g s', () => findAndFollowLink('.shortcuts-snippets')); + Mousetrap.bind('g k', () => findAndFollowLink('.shortcuts-kubernetes')); + Mousetrap.bind('g e', () => findAndFollowLink('.shortcuts-environments')); Mousetrap.bind('i', () => findAndFollowLink('.shortcuts-new-issue')); this.enabledHelp.push('.hidden-shortcut.project'); diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue index 5eeb2a41bae..284a258d3c9 100644 --- a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue +++ b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue @@ -41,7 +41,7 @@ export default { </i> <a v-if="editable" - class="js-sidebar-dropdown-toggle edit-link pull-right" + class="js-sidebar-dropdown-toggle edit-link float-right" href="#" > {{ __('Edit') }} @@ -49,7 +49,7 @@ export default { <a v-if="showToggle" aria-label="Toggle sidebar" - class="gutter-toggle pull-right js-sidebar-toggle" + class="gutter-toggle float-right js-sidebar-toggle" href="#" role="button" > diff --git a/app/assets/javascripts/sidebar/components/assignees/assignees.vue b/app/assets/javascripts/sidebar/components/assignees/assignees.vue index 2d00e8ac7e0..5a374d84796 100644 --- a/app/assets/javascripts/sidebar/components/assignees/assignees.vue +++ b/app/assets/javascripts/sidebar/components/assignees/assignees.vue @@ -130,6 +130,7 @@ export default { v-tooltip data-container="body" data-placement="left" + data-boundary="viewport" :title="collapsedTooltipTitle" > <i diff --git a/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue index 7f0de722f61..3f6e2f05396 100644 --- a/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue +++ b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue @@ -75,6 +75,7 @@ export default { v-tooltip data-container="body" data-placement="left" + data-boundary="viewport" :title="tooltipLabel" > <icon @@ -86,7 +87,7 @@ export default { {{ __('Confidentiality') }} <a v-if="isEditable" - class="pull-right confidential-edit" + class="float-right confidential-edit" href="#" @click.prevent="toggleForm" > diff --git a/app/assets/javascripts/sidebar/components/confidential/edit_form.vue b/app/assets/javascripts/sidebar/components/confidential/edit_form.vue index 3783f71a848..4165aa19acf 100644 --- a/app/assets/javascripts/sidebar/components/confidential/edit_form.vue +++ b/app/assets/javascripts/sidebar/components/confidential/edit_form.vue @@ -32,7 +32,7 @@ export default { </script> <template> - <div class="dropdown open"> + <div class="dropdown show"> <div class="dropdown-menu sidebar-item-warning-message"> <div> <p diff --git a/app/assets/javascripts/sidebar/components/lock/edit_form.vue b/app/assets/javascripts/sidebar/components/lock/edit_form.vue index e1e4715826a..d392977e5e2 100644 --- a/app/assets/javascripts/sidebar/components/lock/edit_form.vue +++ b/app/assets/javascripts/sidebar/components/lock/edit_form.vue @@ -41,7 +41,7 @@ export default { </script> <template> - <div class="dropdown open"> + <div class="dropdown show"> <div class="dropdown-menu sidebar-item-warning-message"> <p class="text" diff --git a/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue b/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue index 1a5e7b67eca..fb69c741dcd 100644 --- a/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue +++ b/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue @@ -99,6 +99,7 @@ export default { v-tooltip data-container="body" data-placement="left" + data-boundary="viewport" :title="tooltipLabel" > <icon @@ -112,7 +113,7 @@ export default { {{ sprintf(__('Lock %{issuableDisplayName}'), { issuableDisplayName: issuableDisplayName }) }} <button v-if="isEditable" - class="pull-right lock-edit" + class="float-right lock-edit" type="button" @click.prevent="toggleForm" > diff --git a/app/assets/javascripts/sidebar/components/participants/participants.vue b/app/assets/javascripts/sidebar/components/participants/participants.vue index 8f9e6761d20..0a945fc7fd5 100644 --- a/app/assets/javascripts/sidebar/components/participants/participants.vue +++ b/app/assets/javascripts/sidebar/components/participants/participants.vue @@ -84,6 +84,7 @@ v-tooltip data-container="body" data-placement="left" + data-boundary="viewport" :title="participantLabel" @click="onClickCollapsedIcon" > diff --git a/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue b/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue index f0df759ef7a..6745c1aafff 100644 --- a/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue +++ b/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue @@ -82,6 +82,7 @@ :title="notificationTooltip" data-container="body" data-placement="left" + data-boundary="viewport" > <icon :name="notificationIcon" @@ -91,12 +92,12 @@ /> </span> </div> - <span class="issuable-header-text hide-collapsed pull-left"> + <span class="issuable-header-text hide-collapsed float-left"> {{ __('Notifications') }} </span> <toggle-button ref="toggleButton" - class="pull-right hide-collapsed js-issuable-subscribe-button" + class="float-right hide-collapsed js-issuable-subscribe-button" :is-loading="showLoadingState" :value="subscribed" @change="toggleSubscription" diff --git a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue index 9d9ee9dea4d..209af1ce152 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue @@ -114,6 +114,7 @@ v-tooltip data-container="body" data-placement="left" + data-boundary="viewport" :title="tooltipText" > <icon name="timer" /> diff --git a/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue index 82c4562f9a9..6f79310b1cc 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue @@ -71,7 +71,7 @@ export default { </div> </div> <div class="compare-display-container"> - <div class="compare-display pull-left"> + <div class="compare-display float-left"> <span class="compare-label"> {{ s__('TimeTracking|Spent') }} </span> @@ -79,7 +79,7 @@ export default { {{ timeSpentHumanReadable }} </span> </div> - <div class="compare-display estimated pull-right"> + <div class="compare-display estimated float-right"> <span class="compare-label"> {{ s__('TimeTrackingEstimated|Est') }} </span> diff --git a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue index 8f5d0bee107..7d56d2fa5ee 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue @@ -116,7 +116,7 @@ export default { <div class="title hide-collapsed"> {{ __('Time tracking') }} <div - class="help-button pull-right" + class="help-button float-right" v-if="!showHelpState" @click="toggleHelpState(true)" > @@ -127,7 +127,7 @@ export default { </i> </div> <div - class="close-help-button pull-right" + class="close-help-button float-right" v-if="showHelpState" @click="toggleHelpState(false)" > diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js index 8486019897d..cd954f75613 100644 --- a/app/assets/javascripts/users_select.js +++ b/app/assets/javascripts/users_select.js @@ -202,7 +202,7 @@ function UsersSelect(currentUser, els, options = {}) { tooltipTitle = __('Assignee'); } $value.html(assigneeTemplate(user)); - $collapsedSidebar.attr('title', tooltipTitle).tooltip('fixTitle'); + $collapsedSidebar.attr('title', tooltipTitle).tooltip('_fixTitle'); return $collapsedSidebar.html(collapsedAssigneeTemplate(user)); }); }; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue index 1fea231c816..1608858da22 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue @@ -127,7 +127,7 @@ export default { </span> <loading-button v-if="deployment.stop_url" - container-class="btn btn-default btn-xs prepend-left-default" + container-class="btn btn-default btn-sm prepend-left-default" label="Stop environment" :loading="isStopping" @click="stopEnvironment" diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue index cb6e9858736..8338fde61c7 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue @@ -2,7 +2,7 @@ import tooltip from '../../vue_shared/directives/tooltip'; export default { - name: 'MRWidgetAuthor', + name: 'MrWidgetAuthor', directives: { tooltip, }, diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue index 8f1fd809a81..644e4b7d81a 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue @@ -1,10 +1,10 @@ <script> - import mrWidgetAuthor from './mr_widget_author.vue'; + import MrWidgetAuthor from './mr_widget_author.vue'; export default { name: 'MRWidgetAuthorTime', components: { - mrWidgetAuthor, + MrWidgetAuthor, }, props: { actionText: { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue index 18ee4c62bf1..51a0fda6555 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue @@ -131,7 +131,7 @@ export default { aria-hidden="true"> </i> </button> - <ul class="dropdown-menu dropdown-menu-align-right"> + <ul class="dropdown-menu dropdown-menu-right"> <li> <a class="js-download-email-patches" diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue deleted file mode 100644 index f0298f732ea..00000000000 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_maintainer_edit.vue +++ /dev/null @@ -1,20 +0,0 @@ -<script> - export default { - name: 'MRWidgetMaintainerEdit', - props: { - maintainerEditAllowed: { - type: Boolean, - default: false, - required: false, - }, - }, - }; -</script> - -<template> - <section class="mr-info-list mr-links"> - <p v-if="maintainerEditAllowed"> - {{ s__("mrWidget|Allows edits from maintainers") }} - </p> - </section> -</template> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue index ebaf2b972eb..b404a592234 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue @@ -42,7 +42,7 @@ @click="refreshWidget" :disabled="isRefreshing" type="button" - class="btn btn-xs btn-default" + class="btn btn-sm btn-default" > <loading-icon v-if="isRefreshing" diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue index dad4b0fe49d..5c1500ab801 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue @@ -43,13 +43,13 @@ To merge this request, first rebase locally.`) }} <a v-if="mr.canMerge && mr.conflictResolutionPath" :href="mr.conflictResolutionPath" - class="js-resolve-conflicts-button btn btn-default btn-xs" + class="js-resolve-conflicts-button btn btn-default btn-sm" > {{ s__("mrWidget|Resolve conflicts") }} </a> <button v-if="mr.canMerge" - class="js-merge-locally-button btn btn-default btn-xs" + class="js-merge-locally-button btn btn-default btn-sm" data-toggle="modal" data-target="#modal_merge_info" > diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue index 7d366c495f0..05fecd4de35 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue @@ -98,7 +98,7 @@ export default { </span> <button @click="refresh" - class="btn btn-default btn-xs js-refresh-button" + class="btn btn-default btn-sm js-refresh-button" type="button" > {{ s__("mrWidget|Refresh now") }} diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue index 7ff7fc7988a..e8352c362d6 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue @@ -1,13 +1,13 @@ <script> import Flash from '../../../flash'; import statusIcon from '../mr_widget_status_icon.vue'; - import mrWidgetAuthor from '../../components/mr_widget_author.vue'; + import MrWidgetAuthor from '../../components/mr_widget_author.vue'; import eventHub from '../../event_hub'; export default { name: 'MRWidgetMergeWhenPipelineSucceeds', components: { - mrWidgetAuthor, + MrWidgetAuthor, statusIcon, }, props: { @@ -94,7 +94,7 @@ :disabled="isCancellingAutoMerge" role="button" href="#" - class="btn btn-xs btn-default js-cancel-auto-merge"> + class="btn btn-sm btn-default js-cancel-auto-merge"> <i v-if="isCancellingAutoMerge" class="fa fa-spinner fa-spin" @@ -129,7 +129,7 @@ :disabled="isRemovingSourceBranch" @click.prevent="removeSourceBranch" role="button" - class="btn btn-xs btn-default js-remove-source-branch" + class="btn btn-sm btn-default js-remove-source-branch" href="#" > <i diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue index 3e36a3a10f9..8c7e0664559 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue @@ -118,7 +118,7 @@ <a v-if="mr.canRevertInCurrentMR" v-tooltip - class="btn btn-close btn-xs" + class="btn btn-close btn-sm" href="#modal-revert-commit" data-toggle="modal" data-container="body" @@ -129,7 +129,7 @@ <a v-else-if="mr.revertInForkPath" v-tooltip - class="btn btn-close btn-xs" + class="btn btn-close btn-sm" data-method="post" :href="mr.revertInForkPath" :title="revertTitle" @@ -139,7 +139,7 @@ <a v-if="mr.canCherryPickInCurrentMR" v-tooltip - class="btn btn-default btn-xs" + class="btn btn-default btn-sm" href="#modal-cherry-pick-commit" data-toggle="modal" data-container="body" @@ -150,7 +150,7 @@ <a v-else-if="mr.cherryPickInForkPath" v-tooltip - class="btn btn-default btn-xs" + class="btn btn-default btn-sm" data-method="post" :href="mr.cherryPickInForkPath" :title="cherryPickTitle" @@ -189,7 +189,7 @@ @click="removeSourceBranch" :disabled="isMakingRequest" type="button" - class="btn btn-xs btn-default js-remove-branch-button" + class="btn btn-sm btn-default js-remove-branch-button" > {{ s__("mrWidget|Remove Source Branch") }} </button> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue index bf8628d18a6..926a3172412 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue @@ -10,6 +10,6 @@ In EE, the configuration extends this object to add a functioning squash-before- button. */ -export default { - template: '', -}; +<script> + export default {}; +</script> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue index 3d9161f6926..086dbabe77e 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue @@ -18,10 +18,10 @@ export default { <template> <div class="mr-widget-body mr-widget-empty-state"> <div class="row"> - <div class="artwork col-sm-5 col-sm-push-7 col-xs-12 text-center"> + <div class="artwork col-md-5 order-md-last col-12 text-center"> <span v-html="emptyStateSVG"></span> </div> - <div class="text col-sm-7 col-sm-pull-5 col-xs-12"> + <div class="text col-md-7 order-md-first col-12"> <span> Merge requests are a place to propose changes you have made to a project and discuss those changes with others. diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue index 0264625a526..1d1c8ebc179 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue @@ -312,7 +312,7 @@ export default { v-else @click="toggleCommitMessageEditor" :disabled="isMergeButtonDisabled" - class="js-modify-commit-message-button btn btn-default btn-xs" + class="js-modify-commit-message-button btn btn-default btn-sm" type="button"> Modify commit message </button> @@ -329,7 +329,7 @@ export default { class="prepend-top-default commit-message-editor"> <div class="form-group clearfix"> <label - class="control-label" + class="col-form-label" for="commit-message"> Commit message </label> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue index a1f7e696795..8ea3f22ecc2 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue @@ -28,7 +28,7 @@ export default { <a v-if="mr.createIssueToResolveDiscussionsPath" :href="mr.createIssueToResolveDiscussionsPath" - class="btn btn-default btn-xs js-create-issue" + class="btn btn-default btn-sm js-create-issue" > {{ s__("mrWidget|Create an issue to resolve them later") }} </a> diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js index 7f5f28091da..15097fa2a3f 100644 --- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js +++ b/app/assets/javascripts/vue_merge_request_widget/dependencies.js @@ -15,7 +15,6 @@ export { default as WidgetHeader } from './components/mr_widget_header.vue'; export { default as WidgetMergeHelp } from './components/mr_widget_merge_help.vue'; export { default as WidgetPipeline } from './components/mr_widget_pipeline.vue'; export { default as Deployment } from './components/deployment.vue'; -export { default as WidgetMaintainerEdit } from './components/mr_widget_maintainer_edit.vue'; export { default as WidgetRelatedLinks } from './components/mr_widget_related_links.vue'; export { default as MergedState } from './components/states/mr_widget_merged.vue'; export { default as FailedToMerge } from './components/states/mr_widget_failed_to_merge.vue'; @@ -41,8 +40,8 @@ export { default as MRWidgetService } from './services/mr_widget_service'; export { default as eventHub } from './event_hub'; export { default as getStateKey } from './stores/get_state_key'; export { default as stateMaps } from './stores/state_maps'; -export { default as SquashBeforeMerge } from './components/states/mr_widget_squash_before_merge'; +export { default as SquashBeforeMerge } from './components/states/mr_widget_squash_before_merge.vue'; export { default as notify } from '../lib/utils/notify'; export { default as SourceBranchRemovalStatus } from './components/source_branch_removal_status.vue'; -export { default as mrWidgetOptions } from './mr_widget_options'; +export { default as mrWidgetOptions } from './mr_widget_options.vue'; diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index 345f9ac1b4b..f69fe03fcb3 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -1,12 +1,13 @@ +<script> + import Project from '~/pages/projects/project'; import SmartInterval from '~/smart_interval'; -import Flash from '../flash'; +import createFlash from '../flash'; import { WidgetHeader, WidgetMergeHelp, WidgetPipeline, Deployment, - WidgetMaintainerEdit, WidgetRelatedLinks, MergedState, ClosedState, @@ -40,10 +41,39 @@ import { setFavicon } from '../lib/utils/common_utils'; export default { el: '#js-vue-mr-widget', name: 'MRWidget', + components: { + 'mr-widget-header': WidgetHeader, + 'mr-widget-merge-help': WidgetMergeHelp, + 'mr-widget-pipeline': WidgetPipeline, + Deployment, + 'mr-widget-related-links': WidgetRelatedLinks, + 'mr-widget-merged': MergedState, + 'mr-widget-closed': ClosedState, + 'mr-widget-merging': MergingState, + 'mr-widget-failed-to-merge': FailedToMerge, + 'mr-widget-wip': WorkInProgressState, + 'mr-widget-archived': ArchivedState, + 'mr-widget-conflicts': ConflictsState, + 'mr-widget-nothing-to-merge': NothingToMergeState, + 'mr-widget-not-allowed': NotAllowedState, + 'mr-widget-missing-branch': MissingBranchState, + 'mr-widget-ready-to-merge': ReadyToMergeState, + 'sha-mismatch': ShaMismatchState, + 'mr-widget-squash-before-merge': SquashBeforeMerge, + 'mr-widget-checking': CheckingState, + 'mr-widget-unresolved-discussions': UnresolvedDiscussionsState, + 'mr-widget-pipeline-blocked': PipelineBlockedState, + 'mr-widget-pipeline-failed': PipelineFailedState, + 'mr-widget-merge-when-pipeline-succeeds': MergeWhenPipelineSucceedsState, + 'mr-widget-auto-merge-failed': AutoMergeFailed, + 'mr-widget-rebase': RebaseState, + SourceBranchRemovalStatus, + }, props: { mrData: { type: Object, required: false, + default: null, }, }, data() { @@ -72,6 +102,13 @@ export default { (!this.mr.isNothingToMergeState && !this.mr.isMergedState); }, }, + created() { + this.initPolling(); + this.bindEventHubListeners(); + }, + mounted() { + this.handleMounted(); + }, methods: { createService(store) { const endpoints = { @@ -99,7 +136,7 @@ export default { cb.call(null, data); } }) - .catch(() => new Flash('Something went wrong. Please try again.')); + .catch(() => createFlash('Something went wrong. Please try again.')); }, initPolling() { this.pollingInterval = new SmartInterval({ @@ -134,7 +171,7 @@ export default { } }) .catch(() => { - new Flash('Something went wrong while fetching the environments for this merge request. Please try again.'); // eslint-disable-line + createFlash('Something went wrong while fetching the environments for this merge request. Please try again.'); // eslint-disable-line }); }, fetchActionsContent() { @@ -147,7 +184,7 @@ export default { Project.initRefSwitcher(); } }) - .catch(() => new Flash('Something went wrong. Please try again.')); + .catch(() => createFlash('Something went wrong. Please try again.')); }, handleNotification(data) { if (data.ci_status === this.mr.ciStatus) return; @@ -202,76 +239,53 @@ export default { this.initDeploymentsPolling(); }, }, - created() { - this.initPolling(); - this.bindEventHubListeners(); - }, - mounted() { - this.handleMounted(); - }, - components: { - 'mr-widget-header': WidgetHeader, - 'mr-widget-merge-help': WidgetMergeHelp, - 'mr-widget-pipeline': WidgetPipeline, - Deployment, - 'mr-widget-maintainer-edit': WidgetMaintainerEdit, - 'mr-widget-related-links': WidgetRelatedLinks, - 'mr-widget-merged': MergedState, - 'mr-widget-closed': ClosedState, - 'mr-widget-merging': MergingState, - 'mr-widget-failed-to-merge': FailedToMerge, - 'mr-widget-wip': WorkInProgressState, - 'mr-widget-archived': ArchivedState, - 'mr-widget-conflicts': ConflictsState, - 'mr-widget-nothing-to-merge': NothingToMergeState, - 'mr-widget-not-allowed': NotAllowedState, - 'mr-widget-missing-branch': MissingBranchState, - 'mr-widget-ready-to-merge': ReadyToMergeState, - 'mr-widget-sha-mismatch': ShaMismatchState, - 'mr-widget-squash-before-merge': SquashBeforeMerge, - 'mr-widget-checking': CheckingState, - 'mr-widget-unresolved-discussions': UnresolvedDiscussionsState, - 'mr-widget-pipeline-blocked': PipelineBlockedState, - 'mr-widget-pipeline-failed': PipelineFailedState, - 'mr-widget-merge-when-pipeline-succeeds': MergeWhenPipelineSucceedsState, - 'mr-widget-auto-merge-failed': AutoMergeFailed, - 'mr-widget-rebase': RebaseState, - SourceBranchRemovalStatus, - }, - template: ` - <div class="mr-state-widget prepend-top-default"> - <mr-widget-header :mr="mr" /> - <mr-widget-pipeline - v-if="shouldRenderPipelines" - :pipeline="mr.pipeline" - :ci-status="mr.ciStatus" - :has-ci="mr.hasCI" - /> - <deployment - v-for="deployment in mr.deployments" - :key="deployment.id" - :deployment="deployment" +}; +</script> +<template> + <div class="mr-state-widget prepend-top-default"> + <mr-widget-header + :mr="mr" + /> + <mr-widget-pipeline + v-if="shouldRenderPipelines" + :pipeline="mr.pipeline" + :ci-status="mr.ciStatus" + :has-ci="mr.hasCI" + /> + <deployment + v-for="deployment in mr.deployments" + :key="deployment.id" + :deployment="deployment" + /> + <div class="mr-widget-section"> + <component + :is="componentName" + :mr="mr" + :service="service" + /> + + <section + v-if="mr.maintainerEditAllowed" + class="mr-info-list mr-links" + > + {{ s__("mrWidget|Allows edits from maintainers") }} + </section> + + <mr-widget-related-links + v-if="shouldRenderRelatedLinks" + :state="mr.state" + :related-links="mr.relatedLinks" + /> + + <source-branch-removal-status + v-if="shouldRenderSourceBranchRemovalStatus" /> - <div class="mr-widget-section"> - <component - :is="componentName" - :mr="mr" - :service="service" /> - <mr-widget-maintainer-edit - :maintainerEditAllowed="mr.maintainerEditAllowed" /> - <mr-widget-related-links - v-if="shouldRenderRelatedLinks" - :state="mr.state" - :related-links="mr.relatedLinks" /> - <source-branch-removal-status - v-if="shouldRenderSourceBranchRemovalStatus" - /> - </div> - <div - class="mr-widget-footer" - v-if="shouldRenderMergeHelp"> - <mr-widget-merge-help /> - </div> </div> - `, -}; + <div + class="mr-widget-footer" + v-if="shouldRenderMergeHelp" + > + <mr-widget-merge-help /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue index 395a71acccf..7b5367ac19b 100644 --- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue @@ -42,7 +42,7 @@ export default { target="_blank"> <icon name="download" - css-classes="pull-left append-right-8" + css-classes="float-left append-right-8" :size="16" /> {{ __('Download') }} diff --git a/app/assets/javascripts/vue_shared/components/deprecated_modal.vue b/app/assets/javascripts/vue_shared/components/deprecated_modal.vue index dcf1489b37c..424af5a0293 100644 --- a/app/assets/javascripts/vue_shared/components/deprecated_modal.vue +++ b/app/assets/javascripts/vue_shared/components/deprecated_modal.vue @@ -87,7 +87,7 @@ <div :id="id" class="modal" - :class="id ? '' : 'show'" + :class="id ? '' : 'd-block'" role="dialog" tabindex="-1" > @@ -99,12 +99,12 @@ <div class="modal-content"> <div class="modal-header"> <slot name="header"> - <h4 class="modal-title pull-left"> + <h4 class="modal-title float-left"> {{ title }} </h4> <button type="button" - class="close pull-right" + class="close float-right" @click="emitCancel($event)" data-dismiss="modal" aria-label="Close" @@ -166,7 +166,7 @@ </div> <div v-if="!id" - class="modal-backdrop fade in" + class="modal-backdrop fade show" > </div> </div> diff --git a/app/assets/javascripts/vue_shared/components/gl_modal.vue b/app/assets/javascripts/vue_shared/components/gl_modal.vue index f28e5e2715d..d5d5a7d3798 100644 --- a/app/assets/javascripts/vue_shared/components/gl_modal.vue +++ b/app/assets/javascripts/vue_shared/components/gl_modal.vue @@ -53,6 +53,11 @@ export default { <div class="modal-content"> <div class="modal-header"> <slot name="header"> + <h4 class="modal-title"> + <slot name="title"> + {{ headerTitleText }} + </slot> + </h4> <button type="button" class="close js-modal-close-action" @@ -62,11 +67,6 @@ export default { > <span aria-hidden="true">×</span> </button> - <h4 class="modal-title"> - <slot name="title"> - {{ headerTitleText }} - </slot> - </h4> </slot> </div> diff --git a/app/assets/javascripts/vue_shared/components/header_ci_component.vue b/app/assets/javascripts/vue_shared/components/header_ci_component.vue index 088187ed348..ca17fa06a00 100644 --- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue +++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue @@ -163,8 +163,8 @@ export default { <button v-if="hasSidebarButton" type="button" - class="btn btn-default visible-xs-block -visible-sm-block sidebar-toggle-btn js-sidebar-build-toggle js-sidebar-build-toggle-header" + class="btn btn-default d-block d-sm-none d-md-none +sidebar-toggle-btn js-sidebar-build-toggle js-sidebar-build-toggle-header" aria-label="Toggle Sidebar" id="toggleSidebar" > diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue index c0ee88bbf72..d63318f3da6 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue @@ -111,7 +111,7 @@ Attach a file </button> <button - class="btn btn-default btn-xs hide button-cancel-uploading-files" + class="btn btn-default btn-sm hide button-cancel-uploading-files" type="button" > Cancel diff --git a/app/assets/javascripts/vue_shared/components/navigation_tabs.vue b/app/assets/javascripts/vue_shared/components/navigation_tabs.vue index 92d187e24bf..08d4936f480 100644 --- a/app/assets/javascripts/vue_shared/components/navigation_tabs.vue +++ b/app/assets/javascripts/vue_shared/components/navigation_tabs.vue @@ -67,7 +67,7 @@ export default { <span v-if="shouldRenderBadge(tab.count)" - class="badge" + class="badge badge-pill" > {{ tab.count }} </span> diff --git a/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue b/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue index 50b1508691b..eccba61a8c0 100644 --- a/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue +++ b/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue @@ -54,7 +54,7 @@ <div class="note-header"> <div class="note-header-info"> <a :href="getUserData.path"> - <span class="hidden-xs">{{ getUserData.name }}</span> + <span class="d-none d-sm-block">{{ getUserData.name }}</span> <span class="note-headline-light">@{{ getUserData.username }}</span> </a> </div> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue index 3fcacd156c5..71ec34f2c7a 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue @@ -116,7 +116,7 @@ v-if="isLoading" :inline="true" /> - <div class="pull-right"> + <div class="float-right"> <button v-if="editable && !editing" type="button" diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue index 34a07f33a23..3c400afdc1d 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue @@ -77,13 +77,13 @@ export default { <div class="clearfix"> <button type="button" - class="btn btn-primary pull-left js-new-label-btn disabled" + class="btn btn-primary float-left js-new-label-btn disabled" > {{ __('Create') }} </button> <button type="button" - class="btn btn-default pull-right js-cancel-label-btn" + class="btn btn-default float-right js-cancel-label-btn" > {{ __('Cancel') }} </button> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue index 7da82e90e29..9ac32ff13c6 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue @@ -21,7 +21,7 @@ export default { </i> <button type="button" - class="edit-link btn btn-blank pull-right js-sidebar-dropdown-toggle" + class="edit-link btn btn-blank float-right js-sidebar-dropdown-toggle" > {{ __('Edit') }} </button> diff --git a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue index bec4e7c99b6..368eeb6c453 100644 --- a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue +++ b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue @@ -40,7 +40,7 @@ export default { :class="cssClass" :title="tooltipTitle(time)" :data-placement="tooltipPlacement" - data-container="body"> - {{ timeFormated(time) }} + data-container="body" + v-text="timeFormated(time)"> </time> </template> diff --git a/app/assets/javascripts/vue_shared/directives/popover.js b/app/assets/javascripts/vue_shared/directives/popover.js index eb35294906b..c913bc34c68 100644 --- a/app/assets/javascripts/vue_shared/directives/popover.js +++ b/app/assets/javascripts/vue_shared/directives/popover.js @@ -17,6 +17,6 @@ export default { }, unbind(el) { - $(el).popover('destroy'); + $(el).popover('dispose'); }, }; diff --git a/app/assets/javascripts/vue_shared/directives/tooltip.js b/app/assets/javascripts/vue_shared/directives/tooltip.js index b7f7e9fec15..155e6b6698a 100644 --- a/app/assets/javascripts/vue_shared/directives/tooltip.js +++ b/app/assets/javascripts/vue_shared/directives/tooltip.js @@ -6,10 +6,10 @@ export default { }, componentUpdated(el) { - $(el).tooltip('fixTitle'); + $(el).tooltip('_fixTitle'); }, unbind(el) { - $(el).tooltip('destroy'); + $(el).tooltip('dispose'); }, }; |