diff options
Diffstat (limited to 'app')
154 files changed, 861 insertions, 1380 deletions
diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js index ea00efe4b46..815248f38ee 100644 --- a/app/assets/javascripts/boards/boards_bundle.js +++ b/app/assets/javascripts/boards/boards_bundle.js @@ -77,9 +77,6 @@ $(() => { }); Store.rootPath = this.boardsEndpoint; - this.filterManager = new FilteredSearchBoards(Store.filter, true); - this.filterManager.setup(); - // Listen for updateTokens event eventHub.$on('updateTokens', this.updateTokens); }, @@ -87,6 +84,9 @@ $(() => { eventHub.$off('updateTokens', this.updateTokens); }, mounted () { + this.filterManager = new FilteredSearchBoards(Store.filter, true); + this.filterManager.setup(); + Store.disabled = this.disabled; gl.boardService.all() .then(response => response.json()) diff --git a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.js b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.js deleted file mode 100644 index 8d3d34f836f..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.js +++ /dev/null @@ -1,17 +0,0 @@ -export default { - props: { - count: { - type: Number, - required: true, - }, - }, - template: ` - <span v-if="count === 50" class="events-info pull-right"> - <i class="fa fa-warning has-tooltip" - aria-hidden="true" - :title="n__('Limited to showing %d event at most', 'Limited to showing %d events at most', 50)" - data-placement="top"></i> - {{ n__('Showing %d event', 'Showing %d events', 50) }} - </span> - `, -}; diff --git a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue new file mode 100644 index 00000000000..6e94ba929b2 --- /dev/null +++ b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue @@ -0,0 +1,26 @@ +<script> + import tooltip from '../../vue_shared/directives/tooltip'; + + export default { + props: { + count: { + type: Number, + required: true, + }, + }, + directives: { + tooltip, + }, + }; +</script> +<template> + <span v-if="count === 50" class="events-info pull-right"> + <i + class="fa fa-warning" + v-tooltip + aria-hidden="true" + :title="n__('Limited to showing %d event at most', 'Limited to showing %d events at most', 50)" + data-placement="top"></i> + {{ n__('Showing %d event', 'Showing %d events', 50) }} + </span> +</template> diff --git a/app/assets/javascripts/cycle_analytics/components/stage_code_component.js b/app/assets/javascripts/cycle_analytics/components/stage_code_component.js deleted file mode 100644 index 7c32a38fbe7..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_code_component.js +++ /dev/null @@ -1,51 +0,0 @@ -/* eslint-disable no-param-reassign */ - -import Vue from 'vue'; -import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; - -const global = window.gl || (window.gl = {}); -global.cycleAnalytics = global.cycleAnalytics || {}; - -global.cycleAnalytics.StageCodeComponent = Vue.extend({ - props: { - items: Array, - stage: Object, - }, - components: { - userAvatarImage, - }, - template: ` - <div> - <div class="events-description"> - {{ stage.description }} - <limit-warning :count="items.length" /> - </div> - <ul class="stage-event-list"> - <li v-for="mergeRequest in items" class="stage-event-item"> - <div class="item-details"> - <!-- FIXME: Pass an alt attribute here for accessibility --> - <user-avatar-image :img-src="mergeRequest.author.avatarUrl"/> - <h5 class="item-title merge-merquest-title"> - <a :href="mergeRequest.url"> - {{ mergeRequest.title }} - </a> - </h5> - <a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a> - · - <span> - {{ s__('OpenedNDaysAgo|Opened') }} - <a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a> - </span> - <span> - {{ s__('ByAuthor|by') }} - <a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ mergeRequest.author.name }}</a> - </span> - </div> - <div class="item-time"> - <total-time :time="mergeRequest.totalTime"></total-time> - </div> - </li> - </ul> - </div> - `, -}); diff --git a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue new file mode 100644 index 00000000000..e4d62b649e5 --- /dev/null +++ b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue @@ -0,0 +1,47 @@ +<script> + import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; + + export default { + props: { + items: Array, + stage: Object, + }, + components: { + userAvatarImage, + }, + }; +</script> +<template> + <div> + <div class="events-description"> + {{ stage.description }} + <limit-warning :count="items.length" /> + </div> + <ul class="stage-event-list"> + <li v-for="mergeRequest in items" class="stage-event-item"> + <div class="item-details"> + <!-- FIXME: Pass an alt attribute here for accessibility --> + <user-avatar-image :img-src="mergeRequest.author.avatarUrl"/> + <h5 class="item-title merge-merquest-title"> + <a :href="mergeRequest.url"> + {{ mergeRequest.title }} + </a> + </h5> + <a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a> + · + <span> + {{ s__('OpenedNDaysAgo|Opened') }} + <a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a> + </span> + <span> + {{ s__('ByAuthor|by') }} + <a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ mergeRequest.author.name }}</a> + </span> + </div> + <div class="item-time"> + <total-time :time="mergeRequest.totalTime"></total-time> + </div> + </li> + </ul> + </div> +</template> diff --git a/app/assets/javascripts/cycle_analytics/components/stage_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_component.vue new file mode 100644 index 00000000000..ab730af8f5b --- /dev/null +++ b/app/assets/javascripts/cycle_analytics/components/stage_component.vue @@ -0,0 +1,53 @@ +<script> + import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; + + export default { + props: { + items: Array, + stage: Object, + }, + components: { + userAvatarImage, + }, + }; +</script> +<template> + <div> + <div class="events-description"> + {{ stage.description }} + <limit-warning :count="items.length" /> + </div> + <ul class="stage-event-list"> + <li + v-for="(issue, i) in items" + :key="i" + class="stage-event-item"> + <div class="item-details"> + <!-- FIXME: Pass an alt attribute here for accessibility --> + <user-avatar-image :img-src="issue.author.avatarUrl"/> + <h5 class="item-title issue-title"> + <a class="issue-title" :href="issue.url"> + {{ issue.title }} + </a> + </h5> + <a :href="issue.url" class="issue-link">#{{ issue.iid }}</a> + · + <span> + {{ s__('OpenedNDaysAgo|Opened') }} + <a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a> + </span> + <span> + {{ s__('ByAuthor|by') }} + <a :href="issue.author.webUrl" class="issue-author-link"> + {{ issue.author.name }} + </a> + </span> + </div> + <div class="item-time"> + <total-time :time="issue.totalTime"/> + </div> + </li> + </ul> + </div> +</template> + diff --git a/app/assets/javascripts/cycle_analytics/components/stage_issue_component.js b/app/assets/javascripts/cycle_analytics/components/stage_issue_component.js deleted file mode 100644 index 5f4a0ac8590..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_issue_component.js +++ /dev/null @@ -1,52 +0,0 @@ -/* eslint-disable no-param-reassign */ -import Vue from 'vue'; -import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; - -const global = window.gl || (window.gl = {}); -global.cycleAnalytics = global.cycleAnalytics || {}; - -global.cycleAnalytics.StageIssueComponent = Vue.extend({ - props: { - items: Array, - stage: Object, - }, - components: { - userAvatarImage, - }, - template: ` - <div> - <div class="events-description"> - {{ stage.description }} - <limit-warning :count="items.length" /> - </div> - <ul class="stage-event-list"> - <li v-for="issue in items" class="stage-event-item"> - <div class="item-details"> - <!-- FIXME: Pass an alt attribute here for accessibility --> - <user-avatar-image :img-src="issue.author.avatarUrl"/> - <h5 class="item-title issue-title"> - <a class="issue-title" :href="issue.url"> - {{ issue.title }} - </a> - </h5> - <a :href="issue.url" class="issue-link">#{{ issue.iid }}</a> - · - <span> - {{ s__('OpenedNDaysAgo|Opened') }} - <a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a> - </span> - <span> - {{ s__('ByAuthor|by') }} - <a :href="issue.author.webUrl" class="issue-author-link"> - {{ issue.author.name }} - </a> - </span> - </div> - <div class="item-time"> - <total-time :time="issue.totalTime"></total-time> - </div> - </li> - </ul> - </div> - `, -}); diff --git a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.js b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.js deleted file mode 100644 index 11fee5410d9..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.js +++ /dev/null @@ -1,53 +0,0 @@ -/* eslint-disable no-param-reassign */ -import Vue from 'vue'; -import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; -import iconCommit from '../svg/icon_commit.svg'; - -const global = window.gl || (window.gl = {}); -global.cycleAnalytics = global.cycleAnalytics || {}; - -global.cycleAnalytics.StagePlanComponent = Vue.extend({ - props: { - items: Array, - stage: Object, - }, - components: { - userAvatarImage, - }, - data() { - return { iconCommit }; - }, - template: ` - <div> - <div class="events-description"> - {{ stage.description }} - <limit-warning :count="items.length" /> - </div> - <ul class="stage-event-list"> - <li v-for="commit in items" class="stage-event-item"> - <div class="item-details item-conmmit-component"> - <!-- FIXME: Pass an alt attribute here for accessibility --> - <user-avatar-image :img-src="commit.author.avatarUrl"/> - <h5 class="item-title commit-title"> - <a :href="commit.commitUrl"> - {{ commit.title }} - </a> - </h5> - <span> - {{ s__('FirstPushedBy|First') }} - <span class="commit-icon">${iconCommit}</span> - <a :href="commit.commitUrl" class="commit-hash-link commit-sha">{{ commit.shortSha }}</a> - {{ s__('FirstPushedBy|pushed by') }} - <a :href="commit.author.webUrl" class="commit-author-link"> - {{ commit.author.name }} - </a> - </span> - </div> - <div class="item-time"> - <total-time :time="commit.totalTime"></total-time> - </div> - </li> - </ul> - </div> - `, -}); diff --git a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue new file mode 100644 index 00000000000..152c086a606 --- /dev/null +++ b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue @@ -0,0 +1,56 @@ +<script> +import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; +import iconCommit from '../svg/icon_commit.svg'; + +export default { + props: { + items: Array, + stage: Object, + }, + components: { + userAvatarImage, + }, + computed: { + iconCommit() { + return iconCommit; + }, + }, +}; +</script> +<template> + <div> + <div class="events-description"> + {{ stage.description }} + <limit-warning :count="items.length" /> + </div> + <ul class="stage-event-list"> + <li + v-for="(commit, i) in items" + :key="i" + class="stage-event-item"> + <div class="item-details item-conmmit-component"> + <!-- FIXME: Pass an alt attribute here for accessibility --> + <user-avatar-image :img-src="commit.author.avatarUrl"/> + <h5 class="item-title commit-title"> + <a :href="commit.commitUrl"> + {{ commit.title }} + </a> + </h5> + <span> + {{ s__('FirstPushedBy|First') }} + <span class="commit-icon" v-html="iconCommit"></span> + <a :href="commit.commitUrl" class="commit-hash-link commit-sha">{{ commit.shortSha }}</a> + {{ s__('FirstPushedBy|pushed by') }} + <a :href="commit.author.webUrl" class="commit-author-link"> + {{ commit.author.name }} + </a> + </span> + </div> + <div class="item-time"> + <total-time :time="commit.totalTime" /> + </div> + </li> + </ul> + </div> +</template> + diff --git a/app/assets/javascripts/cycle_analytics/components/stage_production_component.js b/app/assets/javascripts/cycle_analytics/components/stage_production_component.js deleted file mode 100644 index b7ba9360f70..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_production_component.js +++ /dev/null @@ -1,52 +0,0 @@ -/* eslint-disable no-param-reassign */ -import Vue from 'vue'; -import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; - -const global = window.gl || (window.gl = {}); -global.cycleAnalytics = global.cycleAnalytics || {}; - -global.cycleAnalytics.StageProductionComponent = Vue.extend({ - props: { - items: Array, - stage: Object, - }, - components: { - userAvatarImage, - }, - template: ` - <div> - <div class="events-description"> - {{ stage.description }} - <limit-warning :count="items.length" /> - </div> - <ul class="stage-event-list"> - <li v-for="issue in items" class="stage-event-item"> - <div class="item-details"> - <!-- FIXME: Pass an alt attribute here for accessibility --> - <user-avatar-image :img-src="issue.author.avatarUrl"/> - <h5 class="item-title issue-title"> - <a class="issue-title" :href="issue.url"> - {{ issue.title }} - </a> - </h5> - <a :href="issue.url" class="issue-link">#{{ issue.iid }}</a> - · - <span> - {{ s__('OpenedNDaysAgo|Opened') }} - <a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a> - </span> - <span> - {{ s__('ByAuthor|by') }} - <a :href="issue.author.webUrl" class="issue-author-link"> - {{ issue.author.name }} - </a> - </span> - </div> - <div class="item-time"> - <total-time :time="issue.totalTime"></total-time> - </div> - </li> - </ul> - </div> - `, -}); diff --git a/app/assets/javascripts/cycle_analytics/components/stage_review_component.js b/app/assets/javascripts/cycle_analytics/components/stage_review_component.js deleted file mode 100644 index f41a0d0e4ff..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_review_component.js +++ /dev/null @@ -1,62 +0,0 @@ -/* eslint-disable no-param-reassign */ -import Vue from 'vue'; -import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; - -const global = window.gl || (window.gl = {}); -global.cycleAnalytics = global.cycleAnalytics || {}; - -global.cycleAnalytics.StageReviewComponent = Vue.extend({ - props: { - items: Array, - stage: Object, - }, - components: { - userAvatarImage, - }, - template: ` - <div> - <div class="events-description"> - {{ stage.description }} - <limit-warning :count="items.length" /> - </div> - <ul class="stage-event-list"> - <li v-for="mergeRequest in items" class="stage-event-item"> - <div class="item-details"> - <!-- FIXME: Pass an alt attribute here for accessibility --> - <user-avatar-image :img-src="mergeRequest.author.avatarUrl"/> - <h5 class="item-title merge-merquest-title"> - <a :href="mergeRequest.url"> - {{ mergeRequest.title }} - </a> - </h5> - <a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a> - · - <span> - {{ s__('OpenedNDaysAgo|Opened') }} - <a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a> - </span> - <span> - {{ s__('ByAuthor|by') }} - <a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ mergeRequest.author.name }}</a> - </span> - <template v-if="mergeRequest.state === 'closed'"> - <span class="merge-request-state"> - <i class="fa fa-ban"></i> - {{ mergeRequest.state.toUpperCase() }} - </span> - </template> - <template v-else> - <span class="merge-request-branch" v-if="mergeRequest.branch"> - <i class= "fa fa-code-fork"></i> - <a :href="mergeRequest.branch.url">{{ mergeRequest.branch.name }}</a> - </span> - </template> - </div> - <div class="item-time"> - <total-time :time="mergeRequest.totalTime"></total-time> - </div> - </li> - </ul> - </div> - `, -}); diff --git a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue new file mode 100644 index 00000000000..9e66b690404 --- /dev/null +++ b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue @@ -0,0 +1,62 @@ +<script> + import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; + + export default { + props: { + items: Array, + stage: Object, + }, + components: { + userAvatarImage, + }, + }; +</script> +<template> + <div> + <div class="events-description"> + {{ stage.description }} + <limit-warning :count="items.length" /> + </div> + <ul class="stage-event-list"> + <li + v-for="(mergeRequest, i) in items" + :key="i" + class="stage-event-item"> + <div class="item-details"> + <!-- FIXME: Pass an alt attribute here for accessibility --> + <user-avatar-image :img-src="mergeRequest.author.avatarUrl"/> + <h5 class="item-title merge-merquest-title"> + <a :href="mergeRequest.url"> + {{ mergeRequest.title }} + </a> + </h5> + <a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a> + · + <span> + {{ s__('OpenedNDaysAgo|Opened') }} + <a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a> + </span> + <span> + {{ s__('ByAuthor|by') }} + <a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ mergeRequest.author.name }}</a> + </span> + <template v-if="mergeRequest.state === 'closed'"> + <span class="merge-request-state"> + <i class="fa fa-ban"></i> + {{ mergeRequest.state.toUpperCase() }} + </span> + </template> + <template v-else> + <span class="merge-request-branch" v-if="mergeRequest.branch"> + <i class= "fa fa-code-fork"></i> + <a :href="mergeRequest.branch.url">{{ mergeRequest.branch.name }}</a> + </span> + </template> + </div> + <div class="item-time"> + <total-time :time="mergeRequest.totalTime"/> + </div> + </li> + </ul> + </div> +</template> diff --git a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.js b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.js deleted file mode 100644 index d7c906c9d39..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.js +++ /dev/null @@ -1,53 +0,0 @@ -/* eslint-disable no-param-reassign */ -import Vue from 'vue'; -import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; -import iconBranch from '../svg/icon_branch.svg'; - -const global = window.gl || (window.gl = {}); -global.cycleAnalytics = global.cycleAnalytics || {}; - -global.cycleAnalytics.StageStagingComponent = Vue.extend({ - props: { - items: Array, - stage: Object, - }, - data() { - return { iconBranch }; - }, - components: { - userAvatarImage, - }, - template: ` - <div> - <div class="events-description"> - {{ stage.description }} - <limit-warning :count="items.length" /> - </div> - <ul class="stage-event-list"> - <li v-for="build in items" class="stage-event-item item-build-component"> - <div class="item-details"> - <!-- FIXME: Pass an alt attribute here for accessibility --> - <user-avatar-image :img-src="build.author.avatarUrl"/> - <h5 class="item-title"> - <a :href="build.url" class="pipeline-id">#{{ build.id }}</a> - <i class="fa fa-code-fork"></i> - <a :href="build.branch.url" class="ref-name">{{ build.branch.name }}</a> - <span class="icon-branch">${iconBranch}</span> - <a :href="build.commitUrl" class="commit-sha">{{ build.shortSha }}</a> - </h5> - <span> - <a :href="build.url" class="build-date">{{ build.date }}</a> - {{ s__('ByAuthor|by') }} - <a :href="build.author.webUrl" class="issue-author-link"> - {{ build.author.name }} - </a> - </span> - </div> - <div class="item-time"> - <total-time :time="build.totalTime"></total-time> - </div> - </li> - </ul> - </div> - `, -}); diff --git a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue new file mode 100644 index 00000000000..2787b5ea47b --- /dev/null +++ b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue @@ -0,0 +1,55 @@ +<script> + import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; + import iconBranch from '../svg/icon_branch.svg'; + + export default { + props: { + items: Array, + stage: Object, + }, + components: { + userAvatarImage, + }, + computed: { + iconBranch() { + return iconBranch; + }, + }, + }; +</script> +<template> + <div> + <div class="events-description"> + {{ stage.description }} + <limit-warning :count="items.length" /> + </div> + <ul class="stage-event-list"> + <li + v-for="(build, i) in items" + class="stage-event-item item-build-component" + :key="i"> + <div class="item-details"> + <!-- FIXME: Pass an alt attribute here for accessibility --> + <user-avatar-image :img-src="build.author.avatarUrl"/> + <h5 class="item-title"> + <a :href="build.url" class="pipeline-id">#{{ build.id }}</a> + <i class="fa fa-code-fork"></i> + <a :href="build.branch.url" class="ref-name">{{ build.branch.name }}</a> + <span class="icon-branch" v-html="iconBranch"></span> + <a :href="build.commitUrl" class="commit-sha">{{ build.shortSha }}</a> + </h5> + <span> + <a :href="build.url" class="build-date">{{ build.date }}</a> + {{ s__('ByAuthor|by') }} + <a :href="build.author.webUrl" class="issue-author-link"> + {{ build.author.name }} + </a> + </span> + </div> + <div class="item-time"> + <total-time :time="build.totalTime"/> + </div> + </li> + </ul> + </div> +</template> diff --git a/app/assets/javascripts/cycle_analytics/components/stage_test_component.js b/app/assets/javascripts/cycle_analytics/components/stage_test_component.js deleted file mode 100644 index 78cc97eea0b..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_test_component.js +++ /dev/null @@ -1,49 +0,0 @@ -/* eslint-disable no-param-reassign */ -import Vue from 'vue'; -import iconBuildStatus from '../svg/icon_build_status.svg'; -import iconBranch from '../svg/icon_branch.svg'; - -const global = window.gl || (window.gl = {}); -global.cycleAnalytics = global.cycleAnalytics || {}; - -global.cycleAnalytics.StageTestComponent = Vue.extend({ - props: { - items: Array, - stage: Object, - }, - data() { - return { iconBuildStatus, iconBranch }; - }, - template: ` - <div> - <div class="events-description"> - {{ stage.description }} - <limit-warning :count="items.length" /> - </div> - <ul class="stage-event-list"> - <li v-for="build in items" class="stage-event-item item-build-component"> - <div class="item-details"> - <h5 class="item-title"> - <span class="icon-build-status">${iconBuildStatus}</span> - <a :href="build.url" class="item-build-name">{{ build.name }}</a> - · - <a :href="build.url" class="pipeline-id">#{{ build.id }}</a> - <i class="fa fa-code-fork"></i> - <a :href="build.branch.url" class="ref-name">{{ build.branch.name }}</a> - <span class="icon-branch">${iconBranch}</span> - <a :href="build.commitUrl" class="commit-sha">{{ build.shortSha }}</a> - </h5> - <span> - <a :href="build.url" class="issue-date"> - {{ build.date }} - </a> - </span> - </div> - <div class="item-time"> - <total-time :time="build.totalTime"></total-time> - </div> - </li> - </ul> - </div> - `, -}); diff --git a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue new file mode 100644 index 00000000000..9c3d39ce011 --- /dev/null +++ b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue @@ -0,0 +1,54 @@ +<script> +import iconBuildStatus from '../svg/icon_build_status.svg'; +import iconBranch from '../svg/icon_branch.svg'; + +export default { + props: { + items: Array, + stage: Object, + }, + computed: { + iconBuildStatus() { + return iconBuildStatus; + }, + iconBranch() { + return iconBranch; + }, + }, +}; +</script> +<template> + <div> + <div class="events-description"> + {{ stage.description }} + <limit-warning :count="items.length" /> + </div> + <ul class="stage-event-list"> + <li + v-for="(build, i) in items" + :key="i" + class="stage-event-item item-build-component"> + <div class="item-details"> + <h5 class="item-title"> + <span class="icon-build-status" v-html="iconBuildStatus"></span> + <a :href="build.url" class="item-build-name">{{ build.name }}</a> + · + <a :href="build.url" class="pipeline-id">#{{ build.id }}</a> + <i class="fa fa-code-fork"></i> + <a :href="build.branch.url" class="ref-name">{{ build.branch.name }}</a> + <span class="icon-branch" v-html="iconBranch"></span> + <a :href="build.commitUrl" class="commit-sha">{{ build.shortSha }}</a> + </h5> + <span> + <a :href="build.url" class="issue-date"> + {{ build.date }} + </a> + </span> + </div> + <div class="item-time"> + <total-time :time="build.totalTime"/> + </div> + </li> + </ul> + </div> +</template> diff --git a/app/assets/javascripts/cycle_analytics/components/total_time_component.js b/app/assets/javascripts/cycle_analytics/components/total_time_component.js deleted file mode 100644 index d5e6167b2a8..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/total_time_component.js +++ /dev/null @@ -1,25 +0,0 @@ -/* eslint-disable no-param-reassign */ - -import Vue from 'vue'; - -const global = window.gl || (window.gl = {}); -global.cycleAnalytics = global.cycleAnalytics || {}; - -global.cycleAnalytics.TotalTimeComponent = Vue.extend({ - props: { - time: Object, - }, - template: ` - <span class="total-time"> - <template v-if="Object.keys(time).length"> - <template v-if="time.days">{{ time.days }} <span>{{ n__('day', 'days', time.days) }}</span></template> - <template v-if="time.hours">{{ time.hours }} <span>{{ n__('Time|hr', 'Time|hrs', time.hours) }}</span></template> - <template v-if="time.mins && !time.days">{{ time.mins }} <span>{{ n__('Time|min', 'Time|mins', time.mins) }}</span></template> - <template v-if="time.seconds && Object.keys(time).length === 1 || time.seconds === 0">{{ time.seconds }} <span>{{ s__('Time|s') }}</span></template> - </template> - <template v-else> - -- - </template> - </span> - `, -}); diff --git a/app/assets/javascripts/cycle_analytics/components/total_time_component.vue b/app/assets/javascripts/cycle_analytics/components/total_time_component.vue new file mode 100644 index 00000000000..9941b997b3f --- /dev/null +++ b/app/assets/javascripts/cycle_analytics/components/total_time_component.vue @@ -0,0 +1,29 @@ +<script> + export default { + props: { + time: { + type: Object, + required: false, + default: () => ({}), + }, + }, + computed: { + hasData() { + return Object.keys(this.time).length; + }, + }, + }; +</script> +<template> + <span class="total-time"> + <template v-if="hasData"> + <template v-if="time.days">{{ time.days }} <span>{{ n__('day', 'days', time.days) }}</span></template> + <template v-if="time.hours">{{ time.hours }} <span>{{ n__('Time|hr', 'Time|hrs', time.hours) }}</span></template> + <template v-if="time.mins && !time.days">{{ time.mins }} <span>{{ n__('Time|min', 'Time|mins', time.mins) }}</span></template> + <template v-if="time.seconds && hasDa === 1 || time.seconds === 0">{{ time.seconds }} <span>{{ s__('Time|s') }}</span></template> + </template> + <template v-else> + -- + </template> + </span> +</template> diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js index 5f1221c4c49..8002b0b23c9 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js @@ -3,15 +3,14 @@ import Vue from 'vue'; import Cookies from 'js-cookie'; import Translate from '../vue_shared/translate'; -import LimitWarningComponent from './components/limit_warning_component'; -import './components/stage_code_component'; -import './components/stage_issue_component'; -import './components/stage_plan_component'; -import './components/stage_production_component'; -import './components/stage_review_component'; -import './components/stage_staging_component'; -import './components/stage_test_component'; -import './components/total_time_component'; +import limitWarningComponent from './components/limit_warning_component.vue'; +import stageCodeComponent from './components/stage_code_component.vue'; +import stagePlanComponent from './components/stage_plan_component.vue'; +import stageComponent from './components/stage_component.vue'; +import stageReviewComponent from './components/stage_review_component.vue'; +import stageStagingComponent from './components/stage_staging_component.vue'; +import stageTestComponent from './components/stage_test_component.vue'; +import totalTime from './components/total_time_component.vue'; import CycleAnalyticsService from './cycle_analytics_service'; import CycleAnalyticsStore from './cycle_analytics_store'; @@ -47,13 +46,13 @@ $(() => { }, }, components: { - 'stage-issue-component': gl.cycleAnalytics.StageIssueComponent, - 'stage-plan-component': gl.cycleAnalytics.StagePlanComponent, - 'stage-code-component': gl.cycleAnalytics.StageCodeComponent, - 'stage-test-component': gl.cycleAnalytics.StageTestComponent, - 'stage-review-component': gl.cycleAnalytics.StageReviewComponent, - 'stage-staging-component': gl.cycleAnalytics.StageStagingComponent, - 'stage-production-component': gl.cycleAnalytics.StageProductionComponent, + 'stage-issue-component': stageComponent, + 'stage-plan-component': stagePlanComponent, + 'stage-code-component': stageCodeComponent, + 'stage-test-component': stageTestComponent, + 'stage-review-component': stageReviewComponent, + 'stage-staging-component': stageStagingComponent, + 'stage-production-component': stageComponent, }, created() { this.fetchCycleAnalyticsData(); @@ -136,6 +135,6 @@ $(() => { }); // Register global components - Vue.component('limit-warning', LimitWarningComponent); - Vue.component('total-time', gl.cycleAnalytics.TotalTimeComponent); + Vue.component('limit-warning', limitWarningComponent); + Vue.component('total-time', totalTime); }); diff --git a/app/assets/javascripts/files_comment_button.js b/app/assets/javascripts/files_comment_button.js index d02e4cd5876..a00d29a845a 100644 --- a/app/assets/javascripts/files_comment_button.js +++ b/app/assets/javascripts/files_comment_button.js @@ -7,6 +7,8 @@ * causes reflows, visit https://gist.github.com/paulirish/5d52fb081b3570c81e3a */ +import Cookies from 'js-cookie'; + const LINE_NUMBER_CLASS = 'diff-line-num'; const UNFOLDABLE_LINE_CLASS = 'js-unfold'; const NO_COMMENT_CLASS = 'no-comment-btn'; @@ -27,9 +29,7 @@ export default { this.userCanCreateNote = $diffFile.closest(DIFF_CONTAINER_SELECTOR).data('can-create-note') === ''; } - if (typeof notes !== 'undefined' && !this.isParallelView) { - this.isParallelView = notes.isParallelView && notes.isParallelView(); - } + this.isParallelView = Cookies.get('diff_view') === 'parallel'; if (this.userCanCreateNote) { $diffFile.on('mouseover', LINE_COLUMN_CLASSES, e => this.showButton(this.isParallelView, e)) diff --git a/app/assets/javascripts/lib/utils/sticky.js b/app/assets/javascripts/lib/utils/sticky.js index 283c0ec0410..64db42701ce 100644 --- a/app/assets/javascripts/lib/utils/sticky.js +++ b/app/assets/javascripts/lib/utils/sticky.js @@ -1,14 +1,34 @@ -export const isSticky = (el, scrollY, stickyTop) => { +export const createPlaceholder = () => { + const placeholder = document.createElement('div'); + placeholder.classList.add('sticky-placeholder'); + + return placeholder; +}; + +export const isSticky = (el, scrollY, stickyTop, insertPlaceholder) => { const top = Math.floor(el.offsetTop - scrollY); - if (top <= stickyTop) { + if (top <= stickyTop && !el.classList.contains('is-stuck')) { + const placeholder = insertPlaceholder ? createPlaceholder() : null; + const heightBefore = el.offsetHeight; + el.classList.add('is-stuck'); - } else { + + if (insertPlaceholder) { + el.parentNode.insertBefore(placeholder, el.nextElementSibling); + + placeholder.style.height = `${heightBefore - el.offsetHeight}px`; + } + } else if (top > stickyTop && el.classList.contains('is-stuck')) { el.classList.remove('is-stuck'); + + if (insertPlaceholder && el.nextElementSibling && el.nextElementSibling.classList.contains('sticky-placeholder')) { + el.nextElementSibling.remove(); + } } }; -export default (el) => { +export default (el, insertPlaceholder = true) => { if (!el) return; const computedStyle = window.getComputedStyle(el); @@ -17,7 +37,7 @@ export default (el) => { const stickyTop = parseInt(computedStyle.top, 10); - document.addEventListener('scroll', () => isSticky(el, window.scrollY, stickyTop), { + document.addEventListener('scroll', () => isSticky(el, window.scrollY, stickyTop, insertPlaceholder), { passive: true, }); }; diff --git a/app/assets/javascripts/line_highlighter.js b/app/assets/javascripts/line_highlighter.js index 7400c22543f..a16d00b5cef 100644 --- a/app/assets/javascripts/line_highlighter.js +++ b/app/assets/javascripts/line_highlighter.js @@ -28,148 +28,149 @@ // </div> // </div> // -(function() { - this.LineHighlighter = (function() { - // CSS class applied to highlighted lines - LineHighlighter.prototype.highlightClass = 'hll'; - - // Internal copy of location.hash so we're not dependent on `location` in tests - LineHighlighter.prototype._hash = ''; - - function LineHighlighter(hash) { - if (hash == null) { - // Initialize a LineHighlighter object - // - // hash - String URL hash for dependency injection in tests - hash = location.hash; - } - this.setHash = this.setHash.bind(this); - this.highlightLine = this.highlightLine.bind(this); - this.clickHandler = this.clickHandler.bind(this); - this.highlightHash = this.highlightHash.bind(this); - this._hash = hash; - this.bindEvents(); - this.highlightHash(); - } - LineHighlighter.prototype.bindEvents = function() { - const $fileHolder = $('.file-holder'); - $fileHolder.on('click', 'a[data-line-number]', this.clickHandler); - $fileHolder.on('highlight:line', this.highlightHash); - }; - - LineHighlighter.prototype.highlightHash = function() { - var range; - if (this._hash !== '') { - range = this.hashToRange(this._hash); - if (range[0]) { - this.highlightRange(range); - $.scrollTo("#L" + range[0], { - // Scroll to the first highlighted line on initial load - // Offset -50 for the sticky top bar, and another -100 for some context - offset: -150 - }); - } - } - }; - - LineHighlighter.prototype.clickHandler = function(event) { - var current, lineNumber, range; - event.preventDefault(); - this.clearHighlight(); - lineNumber = $(event.target).closest('a').data('line-number'); - current = this.hashToRange(this._hash); - if (!(current[0] && event.shiftKey)) { - // If there's no current selection, or there is but Shift wasn't held, - // treat this like a single-line selection. - this.setHash(lineNumber); - return this.highlightLine(lineNumber); - } else if (event.shiftKey) { - if (lineNumber < current[0]) { - range = [lineNumber, current[0]]; - } else { - range = [current[0], lineNumber]; - } - this.setHash(range[0], range[1]); - return this.highlightRange(range); - } - }; - - LineHighlighter.prototype.clearHighlight = function() { - return $("." + this.highlightClass).removeClass(this.highlightClass); - // Unhighlight previously highlighted lines - }; - - // Convert a URL hash String into line numbers - // - // hash - Hash String - // - // Examples: - // - // hashToRange('#L5') # => [5, null] - // hashToRange('#L5-15') # => [5, 15] - // hashToRange('#foo') # => [null, null] - // - // Returns an Array - LineHighlighter.prototype.hashToRange = function(hash) { - var first, last, matches; - // ?L(\d+)(?:-(\d+))?$/) - matches = hash.match(/^#?L(\d+)(?:-(\d+))?$/); - if (matches && matches.length) { - first = parseInt(matches[1], 10); - last = matches[2] ? parseInt(matches[2], 10) : null; - return [first, last]; - } else { - return [null, null]; - } - }; - - // Highlight a single line - // - // lineNumber - Line number to highlight - LineHighlighter.prototype.highlightLine = function(lineNumber) { - return $("#LC" + lineNumber).addClass(this.highlightClass); - }; - - // Highlight all lines within a range - // - // range - Array containing the starting and ending line numbers - LineHighlighter.prototype.highlightRange = function(range) { - var i, lineNumber, ref, ref1, results; - if (range[1]) { - results = []; - for (lineNumber = i = ref = range[0], ref1 = range[1]; ref <= ref1 ? i <= ref1 : i >= ref1; lineNumber = ref <= ref1 ? (i += 1) : (i -= 1)) { - results.push(this.highlightLine(lineNumber)); - } - return results; - } else { - return this.highlightLine(range[0]); - } - }; +const LineHighlighter = function(options = {}) { + options.highlightLineClass = options.highlightLineClass || 'hll'; + options.fileHolderSelector = options.fileHolderSelector || '.file-holder'; + options.scrollFileHolder = options.scrollFileHolder || false; + options.hash = options.hash || location.hash; - // Set the URL hash string - LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) { - var hash; - if (lastLineNumber) { - hash = "#L" + firstLineNumber + "-" + lastLineNumber; + this.options = options; + this._hash = options.hash; + this.highlightLineClass = options.highlightLineClass; + this.setHash = this.setHash.bind(this); + this.highlightLine = this.highlightLine.bind(this); + this.clickHandler = this.clickHandler.bind(this); + this.highlightHash = this.highlightHash.bind(this); + + this.bindEvents(); + this.highlightHash(); +}; + +LineHighlighter.prototype.bindEvents = function() { + const $fileHolder = $(this.options.fileHolderSelector); + + $fileHolder.on('click', 'a[data-line-number]', this.clickHandler); + $fileHolder.on('highlight:line', this.highlightHash); +}; + +LineHighlighter.prototype.highlightHash = function() { + var range; + + if (this._hash !== '') { + range = this.hashToRange(this._hash); + + if (range[0]) { + this.highlightRange(range); + const lineSelector = `#L${range[0]}`; + const scrollOptions = { + // Scroll to the first highlighted line on initial load + // Offset -50 for the sticky top bar, and another -100 for some context + offset: -150 + }; + if (this.options.scrollFileHolder) { + $(this.options.fileHolderSelector).scrollTo(lineSelector, scrollOptions); } else { - hash = "#L" + firstLineNumber; + $.scrollTo(lineSelector, scrollOptions); } - this._hash = hash; - return this.__setLocationHash__(hash); - }; - - // Make the actual hash change in the browser - // - // This method is stubbed in tests. - LineHighlighter.prototype.__setLocationHash__ = function(value) { - return history.pushState({ - url: value - // We're using pushState instead of assigning location.hash directly to - // prevent the page from scrolling on the hashchange event - }, document.title, value); - }; - - return LineHighlighter; - })(); -}).call(window); + } + } +}; + +LineHighlighter.prototype.clickHandler = function(event) { + var current, lineNumber, range; + event.preventDefault(); + this.clearHighlight(); + lineNumber = $(event.target).closest('a').data('line-number'); + current = this.hashToRange(this._hash); + if (!(current[0] && event.shiftKey)) { + // If there's no current selection, or there is but Shift wasn't held, + // treat this like a single-line selection. + this.setHash(lineNumber); + return this.highlightLine(lineNumber); + } else if (event.shiftKey) { + if (lineNumber < current[0]) { + range = [lineNumber, current[0]]; + } else { + range = [current[0], lineNumber]; + } + this.setHash(range[0], range[1]); + return this.highlightRange(range); + } +}; + +LineHighlighter.prototype.clearHighlight = function() { + return $("." + this.highlightLineClass).removeClass(this.highlightLineClass); +}; + +// Convert a URL hash String into line numbers +// +// hash - Hash String +// +// Examples: +// +// hashToRange('#L5') # => [5, null] +// hashToRange('#L5-15') # => [5, 15] +// hashToRange('#foo') # => [null, null] +// +// Returns an Array +LineHighlighter.prototype.hashToRange = function(hash) { + var first, last, matches; + // ?L(\d+)(?:-(\d+))?$/) + matches = hash.match(/^#?L(\d+)(?:-(\d+))?$/); + if (matches && matches.length) { + first = parseInt(matches[1], 10); + last = matches[2] ? parseInt(matches[2], 10) : null; + return [first, last]; + } else { + return [null, null]; + } +}; + +// Highlight a single line +// +// lineNumber - Line number to highlight +LineHighlighter.prototype.highlightLine = function(lineNumber) { + return $("#LC" + lineNumber).addClass(this.highlightLineClass); +}; + +// Highlight all lines within a range +// +// range - Array containing the starting and ending line numbers +LineHighlighter.prototype.highlightRange = function(range) { + var i, lineNumber, ref, ref1, results; + if (range[1]) { + results = []; + for (lineNumber = i = ref = range[0], ref1 = range[1]; ref <= ref1 ? i <= ref1 : i >= ref1; lineNumber = ref <= ref1 ? (i += 1) : (i -= 1)) { + results.push(this.highlightLine(lineNumber)); + } + return results; + } else { + return this.highlightLine(range[0]); + } +}; + +// Set the URL hash string +LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) { + var hash; + if (lastLineNumber) { + hash = "#L" + firstLineNumber + "-" + lastLineNumber; + } else { + hash = "#L" + firstLineNumber; + } + this._hash = hash; + return this.__setLocationHash__(hash); +}; + +// Make the actual hash change in the browser +// +// This method is stubbed in tests. +LineHighlighter.prototype.__setLocationHash__ = function(value) { + return history.pushState({ + url: value + // We're using pushState instead of assigning location.hash directly to + // prevent the page from scrolling on the hashchange event + }, document.title, value); +}; + +window.LineHighlighter = LineHighlighter; diff --git a/app/assets/javascripts/locale/index.js b/app/assets/javascripts/locale/index.js index 7ba676d6d20..6a5084efeb8 100644 --- a/app/assets/javascripts/locale/index.js +++ b/app/assets/javascripts/locale/index.js @@ -16,9 +16,8 @@ const locales = allLocales.reduce((d, obj) => { return data; }, {}); -let lang = document.querySelector('html').getAttribute('lang') || 'en'; -lang = lang.replace(/-/g, '_'); - +const langAttribute = document.querySelector('html').getAttribute('lang'); +const lang = (langAttribute || 'en').replace(/-/g, '_'); const locale = new Jed(locales[lang]); /** diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index 8ae127776e8..d3299c15720 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -352,7 +352,7 @@ import { } expandViewContainer() { - const $wrapper = $('.content-wrapper .container-fluid'); + const $wrapper = $('.content-wrapper .container-fluid').not('.breadcrumbs'); if (this.fixedLayoutPref === null) { this.fixedLayoutPref = $wrapper.hasClass('container-limited'); } diff --git a/app/assets/javascripts/profile/gl_crop.js b/app/assets/javascripts/profile/gl_crop.js index 291ae24aa68..4bdda611cfc 100644 --- a/app/assets/javascripts/profile/gl_crop.js +++ b/app/assets/javascripts/profile/gl_crop.js @@ -73,7 +73,8 @@ import _ from 'underscore'; aspectRatio: 1, modal: true, scalable: false, - rotatable: false, + rotatable: true, + checkOrientation: true, zoomable: true, dragMode: 'move', guides: false, diff --git a/app/assets/javascripts/repo/components/repo_preview.vue b/app/assets/javascripts/repo/components/repo_preview.vue index 2200754cbef..0d9d132f766 100644 --- a/app/assets/javascripts/repo/components/repo_preview.vue +++ b/app/assets/javascripts/repo/components/repo_preview.vue @@ -1,23 +1,27 @@ <script> +/* global LineHighlighter */ + import Store from '../stores/repo_store'; export default { data: () => Store, - mounted() { - this.highlightFile(); - }, computed: { html() { return this.activeFile.html; }, }, - methods: { highlightFile() { $(this.$el).find('.file-content').syntaxHighlight(); }, }, - + mounted() { + this.highlightFile(); + this.lineHighlighter = new LineHighlighter({ + fileHolderSelector: '.blob-viewer-container', + scrollFileHolder: true, + }); + }, watch: { html() { this.$nextTick(() => { diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss index 923d14f2c3d..74b846217bb 100644 --- a/app/assets/stylesheets/framework.scss +++ b/app/assets/stylesheets/framework.scss @@ -31,10 +31,12 @@ @import "framework/mobile"; @import "framework/modal"; @import "framework/nav"; +@import "framework/new-nav"; @import "framework/pagination"; @import "framework/panels"; @import "framework/selects"; @import "framework/sidebar"; +@import "framework/new-sidebar"; @import "framework/tables"; @import "framework/notes"; @import "framework/timeline"; diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss index 89d1d1f8ab3..0d1c04026b8 100644 --- a/app/assets/stylesheets/framework/gitlab-theme.scss +++ b/app/assets/stylesheets/framework/gitlab-theme.scss @@ -254,6 +254,10 @@ body { .search-icon { color: $theme-gray-200; } + + .search-input { + color: $gl-text-color; + } } .location-badge { diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index 304bd4443b0..2fee2164190 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -144,3 +144,39 @@ @mixin green-status-color { @include status-color($green-100, $green-500, $green-700); } + +@mixin fade($gradient-direction, $gradient-color) { + visibility: hidden; + opacity: 0; + z-index: 2; + position: absolute; + bottom: 12px; + width: 43px; + height: 30px; + transition-duration: .3s; + -webkit-transform: translateZ(0); + background: linear-gradient(to $gradient-direction, $gradient-color 45%, rgba($gradient-color, 0.4)); + + &.scrolling { + visibility: visible; + opacity: 1; + transition-duration: .3s; + } + + .fa { + position: relative; + top: 5px; + font-size: 18px; + } +} + +@mixin scrolling-links() { + overflow-x: auto; + overflow-y: hidden; + -webkit-overflow-scrolling: touch; + display: flex; + + &::-webkit-scrollbar { + display: none; + } +} diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index 2f7717760ec..f8777d1fd9d 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -1,38 +1,4 @@ -@mixin fade($gradient-direction, $gradient-color) { - visibility: hidden; - opacity: 0; - z-index: 2; - position: absolute; - bottom: 12px; - width: 43px; - height: 30px; - transition-duration: .3s; - -webkit-transform: translateZ(0); - background: linear-gradient(to $gradient-direction, $gradient-color 45%, rgba($gradient-color, 0.4)); - - &.scrolling { - visibility: visible; - opacity: 1; - transition-duration: .3s; - } - - .fa { - position: relative; - top: 5px; - font-size: 18px; - } -} -@mixin scrolling-links() { - overflow-x: auto; - overflow-y: hidden; - -webkit-overflow-scrolling: touch; - display: flex; - - &::-webkit-scrollbar { - display: none; - } -} .nav-links { display: flex; diff --git a/app/assets/stylesheets/new_nav.scss b/app/assets/stylesheets/framework/new-nav.scss index 8c5bafac637..81022d4af2a 100644 --- a/app/assets/stylesheets/new_nav.scss +++ b/app/assets/stylesheets/framework/new-nav.scss @@ -295,75 +295,6 @@ header.navbar-gitlab-new { margin-top: 4px; } -.search { - margin: 4px 8px 0; - - form { - height: 32px; - border: 0; - border-radius: $border-radius-default; - transition: border-color ease-in-out 0.15s, background-color ease-in-out 0.15s; - - &:hover { - box-shadow: none; - } - } - - &.search-active form { - box-shadow: none; - - .search-input { - color: $gl-text-color; - transition: color ease-in-out 0.15s; - } - - .search-input::placeholder { - color: $gl-text-color-tertiary; - } - - .search-input-wrap { - .search-icon, - .clear-icon { - color: $gl-text-color-tertiary; - transition: color ease-in-out 0.15s; - } - } - } - - .search-input { - color: $white-light; - background: none; - transition: color ease-in-out 0.15s; - } - - .search-input::placeholder { - transition: color ease-in-out 0.15s; - } - - .location-badge { - font-size: 12px; - margin: -4px 4px -4px -4px; - line-height: 25px; - padding: 4px 8px; - border-radius: 2px 0 0 2px; - height: 32px; - transition: border-color ease-in-out 0.15s; - } - - &.search-active { - .location-badge { - background-color: $nav-badge-bg; - border-color: $border-color; - } - - .search-input-wrap { - .clear-icon { - color: $white-light; - } - } - } -} - .breadcrumbs { display: flex; min-height: 48px; @@ -375,6 +306,8 @@ header.navbar-gitlab-new { display: flex; width: 100%; position: relative; + padding-top: $gl-padding / 2; + padding-bottom: $gl-padding / 2; align-items: center; border-bottom: 1px solid $border-color; } @@ -386,11 +319,6 @@ header.navbar-gitlab-new { align-self: center; color: $gl-text-color-secondary; - @media (max-width: $screen-xs-max) { - padding-left: 17px; - border-left: 1px solid $gl-text-color-quaternary; - } - .avatar-tile { margin-right: 4px; border: 1px solid $border-color; @@ -420,6 +348,7 @@ header.navbar-gitlab-new { display: flex; align-items: center; position: relative; + padding: 2px 0; &:not(:last-child) { margin-right: 20px; @@ -455,7 +384,7 @@ header.navbar-gitlab-new { margin: 0; font-size: 12px; font-weight: 600; - line-height: 1; + line-height: 16px; a { color: $gl-text-color; diff --git a/app/assets/stylesheets/new_sidebar.scss b/app/assets/stylesheets/framework/new-sidebar.scss index 9c404b7e542..3f1cb97aebc 100644 --- a/app/assets/stylesheets/new_sidebar.scss +++ b/app/assets/stylesheets/framework/new-sidebar.scss @@ -461,6 +461,13 @@ $new-sidebar-collapsed-width: 50px; font-size: 18px; } } + + @media (max-width: $screen-xs-max) { + + .breadcrumbs-links { + padding-left: 17px; + border-left: 1px solid $gl-text-color-quaternary; + } + } } @media (max-width: $screen-xs-max) { diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 00efe86918d..e8bb42f4a8c 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -6,6 +6,8 @@ $gutter_width: 290px; $gutter_inner_width: 250px; $sidebar-transition-duration: .15s; $sidebar-breakpoint: 1024px; +$default-transition-duration: .15s; +$right-sidebar-transition-duration: .3s; /* * Color schema diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss index 700be173039..3305a482a0d 100644 --- a/app/assets/stylesheets/pages/boards.scss +++ b/app/assets/stylesheets/pages/boards.scss @@ -55,6 +55,15 @@ .boards-app { position: relative; + + @media (min-width: $screen-sm-min) { + transition: width $right-sidebar-transition-duration; + width: 100%; + + &.is-compact { + width: calc(100% - #{$gutter_width}); + } + } } .boards-app-loading { @@ -78,11 +87,6 @@ height: calc(100vh - 222px); // scss-lint:enable DuplicateProperty min-height: 475px; - transition: width .2s; - - &.is-compact { - width: calc(100% - 290px); - } } } @@ -412,14 +416,6 @@ .page-with-layout-nav.page-with-sub-nav .issue-boards-sidebar, .page-with-new-sidebar.page-with-sidebar .issue-boards-sidebar { - position: absolute; - - &.right-sidebar { - top: 0; - bottom: 0; - height: 100%; - } - .issuable-sidebar-header { position: relative; } @@ -457,8 +453,8 @@ .right-sidebar.right-sidebar-expanded { &.boards-sidebar-slide-enter-active, &.boards-sidebar-slide-leave-active { - transition: width .2s, - padding .2s; + transition: width $right-sidebar-transition-duration, + padding $right-sidebar-transition-duration; } &.boards-sidebar-slide-enter, diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index 951580ea1fe..e4bd783c8bc 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -451,7 +451,7 @@ } .files { - margin-top: -1px; + margin-top: 1px; .diff-file:last-child { margin-bottom: 0; @@ -535,7 +535,6 @@ } .diff-notes-collapse { - position: relative; width: 19px; height: 19px; padding: 0; @@ -543,11 +542,7 @@ z-index: 100; svg { - position: absolute; - left: 50%; - top: 50%; - margin-left: -5.5px; - margin-top: -5.5px; + vertical-align: text-top; } path { @@ -586,11 +581,6 @@ top: 76px; } - + .files, - + .alert { - margin-top: 1px; - } - &:not(.is-stuck) .diff-stats-additions-deletions-collapsed { display: none; } @@ -605,11 +595,6 @@ .inline-parallel-buttons { display: none; } - - + .files, - + .alert { - margin-top: 32px; - } } } } diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 3ddf3d8ea7a..7eb28354e6d 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -223,14 +223,14 @@ top: $new-navbar-height; bottom: 0; right: 0; - transition: width .3s; + transition: width $right-sidebar-transition-duration; background: $gray-light; z-index: 200; overflow: hidden; .issuable-sidebar { width: calc(100% + 100px); - height: calc(100% - #{$new-navbar-height}); + height: 100%; overflow-y: scroll; overflow-x: hidden; -webkit-overflow-scrolling: touch; diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index 4d4d92f9494..c36fe25f74d 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -54,6 +54,10 @@ border-radius: $border-radius-default; color: $almost-black; + .code.white pre .hll { + background-color: $well-light-border !important; + } + .tree-content-holder { display: flex; min-height: 300px; diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss index 13dd7b5a780..2fa710a05b5 100644 --- a/app/assets/stylesheets/pages/search.scss +++ b/app/assets/stylesheets/pages/search.scss @@ -28,9 +28,7 @@ input[type="checkbox"]:hover { } .search { - margin-right: 10px; - margin-left: 10px; - margin-top: ($header-height - 35) / 2; + margin: 4px 8px 0; form { @extend .form-control; @@ -38,15 +36,23 @@ input[type="checkbox"]:hover { padding: 4px; width: $search-input-width; line-height: 24px; + height: 32px; + border: 0; + border-radius: $border-radius-default; + transition: border-color ease-in-out $default-transition-duration, background-color ease-in-out $default-transition-duration; &:hover { - border-color: lighten($dropdown-input-focus-border, 20%); - box-shadow: 0 0 4px lighten($search-input-focus-shadow-color, 20%); + box-shadow: none; } } - .location-text { - font-style: normal; + .location-badge { + font-size: 12px; + margin: -4px 4px -4px -4px; + line-height: 25px; + padding: 4px 8px; + border-radius: $border-radius-default 0 0 $border-radius-default; + transition: border-color ease-in-out $default-transition-duration; } .search-input { @@ -56,41 +62,26 @@ input[type="checkbox"]:hover { margin-left: 5px; line-height: 25px; width: 98%; + color: $white-light; + background: none; + transition: color ease-in-out $default-transition-duration; } - .location-badge { - line-height: 25px; - padding: 0 5px; - border-radius: $border-radius-default; - font-size: 14px; - font-style: normal; - color: $note-disabled-comment-color; - display: inline-block; - background-color: $gray-normal; - vertical-align: top; - cursor: default; + .search-input::placeholder { + transition: color ease-in-out $default-transition-duration; } .search-input-container { - display: -webkit-flex; display: flex; position: relative; } .search-input-wrap { - // Fallback if flexbox is not supported - display: inline-block; - } - - .search-input-wrap { - width: 100%; - .search-icon, .clear-icon { position: absolute; right: 5px; top: 0; - color: $location-icon-color; &::before { font-family: FontAwesome; @@ -101,7 +92,7 @@ input[type="checkbox"]:hover { .search-icon { @extend .fa-search; - transition: color 0.15s; + transition: color $default-transition-duration; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; @@ -148,21 +139,32 @@ input[type="checkbox"]:hover { form { @extend .form-control:focus; border-color: $dropdown-input-focus-border; - box-shadow: 0 0 4px $search-input-focus-shadow-color; - } + box-shadow: none; + + .search-input-wrap { + .search-icon, + .clear-icon { + color: $gl-text-color-tertiary; + transition: color ease-in-out $default-transition-duration; + } + } - .location-badge { - transition: all 0.15s; - background-color: $location-badge-active-bg; - color: $white-light; - } + .search-input { + color: $gl-text-color; + transition: color ease-in-out $default-transition-duration; + } - .search-input-wrap { - i { - color: $layout-link-gray; + .search-input::placeholder { + color: $gl-text-color-tertiary; } } + .location-badge { + transition: all $default-transition-duration; + background-color: $nav-badge-bg; + border-color: $border-color; + } + .dropdown-menu { transition-duration: 100ms, 75ms; transition-delay: 75ms, 100ms; diff --git a/app/assets/stylesheets/test.scss b/app/assets/stylesheets/test.scss index 7d9f3da79c5..06733b7f1a9 100644 --- a/app/assets/stylesheets/test.scss +++ b/app/assets/stylesheets/test.scss @@ -15,3 +15,9 @@ -ms-animation: none !important; animation: none !important; } + +// Disable sticky changes bar for tests +.diff-files-changed { + position: relative !important; + top: 0 !important; +} diff --git a/app/controllers/admin/applications_controller.rb b/app/controllers/admin/applications_controller.rb index 16590e66d61..fb6d8c0bb81 100644 --- a/app/controllers/admin/applications_controller.rb +++ b/app/controllers/admin/applications_controller.rb @@ -22,8 +22,7 @@ class Admin::ApplicationsController < Admin::ApplicationController @application = Doorkeeper::Application.new(application_params) if @application.save - flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create]) - redirect_to admin_application_url(@application) + redirect_to_admin_page else render :new end @@ -42,6 +41,13 @@ class Admin::ApplicationsController < Admin::ApplicationController redirect_to admin_applications_url, status: 302, notice: 'Application was successfully destroyed.' end + protected + + def redirect_to_admin_page + flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create]) + redirect_to admin_application_url(@application) + end + private def set_application diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index cbcef70e957..676a7203c7d 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -128,7 +128,7 @@ class Admin::UsersController < Admin::ApplicationController end respond_to do |format| - result = Users::UpdateService.new(user, user_params_with_pass).execute do |user| + result = Users::UpdateService.new(current_user, user_params_with_pass.merge(user: user)).execute do |user| user.skip_reconfirmation! end @@ -155,7 +155,7 @@ class Admin::UsersController < Admin::ApplicationController def remove_email email = user.emails.find(params[:email_id]) - success = Emails::DestroyService.new(user, email: email.email).execute + success = Emails::DestroyService.new(current_user, user: user, email: email.email).execute respond_to do |format| if success @@ -219,7 +219,7 @@ class Admin::UsersController < Admin::ApplicationController end def update_user(&block) - result = Users::UpdateService.new(user).execute(&block) + result = Users::UpdateService.new(current_user, user: user).execute(&block) result[:status] == :success end diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb index 8921d55c3d0..3181f517087 100644 --- a/app/controllers/concerns/issuable_collections.rb +++ b/app/controllers/concerns/issuable_collections.rb @@ -106,7 +106,7 @@ module IssuableCollections # @filter_params[:authorized_only] = true end - @filter_params + @filter_params.permit(IssuableFinder::VALID_PARAMS) end def set_default_state diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb index 306afb65f10..10d2665c06a 100644 --- a/app/controllers/confirmations_controller.rb +++ b/app/controllers/confirmations_controller.rb @@ -12,10 +12,14 @@ class ConfirmationsController < Devise::ConfirmationsController def after_confirmation_path_for(resource_name, resource) if signed_in?(resource_name) - after_sign_in_path_for(resource) + after_sign_in(resource) else flash[:notice] += " Please sign in." new_session_path(resource_name) end end + + def after_sign_in(resource) + after_sign_in_path_for(resource) + end end diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb index 2ae4785b12c..b02e64a132b 100644 --- a/app/controllers/oauth/applications_controller.rb +++ b/app/controllers/oauth/applications_controller.rb @@ -21,14 +21,20 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController @application.owner = current_user if @application.save - flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create]) - redirect_to oauth_application_url(@application) + redirect_to_oauth_application_page else set_index_vars render :index end end + protected + + def redirect_to_oauth_application_page + flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create]) + redirect_to oauth_application_url(@application) + end + private def verify_user_oauth_applications_enabled diff --git a/app/controllers/profiles/avatars_controller.rb b/app/controllers/profiles/avatars_controller.rb index 408650aac54..39b9f8a84d1 100644 --- a/app/controllers/profiles/avatars_controller.rb +++ b/app/controllers/profiles/avatars_controller.rb @@ -2,7 +2,7 @@ class Profiles::AvatarsController < Profiles::ApplicationController def destroy @user = current_user - Users::UpdateService.new(@user).execute { |user| user.remove_avatar! } + Users::UpdateService.new(current_user, user: @user).execute { |user| user.remove_avatar! } redirect_to profile_path, status: 302 end diff --git a/app/controllers/profiles/emails_controller.rb b/app/controllers/profiles/emails_controller.rb index ddb67d1c4d1..97db84b92d4 100644 --- a/app/controllers/profiles/emails_controller.rb +++ b/app/controllers/profiles/emails_controller.rb @@ -5,7 +5,7 @@ class Profiles::EmailsController < Profiles::ApplicationController end def create - @email = Emails::CreateService.new(current_user, email_params).execute + @email = Emails::CreateService.new(current_user, email_params.merge(user: current_user)).execute if @email.errors.blank? NotificationService.new.new_email(@email) @@ -19,7 +19,7 @@ class Profiles::EmailsController < Profiles::ApplicationController def destroy @email = current_user.emails.find(params[:id]) - Emails::DestroyService.new(current_user, email: @email.email).execute + Emails::DestroyService.new(current_user, user: current_user, email: @email.email).execute respond_to do |format| format.html { redirect_to profile_emails_url, status: 302 } diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb index 89d6d7f1b52..069e6a810f2 100644 --- a/app/controllers/profiles/keys_controller.rb +++ b/app/controllers/profiles/keys_controller.rb @@ -14,7 +14,7 @@ class Profiles::KeysController < Profiles::ApplicationController @key = Keys::CreateService.new(current_user, key_params).execute if @key.persisted? - redirect_to profile_key_path(@key) + redirect_to_profile_key_path else @keys = current_user.keys.select(&:persisted?) render :index @@ -50,6 +50,12 @@ class Profiles::KeysController < Profiles::ApplicationController end end + protected + + def redirect_to_profile_key_path + redirect_to profile_key_path(@key) + end + private def key_params diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb index 960b7512602..8a38ba65d4c 100644 --- a/app/controllers/profiles/notifications_controller.rb +++ b/app/controllers/profiles/notifications_controller.rb @@ -7,7 +7,7 @@ class Profiles::NotificationsController < Profiles::ApplicationController end def update - result = Users::UpdateService.new(current_user, user_params).execute + result = Users::UpdateService.new(current_user, user_params.merge(user: current_user)).execute if result[:status] == :success flash[:notice] = "Notification settings saved" diff --git a/app/controllers/profiles/passwords_controller.rb b/app/controllers/profiles/passwords_controller.rb index 7beb52dd8e8..dcfcb855ab5 100644 --- a/app/controllers/profiles/passwords_controller.rb +++ b/app/controllers/profiles/passwords_controller.rb @@ -21,10 +21,10 @@ class Profiles::PasswordsController < Profiles::ApplicationController password_automatically_set: false } - result = Users::UpdateService.new(@user, password_attributes).execute + result = Users::UpdateService.new(current_user, password_attributes.merge(user: @user)).execute if result[:status] == :success - Users::UpdateService.new(@user, password_expires_at: nil).execute + Users::UpdateService.new(current_user, user: @user, password_expires_at: nil).execute redirect_to root_path, notice: 'Password successfully changed' else @@ -46,7 +46,7 @@ class Profiles::PasswordsController < Profiles::ApplicationController return end - result = Users::UpdateService.new(@user, password_attributes).execute + result = Users::UpdateService.new(current_user, password_attributes.merge(user: @user)).execute if result[:status] == :success flash[:notice] = "Password was successfully updated. Please login with it" diff --git a/app/controllers/profiles/preferences_controller.rb b/app/controllers/profiles/preferences_controller.rb index cce2a847b53..ed0f98179eb 100644 --- a/app/controllers/profiles/preferences_controller.rb +++ b/app/controllers/profiles/preferences_controller.rb @@ -6,7 +6,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController def update begin - result = Users::UpdateService.new(user, preferences_params).execute + result = Users::UpdateService.new(current_user, preferences_params.merge(user: user)).execute if result[:status] == :success flash[:notice] = 'Preferences saved.' diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb index 1a4f77639e7..aa9789f8a0f 100644 --- a/app/controllers/profiles/two_factor_auths_controller.rb +++ b/app/controllers/profiles/two_factor_auths_controller.rb @@ -10,7 +10,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController current_user.otp_grace_period_started_at = Time.current end - Users::UpdateService.new(current_user).execute! + Users::UpdateService.new(current_user, user: current_user).execute! if two_factor_authentication_required? && !current_user.two_factor_enabled? two_factor_authentication_reason( @@ -41,7 +41,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController def create if current_user.validate_and_consume_otp!(params[:pin_code]) - Users::UpdateService.new(current_user, otp_required_for_login: true).execute! do |user| + Users::UpdateService.new(current_user, user: current_user, otp_required_for_login: true).execute! do |user| @codes = user.generate_otp_backup_codes! end @@ -70,7 +70,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController end def codes - Users::UpdateService.new(current_user).execute! do |user| + Users::UpdateService.new(current_user, user: current_user).execute! do |user| @codes = user.generate_otp_backup_codes! end end diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index d83824fef06..5d87037f012 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -10,7 +10,7 @@ class ProfilesController < Profiles::ApplicationController def update respond_to do |format| - result = Users::UpdateService.new(@user, user_params).execute + result = Users::UpdateService.new(current_user, user_params.merge(user: @user)).execute if result[:status] == :success message = "Profile was successfully updated" @@ -25,7 +25,7 @@ class ProfilesController < Profiles::ApplicationController end def reset_private_token - Users::UpdateService.new(@user).execute! do |user| + Users::UpdateService.new(current_user, user: @user).execute! do |user| user.reset_authentication_token! end @@ -35,7 +35,7 @@ class ProfilesController < Profiles::ApplicationController end def reset_incoming_email_token - Users::UpdateService.new(@user).execute! do |user| + Users::UpdateService.new(current_user, user: @user).execute! do |user| user.reset_incoming_email_token! end @@ -45,7 +45,7 @@ class ProfilesController < Profiles::ApplicationController end def reset_rss_token - Users::UpdateService.new(@user).execute! do |user| + Users::UpdateService.new(current_user, user: @user).execute! do |user| user.reset_rss_token! end @@ -61,7 +61,7 @@ class ProfilesController < Profiles::ApplicationController end def update_username - result = Users::UpdateService.new(@user, username: user_params[:username]).execute + result = Users::UpdateService.new(current_user, user: @user, username: user_params[:username]).execute options = if result[:status] == :success { notice: "Username successfully changed" } diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index be6491d042c..fe3bb117410 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -55,7 +55,7 @@ class SessionsController < Devise::SessionsController return unless user && user.require_password_creation? - Users::UpdateService.new(user).execute do |user| + Users::UpdateService.new(current_user, user: user).execute do |user| @token = user.generate_reset_token end diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index 0a2e3c709d9..24c07f3dc70 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -25,6 +25,28 @@ class IssuableFinder NONE = '0'.freeze + SCALAR_PARAMS = %i[ + assignee_id + assignee_username + author_id + author_username + authorized_only + due_date + group_id + iids + label_name + milestone_title + non_archived + project_id + scope + search + sort + state + ].freeze + ARRAY_PARAMS = { label_name: [], iids: [], assignee_username: [] }.freeze + + VALID_PARAMS = (SCALAR_PARAMS + [ARRAY_PARAMS]).freeze + attr_accessor :current_user, :params def initialize(current_user, params = {}) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index acaa028eaa2..3d5acc00f8f 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -434,7 +434,7 @@ module Ci def update_duration return unless started_at - self.duration = Gitlab::Ci::PipelineDuration.from_pipeline(self) + self.duration = Gitlab::Ci::Pipeline::Duration.from_pipeline(self) end def execute_hooks diff --git a/app/models/commit.rb b/app/models/commit.rb index 2ae8890c1b3..6dba154a6ea 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -25,8 +25,8 @@ class Commit DIFF_HARD_LIMIT_FILES = 1000 DIFF_HARD_LIMIT_LINES = 50000 - # The SHA can be between 7 and 40 hex characters. - COMMIT_SHA_PATTERN = '\h{7,40}'.freeze + MIN_SHA_LENGTH = 7 + COMMIT_SHA_PATTERN = /\h{#{MIN_SHA_LENGTH},40}/.freeze def banzai_render_context(field) context = { pipeline: :single_line, project: self.project } @@ -53,7 +53,7 @@ class Commit # Truncate sha to 8 characters def truncate_sha(sha) - sha[0..7] + sha[0..MIN_SHA_LENGTH] end def max_diff_options @@ -100,7 +100,7 @@ class Commit def self.reference_pattern @reference_pattern ||= %r{ (?:#{Project.reference_pattern}#{reference_prefix})? - (?<commit>\h{7,40}) + (?<commit>#{COMMIT_SHA_PATTERN}) }x end @@ -216,9 +216,8 @@ class Commit @raw.respond_to?(method, include_private) || super end - # Truncate sha to 8 characters def short_id - @raw.short_id(7) + @raw.short_id(MIN_SHA_LENGTH) end def diff_refs diff --git a/app/models/repository.rb b/app/models/repository.rb index 90cede9d3d4..f0de2697dfc 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -489,13 +489,7 @@ class Repository def exists? return false unless full_path - Gitlab::GitalyClient.migrate(:repository_exists) do |enabled| - if enabled - raw_repository.exists? - else - refs_directory_exists? - end - end + raw_repository.exists? end cache_method :exists? @@ -534,8 +528,11 @@ class Repository cache_method :tag_count, fallback: 0 def avatar - if tree = file_on_head(:avatar) - tree.path + # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/38327 + Gitlab::GitalyClient.allow_n_plus_1_calls do + if tree = file_on_head(:avatar) + tree.path + end end end cache_method :avatar @@ -1060,12 +1057,6 @@ class Repository blob.data end - def refs_directory_exists? - circuit_breaker.perform do - File.exist?(File.join(path_to_repo, 'refs')) - end - end - def cache # TODO: should we use UUIDs here? We could move repositories without clearing this cache @cache ||= RepositoryCache.new(full_path, @project.id) @@ -1117,10 +1108,6 @@ class Repository Gitlab::Git::Repository.new(project.repository_storage, disk_path + '.git', Gitlab::GlRepository.gl_repository(project, false)) end - def circuit_breaker - @circuit_breaker ||= Gitlab::Git::Storage::CircuitBreaker.for_storage(project.repository_storage) - end - def find_commits_by_message_by_shelling_out(query, ref, path, limit, offset) ref ||= root_ref diff --git a/app/models/user.rb b/app/models/user.rb index 09c9b3250eb..103ac78783f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -60,7 +60,7 @@ class User < ActiveRecord::Base lease = Gitlab::ExclusiveLease.new("user_update_tracked_fields:#{id}", timeout: 1.hour.to_i) return unless lease.try_obtain - Users::UpdateService.new(self).execute(validate: false) + Users::UpdateService.new(self, user: self).execute(validate: false) end attr_accessor :force_random_password @@ -526,8 +526,8 @@ class User < ActiveRecord::Base def update_emails_with_primary_email primary_email_record = emails.find_by(email: email) if primary_email_record - Emails::DestroyService.new(self, email: email).execute - Emails::CreateService.new(self, email: email_was).execute + Emails::DestroyService.new(self, user: self, email: email).execute + Emails::CreateService.new(self, user: self, email: email_was).execute end end @@ -1000,7 +1000,7 @@ class User < ActiveRecord::Base if attempts_exceeded? lock_access! unless access_locked? else - Users::UpdateService.new(self).execute(validate: false) + Users::UpdateService.new(self, user: self).execute(validate: false) end end @@ -1186,7 +1186,7 @@ class User < ActiveRecord::Base &creation_block ) - Users::UpdateService.new(user).execute(validate: false) + Users::UpdateService.new(user, user: user).execute(validate: false) user ensure Gitlab::ExclusiveLease.cancel(lease_key, uuid) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index d20de9b16a4..31a712ccc1b 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -2,110 +2,55 @@ module Ci class CreatePipelineService < BaseService attr_reader :pipeline - def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil) + SEQUENCE = [Gitlab::Ci::Pipeline::Chain::Validate::Abilities, + Gitlab::Ci::Pipeline::Chain::Validate::Repository, + Gitlab::Ci::Pipeline::Chain::Validate::Config, + Gitlab::Ci::Pipeline::Chain::Skip, + Gitlab::Ci::Pipeline::Chain::Create].freeze + + def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil, &block) @pipeline = Ci::Pipeline.new( source: source, project: project, ref: ref, sha: sha, before_sha: before_sha, - tag: tag?, + tag: tag_exists?, trigger_requests: Array(trigger_request), user: current_user, pipeline_schedule: schedule, protected: project.protected_for?(ref) ) - result = validate_project_and_git_items || - validate_pipeline(ignore_skip_ci: ignore_skip_ci, - save_on_errors: save_on_errors) + command = OpenStruct.new(ignore_skip_ci: ignore_skip_ci, + save_incompleted: save_on_errors, + seeds_block: block, + project: project, + current_user: current_user) - return result if result + sequence = Gitlab::Ci::Pipeline::Chain::Sequence + .new(pipeline, command, SEQUENCE) - begin - Ci::Pipeline.transaction do - pipeline.save! + sequence.build! do |pipeline, sequence| + update_merge_requests_head_pipeline if pipeline.persisted? - yield(pipeline) if block_given? + if sequence.complete? + cancel_pending_pipelines if project.auto_cancel_pending_pipelines? + pipeline_created_counter.increment(source: source) - Ci::CreatePipelineStagesService - .new(project, current_user) - .execute(pipeline) + pipeline.process! end - rescue ActiveRecord::RecordInvalid => e - return error("Failed to persist the pipeline: #{e}") end - - update_merge_requests_head_pipeline - - cancel_pending_pipelines if project.auto_cancel_pending_pipelines? - - pipeline_created_counter.increment(source: source) - - pipeline.tap(&:process!) end private - def validate_project_and_git_items - unless project.builds_enabled? - return error('Pipeline is disabled') - end - - unless allowed_to_trigger_pipeline? - if can?(current_user, :create_pipeline, project) - return error("Insufficient permissions for protected ref '#{ref}'") - else - return error('Insufficient permissions to create a new pipeline') - end - end - - unless branch? || tag? - return error('Reference not found') - end - - unless commit - return error('Commit not found') - end - end - - def validate_pipeline(ignore_skip_ci:, save_on_errors:) - unless pipeline.config_processor - unless pipeline.ci_yaml_file - return error("Missing #{pipeline.ci_yaml_file_path} file") - end - return error(pipeline.yaml_errors, save: save_on_errors) - end - - if !ignore_skip_ci && skip_ci? - pipeline.skip if save_on_errors - return pipeline - end - - unless pipeline.has_stage_seeds? - return error('No stages / jobs for this pipeline.') - end - end - - def allowed_to_trigger_pipeline? - if current_user - allowed_to_create? - else # legacy triggers don't have a corresponding user - !project.protected_for?(ref) - end + def commit + @commit ||= project.commit(origin_sha || origin_ref) end - def allowed_to_create? - return unless can?(current_user, :create_pipeline, project) - - access = Gitlab::UserAccess.new(current_user, project: project) - if branch? - access.can_update_branch?(ref) - elsif tag? - access.can_create_tag?(ref) - else - true # Allow it for now and we'll reject when we check ref existence - end + def sha + commit.try(:id) end def update_merge_requests_head_pipeline @@ -115,11 +60,6 @@ module Ci .update_all(head_pipeline_id: @pipeline.id) end - def skip_ci? - return false unless pipeline.git_commit_message - pipeline.git_commit_message =~ /\[(ci[ _-]skip|skip[ _-]ci)\]/i - end - def cancel_pending_pipelines Gitlab::OptimisticLocking.retry_lock(auto_cancelable_pipelines) do |cancelables| cancelables.find_each do |cancelable| @@ -136,14 +76,6 @@ module Ci .created_or_pending end - def commit - @commit ||= project.commit(origin_sha || origin_ref) - end - - def sha - commit.try(:id) - end - def before_sha params[:checkout_sha] || params[:before] || Gitlab::Git::BLANK_SHA end @@ -156,41 +88,17 @@ module Ci params[:ref] end - def branch? - return @is_branch if defined?(@is_branch) - - @is_branch = - project.repository.ref_exists?(Gitlab::Git::BRANCH_REF_PREFIX + ref) - end - - def tag? - return @is_tag if defined?(@is_tag) - - @is_tag = - project.repository.ref_exists?(Gitlab::Git::TAG_REF_PREFIX + ref) + def tag_exists? + project.repository.tag_exists?(ref) end def ref @ref ||= Gitlab::Git.ref_name(origin_ref) end - def valid_sha? - origin_sha && origin_sha != Gitlab::Git::BLANK_SHA - end - - def error(message, save: false) - pipeline.tap do - pipeline.errors.add(:base, message) - - if save - pipeline.drop - update_merge_requests_head_pipeline - end - end - end - def pipeline_created_counter - @pipeline_created_counter ||= Gitlab::Metrics.counter(:pipelines_created_total, "Counter of pipelines created") + @pipeline_created_counter ||= Gitlab::Metrics + .counter(:pipelines_created_total, "Counter of pipelines created") end end end diff --git a/app/services/emails/base_service.rb b/app/services/emails/base_service.rb index ace49889097..7f591c89411 100644 --- a/app/services/emails/base_service.rb +++ b/app/services/emails/base_service.rb @@ -1,7 +1,8 @@ module Emails class BaseService - def initialize(user, opts) - @user = user + def initialize(current_user, opts) + @current_user = current_user + @user = opts.delete(:user) @email = opts[:email] end end diff --git a/app/services/emails/destroy_service.rb b/app/services/emails/destroy_service.rb index d586b9dfe0c..44011cc36c8 100644 --- a/app/services/emails/destroy_service.rb +++ b/app/services/emails/destroy_service.rb @@ -1,13 +1,13 @@ module Emails class DestroyService < ::Emails::BaseService def execute - Email.find_by_email!(@email).destroy && update_secondary_emails! + update_secondary_emails! if Email.find_by_email!(@email).destroy end private def update_secondary_emails! - result = ::Users::UpdateService.new(@user).execute do |user| + result = ::Users::UpdateService.new(@current_user, user: @user).execute do |user| user.update_secondary_emails! end diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 07cbd8f92a9..bf26859dd6d 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -14,13 +14,13 @@ module MergeRequests @merge_request = merge_request unless @merge_request.mergeable? - return log_merge_error('Merge request is not mergeable', save_message_on_model: true) + return handle_merge_error(log_message: 'Merge request is not mergeable', save_message_on_model: true) end @source = find_merge_source unless @source - return log_merge_error('No source for merge', save_message_on_model: true) + return handle_merge_error(log_message: 'No source for merge', save_message_on_model: true) end merge_request.in_locked_state do @@ -31,8 +31,7 @@ module MergeRequests end end rescue MergeError => e - clean_merge_jid - log_merge_error(e.message, save_message_on_model: true) + handle_merge_error(log_message: e.message, save_message_on_model: true) end private @@ -74,10 +73,16 @@ module MergeRequests @merge_request.force_remove_source_branch? ? @merge_request.author : current_user end - def log_merge_error(message, save_message_on_model: false) - Rails.logger.error("MergeService ERROR: #{merge_request_info} - #{message}") + # Logs merge error message and cleans `MergeRequest#merge_jid`. + # + def handle_merge_error(log_message:, save_message_on_model: false) + Rails.logger.error("MergeService ERROR: #{merge_request_info} - #{log_message}") - @merge_request.update(merge_error: message) if save_message_on_model + if save_message_on_model + @merge_request.update(merge_error: log_message, merge_jid: nil) + else + clean_merge_jid + end end def merge_request_info diff --git a/app/services/users/update_service.rb b/app/services/users/update_service.rb index 6188b8a4349..15ca1a55a5b 100644 --- a/app/services/users/update_service.rb +++ b/app/services/users/update_service.rb @@ -2,22 +2,21 @@ module Users class UpdateService < BaseService include NewUserNotifier - def initialize(user, params = {}) - @user = user + def initialize(current_user, params = {}) + @current_user = current_user + @user = params.delete(:user) @params = params.dup end def execute(validate: true, &block) yield(@user) if block_given? - assign_attributes(&block) - user_exists = @user.persisted? - if @user.save(validate: validate) - notify_new_user(@user, nil) unless user_exists + assign_attributes(&block) - success + if @user.save(validate: validate) + notify_success(user_exists) else error(@user.errors.full_messages.uniq.join('. ')) end @@ -33,6 +32,12 @@ module Users private + def notify_success(user_exists) + notify_new_user(@user, nil) unless user_exists + + success + end + def assign_attributes(&block) if @user.user_synced_attributes_metadata params.except!(*@user.user_synced_attributes_metadata.read_only_attributes) diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml index e5842bd1ea0..3ef8f2a3acb 100644 --- a/app/views/admin/background_jobs/show.html.haml +++ b/app/views/admin/background_jobs/show.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Background Jobs" -= render 'admin/monitoring/head' %div{ class: container_class } %h3.page-title Background Jobs diff --git a/app/views/admin/cohorts/index.html.haml b/app/views/admin/cohorts/index.html.haml index bff53da1d9a..5e9a8c083af 100644 --- a/app/views/admin/cohorts/index.html.haml +++ b/app/views/admin/cohorts/index.html.haml @@ -1,6 +1,5 @@ - breadcrumb_title "Cohorts" - @no_container = true -= render "admin/dashboard/head" %div{ class: container_class } - if @cohorts diff --git a/app/views/admin/conversational_development_index/show.html.haml b/app/views/admin/conversational_development_index/show.html.haml index 833d4c612f8..30dd87f0463 100644 --- a/app/views/admin/conversational_development_index/show.html.haml +++ b/app/views/admin/conversational_development_index/show.html.haml @@ -1,8 +1,6 @@ - @no_container = true - page_title 'ConvDev Index' -= render 'admin/monitoring/head' - .container - if show_callout?('convdev_intro_callout_dismissed') = render 'callout' diff --git a/app/views/admin/dashboard/_head.html.haml b/app/views/admin/dashboard/_head.html.haml deleted file mode 100644 index c2151710884..00000000000 --- a/app/views/admin/dashboard/_head.html.haml +++ /dev/null @@ -1,37 +0,0 @@ -= content_for :sub_nav do - .scrolling-tabs-container.sub-nav-scroll - = render 'shared/nav_scroll' - .nav-links.sub-nav.scrolling-tabs - %ul{ class: (container_class) } - = nav_link(controller: :dashboard, html_options: {class: 'home'}) do - = link_to admin_root_path, title: 'Overview' do - %span - Overview - = nav_link(controller: [:admin, :projects]) do - = link_to admin_projects_path, title: 'Projects' do - %span - Projects - = nav_link(controller: :users) do - = link_to admin_users_path, title: 'Users' do - %span - Users - = nav_link(controller: :groups) do - = link_to admin_groups_path, title: 'Groups' do - %span - Groups - = nav_link path: 'builds#index' do - = link_to admin_jobs_path, title: 'Jobs' do - %span - Jobs - = nav_link path: ['runners#index', 'runners#show'] do - = link_to admin_runners_path, title: 'Runners' do - %span - Runners - = nav_link path: 'cohorts#index' do - = link_to admin_cohorts_path, title: 'Cohorts' do - %span - Cohorts - = nav_link(controller: :conversational_development_index) do - = link_to admin_conversational_development_index_path, title: 'ConvDev Index' do - %span - ConvDev Index diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index d212c7ca965..2f0143c7eff 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -1,6 +1,5 @@ - @no_container = true - breadcrumb_title "Dashboard" -= render "admin/dashboard/head" %div{ class: container_class } .admin-dashboard.prepend-top-default diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index e5f380c78e2..535251fef5e 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Groups" -= render "admin/dashboard/head" %div{ class: container_class } .top-area diff --git a/app/views/admin/health_check/show.html.haml b/app/views/admin/health_check/show.html.haml index 517db50b97f..10a3bed0a4f 100644 --- a/app/views/admin/health_check/show.html.haml +++ b/app/views/admin/health_check/show.html.haml @@ -1,7 +1,6 @@ - @no_container = true - page_title _('Health Check') - no_errors = @errors.blank? && @failing_storage_statuses.blank? -= render 'admin/monitoring/head' %div{ class: container_class } %h3.page-title= page_title diff --git a/app/views/admin/jobs/index.html.haml b/app/views/admin/jobs/index.html.haml index aa6e9db3900..0310498ae54 100644 --- a/app/views/admin/jobs/index.html.haml +++ b/app/views/admin/jobs/index.html.haml @@ -1,6 +1,5 @@ - breadcrumb_title "Jobs" - @no_container = true -= render "admin/dashboard/head" %div{ class: container_class } diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml index ee87f25a225..78757b6384f 100644 --- a/app/views/admin/logs/show.html.haml +++ b/app/views/admin/logs/show.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Logs" -= render 'admin/monitoring/head' %div{ class: container_class } %ul.nav-links.log-tabs diff --git a/app/views/admin/monitoring/_head.html.haml b/app/views/admin/monitoring/_head.html.haml deleted file mode 100644 index b3530915068..00000000000 --- a/app/views/admin/monitoring/_head.html.haml +++ /dev/null @@ -1,25 +0,0 @@ -= content_for :sub_nav do - .scrolling-tabs-container.sub-nav-scroll - = render 'shared/nav_scroll' - .nav-links.sub-nav.scrolling-tabs - %ul{ class: (container_class) } - = nav_link(controller: :system_info) do - = link_to admin_system_info_path, title: 'System Info' do - %span - System Info - = nav_link(controller: :background_jobs) do - = link_to admin_background_jobs_path, title: 'Background Jobs' do - %span - Background Jobs - = nav_link(controller: :logs) do - = link_to admin_logs_path, title: 'Logs' do - %span - Logs - = nav_link(controller: :health_check) do - = link_to admin_health_check_path, title: 'Health Check' do - %span - Health Check - = nav_link(controller: :requests_profiles) do - = link_to admin_requests_profiles_path, title: 'Requests Profiles' do - %span - Requests Profiles diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 3301f55b8a8..3f202fbf4fe 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -2,7 +2,6 @@ - page_title "Projects" - params[:visibility_level] ||= [] -= render "admin/dashboard/head" %div{ class: container_class } .top-area diff --git a/app/views/admin/requests_profiles/index.html.haml b/app/views/admin/requests_profiles/index.html.haml index b7db18b2d32..cb02a750490 100644 --- a/app/views/admin/requests_profiles/index.html.haml +++ b/app/views/admin/requests_profiles/index.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title 'Requests Profiles' -= render 'admin/monitoring/head' %div{ class: container_class } %h3.page-title diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml index 6793ce557c4..43cea1358cc 100644 --- a/app/views/admin/runners/index.html.haml +++ b/app/views/admin/runners/index.html.haml @@ -1,6 +1,5 @@ - breadcrumb_title "Runners" - @no_container = true -= render "admin/dashboard/head" %div{ class: container_class } .bs-callout diff --git a/app/views/admin/system_info/show.html.haml b/app/views/admin/system_info/show.html.haml index fd0281e4961..6bf979a937e 100644 --- a/app/views/admin/system_info/show.html.haml +++ b/app/views/admin/system_info/show.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "System Info" -= render 'admin/monitoring/head' %div{ class: container_class } .prepend-top-default diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index 5516134d8a0..38ce1564eff 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Users" -= render "admin/dashboard/head" %div{ class: container_class } .prepend-top-default diff --git a/app/views/groups/_head.html.haml b/app/views/groups/_head.html.haml deleted file mode 100644 index 0f63774fb9b..00000000000 --- a/app/views/groups/_head.html.haml +++ /dev/null @@ -1,17 +0,0 @@ -= content_for :sub_nav do - .scrolling-tabs-container.sub-nav-scroll - = render 'shared/nav_scroll' - .nav-links.sub-nav.scrolling-tabs - %ul{ class: container_class } - = nav_link(path: ['groups#show', 'groups#subgroups'], html_options: { class: 'home' }) do - = link_to group_path(@group), title: 'Group Home' do - %span - Home - - = nav_link(path: 'groups#activity') do - = link_to activity_group_path(@group), title: 'Activity' do - %span - Activity - -.hidden-xs - = render "projects/last_push" diff --git a/app/views/groups/_head_issues.html.haml b/app/views/groups/_head_issues.html.haml deleted file mode 100644 index d554bc23743..00000000000 --- a/app/views/groups/_head_issues.html.haml +++ /dev/null @@ -1,19 +0,0 @@ -= content_for :sub_nav do - .scrolling-tabs-container.sub-nav-scroll - = render 'shared/nav_scroll' - .nav-links.sub-nav.scrolling-tabs - %ul{ class: container_class } - = nav_link(path: 'groups#issues', html_options: { class: 'home' }) do - = link_to issues_group_path(@group), title: 'List' do - %span - List - - = nav_link(path: 'labels#index') do - = link_to group_labels_path(@group), title: 'Labels' do - %span - Labels - - = nav_link(path: 'milestones#index') do - = link_to group_milestones_path(@group), title: 'Milestones' do - %span - Milestones diff --git a/app/views/groups/_settings_head.html.haml b/app/views/groups/_settings_head.html.haml deleted file mode 100644 index 623d233a46a..00000000000 --- a/app/views/groups/_settings_head.html.haml +++ /dev/null @@ -1,19 +0,0 @@ -= content_for :sub_nav do - .scrolling-tabs-container.sub-nav-scroll - = render 'shared/nav_scroll' - .nav-links.sub-nav.scrolling-tabs - %ul{ class: container_class } - = nav_link(path: 'groups#edit') do - = link_to edit_group_path(@group), title: 'General' do - %span - General - - = nav_link(path: 'groups#projects') do - = link_to projects_group_path(@group), title: 'Projects' do - %span - Projects - - = nav_link(controller: :ci_cd) do - = link_to group_settings_ci_cd_path(@group), title: 'Pipelines' do - %span - Pipelines diff --git a/app/views/groups/activity.html.haml b/app/views/groups/activity.html.haml index 3969e56f937..cb7dab26332 100644 --- a/app/views/groups/activity.html.haml +++ b/app/views/groups/activity.html.haml @@ -2,7 +2,6 @@ = auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity") - page_title "Activity" -= render 'groups/head' %section.activities = render 'activities' diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 0d3308833b7..15606dd30fd 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -1,5 +1,4 @@ - breadcrumb_title "General Settings" -= render "groups/settings_head" .panel.panel-default.prepend-top-default .panel-heading Group settings diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml index 7f411927429..07e64d9aeaf 100644 --- a/app/views/groups/issues.html.haml +++ b/app/views/groups/issues.html.haml @@ -1,6 +1,5 @@ - page_title "Issues" - group_issues_exists = group_issues(@group).exists? -= render "head_issues" = content_for :meta_tags do = auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@group.name} issues") diff --git a/app/views/groups/labels/index.html.haml b/app/views/groups/labels/index.html.haml index 89165096fe2..d10efdad53b 100644 --- a/app/views/groups/labels/index.html.haml +++ b/app/views/groups/labels/index.html.haml @@ -1,8 +1,5 @@ - page_title 'Labels' -= render "groups/head_issues" - - .top-area.adjust .nav-text Labels can be applied to issues and merge requests. Group labels are available for any project within the group. diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml index ed582e521c4..cb4fc69d5b8 100644 --- a/app/views/groups/milestones/index.html.haml +++ b/app/views/groups/milestones/index.html.haml @@ -1,7 +1,5 @@ - page_title "Milestones" -= render "groups/head_issues" - .top-area = render 'shared/milestones_filter', counts: @milestone_states diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml index 7f3f2f707f7..8d2bc810a7d 100644 --- a/app/views/groups/projects.html.haml +++ b/app/views/groups/projects.html.haml @@ -1,5 +1,4 @@ - breadcrumb_title "Projects" -= render "groups/settings_head" .panel.panel-default.prepend-top-default .panel-heading diff --git a/app/views/groups/settings/ci_cd/show.html.haml b/app/views/groups/settings/ci_cd/show.html.haml index 9f9ae01e7c5..472da2a6a72 100644 --- a/app/views/groups/settings/ci_cd/show.html.haml +++ b/app/views/groups/settings/ci_cd/show.html.haml @@ -1,5 +1,4 @@ - breadcrumb_title "CI / CD Settings" - page_title "CI / CD" -= render "groups/settings_head" = render 'ci/variables/index' diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index f4f76887422..3ca63f9c3e0 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -4,7 +4,6 @@ = content_for :meta_tags do = auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity") -= render 'groups/head' = render 'groups/home_panel' .groups-header{ class: container_class } diff --git a/app/views/groups/subgroups.html.haml b/app/views/groups/subgroups.html.haml index 7abc84412c6..869b3b243c6 100644 --- a/app/views/groups/subgroups.html.haml +++ b/app/views/groups/subgroups.html.haml @@ -1,7 +1,6 @@ - breadcrumb_title "Details" - @no_container = true -= render 'head' = render 'groups/home_panel' .groups-header{ class: container_class } diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index e6a10e500a4..e3a9e99250e 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -32,10 +32,6 @@ = stylesheet_link_tag "test", media: "all" if Rails.env.test? = stylesheet_link_tag 'performance_bar' if performance_bar_enabled? - // TODO: Combine these 2 stylesheets into application.scss - = stylesheet_link_tag "new_nav", media: "all" - = stylesheet_link_tag "new_sidebar", media: "all" - = Gon::Base.render_data - if content_for?(:library_javascripts) diff --git a/app/views/projects/_head.html.haml b/app/views/projects/_head.html.haml deleted file mode 100644 index dba84838a52..00000000000 --- a/app/views/projects/_head.html.haml +++ /dev/null @@ -1,17 +0,0 @@ -= content_for :sub_nav do - .scrolling-tabs-container.sub-nav-scroll - = render 'shared/nav_scroll' - .nav-links.sub-nav.scrolling-tabs - %ul{ class: container_class } - = nav_link(path: 'projects#show') do - = link_to project_path(@project), title: _('Project home'), class: 'shortcuts-project' do - %span= _('Home') - - = nav_link(path: 'projects#activity') do - = link_to activity_project_path(@project), title: _('Activity'), class: 'shortcuts-project-activity' do - %span= _('Activity') - - - if can?(current_user, :read_cycle_analytics, @project) - = nav_link(path: 'cycle_analytics#show') do - = link_to project_cycle_analytics_path(@project), title: _('Cycle Analytics'), class: 'shortcuts-project-cycle-analytics' do - %span= _('Cycle Analytics') diff --git a/app/views/projects/activity.html.haml b/app/views/projects/activity.html.haml index f80dadb8037..d0ab39033cf 100644 --- a/app/views/projects/activity.html.haml +++ b/app/views/projects/activity.html.haml @@ -2,8 +2,6 @@ - page_title _("Activity") -= render "projects/head" - = render 'projects/last_push' = render 'projects/activity' diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml index 4cc3218d967..05857573297 100644 --- a/app/views/projects/artifacts/browse.html.haml +++ b/app/views/projects/artifacts/browse.html.haml @@ -1,6 +1,5 @@ - breadcrumb_title _('Artifacts') - page_title @path.presence, 'Artifacts', "#{@build.name} (##{@build.id})", 'Jobs' -= render "projects/pipelines/head" = render "projects/jobs/header", show_controls: false diff --git a/app/views/projects/artifacts/file.html.haml b/app/views/projects/artifacts/file.html.haml index b85bbcb980e..2942d618a42 100644 --- a/app/views/projects/artifacts/file.html.haml +++ b/app/views/projects/artifacts/file.html.haml @@ -1,5 +1,4 @@ - page_title @path, 'Artifacts', "#{@build.name} (##{@build.id})", 'Jobs' -= render "projects/pipelines/head" = render "projects/jobs/header", show_controls: false diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml index 60ac202bde0..e45861ac08d 100644 --- a/app/views/projects/blame/show.html.haml +++ b/app/views/projects/blame/show.html.haml @@ -1,7 +1,6 @@ - @no_container = true - project_duration = age_map_duration(@blame_groups, @project) - page_title "Blame", @blob.path, @ref -= render "projects/commits/head" %div{ class: container_class } #blob-content-holder.tree-holder diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml index 992fe7f717f..626cbc9e41d 100644 --- a/app/views/projects/blob/edit.html.haml +++ b/app/views/projects/blob/edit.html.haml @@ -4,7 +4,6 @@ - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/ace.js') = page_specific_javascript_bundle_tag('blob') -= render "projects/commits/head" %div{ class: container_class } - if @conflict diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml index 240e62d5ac5..c4712bf3736 100644 --- a/app/views/projects/blob/show.html.haml +++ b/app/views/projects/blob/show.html.haml @@ -2,7 +2,6 @@ - @no_container = true - page_title @blob.path, @ref -= render "projects/commits/head" - content_for :page_specific_javascripts do = webpack_bundle_tag 'blob' diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml index ea6e7e9db6c..7d9645d79e6 100644 --- a/app/views/projects/branches/index.html.haml +++ b/app/views/projects/branches/index.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title _('Branches') -= render "projects/commits/head" %div{ class: container_class } .top-area.adjust diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml index 717de85c5d2..abb292f8f27 100644 --- a/app/views/projects/commit/show.html.haml +++ b/app/views/projects/commit/show.html.haml @@ -6,7 +6,6 @@ - @content_class = limited_container_width - page_title "#{@commit.title} (#{@commit.short_id})", "Commits" - page_description @commit.description -= render "projects/commits/head" .container-fluid{ class: [limited_container_width, container_class] } = render "commit_box" diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml deleted file mode 100644 index e1549baef89..00000000000 --- a/app/views/projects/commits/_head.html.haml +++ /dev/null @@ -1,36 +0,0 @@ -= content_for :sub_nav do - .scrolling-tabs-container.sub-nav-scroll - = render 'shared/nav_scroll' - .nav-links.sub-nav.scrolling-tabs - %ul{ class: (container_class) } - = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do - = link_to project_tree_path(@project) do - #{ _('Files') } - - = nav_link(controller: [:commit, :commits]) do - = link_to project_commits_path(@project, current_ref) do - #{ _('Commits') } - - = nav_link(html_options: {class: branches_tab_class}) do - = link_to project_branches_path(@project) do - #{ _('Branches') } - - = nav_link(controller: [:tags, :releases]) do - = link_to project_tags_path(@project) do - #{ _('Tags') } - - = nav_link(path: 'graphs#show') do - = link_to project_graph_path(@project, current_ref) do - #{ _('Contributors') } - - = nav_link(controller: %w(network)) do - = link_to project_network_path(@project, current_ref) do - #{ s_('ProjectNetworkGraph|Graph') } - - = nav_link(controller: :compare) do - = link_to project_compare_index_path(@project, from: @repository.root_ref, to: current_ref) do - #{ _('Compare') } - - = nav_link(path: 'graphs#charts') do - = link_to charts_project_graph_path(@project, current_ref) do - #{ _('Charts') } diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index e873b931683..ef305120525 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -5,9 +5,6 @@ = content_for :meta_tags do = auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits") -= content_for :sub_nav do - = render "head" - .js-project-commits-show{ 'data-commits-limit' => @limit } %div{ class: container_class } .tree-holder diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml index 1ce3ad0c0fd..3ad0166e9cd 100644 --- a/app/views/projects/compare/index.html.haml +++ b/app/views/projects/compare/index.html.haml @@ -1,7 +1,6 @@ - @no_container = true - breadcrumb_title "Compare Revisions" - page_title "Compare" -= render "projects/commits/head" %div{ class: container_class } .sub-header-block diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml index 7cc42455394..f87f1d476f5 100644 --- a/app/views/projects/compare/show.html.haml +++ b/app/views/projects/compare/show.html.haml @@ -1,7 +1,6 @@ - @no_container = true - add_to_breadcrumbs "Compare Revisions", project_compare_index_path(@project) - page_title "#{params[:from]}...#{params[:to]}" -= render "projects/commits/head" %div{ class: container_class } .sub-header-block.no-bottom-space diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml index 8d008be5aae..c06e9f323af 100644 --- a/app/views/projects/cycle_analytics/show.html.haml +++ b/app/views/projects/cycle_analytics/show.html.haml @@ -4,8 +4,6 @@ = page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('cycle_analytics') -= render "projects/head" - #cycle-analytics{ class: container_class, "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } } - if @cycle_analytics_no_data .landing.content-block{ "v-if" => "!isOverviewDialogDismissed" } diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 0a3045604f4..8ae4fd94146 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -3,8 +3,6 @@ - @content_class = "limit-container-width" unless fluid_layout - expanded = Rails.env.test? -= render "projects/settings/head" - .project-edit-container %section.settings.general-settings .settings-header diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index d5b83b53ebb..3f3ce10419f 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -3,7 +3,6 @@ = render partial: 'flash_messages', locals: { project: @project } -= render "projects/head" = render "home_panel" .row-content-block.second-block.center diff --git a/app/views/projects/environments/edit.html.haml b/app/views/projects/environments/edit.html.haml index 3871165763c..d6ff3f729b4 100644 --- a/app/views/projects/environments/edit.html.haml +++ b/app/views/projects/environments/edit.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Edit", @environment.name, "Environments" -= render "projects/pipelines/head" %div{ class: container_class } %h3.page-title diff --git a/app/views/projects/environments/folder.html.haml b/app/views/projects/environments/folder.html.haml index f7e3733ba0b..1bcc955ddc8 100644 --- a/app/views/projects/environments/folder.html.haml +++ b/app/views/projects/environments/folder.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Environments" -= render "projects/pipelines/head" - content_for :page_specific_javascripts do = page_specific_javascript_bundle_tag('common_vue') diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index acc80b49dd0..2e85f608823 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -1,7 +1,6 @@ - @no_container = true - page_title "Environments" - add_to_breadcrumbs("Pipelines", project_pipelines_path(@project)) -= render "projects/pipelines/head" - content_for :page_specific_javascripts do = page_specific_javascript_bundle_tag('common_vue') diff --git a/app/views/projects/environments/metrics.html.haml b/app/views/projects/environments/metrics.html.haml index 4a65b46f029..e0aedcac5e1 100644 --- a/app/views/projects/environments/metrics.html.haml +++ b/app/views/projects/environments/metrics.html.haml @@ -4,7 +4,6 @@ = webpack_bundle_tag 'common_vue' = webpack_bundle_tag 'common_d3' = webpack_bundle_tag 'monitoring' -= render "projects/pipelines/head" .prometheus-container{ class: container_class } .top-area @@ -21,4 +20,3 @@ "empty-unable-to-connect-svg-path": image_path('illustrations/monitoring/unable_to_connect'), "additional-metrics": additional_metrics_project_environment_path(@project, @environment, format: :json), "has-metrics": "#{@environment.has_metrics?}", deployment_endpoint: project_environment_deployments_path(@project, @environment, format: :json) } } - diff --git a/app/views/projects/environments/new.html.haml b/app/views/projects/environments/new.html.haml index 88f43a1e7e4..62b08e85e22 100644 --- a/app/views/projects/environments/new.html.haml +++ b/app/views/projects/environments/new.html.haml @@ -1,7 +1,6 @@ - @no_container = true - breadcrumb_title "Environments" - page_title 'New Environment' -= render "projects/pipelines/head" %div{ class: container_class } %h3.page-title diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml index c35d1b5aaee..d7859c9fbeb 100644 --- a/app/views/projects/environments/show.html.haml +++ b/app/views/projects/environments/show.html.haml @@ -2,7 +2,6 @@ - add_to_breadcrumbs "Environments", project_environments_path(@project) - breadcrumb_title @environment.name - page_title "Environments" -= render "projects/pipelines/head" %div{ class: container_class } .row.top-area.adjust diff --git a/app/views/projects/environments/terminal.html.haml b/app/views/projects/environments/terminal.html.haml index 464135b5ac7..a073a164f11 100644 --- a/app/views/projects/environments/terminal.html.haml +++ b/app/views/projects/environments/terminal.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Terminal for environment", @environment.name -= render "projects/pipelines/head" - content_for :page_specific_javascripts do = stylesheet_link_tag "xterm/xterm" diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml index 021575160ea..a3467eb6f05 100644 --- a/app/views/projects/find_file/show.html.haml +++ b/app/views/projects/find_file/show.html.haml @@ -1,5 +1,4 @@ - page_title "Find File", @ref -= render "projects/commits/head" .file-finder-holder.tree-holder.clearfix.js-file-finder{ 'data-file-find-url': "#{escape_javascript(project_files_path(@project, @ref, @options.merge(format: :json)))}", 'data-find-tree-url': escape_javascript(project_tree_path(@project, @ref)), 'data-blob-url-template': escape_javascript(project_blob_path(@project, @id || @commit.id)) } .nav-block diff --git a/app/views/projects/graphs/charts.html.haml b/app/views/projects/graphs/charts.html.haml index f0ef647ddb3..ffb9238a65a 100644 --- a/app/views/projects/graphs/charts.html.haml +++ b/app/views/projects/graphs/charts.html.haml @@ -4,7 +4,6 @@ = webpack_bundle_tag('common_d3') = webpack_bundle_tag('graphs') = webpack_bundle_tag('graphs_charts') -= render "projects/commits/head" .repo-charts{ class: container_class } %h4.sub-header diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml index 08b38428b50..70156c03e3c 100644 --- a/app/views/projects/graphs/show.html.haml +++ b/app/views/projects/graphs/show.html.haml @@ -5,8 +5,6 @@ = webpack_bundle_tag('graphs') = webpack_bundle_tag('graphs_show') -= render 'projects/commits/head' - .js-graphs-show{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) } .sub-header-block .tree-ref-holder diff --git a/app/views/projects/hook_logs/show.html.haml b/app/views/projects/hook_logs/show.html.haml index ab5a7b117d7..1cf4105bd27 100644 --- a/app/views/projects/hook_logs/show.html.haml +++ b/app/views/projects/hook_logs/show.html.haml @@ -1,5 +1,3 @@ -= render 'projects/settings/head' - .row.prepend-top-default.append-bottom-default .col-lg-3 %h4.prepend-top-0 diff --git a/app/views/projects/hooks/edit.html.haml b/app/views/projects/hooks/edit.html.haml index c8c17d2d828..b1219f019d7 100644 --- a/app/views/projects/hooks/edit.html.haml +++ b/app/views/projects/hooks/edit.html.haml @@ -1,5 +1,4 @@ - page_title 'Integrations' -= render 'projects/settings/head' .row.prepend-top-default .col-lg-3 @@ -19,4 +18,3 @@ %hr = render partial: 'projects/hook_logs/index', locals: { hook: @hook, hook_logs: @hook_logs, project: @project } - diff --git a/app/views/projects/issues/_head.html.haml b/app/views/projects/issues/_head.html.haml deleted file mode 100644 index e9f21594a71..00000000000 --- a/app/views/projects/issues/_head.html.haml +++ /dev/null @@ -1,33 +0,0 @@ -= content_for :sub_nav do - .scrolling-tabs-container.sub-nav-scroll - = render 'shared/nav_scroll' - .nav-links.sub-nav.scrolling-tabs - %ul{ class: (container_class) } - - if project_nav_tab?(:issues) && !current_controller?(:merge_requests) - = nav_link(controller: :issues) do - = link_to project_issues_path(@project), title: 'Issues' do - %span - List - - = nav_link(controller: :boards) do - = link_to project_boards_path(@project), title: 'Board' do - %span - Board - - - if project_nav_tab?(:merge_requests) && current_controller?(:merge_requests) - = nav_link(controller: :merge_requests) do - = link_to project_merge_requests_path(@project), title: 'Merge Requests' do - %span - Merge Requests - - - if project_nav_tab? :labels - = nav_link(controller: :labels) do - = link_to project_labels_path(@project), title: 'Labels' do - %span - Labels - - - if project_nav_tab? :milestones - = nav_link(controller: :milestones) do - = link_to project_milestones_path(@project), title: 'Milestones' do - %span - Milestones diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml index e72c94695bc..bfaf024428d 100644 --- a/app/views/projects/issues/index.html.haml +++ b/app/views/projects/issues/index.html.haml @@ -3,8 +3,6 @@ - page_title "Issues" - new_issue_email = @project.new_issue_address(current_user) -= content_for :sub_nav do - = render "projects/issues/head" - content_for :page_specific_javascripts do = webpack_bundle_tag 'common_vue' diff --git a/app/views/projects/jobs/index.html.haml b/app/views/projects/jobs/index.html.haml index 8604c7d3ea4..4a238b99b58 100644 --- a/app/views/projects/jobs/index.html.haml +++ b/app/views/projects/jobs/index.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Jobs" -= render "projects/pipelines/head" %div{ class: container_class } .top-area diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml index 975c08c06e6..ce0e3872240 100644 --- a/app/views/projects/jobs/show.html.haml +++ b/app/views/projects/jobs/show.html.haml @@ -2,7 +2,6 @@ - add_to_breadcrumbs "Jobs", project_jobs_path(@project) - breadcrumb_title "##{@build.id}" - page_title "#{@build.name} (##{@build.id})", "Jobs" -= render "projects/pipelines/head" %div{ class: container_class } .build-page.js-build-page diff --git a/app/views/projects/labels/edit.html.haml b/app/views/projects/labels/edit.html.haml index 84b0b65d1c0..b8ee4305142 100644 --- a/app/views/projects/labels/edit.html.haml +++ b/app/views/projects/labels/edit.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Edit", @label.name, "Labels" -= render "shared/mr_head" %div{ class: container_class } %h3.page-title diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml index 10d07ce8e45..80e4dce1a80 100644 --- a/app/views/projects/labels/index.html.haml +++ b/app/views/projects/labels/index.html.haml @@ -3,8 +3,6 @@ - hide_class = '' - can_admin_label = can?(current_user, :admin_label, @project) -= render "shared/mr_head" - - if @labels.exists? || @prioritized_labels.exists? %div{ class: container_class } .top-area.adjust diff --git a/app/views/projects/labels/new.html.haml b/app/views/projects/labels/new.html.haml index 562b6fb8d8c..02f59f30a39 100644 --- a/app/views/projects/labels/new.html.haml +++ b/app/views/projects/labels/new.html.haml @@ -1,7 +1,6 @@ - @no_container = true - breadcrumb_title "Labels" - page_title "New Label" -= render "shared/mr_head" %div{ class: container_class } %h3.page-title diff --git a/app/views/projects/merge_requests/_head.html.haml b/app/views/projects/merge_requests/_head.html.haml deleted file mode 100644 index 1e505222887..00000000000 --- a/app/views/projects/merge_requests/_head.html.haml +++ /dev/null @@ -1,21 +0,0 @@ -= content_for :sub_nav do - .scrolling-tabs-container.sub-nav-scroll - = render 'shared/nav_scroll' - .nav-links.sub-nav.scrolling-tabs - %ul{ class: (container_class) } - = nav_link(controller: :merge_requests) do - = link_to project_merge_requests_path(@project), title: 'Merge Requests' do - %span - List - - - if project_nav_tab? :labels - = nav_link(controller: :labels) do - = link_to project_labels_path(@project), title: 'Labels' do - %span - Labels - - - if project_nav_tab? :milestones - = nav_link(controller: :milestones) do - = link_to project_milestones_path(@project), title: 'Milestones' do - %span - Milestones diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml index 2c53891a92d..6b8dcb3e60b 100644 --- a/app/views/projects/merge_requests/index.html.haml +++ b/app/views/projects/merge_requests/index.html.haml @@ -4,9 +4,6 @@ - new_merge_request_path = project_new_merge_request_path(merge_project) if merge_project - page_title "Merge Requests" -- unless @project.issues_enabled? - = content_for :sub_nav do - = render "projects/merge_requests/head" - content_for :page_specific_javascripts do = webpack_bundle_tag 'common_vue' diff --git a/app/views/projects/milestones/edit.html.haml b/app/views/projects/milestones/edit.html.haml index 1e66c6079e3..af3f25c6a30 100644 --- a/app/views/projects/milestones/edit.html.haml +++ b/app/views/projects/milestones/edit.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Edit", @milestone.title, "Milestones" -= render "shared/mr_head" %div{ class: container_class } diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml index f3abecdd302..fcbf7cb802b 100644 --- a/app/views/projects/milestones/index.html.haml +++ b/app/views/projects/milestones/index.html.haml @@ -1,8 +1,6 @@ - @no_container = true - page_title 'Milestones' -= render "shared/mr_head" - %div{ class: container_class } .top-area = render 'shared/milestones_filter', counts: milestone_counts(@project.milestones) diff --git a/app/views/projects/milestones/new.html.haml b/app/views/projects/milestones/new.html.haml index 84ffbc0a926..c301f517013 100644 --- a/app/views/projects/milestones/new.html.haml +++ b/app/views/projects/milestones/new.html.haml @@ -1,7 +1,6 @@ - @no_container = true - breadcrumb_title "Milestones" - page_title "New Milestone" -= render "shared/mr_head" %div{ class: container_class } %h3.page-title diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index 1f5f18801ad..a5153df1159 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -3,7 +3,6 @@ - breadcrumb_title @milestone.title - page_title @milestone.title, "Milestones" - page_description @milestone.description -= render "shared/mr_head" %div{ class: container_class } .detail-page-header.milestone-page-header diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml index e29cb277389..8a19497c55b 100644 --- a/app/views/projects/network/show.html.haml +++ b/app/views/projects/network/show.html.haml @@ -2,7 +2,6 @@ - page_title "Graph", @ref - content_for :page_specific_javascripts do = page_specific_javascript_bundle_tag('network') -= render "projects/commits/head" = render "head" %div{ class: container_class } .project-network diff --git a/app/views/projects/pages/show.html.haml b/app/views/projects/pages/show.html.haml index 098b0ef56ef..04e647c0dc6 100644 --- a/app/views/projects/pages/show.html.haml +++ b/app/views/projects/pages/show.html.haml @@ -1,5 +1,4 @@ - page_title 'Pages' -= render "projects/settings/head" %h3.page_title Pages diff --git a/app/views/projects/pipeline_schedules/index.html.haml b/app/views/projects/pipeline_schedules/index.html.haml index 2b081786b6a..4fbdd1dd5e4 100644 --- a/app/views/projects/pipeline_schedules/index.html.haml +++ b/app/views/projects/pipeline_schedules/index.html.haml @@ -7,8 +7,6 @@ - @no_container = true - page_title _("Pipeline Schedules") -= render "projects/pipelines/head" - %div{ class: container_class } #pipeline-schedules-callout{ data: { docs_url: help_page_path('user/project/pipelines/schedules') } } .top-area diff --git a/app/views/projects/pipelines/_head.html.haml b/app/views/projects/pipelines/_head.html.haml deleted file mode 100644 index ee2f236cec4..00000000000 --- a/app/views/projects/pipelines/_head.html.haml +++ /dev/null @@ -1,34 +0,0 @@ -= content_for :sub_nav do - .scrolling-tabs-container.sub-nav-scroll - = render 'shared/nav_scroll' - .nav-links.sub-nav.scrolling-tabs - %ul{ class: (container_class) } - - if project_nav_tab? :pipelines - = nav_link(path: ['pipelines#index', 'pipelines#show']) do - = link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do - %span - Pipelines - - - if project_nav_tab? :builds - = nav_link(controller: [:jobs, :artifacts]) do - = link_to project_jobs_path(@project), title: 'Jobs', class: 'shortcuts-builds' do - %span - Jobs - - - if project_nav_tab? :pipelines - = nav_link(controller: :pipeline_schedules) do - = link_to pipeline_schedules_path(@project), title: 'Schedules', class: 'shortcuts-builds' do - %span - Schedules - - - if project_nav_tab? :environments - = nav_link(controller: :environments) do - = link_to project_environments_path(@project), title: 'Environments', class: 'shortcuts-environments' do - %span - Environments - - - if @project.feature_available?(:builds, current_user) && !@project.empty_repo? - = nav_link(path: 'pipelines#charts') do - = link_to charts_project_pipelines_path(@project), title: 'Charts', class: 'shortcuts-pipelines-charts' do - %span - Charts diff --git a/app/views/projects/pipelines/charts.html.haml b/app/views/projects/pipelines/charts.html.haml index 487ac87186d..ba55bc23add 100644 --- a/app/views/projects/pipelines/charts.html.haml +++ b/app/views/projects/pipelines/charts.html.haml @@ -4,7 +4,6 @@ - content_for :page_specific_javascripts do = page_specific_javascript_bundle_tag('common_d3') = page_specific_javascript_bundle_tag('graphs') -= render 'head' %div{ class: container_class } .sub-header-block diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml index 4f53efcf791..a10a7c23924 100644 --- a/app/views/projects/pipelines/index.html.haml +++ b/app/views/projects/pipelines/index.html.haml @@ -1,6 +1,5 @@ - @no_container = true - page_title "Pipelines" -= render "projects/pipelines/head" %div{ 'class' => container_class } - if show_auto_devops_callout?(@project) diff --git a/app/views/projects/pipelines/show.html.haml b/app/views/projects/pipelines/show.html.haml index 7cc9fe79afd..2174154b207 100644 --- a/app/views/projects/pipelines/show.html.haml +++ b/app/views/projects/pipelines/show.html.haml @@ -2,7 +2,6 @@ - add_to_breadcrumbs "Pipelines", project_pipelines_path(@project) - breadcrumb_title "##{@pipeline.id}" - page_title "Pipeline" -= render "projects/pipelines/head" .js-pipeline-container{ class: container_class, data: { controller_action: "#{controller.action_name}" } } - if @commit diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml index c786298e341..4d962f9433f 100644 --- a/app/views/projects/releases/edit.html.haml +++ b/app/views/projects/releases/edit.html.haml @@ -2,7 +2,6 @@ - add_to_breadcrumbs "Tags", project_tags_path(@project) - breadcrumb_title @tag.name - page_title "Edit", @tag.name, "Tags" -= render "projects/commits/head" %div{ class: container_class } .sub-header-block.no-bottom-space diff --git a/app/views/projects/services/edit.html.haml b/app/views/projects/services/edit.html.haml index 3e2a24a4c32..25770df1c90 100644 --- a/app/views/projects/services/edit.html.haml +++ b/app/views/projects/services/edit.html.haml @@ -2,5 +2,4 @@ - page_title @service.title, "Services" - add_to_breadcrumbs("Settings", edit_project_path(@project)) -= render "projects/settings/head" = render 'form' diff --git a/app/views/projects/settings/_head.html.haml b/app/views/projects/settings/_head.html.haml deleted file mode 100644 index 7d24c6a9122..00000000000 --- a/app/views/projects/settings/_head.html.haml +++ /dev/null @@ -1,30 +0,0 @@ -= content_for :sub_nav do - .scrolling-tabs-container.sub-nav-scroll - = render 'shared/nav_scroll' - .nav-links.sub-nav.scrolling-tabs - %ul{ class: container_class } - - can_edit = can?(current_user, :admin_project, @project) - - if can_edit - = nav_link(controller: :projects) do - = link_to edit_project_path(@project), title: 'General' do - %span - General - - if can_edit - = nav_link(controller: [:integrations, :services, :hooks, :hook_logs]) do - = link_to project_settings_integrations_path(@project), title: 'Integrations' do - %span - Integrations - = nav_link(controller: :repository) do - = link_to project_settings_repository_path(@project), title: 'Repository' do - %span - Repository - - if @project.feature_available?(:builds, current_user) - = nav_link(controller: :ci_cd) do - = link_to project_settings_ci_cd_path(@project), title: 'Pipelines' do - %span - Pipelines - - if @project.pages_available? - = nav_link(controller: :pages) do - = link_to project_pages_path(@project), title: 'Pages' do - %span - Pages diff --git a/app/views/projects/settings/ci_cd/show.html.haml b/app/views/projects/settings/ci_cd/show.html.haml index 47c056d097a..62455d0d40d 100644 --- a/app/views/projects/settings/ci_cd/show.html.haml +++ b/app/views/projects/settings/ci_cd/show.html.haml @@ -2,8 +2,6 @@ - page_title "CI / CD Settings" - page_title "CI / CD" -= render "projects/settings/head" - - expanded = Rails.env.test? %section.settings#js-general-pipeline-settings diff --git a/app/views/projects/settings/integrations/show.html.haml b/app/views/projects/settings/integrations/show.html.haml index 933daa7f549..2f1a548e119 100644 --- a/app/views/projects/settings/integrations/show.html.haml +++ b/app/views/projects/settings/integrations/show.html.haml @@ -1,6 +1,5 @@ - @content_class = "limit-container-width" unless fluid_layout - breadcrumb_title "Integrations Settings" - page_title 'Integrations' -= render "projects/settings/head" = render 'projects/hooks/index' = render 'projects/services/index' diff --git a/app/views/projects/settings/members/show.html.haml b/app/views/projects/settings/members/show.html.haml index 1e7695ac397..ea2cd36b212 100644 --- a/app/views/projects/settings/members/show.html.haml +++ b/app/views/projects/settings/members/show.html.haml @@ -1,6 +1,5 @@ - @content_class = "limit-container-width" unless fluid_layout - page_title "Members" -= render "projects/settings/head" = render "projects/project_members/index" diff --git a/app/views/projects/settings/repository/show.html.haml b/app/views/projects/settings/repository/show.html.haml index 6d4af72b8ea..517d51993d2 100644 --- a/app/views/projects/settings/repository/show.html.haml +++ b/app/views/projects/settings/repository/show.html.haml @@ -2,8 +2,6 @@ - page_title "Repository" - @content_class = "limit-container-width" unless fluid_layout -= render "projects/settings/head" - - content_for :page_specific_javascripts do = page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('deploy_keys') diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index d8f5114f4b5..705a4607ad2 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -7,7 +7,6 @@ = render partial: 'flash_messages', locals: { project: @project } -= render "projects/head" = render "projects/last_push" = render "home_panel" diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml index a6fe02fcae0..27d58d4c0e8 100644 --- a/app/views/projects/tags/index.html.haml +++ b/app/views/projects/tags/index.html.haml @@ -2,7 +2,6 @@ - @sort ||= sort_value_recently_updated - page_title "Tags" - add_to_breadcrumbs("Repository", project_tree_path(@project)) -= render "projects/commits/head" .flex-list{ class: container_class } .top-area.adjust diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml index 5d6eb4f4026..43aa2b27af6 100644 --- a/app/views/projects/tags/show.html.haml +++ b/app/views/projects/tags/show.html.haml @@ -2,7 +2,6 @@ - add_to_breadcrumbs "Tags", project_tags_path(@project) - breadcrumb_title @tag.name - page_title @tag.name, "Tags" -= render "projects/commits/head" %div{ class: container_class } .top-area.multi-line diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml index d84a1fd7ee1..f819f2addaa 100644 --- a/app/views/projects/tree/show.html.haml +++ b/app/views/projects/tree/show.html.haml @@ -11,8 +11,6 @@ = webpack_bundle_tag 'common_vue' = webpack_bundle_tag 'repo' -= render "projects/commits/head" - %div{ class: [container_class, ("limit-container-width" unless fluid_layout)] } - if show_auto_devops_callout?(@project) = render 'shared/auto_devops_callout' diff --git a/app/views/shared/_auto_devops_callout.html.haml b/app/views/shared/_auto_devops_callout.html.haml index 2f09c2fec87..7c633175a06 100644 --- a/app/views/shared/_auto_devops_callout.html.haml +++ b/app/views/shared/_auto_devops_callout.html.haml @@ -6,10 +6,10 @@ .svg-container = custom_icon('icon_autodevops') .user-callout-copy - %h4= _('Auto DevOps (Beta)') - %p= _('Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration.') + %h4= s_('AutoDevOps|Auto DevOps (Beta)') + %p= s_('AutoDevOps|Auto DevOps can be activated for this project. It will automatically build, test, and deploy your application based on a predefined CI/CD configuration.') %p - #{s_('AutoDevOps|Learn more in the')} - = link_to _('Auto DevOps documentation'), help_page_path('topics/autodevops/index.md'), target: '_blank', rel: 'noopener noreferrer' + - link = link_to(s_('AutoDevOps|Auto DevOps documentation'), help_page_path('topics/autodevops/index.md'), target: '_blank', rel: 'noopener noreferrer') + = s_('AutoDevOps|Learn more in the %{link_to_documentation}').html_safe % { link_to_documentation: link } - = link_to _('Enable in settings'), project_settings_ci_cd_path(@project, anchor: 'js-general-pipeline-settings'), class: 'btn btn-primary js-close-callout' + = link_to s_('AutoDevOps|Enable in settings'), project_settings_ci_cd_path(@project, anchor: 'js-general-pipeline-settings'), class: 'btn btn-primary js-close-callout' diff --git a/app/views/shared/_mr_head.html.haml b/app/views/shared/_mr_head.html.haml deleted file mode 100644 index e7355ae2eea..00000000000 --- a/app/views/shared/_mr_head.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -- if @project.issues_enabled? - = render "projects/issues/head" -- else - = render "projects/merge_requests/head" diff --git a/app/views/shared/_nav_scroll.html.haml b/app/views/shared/_nav_scroll.html.haml deleted file mode 100644 index 61646f150c1..00000000000 --- a/app/views/shared/_nav_scroll.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -.fade-left - = icon('angle-left') -.fade-right - = icon('angle-right') diff --git a/app/views/shared/boards/_show.html.haml b/app/views/shared/boards/_show.html.haml index 722890a01e5..ee8ad8e3999 100644 --- a/app/views/shared/boards/_show.html.haml +++ b/app/views/shared/boards/_show.html.haml @@ -12,13 +12,11 @@ %script#js-board-template{ type: "text/x-template" }= render "shared/boards/components/board" %script#js-board-modal-filter{ type: "text/x-template" }= render "shared/issuable/search_bar", type: :boards_modal -= render "projects/issues/head" +#board-app.boards-app{ "v-cloak" => true, data: board_data, ":class" => "{ 'is-compact': detailIssueVisible }" } + .hidden-xs.hidden-sm + = render 'shared/issuable/search_bar', type: :boards -.hidden-xs.hidden-sm - = render 'shared/issuable/search_bar', type: :boards - -#board-app.boards-app{ "v-cloak" => true, data: board_data } - .boards-list{ ":class" => "{ 'is-compact': detailIssueVisible }" } + .boards-list .boards-app-loading.text-center{ "v-if" => "loading" } = icon("spinner spin") %board{ "v-cloak" => true, |