diff options
278 files changed, 1532 insertions, 1658 deletions
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index b3d91f9cfc0..da902181863 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -5.9.0 +5.9.2 @@ -26,7 +26,7 @@ gem 'doorkeeper', '~> 4.2.0' gem 'doorkeeper-openid_connect', '~> 1.1.0' gem 'omniauth', '~> 1.4.2' gem 'omniauth-auth0', '~> 1.4.1' -gem 'omniauth-azure-oauth2', '~> 0.0.6' +gem 'omniauth-azure-oauth2', '~> 0.0.9' gem 'omniauth-cas3', '~> 1.1.4' gem 'omniauth-facebook', '~> 4.0.0' gem 'omniauth-github', '~> 1.1.1' diff --git a/Gemfile.lock b/Gemfile.lock index 4b2f86fe48d..3313a687ff0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -194,7 +194,7 @@ GEM factory_girl_rails (4.7.0) factory_girl (~> 4.7.0) railties (>= 3.0.0) - faraday (0.12.1) + faraday (0.12.2) multipart-post (>= 1.2, < 3) faraday_middleware (0.11.0.1) faraday (>= 0.7.4, < 1.0) @@ -516,10 +516,10 @@ GEM omniauth-oauth2 (~> 1.1) omniauth-authentiq (0.3.1) omniauth-oauth2 (~> 1.3, >= 1.3.1) - omniauth-azure-oauth2 (0.0.6) + omniauth-azure-oauth2 (0.0.9) jwt (~> 1.0) omniauth (~> 1.0) - omniauth-oauth2 (~> 1.1) + omniauth-oauth2 (~> 1.4) omniauth-cas3 (1.1.4) addressable (~> 2.3) nokogiri (~> 1.7, >= 1.7.1) @@ -545,7 +545,7 @@ GEM omniauth-oauth (1.1.0) oauth omniauth (~> 1.0) - omniauth-oauth2 (1.3.1) + omniauth-oauth2 (1.4.0) oauth2 (~> 1.0) omniauth (~> 1.2) omniauth-oauth2-generic (0.2.2) @@ -1075,7 +1075,7 @@ DEPENDENCIES omniauth (~> 1.4.2) omniauth-auth0 (~> 1.4.1) omniauth-authentiq (~> 0.3.1) - omniauth-azure-oauth2 (~> 0.0.6) + omniauth-azure-oauth2 (~> 0.0.9) omniauth-cas3 (~> 1.1.4) omniauth-facebook (~> 4.0.0) omniauth-github (~> 1.1.1) diff --git a/app/assets/images/favicon-blue.ico b/app/assets/images/favicon-blue.ico Binary files differindex 156fcf07588..156fcf07588 100755..100644 --- a/app/assets/images/favicon-blue.ico +++ b/app/assets/images/favicon-blue.ico 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 6583e471a48..8002b0b23c9 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js @@ -3,60 +3,63 @@ 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 './cycle_analytics_service'; -import './cycle_analytics_store'; +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'; Vue.use(Translate); $(() => { const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed'; - const cycleAnalyticsEl = document.querySelector('#cycle-analytics'); - const cycleAnalyticsStore = gl.cycleAnalytics.CycleAnalyticsStore; - const cycleAnalyticsService = new gl.cycleAnalytics.CycleAnalyticsService({ - requestPath: cycleAnalyticsEl.dataset.requestPath, - }); gl.cycleAnalyticsApp = new Vue({ el: '#cycle-analytics', name: 'CycleAnalytics', - data: { - state: cycleAnalyticsStore.state, - isLoading: false, - isLoadingStage: false, - isEmptyStage: false, - hasError: false, - startDate: 30, - isOverviewDialogDismissed: Cookies.get(OVERVIEW_DIALOG_COOKIE), + data() { + const cycleAnalyticsEl = document.querySelector('#cycle-analytics'); + const cycleAnalyticsService = new CycleAnalyticsService({ + requestPath: cycleAnalyticsEl.dataset.requestPath, + }); + + return { + store: CycleAnalyticsStore, + state: CycleAnalyticsStore.state, + isLoading: false, + isLoadingStage: false, + isEmptyStage: false, + hasError: false, + startDate: 30, + isOverviewDialogDismissed: Cookies.get(OVERVIEW_DIALOG_COOKIE), + service: cycleAnalyticsService, + }; }, computed: { currentStage() { - return cycleAnalyticsStore.currentActiveStage(); + return this.store.currentActiveStage(); }, }, 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(); }, methods: { handleError() { - cycleAnalyticsStore.setErrorState(true); + this.store.setErrorState(true); return new Flash('There was an error while fetching cycle analytics data.'); }, initDropdown() { @@ -77,17 +80,17 @@ $(() => { this.isLoading = true; - cycleAnalyticsService + this.service .fetchCycleAnalyticsData(fetchOptions) - .done((response) => { - cycleAnalyticsStore.setCycleAnalyticsData(response); + .then(resp => resp.json()) + .then((response) => { + this.store.setCycleAnalyticsData(response); this.selectDefaultStage(); this.initDropdown(); + this.isLoading = false; }) - .error(() => { + .catch(() => { this.handleError(); - }) - .always(() => { this.isLoading = false; }); }, @@ -100,27 +103,27 @@ $(() => { if (this.currentStage === stage) return; if (!stage.isUserAllowed) { - cycleAnalyticsStore.setActiveStage(stage); + this.store.setActiveStage(stage); return; } this.isLoadingStage = true; - cycleAnalyticsStore.setStageEvents([], stage); - cycleAnalyticsStore.setActiveStage(stage); + this.store.setStageEvents([], stage); + this.store.setActiveStage(stage); - cycleAnalyticsService + this.service .fetchStageData({ stage, startDate: this.startDate, }) - .done((response) => { + .then(resp => resp.json()) + .then((response) => { this.isEmptyStage = !response.events.length; - cycleAnalyticsStore.setStageEvents(response.events, stage); + this.store.setStageEvents(response.events, stage); + this.isLoadingStage = false; }) - .error(() => { + .catch(() => { this.isEmptyStage = true; - }) - .always(() => { this.isLoadingStage = false; }); }, @@ -132,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/cycle_analytics/cycle_analytics_service.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js index 6504d7db2f2..f496c38208d 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js @@ -1,27 +1,16 @@ -/* eslint-disable no-param-reassign */ +import Vue from 'vue'; +import VueResource from 'vue-resource'; -const global = window.gl || (window.gl = {}); -global.cycleAnalytics = global.cycleAnalytics || {}; +Vue.use(VueResource); -class CycleAnalyticsService { +export default class CycleAnalyticsService { constructor(options) { this.requestPath = options.requestPath; + this.cycleAnalytics = Vue.resource(this.requestPath); } - fetchCycleAnalyticsData(options) { - options = options || { startDate: 30 }; - - return $.ajax({ - url: this.requestPath, - method: 'GET', - dataType: 'json', - contentType: 'application/json', - data: { - cycle_analytics: { - start_date: options.startDate, - }, - }, - }); + fetchCycleAnalyticsData(options = { startDate: 30 }) { + return this.cycleAnalytics.get({ cycle_analytics: { start_date: options.startDate } }); } fetchStageData(options) { @@ -30,12 +19,12 @@ class CycleAnalyticsService { startDate, } = options; - return $.get(`${this.requestPath}/events/${stage.name}.json`, { - cycle_analytics: { - start_date: startDate, + return Vue.http.get(`${this.requestPath}/events/${stage.name}.json`, { + params: { + cycle_analytics: { + start_date: startDate, + }, }, }); } } - -global.cycleAnalytics.CycleAnalyticsService = CycleAnalyticsService; diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js index 991f8c1f6fd..8bf9ae17de0 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js @@ -4,9 +4,6 @@ import { __ } from '../locale'; import '../lib/utils/text_utility'; import DEFAULT_EVENT_OBJECTS from './default_event_objects'; -const global = window.gl || (window.gl = {}); -global.cycleAnalytics = global.cycleAnalytics || {}; - const EMPTY_STAGE_TEXTS = { issue: __('The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.'), plan: __('The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.'), @@ -17,7 +14,7 @@ const EMPTY_STAGE_TEXTS = { production: __('The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.'), }; -global.cycleAnalytics.CycleAnalyticsStore = { +export default { state: { summary: '', stats: '', diff --git a/app/assets/javascripts/fly_out_nav.js b/app/assets/javascripts/fly_out_nav.js index 157280d66e3..98837c3b2a0 100644 --- a/app/assets/javascripts/fly_out_nav.js +++ b/app/assets/javascripts/fly_out_nav.js @@ -34,7 +34,7 @@ export const canShowActiveSubItems = (el) => { export const canShowSubItems = () => bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'md' || bp.getBreakpointSize() === 'lg'; export const getHideSubItemsInterval = () => { - if (!currentOpenMenu) return 0; + if (!currentOpenMenu || !mousePos.length) return 0; const currentMousePos = mousePos[mousePos.length - 1]; const prevMousePos = mousePos[0]; 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/repo/helpers/repo_helper.js b/app/assets/javascripts/repo/helpers/repo_helper.js index 2bd8d7eea65..655e4e7605b 100644 --- a/app/assets/javascripts/repo/helpers/repo_helper.js +++ b/app/assets/javascripts/repo/helpers/repo_helper.js @@ -178,8 +178,8 @@ const RepoHelper = { setFile(data, file) { const newFile = data; + newFile.url = file.url || Service.url; // Grab the URL from service, happens on page refresh. - newFile.url = file.url; if (newFile.render_error === 'too_large' || newFile.render_error === 'collapsed') { newFile.tooLarge = true; } 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/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 5c68059f485..1d72a70f0f5 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -260,7 +260,7 @@ position: relative; border: 1px solid $blue-300; border-radius: $border-radius-default; - background-color: $blue-25; + background-color: $blue-50; justify-content: center; .dismiss-button { diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index 2bcd23a15e6..c0d8e6c328c 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -779,6 +779,14 @@ white-space: normal; width: 100%; + &.dropdown-menu-user-link { + white-space: nowrap; + + .dropdown-menu-user-username { + display: block; + } + } + // make sure the text color is not overriden &.text-danger { color: $brand-danger; diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss index 7fa58b11d9d..0d1c04026b8 100644 --- a/app/assets/stylesheets/framework/gitlab-theme.scss +++ b/app/assets/stylesheets/framework/gitlab-theme.scss @@ -242,10 +242,10 @@ body { &:hover { background-color: $white-light; - box-shadow: inset 0 0 0 1px $blue-100; + box-shadow: inset 0 0 0 1px $blue-200; .location-badge { - box-shadow: inset 0 0 0 1px $blue-100; + box-shadow: inset 0 0 0 1px $blue-200; } } } @@ -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 d40b65bb2cc..2fee2164190 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -142,5 +142,41 @@ } @mixin green-status-color { - @include status-color($green-50, $green-500, $green-700); + @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..d4b3fb238d5 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; @@ -386,11 +317,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; 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/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss index 4c35e3a9c3c..3ea77eb7a43 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss @@ -137,7 +137,7 @@ $well-border: #eee; //## $code-color: $red-600; -$code-bg: lighten($red-50, 2%); +$code-bg: lighten($red-100, 2%); $kbd-color: $white-light; $kbd-bg: #333; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index a3da9fd44e8..ca514add9cd 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -6,6 +6,7 @@ $gutter_width: 290px; $gutter_inner_width: 250px; $sidebar-transition-duration: .15s; $sidebar-breakpoint: 1024px; +$default-transition-duration: .15s; /* * Color schema @@ -27,46 +28,45 @@ $gray-dark: darken($gray-light, $darken-dark-factor); $gray-darker: #eee; $gray-darkest: #c4c4c4; -$green-25: #f6fcf8; -$green-50: #e4f5eb; -$green-100: #bae6cc; -$green-200: #8dd5aa; -$green-300: #5fc488; -$green-400: #3cb76f; +$green-50: #f1fdf6; +$green-100: #dcf5e7; +$green-200: #b3e6c8; +$green-300: #75d09b; +$green-400: #37b96d; $green-500: #1aaa55; $green-600: #168f48; $green-700: #12753a; $green-800: #0e5a2d; $green-900: #0a4020; +$green-950: #072b15; -$blue-25: #f6fafd; -$blue-50: #e4eff9; -$blue-100: #bcd7f1; -$blue-200: #8fbce8; -$blue-300: #62a1df; -$blue-400: #418cd8; +$blue-50: #f6fafe; +$blue-100: #e4f0fb; +$blue-200: #b8d6f4; +$blue-300: #73afea; +$blue-400: #2e87e0; $blue-500: #1f78d1; $blue-600: #1b69b6; $blue-700: #17599c; $blue-800: #134a81; $blue-900: #0f3b66; +$blue-950: #0a2744; -$orange-25: #fffcf8; -$orange-50: #fff2e1; -$orange-100: #fedfb3; -$orange-200: #feca81; -$orange-300: #fdb44f; -$orange-400: #fca429; +$orange-50: #fffaf4; +$orange-100: #fff1de; +$orange-200: #fed69f; +$orange-300: #fdbc60; +$orange-400: #fca121; $orange-500: #fc9403; $orange-600: #de7e00; $orange-700: #c26700; -$orange-800: #a35100; -$orange-900: #853b00; +$orange-800: #a35200; +$orange-900: #853c00; +$orange-950: #592800; -$red-25: #fef7f6; -$red-50: #fbe7e4; -$red-100: #f4c4bc; -$red-200: #ed9d90; +$red-50: #fef6f5; +$red-100: #fbe5e1; +$red-200: #f2b4a9; $red-300: #e67664; $red-400: #e05842; $red-500: #db3b21; @@ -74,6 +74,7 @@ $red-600: #c0341d; $red-700: #a62d19; $red-800: #8b2615; $red-900: #711e11; +$red-950: #4b140b; // GitLab themes @@ -184,8 +185,8 @@ $list-text-disabled-color: $gl-text-color-tertiary; $list-border-light: #eee; $list-border: rgba(0, 0, 0, 0.05); $list-text-height: 42px; -$list-warning-row-bg: $orange-50; -$list-warning-row-border: $orange-100; +$list-warning-row-bg: $orange-100; +$list-warning-row-border: $orange-200; $list-warning-row-color: $orange-700; /* @@ -214,8 +215,8 @@ $gl-sidebar-padding: 22px; /* * Misc */ -$row-hover: $blue-25; -$row-hover-border: $blue-100; +$row-hover: $blue-50; +$row-hover-border: $blue-200; $progress-color: #c0392b; $header-height: 50px; $new-navbar-height: 40px; @@ -265,8 +266,8 @@ $time-color: #999; $project-member-show-color: #aaa; $gl-promo-color: #aaa; $error-bg: $red-400; -$warning-message-bg: $orange-50; -$warning-message-border: $orange-100; +$warning-message-bg: $orange-100; +$warning-message-border: $orange-200; $warning-message-color: $orange-700; $control-group-descr-color: #666; $table-permission-x-bg: #d9edf7; @@ -451,17 +452,17 @@ $builds-trace-bg: #111; /* * Callout */ -$callout-danger-bg: $red-50; -$callout-danger-border: $red-100; +$callout-danger-bg: $red-100; +$callout-danger-border: $red-200; $callout-danger-color: $red-700; -$callout-warning-bg: $orange-50; -$callout-warning-border: $orange-100; +$callout-warning-bg: $orange-100; +$callout-warning-border: $orange-200; $callout-warning-color: $orange-700; -$callout-info-bg: $blue-50; -$callout-info-border: $blue-100; +$callout-info-bg: $blue-100; +$callout-info-border: $blue-200; $callout-info-color: $blue-700; -$callout-success-bg: $green-50; -$callout-success-border: $green-100; +$callout-success-bg: $green-100; +$callout-success-border: $green-200; $callout-success-color: $green-700; /* diff --git a/app/assets/stylesheets/pages/convdev_index.scss b/app/assets/stylesheets/pages/convdev_index.scss index 16702442f50..fb1899284fd 100644 --- a/app/assets/stylesheets/pages/convdev_index.scss +++ b/app/assets/stylesheets/pages/convdev_index.scss @@ -83,7 +83,7 @@ $space-between-cards: 8px; border-top-color: $color-low-score; .card-score-big { - background-color: $red-25; + background-color: $red-50; } } @@ -91,7 +91,7 @@ $space-between-cards: 8px; border-top-color: $color-average-score; .card-score-big { - background-color: $orange-25; + background-color: $orange-50; } } @@ -99,7 +99,7 @@ $space-between-cards: 8px; border-top-color: $color-high-score; .card-score-big { - background-color: $green-25; + background-color: $green-50; } } diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index 951580ea1fe..ed9d5e98467 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; @@ -586,11 +586,6 @@ top: 76px; } - + .files, - + .alert { - margin-top: 1px; - } - &:not(.is-stuck) .diff-stats-additions-deletions-collapsed { display: none; } @@ -605,11 +600,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 d01ee4b033c..3ddf3d8ea7a 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -7,7 +7,7 @@ .is-confidential { color: $orange-600; - background-color: $orange-50; + background-color: $orange-100; border-radius: $border-radius-default; padding: 5px; margin: 0 3px 0 -4px; diff --git a/app/assets/stylesheets/pages/merge_conflicts.scss b/app/assets/stylesheets/pages/merge_conflicts.scss index 35cefd449f1..dbf3e2b763c 100644 --- a/app/assets/stylesheets/pages/merge_conflicts.scss +++ b/app/assets/stylesheets/pages/merge_conflicts.scss @@ -255,7 +255,7 @@ $colors: ( &.saved { .editor { - border-top: solid 2px $green-200; + border-top: solid 2px $green-300; } } diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index 5d7c85b16ef..be4db597689 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -103,7 +103,7 @@ .confidential-issue-warning { color: $orange-600; - background-color: $orange-50; + background-color: $orange-100; border-radius: $border-radius-default $border-radius-default 0 0; border: 1px solid $border-gray-normal; border-bottom: none; diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 9d03a042aa3..086dd528579 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -644,20 +644,20 @@ button.mini-pipeline-graph-dropdown-toggle { // Dropdown button animation in mini pipeline graph &.ci-status-icon-success { - @include mini-pipeline-graph-color($green-50, $green-500, $green-600); + @include mini-pipeline-graph-color($green-100, $green-500, $green-600); } &.ci-status-icon-failed { - @include mini-pipeline-graph-color($red-50, $red-500, $red-600); + @include mini-pipeline-graph-color($red-100, $red-500, $red-600); } &.ci-status-icon-pending, &.ci-status-icon-success_with_warnings { - @include mini-pipeline-graph-color($orange-50, $orange-500, $orange-600); + @include mini-pipeline-graph-color($orange-100, $orange-500, $orange-600); } &.ci-status-icon-running { - @include mini-pipeline-graph-color($blue-50, $blue-400, $blue-600); + @include mini-pipeline-graph-color($blue-100, $blue-400, $blue-600); } &.ci-status-icon-canceled, diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index c5d6ff66dd6..67abe6e88ed 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -291,7 +291,7 @@ table.u2f-registrations { .bordered-box { border: 1px solid $blue-300; border-radius: $border-radius-default; - background-color: $blue-25; + background-color: $blue-50; position: relative; display: flex; justify-content: center; @@ -379,7 +379,7 @@ table.u2f-registrations { .nav-wip { border: 1px solid $blue-500; - background: $blue-25; + background: $blue-50; padding: $gl-padding; margin-bottom: $gl-padding; 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/pages/status.scss b/app/assets/stylesheets/pages/status.scss index 36f622db136..25c80e1f950 100644 --- a/app/assets/stylesheets/pages/status.scss +++ b/app/assets/stylesheets/pages/status.scss @@ -18,7 +18,7 @@ } &.ci-failed { - @include status-color($red-50, $red-500, $red-600); + @include status-color($red-100, $red-500, $red-600); } &.ci-success { @@ -39,12 +39,12 @@ &.ci-pending, &.ci-failed_with_warnings, &.ci-success_with_warnings { - @include status-color($orange-50, $orange-500, $orange-700); + @include status-color($orange-100, $orange-500, $orange-700); } &.ci-info, &.ci-running { - @include status-color($blue-50, $blue-500, $blue-600); + @include status-color($blue-100, $blue-500, $blue-600); } &.ci-created, 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/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb index 0d0e53d4b76..8921d55c3d0 100644 --- a/app/controllers/concerns/issuable_collections.rb +++ b/app/controllers/concerns/issuable_collections.rb @@ -117,19 +117,32 @@ module IssuableCollections key = 'issuable_sort' cookies[key] = params[:sort] if params[:sort].present? - - # id_desc and id_asc are old values for these two. - cookies[key] = sort_value_recently_created if cookies[key] == 'id_desc' - cookies[key] = sort_value_oldest_created if cookies[key] == 'id_asc' - + cookies[key] = update_cookie_value(cookies[key]) params[:sort] = cookies[key] end def default_sort_order case params[:state] - when 'opened', 'all' then sort_value_recently_created + when 'opened', 'all' then sort_value_created_date when 'merged', 'closed' then sort_value_recently_updated - else sort_value_recently_created + else sort_value_created_date + end + end + + # Update old values to the actual ones. + def update_cookie_value(value) + case value + when 'id_asc' then sort_value_oldest_created + when 'id_desc' then sort_value_recently_created + when 'created_asc' then sort_value_created_date + when 'created_desc' then sort_value_created_date + when 'due_date_asc' then sort_value_due_date + when 'due_date_desc' then sort_value_due_date + when 'milestone_due_asc' then sort_value_milestone + when 'milestone_due_desc' then sort_value_milestone + when 'downvotes_asc' then sort_value_popularity + when 'downvotes_desc' then sort_value_popularity + else value end end end diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb index a4c226a6aad..be11d453898 100644 --- a/app/helpers/avatars_helper.rb +++ b/app/helpers/avatars_helper.rb @@ -13,22 +13,29 @@ module AvatarsHelper user_name = options[:user].try(:name) || options[:user_name] avatar_url = options[:url] || avatar_icon(options[:user] || options[:user_email], avatar_size) has_tooltip = options[:has_tooltip].nil? ? true : options[:has_tooltip] - data_attributes = {} + data_attributes = options[:data] || {} css_class = %W[avatar s#{avatar_size}].push(*options[:css_class]) if has_tooltip css_class.push('has-tooltip') - data_attributes = { container: 'body' } + data_attributes[:container] = 'body' end - image_tag( - avatar_url, + if options[:lazy] + css_class << 'lazy' + data_attributes[:src] = avatar_url + avatar_url = LazyImageTagHelper.placeholder_image + end + + image_options = { + alt: "#{user_name}'s avatar", + src: avatar_url, + data: data_attributes, class: css_class, - alt: "#{user_name}'s avatar", - title: user_name, - data: data_attributes, - lazy: true - ) + title: user_name + } + + tag(:img, image_options) end def user_avatar(options = {}) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index ddeff490d3a..21fb17e06d6 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -239,8 +239,8 @@ module ProjectsHelper end end - def has_projects_or_name?(projects, params) - !!(params[:name] || any_projects?(projects)) + def show_projects?(projects, params) + !!(params[:personal] || params[:name] || any_projects?(projects)) end private diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb index c4a73bedbcd..1b542ed2a96 100644 --- a/app/helpers/sorting_helper.rb +++ b/app/helpers/sorting_helper.rb @@ -1,34 +1,38 @@ module SortingHelper def sort_options_hash { - sort_value_name => sort_title_name, - sort_value_name_desc => sort_title_name_desc, - sort_value_recently_updated => sort_title_recently_updated, - sort_value_oldest_updated => sort_title_oldest_updated, + sort_value_created_date => sort_title_created_date, + sort_value_downvotes => sort_title_downvotes, + sort_value_due_date => sort_title_due_date, + sort_value_due_date_later => sort_title_due_date_later, + sort_value_due_date_soon => sort_title_due_date_soon, + sort_value_label_priority => sort_title_label_priority, + sort_value_largest_group => sort_title_largest_group, + sort_value_largest_repo => sort_title_largest_repo, + sort_value_milestone => sort_title_milestone, + sort_value_milestone_later => sort_title_milestone_later, + sort_value_milestone_soon => sort_title_milestone_soon, + sort_value_name => sort_title_name, + sort_value_name_desc => sort_title_name_desc, + sort_value_oldest_created => sort_title_oldest_created, + sort_value_oldest_signin => sort_title_oldest_signin, + sort_value_oldest_updated => sort_title_oldest_updated, sort_value_recently_created => sort_title_recently_created, - sort_value_oldest_created => sort_title_oldest_created, - sort_value_milestone_soon => sort_title_milestone_soon, - sort_value_milestone_later => sort_title_milestone_later, - sort_value_due_date_soon => sort_title_due_date_soon, - sort_value_due_date_later => sort_title_due_date_later, - sort_value_largest_repo => sort_title_largest_repo, - sort_value_largest_group => sort_title_largest_group, - sort_value_recently_signin => sort_title_recently_signin, - sort_value_oldest_signin => sort_title_oldest_signin, - sort_value_downvotes => sort_title_downvotes, - sort_value_upvotes => sort_title_upvotes, - sort_value_priority => sort_title_priority, - sort_value_label_priority => sort_title_label_priority + sort_value_recently_signin => sort_title_recently_signin, + sort_value_recently_updated => sort_title_recently_updated, + sort_value_popularity => sort_title_popularity, + sort_value_priority => sort_title_priority, + sort_value_upvotes => sort_title_upvotes } end def projects_sort_options_hash options = { - sort_value_name => sort_title_name, - sort_value_latest_activity => sort_title_latest_activity, - sort_value_oldest_activity => sort_title_oldest_activity, - sort_value_recently_created => sort_title_recently_created, - sort_value_oldest_created => sort_title_oldest_created + sort_value_latest_activity => sort_title_latest_activity, + sort_value_name => sort_title_name, + sort_value_oldest_activity => sort_title_oldest_activity, + sort_value_oldest_created => sort_title_oldest_created, + sort_value_recently_created => sort_title_recently_created } if current_controller?('admin/projects') @@ -40,160 +44,174 @@ module SortingHelper def member_sort_options_hash { - sort_value_access_level_asc => sort_title_access_level_asc, + sort_value_access_level_asc => sort_title_access_level_asc, sort_value_access_level_desc => sort_title_access_level_desc, - sort_value_last_joined => sort_title_last_joined, - sort_value_oldest_joined => sort_title_oldest_joined, - sort_value_name => sort_title_name_asc, - sort_value_name_desc => sort_title_name_desc, - sort_value_recently_signin => sort_title_recently_signin, - sort_value_oldest_signin => sort_title_oldest_signin + sort_value_last_joined => sort_title_last_joined, + sort_value_name => sort_title_name_asc, + sort_value_name_desc => sort_title_name_desc, + sort_value_oldest_joined => sort_title_oldest_joined, + sort_value_oldest_signin => sort_title_oldest_signin, + sort_value_recently_signin => sort_title_recently_signin } end def milestone_sort_options_hash { - sort_value_name => sort_title_name_asc, - sort_value_name_desc => sort_title_name_desc, - sort_value_due_date_soon => sort_title_due_date_soon, - sort_value_due_date_later => sort_title_due_date_later, - sort_value_start_date_soon => sort_title_start_date_soon, - sort_value_start_date_later => sort_title_start_date_later + sort_value_name => sort_title_name_asc, + sort_value_name_desc => sort_title_name_desc, + sort_value_due_date_later => sort_title_due_date_later, + sort_value_due_date_soon => sort_title_due_date_soon, + sort_value_start_date_later => sort_title_start_date_later, + sort_value_start_date_soon => sort_title_start_date_soon } end def branches_sort_options_hash { - sort_value_name => sort_title_name, - sort_value_recently_updated => sort_title_recently_updated, - sort_value_oldest_updated => sort_title_oldest_updated + sort_value_name => sort_title_name, + sort_value_oldest_updated => sort_title_oldest_updated, + sort_value_recently_updated => sort_title_recently_updated } end def tags_sort_options_hash { - sort_value_name => sort_title_name, - sort_value_recently_updated => sort_title_recently_updated, - sort_value_oldest_updated => sort_title_oldest_updated + sort_value_name => sort_title_name, + sort_value_oldest_updated => sort_title_oldest_updated, + sort_value_recently_updated => sort_title_recently_updated } end - def sort_title_priority - s_('SortOptions|Priority') + def sortable_item(item, path, sorted_by) + link_to item, path, class: sorted_by == item ? 'is-active' : '' end - def sort_title_label_priority - s_('SortOptions|Label priority') + # Titles. + def sort_title_access_level_asc + s_('SortOptions|Access level, ascending') end - def sort_title_oldest_updated - s_('SortOptions|Oldest updated') + def sort_title_access_level_desc + s_('SortOptions|Access level, descending') end - def sort_title_recently_updated - s_('SortOptions|Last updated') + def sort_title_created_date + s_('SortOptions|Created date') end - def sort_title_oldest_activity - s_('SortOptions|Oldest updated') + def sort_title_downvotes + s_('SortOptions|Least popular') end - def sort_title_latest_activity - s_('SortOptions|Last updated') + def sort_title_due_date + s_('SortOptions|Due date') end - def sort_title_oldest_created - s_('SortOptions|Oldest created') + def sort_title_due_date_later + s_('SortOptions|Due later') end - def sort_title_recently_created - s_('SortOptions|Last created') + def sort_title_due_date_soon + s_('SortOptions|Due soon') end - def sort_title_milestone_soon - s_('SortOptions|Milestone due soon') + def sort_title_label_priority + s_('SortOptions|Label priority') end - def sort_title_milestone_later - s_('SortOptions|Milestone due later') + def sort_title_largest_group + s_('SortOptions|Largest group') end - def sort_title_due_date_soon - s_('SortOptions|Due soon') + def sort_title_largest_repo + s_('SortOptions|Largest repository') end - def sort_title_due_date_later - s_('SortOptions|Due later') + def sort_title_last_joined + s_('SortOptions|Last joined') end - def sort_title_start_date_soon - s_('SortOptions|Start soon') + def sort_title_latest_activity + s_('SortOptions|Last updated') end - def sort_title_start_date_later - s_('SortOptions|Start later') + def sort_title_milestone + s_('SortOptions|Milestone') + end + + def sort_title_milestone_later + s_('SortOptions|Milestone due later') + end + + def sort_title_milestone_soon + s_('SortOptions|Milestone due soon') end def sort_title_name s_('SortOptions|Name') end - def sort_title_largest_repo - s_('SortOptions|Largest repository') + def sort_title_name_asc + s_('SortOptions|Name, ascending') end - def sort_title_largest_group - s_('SortOptions|Largest group') + def sort_title_name_desc + s_('SortOptions|Name, descending') end - def sort_title_recently_signin - s_('SortOptions|Recent sign in') + def sort_title_oldest_activity + s_('SortOptions|Oldest updated') end - def sort_title_oldest_signin - s_('SortOptions|Oldest sign in') + def sort_title_oldest_created + s_('SortOptions|Oldest created') end - def sort_title_downvotes - s_('SortOptions|Least popular') + def sort_title_oldest_joined + s_('SortOptions|Oldest joined') end - def sort_title_upvotes - s_('SortOptions|Most popular') + def sort_title_oldest_signin + s_('SortOptions|Oldest sign in') end - def sort_title_last_joined - s_('SortOptions|Last joined') + def sort_title_oldest_updated + s_('SortOptions|Oldest updated') end - def sort_title_oldest_joined - s_('SortOptions|Oldest joined') + def sort_title_popularity + s_('SortOptions|Popularity') end - def sort_title_access_level_asc - s_('SortOptions|Access level, ascending') + def sort_title_priority + s_('SortOptions|Priority') end - def sort_title_access_level_desc - s_('SortOptions|Access level, descending') + def sort_title_recently_created + s_('SortOptions|Last created') end - def sort_title_name_asc - s_('SortOptions|Name, ascending') + def sort_title_recently_signin + s_('SortOptions|Recent sign in') end - def sort_title_name_desc - s_('SortOptions|Name, descending') + def sort_title_recently_updated + s_('SortOptions|Last updated') end - def sort_value_last_joined - 'last_joined' + def sort_title_start_date_later + s_('SortOptions|Start later') end - def sort_value_oldest_joined - 'oldest_joined' + def sort_title_start_date_soon + s_('SortOptions|Start soon') end + def sort_title_upvotes + s_('SortOptions|Most popular') + end + + # Values. def sort_value_access_level_asc 'access_level_asc' end @@ -202,88 +220,112 @@ module SortingHelper 'access_level_desc' end - def sort_value_name_desc - 'name_desc' + def sort_value_created_date + 'created_date' end - def sort_value_priority - 'priority' + def sort_value_downvotes + 'downvotes_desc' + end + + def sort_value_due_date + 'due_date' + end + + def sort_value_due_date_later + 'due_date_desc' + end + + def sort_value_due_date_soon + 'due_date_asc' end def sort_value_label_priority 'label_priority' end - def sort_value_oldest_updated - 'updated_asc' + def sort_value_largest_group + 'storage_size_desc' end - def sort_value_recently_updated - 'updated_desc' + def sort_value_largest_repo + 'storage_size_desc' end - def sort_value_oldest_activity - 'latest_activity_asc' + def sort_value_last_joined + 'last_joined' end def sort_value_latest_activity 'latest_activity_desc' end - def sort_value_oldest_created - 'created_asc' + def sort_value_milestone + 'milestone' end - def sort_value_recently_created - 'created_desc' + def sort_value_milestone_later + 'milestone_due_desc' end def sort_value_milestone_soon 'milestone_due_asc' end - def sort_value_milestone_later - 'milestone_due_desc' + def sort_value_name + 'name_asc' end - def sort_value_due_date_soon - 'due_date_asc' + def sort_value_name_desc + 'name_desc' end - def sort_value_due_date_later - 'due_date_desc' + def sort_value_oldest_activity + 'latest_activity_asc' end - def sort_value_start_date_soon - 'start_date_asc' + def sort_value_oldest_created + 'created_asc' end - def sort_value_start_date_later - 'start_date_desc' + def sort_value_oldest_signin + 'oldest_sign_in' end - def sort_value_name - 'name_asc' + def sort_value_oldest_joined + 'oldest_joined' end - def sort_value_largest_repo - 'storage_size_desc' + def sort_value_oldest_updated + 'updated_asc' end - def sort_value_largest_group - 'storage_size_desc' + def sort_value_popularity + 'popularity' + end + + def sort_value_priority + 'priority' + end + + def sort_value_recently_created + 'created_desc' end def sort_value_recently_signin 'recent_sign_in' end - def sort_value_oldest_signin - 'oldest_sign_in' + def sort_value_recently_updated + 'updated_desc' end - def sort_value_downvotes - 'downvotes_desc' + def sort_value_start_date_later + 'start_date_desc' + end + + def sort_value_start_date_soon + 'start_date_asc' end def sort_value_upvotes diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index a0d07902ba2..c6509f89117 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -174,7 +174,7 @@ module Ci end def assignable_for?(project) - !locked? || projects.exists?(id: project.id) + is_shared? || projects.exists?(id: project.id) end def accepting_tags?(build) 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/concerns/issuable.rb b/app/models/concerns/issuable.rb index 265f6e48540..fc30d008dea 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -143,16 +143,18 @@ module Issuable end def sort(method, excluded_labels: []) - sorted = case method.to_s - when 'milestone_due_asc' then order_milestone_due_asc - when 'milestone_due_desc' then order_milestone_due_desc - when 'downvotes_desc' then order_downvotes_desc - when 'upvotes_desc' then order_upvotes_desc - when 'label_priority' then order_labels_priority(excluded_labels: excluded_labels) - when 'priority' then order_due_date_and_labels_priority(excluded_labels: excluded_labels) - else - order_by(method) - end + sorted = + case method.to_s + when 'downvotes_desc' then order_downvotes_desc + when 'label_priority' then order_labels_priority(excluded_labels: excluded_labels) + when 'milestone' then order_milestone_due_asc + when 'milestone_due_asc' then order_milestone_due_asc + when 'milestone_due_desc' then order_milestone_due_desc + when 'popularity' then order_upvotes_desc + when 'priority' then order_due_date_and_labels_priority(excluded_labels: excluded_labels) + when 'upvotes_desc' then order_upvotes_desc + else order_by(method) + end # Break ties with the ID column for pagination sorted.order(id: :desc) @@ -214,7 +216,7 @@ module Issuable def grouping_columns(sort) grouping_columns = [arel_table[:id]] - if %w(milestone_due_desc milestone_due_asc).include?(sort) + if %w(milestone_due_desc milestone_due_asc milestone).include?(sort) milestone_table = Milestone.arel_table grouping_columns << milestone_table[:id] grouping_columns << milestone_table[:due_date] diff --git a/app/models/concerns/sortable.rb b/app/models/concerns/sortable.rb index db3cd257584..cefa5c13c5f 100644 --- a/app/models/concerns/sortable.rb +++ b/app/models/concerns/sortable.rb @@ -19,14 +19,15 @@ module Sortable module ClassMethods def order_by(method) case method.to_s - when 'name_asc' then order_name_asc - when 'name_desc' then order_name_desc - when 'updated_asc' then order_updated_asc - when 'updated_desc' then order_updated_desc - when 'created_asc' then order_created_asc + when 'created_asc' then order_created_asc + when 'created_date' then order_created_desc when 'created_desc' then order_created_desc - when 'id_desc' then order_id_desc - when 'id_asc' then order_id_asc + when 'id_asc' then order_id_asc + when 'id_desc' then order_id_desc + when 'name_asc' then order_name_asc + when 'name_desc' then order_name_desc + when 'updated_asc' then order_updated_asc + when 'updated_desc' then order_updated_desc else all end diff --git a/app/models/issue.rb b/app/models/issue.rb index 92a454300af..155c5d972b7 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -116,7 +116,8 @@ class Issue < ActiveRecord::Base def self.sort(method, excluded_labels: []) case method.to_s - when 'due_date_asc' then order_due_date_asc + when 'due_date' then order_due_date_asc + when 'due_date_asc' then order_due_date_asc when 'due_date_desc' then order_due_date_desc else super 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/dashboard/projects/_nav.html.haml b/app/views/dashboard/projects/_nav.html.haml new file mode 100644 index 00000000000..3701e1c0578 --- /dev/null +++ b/app/views/dashboard/projects/_nav.html.haml @@ -0,0 +1,6 @@ +.top-area + %ul.nav-links + = nav_link(html_options: { class: ("active" unless params[:personal].present?) }) do + = link_to s_('DashboardProjects|All'), dashboard_projects_path + = nav_link(html_options: { class: ("active" if params[:personal].present?) }) do + = link_to s_('DashboardProjects|Personal'), filter_projects_path(personal: true) diff --git a/app/views/dashboard/projects/index.html.haml b/app/views/dashboard/projects/index.html.haml index a4dc49d2120..57a4da353fe 100644 --- a/app/views/dashboard/projects/index.html.haml +++ b/app/views/dashboard/projects/index.html.haml @@ -10,8 +10,9 @@ = render "projects/last_push" %div{ class: container_class } - - if has_projects_or_name?(@projects, params) + - if show_projects?(@projects, params) = render 'dashboard/projects_head' + = render 'nav' = render 'projects' - else = render "zero_authorized_projects" 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/notes/_actions.html.haml b/app/views/projects/notes/_actions.html.haml index de76832331a..ab87b5e0005 100644 --- a/app/views/projects/notes/_actions.html.haml +++ b/app/views/projects/notes/_actions.html.haml @@ -1,7 +1,8 @@ +- access = note_max_access_for_user(note) - if note.has_special_role?(Note::SpecialRole::FIRST_TIME_CONTRIBUTOR) %span.note-role.note-role-special.has-tooltip{ title: _("This is the author's first Merge Request to this project. Handle with care.") } = issuable_first_contribution_icon -- if access = note_max_access_for_user(note) +- if access.nonzero? %span.note-role.note-role-access= Gitlab::Access.human_access(access) - if note.resolvable? 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/pipelines_settings/_show.html.haml b/app/views/projects/pipelines_settings/_show.html.haml index 21d01242c0e..77211099830 100644 --- a/app/views/projects/pipelines_settings/_show.html.haml +++ b/app/views/projects/pipelines_settings/_show.html.haml @@ -26,7 +26,8 @@ %strong Disable Auto DevOps %br %span.descr - An explicit <code>.gitlab-ci.yml</code> needs to be specified before you can begin using Continious Integration and Delivery. + An explicit <code>.gitlab-ci.yml</code> needs to be specified before you can begin using Continuous Integration and Delivery. + .radio = form.label :enabled_nil do = form.radio_button :enabled, '' 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/_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/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml index 785a500e44e..7ff5e679f17 100644 --- a/app/views/shared/_sort_dropdown.html.haml +++ b/app/views/shared/_sort_dropdown.html.haml @@ -1,36 +1,16 @@ +- sorted_by = sort_options_hash[@sort] - viewing_issues = controller.controller_name == 'issues' || controller.action_name == 'issues' .dropdown.inline.prepend-left-10 - %button.dropdown-toggle{ type: 'button', data: {toggle: 'dropdown' } } - - if @sort.present? - = sort_options_hash[@sort] - - else - = sort_title_recently_created + %button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown' } } + = sorted_by = icon('chevron-down') - %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-sort + %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable.dropdown-menu-sort %li - = link_to page_filter_path(sort: sort_value_priority, label: true) do - = sort_title_priority - = link_to page_filter_path(sort: sort_value_label_priority, label: true) do - = sort_title_label_priority - = link_to page_filter_path(sort: sort_value_recently_created, label: true) do - = sort_title_recently_created - = link_to page_filter_path(sort: sort_value_oldest_created, label: true) do - = sort_title_oldest_created - = link_to page_filter_path(sort: sort_value_recently_updated, label: true) do - = sort_title_recently_updated - = link_to page_filter_path(sort: sort_value_oldest_updated, label: true) do - = sort_title_oldest_updated - = link_to page_filter_path(sort: sort_value_milestone_soon, label: true) do - = sort_title_milestone_soon - = link_to page_filter_path(sort: sort_value_milestone_later, label: true) do - = sort_title_milestone_later - - if viewing_issues - = link_to page_filter_path(sort: sort_value_due_date_soon, label: true) do - = sort_title_due_date_soon - = link_to page_filter_path(sort: sort_value_due_date_later, label: true) do - = sort_title_due_date_later - = link_to page_filter_path(sort: sort_value_upvotes, label: true) do - = sort_title_upvotes - = link_to page_filter_path(sort: sort_value_downvotes, label: true) do - = sort_title_downvotes + = sortable_item(sort_title_priority, page_filter_path(sort: sort_value_priority, label: true), sorted_by) + = sortable_item(sort_title_created_date, page_filter_path(sort: sort_value_created_date, label: true), sorted_by) + = sortable_item(sort_title_recently_updated, page_filter_path(sort: sort_value_recently_updated, label: true), sorted_by) + = sortable_item(sort_title_milestone, page_filter_path(sort: sort_value_milestone, label: true), sorted_by) + = sortable_item(sort_title_due_date, page_filter_path(sort: sort_value_due_date, label: true), sorted_by) if viewing_issues + = sortable_item(sort_title_popularity, page_filter_path(sort: sort_value_popularity, label: true), sorted_by) + = sortable_item(sort_title_label_priority, page_filter_path(sort: sort_value_label_priority, label: true), sorted_by) diff --git a/app/views/shared/boards/_show.html.haml b/app/views/shared/boards/_show.html.haml index 722890a01e5..7e22c678e81 100644 --- a/app/views/shared/boards/_show.html.haml +++ b/app/views/shared/boards/_show.html.haml @@ -12,8 +12,6 @@ %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" - .hidden-xs.hidden-sm = render 'shared/issuable/search_bar', type: :boards diff --git a/app/views/shared/icons/_icon_status_canceled.svg b/app/views/shared/icons/_icon_status_canceled.svg index bd5d04e1cd7..bd5d04e1cd7 100755..100644 --- a/app/views/shared/icons/_icon_status_canceled.svg +++ b/app/views/shared/icons/_icon_status_canceled.svg diff --git a/app/views/shared/icons/_icon_status_created.svg b/app/views/shared/icons/_icon_status_created.svg index 326ad04e017..326ad04e017 100755..100644 --- a/app/views/shared/icons/_icon_status_created.svg +++ b/app/views/shared/icons/_icon_status_created.svg diff --git a/app/views/shared/icons/_icon_status_failed.svg b/app/views/shared/icons/_icon_status_failed.svg index 64da5aa31fc..64da5aa31fc 100755..100644 --- a/app/views/shared/icons/_icon_status_failed.svg +++ b/app/views/shared/icons/_icon_status_failed.svg diff --git a/app/views/shared/icons/_icon_status_manual.svg b/app/views/shared/icons/_icon_status_manual.svg index c98839f51a9..c98839f51a9 100755..100644 --- a/app/views/shared/icons/_icon_status_manual.svg +++ b/app/views/shared/icons/_icon_status_manual.svg diff --git a/app/views/shared/icons/_icon_status_pending.svg b/app/views/shared/icons/_icon_status_pending.svg index 02d5da407e3..02d5da407e3 100755..100644 --- a/app/views/shared/icons/_icon_status_pending.svg +++ b/app/views/shared/icons/_icon_status_pending.svg diff --git a/app/views/shared/icons/_icon_status_running.svg b/app/views/shared/icons/_icon_status_running.svg index 532f4fee33c..532f4fee33c 100755..100644 --- a/app/views/shared/icons/_icon_status_running.svg +++ b/app/views/shared/icons/_icon_status_running.svg diff --git a/app/views/shared/icons/_icon_status_skipped.svg b/app/views/shared/icons/_icon_status_skipped.svg index a9ba29c922c..a9ba29c922c 100755..100644 --- a/app/views/shared/icons/_icon_status_skipped.svg +++ b/app/views/shared/icons/_icon_status_skipped.svg diff --git a/app/views/shared/icons/_icon_status_success.svg b/app/views/shared/icons/_icon_status_success.svg index eed5006bebe..eed5006bebe 100755..100644 --- a/app/views/shared/icons/_icon_status_success.svg +++ b/app/views/shared/icons/_icon_status_success.svg diff --git a/app/views/shared/icons/_icon_status_warning.svg b/app/views/shared/icons/_icon_status_warning.svg index cb785635b7e..cb785635b7e 100755..100644 --- a/app/views/shared/icons/_icon_status_warning.svg +++ b/app/views/shared/icons/_icon_status_warning.svg diff --git a/app/views/shared/issuable/_user_dropdown_item.html.haml b/app/views/shared/issuable/_user_dropdown_item.html.haml index 48d04678d47..4a3547e9e70 100644 --- a/app/views/shared/issuable/_user_dropdown_item.html.haml +++ b/app/views/shared/issuable/_user_dropdown_item.html.haml @@ -4,7 +4,7 @@ %li.filter-dropdown-item{ class: ('js-current-user' if user == current_user) } %button.btn.btn-link.dropdown-user{ type: :button } .avatar-container.s40 - = user_avatar_without_link(user: user, lazy: avatar[:lazy], url: avatar[:url], size: 40, has_tooltip: false).gsub('/images/{{avatar_url}}','{{avatar_url}}').html_safe + = user_avatar_without_link(user: user, lazy: avatar[:lazy], url: avatar[:url], size: 40, has_tooltip: false) .dropdown-user-details %span = user.name diff --git a/changelogs/unreleased/34371-cycle-analitcs-global.yml b/changelogs/unreleased/34371-cycle-analitcs-global.yml new file mode 100644 index 00000000000..5e9f0a85e9a --- /dev/null +++ b/changelogs/unreleased/34371-cycle-analitcs-global.yml @@ -0,0 +1,5 @@ +--- +title: Removes cycle analytics service and store from global namespace +merge_request: +author: +type: other diff --git a/changelogs/unreleased/37912-fix-dash-in-note-access-role.yml b/changelogs/unreleased/37912-fix-dash-in-note-access-role.yml new file mode 100644 index 00000000000..f9f4120479c --- /dev/null +++ b/changelogs/unreleased/37912-fix-dash-in-note-access-role.yml @@ -0,0 +1,5 @@ +--- +title: Notes will not show an empty bubble when the author isn't a member. +merge_request: 14450 +author: +type: fixed diff --git a/changelogs/unreleased/dm-bitbucket-import-truncated-shas.yml b/changelogs/unreleased/dm-bitbucket-import-truncated-shas.yml new file mode 100644 index 00000000000..057407b78d9 --- /dev/null +++ b/changelogs/unreleased/dm-bitbucket-import-truncated-shas.yml @@ -0,0 +1,6 @@ +--- +title: Fix bug that caused merge requests with diff notes imported from Bitbucket + to raise errors +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/dm-simple-project-avatar-url.yml b/changelogs/unreleased/dm-simple-project-avatar-url.yml new file mode 100644 index 00000000000..e517345f5d2 --- /dev/null +++ b/changelogs/unreleased/dm-simple-project-avatar-url.yml @@ -0,0 +1,5 @@ +--- +title: Expose avatar_url when requesting list of projects from API with simple=true +merge_request: +author: +type: added diff --git a/changelogs/unreleased/expose-last-pipeline-details-in-api-for-single-commit.yml b/changelogs/unreleased/expose-last-pipeline-details-in-api-for-single-commit.yml new file mode 100644 index 00000000000..d16e052cd92 --- /dev/null +++ b/changelogs/unreleased/expose-last-pipeline-details-in-api-for-single-commit.yml @@ -0,0 +1,5 @@ +--- +title: Expose last pipeline details in API response when getting a single commit +merge_request: 13521 +author: Mehdi Lahmam (@mehlah) +type: added diff --git a/changelogs/unreleased/fix-locked-shared-runners-problem.yml b/changelogs/unreleased/fix-locked-shared-runners-problem.yml new file mode 100644 index 00000000000..3e3cccf79eb --- /dev/null +++ b/changelogs/unreleased/fix-locked-shared-runners-problem.yml @@ -0,0 +1,5 @@ +--- +title: Make locked setting of Runner to not affect jobs scheduling +merge_request: 14483 +author: +type: fixed diff --git a/changelogs/unreleased/improve_sorting_list.yml b/changelogs/unreleased/improve_sorting_list.yml new file mode 100644 index 00000000000..a3730e23ed1 --- /dev/null +++ b/changelogs/unreleased/improve_sorting_list.yml @@ -0,0 +1,5 @@ +--- +title: Improve list of sorting options +merge_request: 14320 +author: Vitaliy @blackst0ne Klachkov +type: added diff --git a/changelogs/unreleased/project-page-clearer.yml b/changelogs/unreleased/project-page-clearer.yml new file mode 100644 index 00000000000..7db01373360 --- /dev/null +++ b/changelogs/unreleased/project-page-clearer.yml @@ -0,0 +1,5 @@ +--- +title: Added tabs to dashboard/projects to easily switch to personal projects +merge_request: +author: +type: added diff --git a/changelogs/unreleased/remove-temporary-ci-index.yml b/changelogs/unreleased/remove-temporary-ci-index.yml new file mode 100644 index 00000000000..a319f7fff7f --- /dev/null +++ b/changelogs/unreleased/remove-temporary-ci-index.yml @@ -0,0 +1,5 @@ +--- +title: Remove an index on ci_builds meant to be only temporary +merge_request: +author: +type: other diff --git a/config/application.rb b/config/application.rb index da9bb25c8b9..30117b6a98e 100644 --- a/config/application.rb +++ b/config/application.rb @@ -105,8 +105,6 @@ module Gitlab config.assets.precompile << "lib/ace.js" config.assets.precompile << "vendor/assets/fonts/*" config.assets.precompile << "test.css" - config.assets.precompile << "new_nav.css" - config.assets.precompile << "new_sidebar.css" # Version of your assets, change this if you want to expire all your assets config.assets.version = '1.0' diff --git a/db/migrate/20170828135939_migrate_user_external_mail_data.rb b/db/migrate/20170828135939_migrate_user_external_mail_data.rb index 395181a3b22..f7ac87374b6 100644 --- a/db/migrate/20170828135939_migrate_user_external_mail_data.rb +++ b/db/migrate/20170828135939_migrate_user_external_mail_data.rb @@ -33,7 +33,7 @@ class MigrateUserExternalMailData < ActiveRecord::Migration SELECT true FROM user_synced_attributes_metadata WHERE user_id = users.id - AND provider = users.email_provider OR (provider IS NULL AND users.email_provider IS NULL) + AND (provider = users.email_provider OR (provider IS NULL AND users.email_provider IS NULL)) ) AND id BETWEEN #{start_id} AND #{end_id} EOF diff --git a/db/migrate/20170919211300_remove_temporary_ci_builds_index.rb b/db/migrate/20170919211300_remove_temporary_ci_builds_index.rb new file mode 100644 index 00000000000..b2009b282e9 --- /dev/null +++ b/db/migrate/20170919211300_remove_temporary_ci_builds_index.rb @@ -0,0 +1,27 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class RemoveTemporaryCiBuildsIndex < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + # To use create/remove index concurrently + disable_ddl_transaction! + + def up + return unless index_exists?(:ci_builds, :id, name: 'index_for_ci_builds_retried_migration') + remove_concurrent_index(:ci_builds, :id, name: "index_for_ci_builds_retried_migration") + end + + def down + # this was a temporary index for a migration that was never + # present previously so this probably shouldn't be here but it's + # easier to test the drop if we have a way to create it. + add_concurrent_index("ci_builds", ["id"], + name: "index_for_ci_builds_retried_migration", + where: "(retried IS NULL)", + using: :btree) + end +end diff --git a/db/post_migrate/20170828170502_post_deploy_migrate_user_external_mail_data.rb b/db/post_migrate/20170828170502_post_deploy_migrate_user_external_mail_data.rb index a475b242921..fd1437b07f5 100644 --- a/db/post_migrate/20170828170502_post_deploy_migrate_user_external_mail_data.rb +++ b/db/post_migrate/20170828170502_post_deploy_migrate_user_external_mail_data.rb @@ -33,7 +33,7 @@ class PostDeployMigrateUserExternalMailData < ActiveRecord::Migration SELECT true FROM user_synced_attributes_metadata WHERE user_id = users.id - AND provider = users.email_provider OR (provider IS NULL AND users.email_provider IS NULL) + AND (provider = users.email_provider OR (provider IS NULL AND users.email_provider IS NULL)) ) AND id BETWEEN #{start_id} AND #{end_id} EOF diff --git a/db/schema.rb b/db/schema.rb index 80ef91ec95d..330336e8e61 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -256,7 +256,6 @@ ActiveRecord::Schema.define(version: 20170921115009) do add_index "ci_builds", ["commit_id", "status", "type"], name: "index_ci_builds_on_commit_id_and_status_and_type", using: :btree add_index "ci_builds", ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree add_index "ci_builds", ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref", using: :btree - add_index "ci_builds", ["id"], name: "index_for_ci_builds_retried_migration", where: "(retried IS NULL)", using: :btree add_index "ci_builds", ["project_id"], name: "index_ci_builds_on_project_id", using: :btree add_index "ci_builds", ["protected"], name: "index_ci_builds_on_protected", using: :btree add_index "ci_builds", ["runner_id"], name: "index_ci_builds_on_runner_id", using: :btree diff --git a/doc/api/commits.md b/doc/api/commits.md index 2a78553782f..5a4a8d888b3 100644 --- a/doc/api/commits.md +++ b/doc/api/commits.md @@ -181,6 +181,12 @@ Example response: "parent_ids": [ "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" ], + "last_pipeline" : { + "id": 8, + "ref": "master", + "sha": "2dc6aa325a317eda67812f05600bdf0fcdc70ab0" + "status": "created" + } "stats": { "additions": 15, "deletions": 10, diff --git a/doc/development/background_migrations.md b/doc/development/background_migrations.md index f83a60e49e8..5452b0e7a2f 100644 --- a/doc/development/background_migrations.md +++ b/doc/development/background_migrations.md @@ -215,14 +215,29 @@ same time will ensure that both existing and new data is migrated. In the next release we can remove the `after_commit` hooks and related code. We will also need to add a post-deployment migration that consumes any remaining -jobs. Such a migration would look like this: +jobs and manually run on any un-migrated rows. Such a migration would look like +this: ```ruby class ConsumeRemainingExtractServicesUrlJobs < ActiveRecord::Migration disable_ddl_transaction! + class Service < ActiveRecord::Base + include ::EachBatch + + self.table_name = 'services' + end + def up + # This must be included Gitlab::BackgroundMigration.steal('ExtractServicesUrl') + + # This should be included, but can be skipped - see below + Service.where(url: nil).each_batch(of: 50) do |batch| + range = batch.pluck('MIN(id)', 'MAX(id)').first + + Gitlab::BackgroundMigration::ExtractServicesUrl.new.perform(*range) + end end def down @@ -230,6 +245,15 @@ class ConsumeRemainingExtractServicesUrlJobs < ActiveRecord::Migration end ``` +The final step runs for any un-migrated rows after all of the jobs have been +processed. This is in case a Sidekiq process running the background migrations +received SIGKILL, leading to the jobs being lost. (See +[more reliable Sidekiq queue][reliable-sidekiq] for more information.) + +If the application does not depend on the data being 100% migrated (for +instance, the data is advisory, and not mission-critical), then this final step +can be skipped. + This migration will then process any jobs for the ExtractServicesUrl migration and continue once all jobs have been processed. Once done you can safely remove the `services.properties` column. @@ -254,6 +278,9 @@ for more details. 1. Make sure that background migration jobs are idempotent. 1. Make sure that tests you write are not false positives. +1. Make sure that if the data being migrated is critical and cannot be lost, the + clean-up migration also checks the final state of the data before completing. [migrations-readme]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/migrations/README.md [issue-rspec-hooks]: https://gitlab.com/gitlab-org/gitlab-ce/issues/35351 +[reliable-sidekiq]: https://gitlab.com/gitlab-org/gitlab-ce/issues/36791 diff --git a/doc/development/licensing.md b/doc/development/licensing.md index 9a5811d8474..a75cdf22f40 100644 --- a/doc/development/licensing.md +++ b/doc/development/licensing.md @@ -65,6 +65,7 @@ Libraries with the following licenses are unacceptable for use: - [GNU AGPLv3][AGPLv3]: AGPL-licensed libraries cannot be linked to from non-GPL projects. - [Open Software License (OSL)][OSL]: is a copyleft license. In addition, the FSF [recommend against its use][OSL-GNU]. - [Facebook BSD + PATENTS][Facebook]: is a 3-clause BSD license with a patent grant that has been deemed [Category X][x-list] by the Apache foundation. +- [WTFPL][WTFPL]: is a public domain dedication [rejected by the OSI (3.2)][WTFPL-OSI]. Also has a strong language which is not in accordance with our diversity policy. ## Requesting Approval for Licenses @@ -108,3 +109,5 @@ Gems which are included only in the "development" or "test" groups by Bundler ar [x-list]: https://www.apache.org/legal/resolved.html#category-x [Acceptable-Licenses]: #acceptable-licenses [Unacceptable-Licenses]: #unacceptable-licenses +[WTFPL]: https://wtfpl.net +[WTFPL-OSI]: https://opensource.org/minutes20090304 diff --git a/doc/install/kubernetes/gitlab_omnibus.md b/doc/install/kubernetes/gitlab_omnibus.md index 150eb3a8bce..8c110a37380 100644 --- a/doc/install/kubernetes/gitlab_omnibus.md +++ b/doc/install/kubernetes/gitlab_omnibus.md @@ -148,8 +148,15 @@ helm install --name gitlab --set baseDomain=gitlab.io,baseIP=1.1.1.1,gitlab=ee,g ## Updating GitLab using the Helm Chart +>**Note**: If you are upgrading from a previous version to 0.1.35 or above, you will need to change the access mode values for GitLab's storage. To do this, set the following in `values.yaml` or on the CLI: +``` +gitlabDataAccessMode=ReadWriteMany +gitlabRegistryAccessMode=ReadWriteMany +gitlabConfigAccessMode=ReadWriteMany +``` + Once your GitLab Chart is installed, configuration changes and chart updates -should we done using `helm upgrade`: +should be done using `helm upgrade`: ```bash helm upgrade -f values.yaml gitlab gitlab/gitlab-omnibus @@ -179,5 +186,13 @@ To uninstall the GitLab Chart, run the following: helm delete gitlab ``` +## Troubleshooting + +### Storage errors when updating `gitlab-omnibus` versions prior to 0.1.35 + +Users upgrading `gitlab-omnibus` from a version prior to 0.1.35, may see an error like: `Error: UPGRADE FAILED: PersistentVolumeClaim "gitlab-gitlab-config-storage" is invalid: spec: Forbidden: field is immutable after creation`. + +This is due to a change in the access mode for GitLab storage in version 0.1.35. To successfully upgrade, the access mode flags must be set to `ReadWriteMany` as detailed in the [update section](#updating-gitlab-using-the-helm-chart). + [kube-srv]: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types [storageclass]: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#storageclasses diff --git a/doc/integration/azure.md b/doc/integration/azure.md index 5e3e9f5ab77..f3c9c498634 100644 --- a/doc/integration/azure.md +++ b/doc/integration/azure.md @@ -74,6 +74,9 @@ To enable the Microsoft Azure OAuth2 OmniAuth provider you must register your ap tenant_id: "TENANT ID" } } ``` + The `base_azure_url` is optional and can be added for different locales; + e.g. `base_azure_url: "https://login.microsoftonline.de"`. + 1. Replace 'CLIENT ID', 'CLIENT SECRET' and 'TENANT ID' with the values you got above. 1. Save the configuration file. diff --git a/doc/university/training/gitlab_flow.md b/doc/university/training/gitlab_flow.md index a7db1f2e069..a7db1f2e069 100755..100644 --- a/doc/university/training/gitlab_flow.md +++ b/doc/university/training/gitlab_flow.md diff --git a/doc/university/training/index.md b/doc/university/training/index.md index 03179ff5a77..03179ff5a77 100755..100644 --- a/doc/university/training/index.md +++ b/doc/university/training/index.md diff --git a/doc/university/training/topics/additional_resources.md b/doc/university/training/topics/additional_resources.md index 3ed601625cf..3ed601625cf 100755..100644 --- a/doc/university/training/topics/additional_resources.md +++ b/doc/university/training/topics/additional_resources.md diff --git a/doc/university/training/topics/agile_git.md b/doc/university/training/topics/agile_git.md index e6e4fea9b51..e6e4fea9b51 100755..100644 --- a/doc/university/training/topics/agile_git.md +++ b/doc/university/training/topics/agile_git.md diff --git a/doc/university/training/topics/bisect.md b/doc/university/training/topics/bisect.md index a60c4365e0c..a60c4365e0c 100755..100644 --- a/doc/university/training/topics/bisect.md +++ b/doc/university/training/topics/bisect.md diff --git a/doc/university/training/topics/cherry_picking.md b/doc/university/training/topics/cherry_picking.md index af7a70a2818..af7a70a2818 100755..100644 --- a/doc/university/training/topics/cherry_picking.md +++ b/doc/university/training/topics/cherry_picking.md diff --git a/doc/university/training/topics/env_setup.md b/doc/university/training/topics/env_setup.md index 8149379b36f..8149379b36f 100755..100644 --- a/doc/university/training/topics/env_setup.md +++ b/doc/university/training/topics/env_setup.md diff --git a/doc/university/training/topics/explore_gitlab.md b/doc/university/training/topics/explore_gitlab.md index b65457728c0..b65457728c0 100755..100644 --- a/doc/university/training/topics/explore_gitlab.md +++ b/doc/university/training/topics/explore_gitlab.md diff --git a/doc/university/training/topics/feature_branching.md b/doc/university/training/topics/feature_branching.md index 4b34406ea75..4b34406ea75 100755..100644 --- a/doc/university/training/topics/feature_branching.md +++ b/doc/university/training/topics/feature_branching.md diff --git a/doc/university/training/topics/getting_started.md b/doc/university/training/topics/getting_started.md index ec7bb2631aa..ec7bb2631aa 100755..100644 --- a/doc/university/training/topics/getting_started.md +++ b/doc/university/training/topics/getting_started.md diff --git a/doc/university/training/topics/git_add.md b/doc/university/training/topics/git_add.md index 9ffb4b9c859..9ffb4b9c859 100755..100644 --- a/doc/university/training/topics/git_add.md +++ b/doc/university/training/topics/git_add.md diff --git a/doc/university/training/topics/git_intro.md b/doc/university/training/topics/git_intro.md index ca1ff29d93b..ca1ff29d93b 100755..100644 --- a/doc/university/training/topics/git_intro.md +++ b/doc/university/training/topics/git_intro.md diff --git a/doc/university/training/topics/git_log.md b/doc/university/training/topics/git_log.md index 32ebceff491..32ebceff491 100755..100644 --- a/doc/university/training/topics/git_log.md +++ b/doc/university/training/topics/git_log.md diff --git a/doc/university/training/topics/gitlab_flow.md b/doc/university/training/topics/gitlab_flow.md index 8e5d3baf959..8e5d3baf959 100755..100644 --- a/doc/university/training/topics/gitlab_flow.md +++ b/doc/university/training/topics/gitlab_flow.md diff --git a/doc/university/training/topics/merge_conflicts.md b/doc/university/training/topics/merge_conflicts.md index 77807b3e7ef..77807b3e7ef 100755..100644 --- a/doc/university/training/topics/merge_conflicts.md +++ b/doc/university/training/topics/merge_conflicts.md diff --git a/doc/university/training/topics/merge_requests.md b/doc/university/training/topics/merge_requests.md index 5b446f02f63..5b446f02f63 100755..100644 --- a/doc/university/training/topics/merge_requests.md +++ b/doc/university/training/topics/merge_requests.md diff --git a/doc/university/training/topics/rollback_commits.md b/doc/university/training/topics/rollback_commits.md index cf647284604..cf647284604 100755..100644 --- a/doc/university/training/topics/rollback_commits.md +++ b/doc/university/training/topics/rollback_commits.md diff --git a/doc/university/training/topics/stash.md b/doc/university/training/topics/stash.md index c1bdda32645..c1bdda32645 100755..100644 --- a/doc/university/training/topics/stash.md +++ b/doc/university/training/topics/stash.md diff --git a/doc/university/training/topics/subtree.md b/doc/university/training/topics/subtree.md index 5d869af64c1..5d869af64c1 100755..100644 --- a/doc/university/training/topics/subtree.md +++ b/doc/university/training/topics/subtree.md diff --git a/doc/university/training/topics/tags.md b/doc/university/training/topics/tags.md index e9607b5a875..e9607b5a875 100755..100644 --- a/doc/university/training/topics/tags.md +++ b/doc/university/training/topics/tags.md diff --git a/doc/university/training/topics/unstage.md b/doc/university/training/topics/unstage.md index 17dbb64b9e6..17dbb64b9e6 100755..100644 --- a/doc/university/training/topics/unstage.md +++ b/doc/university/training/topics/unstage.md diff --git a/doc/university/training/user_training.md b/doc/university/training/user_training.md index 9e38df26b6a..9e38df26b6a 100755..100644 --- a/doc/university/training/user_training.md +++ b/doc/university/training/user_training.md diff --git a/doc/user/project/integrations/img/webhook_logs.png b/doc/user/project/integrations/img/webhook_logs.png Binary files differindex 917068d9398..917068d9398 100755..100644 --- a/doc/user/project/integrations/img/webhook_logs.png +++ b/doc/user/project/integrations/img/webhook_logs.png diff --git a/doc/user/project/issues/img/button_close_issue.png b/doc/user/project/issues/img/button_close_issue.png Binary files differindex 8fb2e23f58a..8fb2e23f58a 100755..100644 --- a/doc/user/project/issues/img/button_close_issue.png +++ b/doc/user/project/issues/img/button_close_issue.png diff --git a/doc/user/project/issues/img/closing_and_related_issues.png b/doc/user/project/issues/img/closing_and_related_issues.png Binary files differindex c6543e85fdb..c6543e85fdb 100755..100644 --- a/doc/user/project/issues/img/closing_and_related_issues.png +++ b/doc/user/project/issues/img/closing_and_related_issues.png diff --git a/doc/user/project/issues/img/confidential_issues_create.png b/doc/user/project/issues/img/confidential_issues_create.png Binary files differindex 0a141eb39f8..0a141eb39f8 100755..100644 --- a/doc/user/project/issues/img/confidential_issues_create.png +++ b/doc/user/project/issues/img/confidential_issues_create.png diff --git a/doc/user/project/issues/img/confidential_issues_search_guest.png b/doc/user/project/issues/img/confidential_issues_search_guest.png Binary files differindex dc1b4ba8ad7..dc1b4ba8ad7 100755..100644 --- a/doc/user/project/issues/img/confidential_issues_search_guest.png +++ b/doc/user/project/issues/img/confidential_issues_search_guest.png diff --git a/doc/user/project/issues/img/confidential_issues_search_master.png b/doc/user/project/issues/img/confidential_issues_search_master.png Binary files differindex fc01f4da9db..fc01f4da9db 100755..100644 --- a/doc/user/project/issues/img/confidential_issues_search_master.png +++ b/doc/user/project/issues/img/confidential_issues_search_master.png diff --git a/doc/user/project/issues/img/due_dates_create.png b/doc/user/project/issues/img/due_dates_create.png Binary files differindex ece35d44213..ece35d44213 100755..100644 --- a/doc/user/project/issues/img/due_dates_create.png +++ b/doc/user/project/issues/img/due_dates_create.png diff --git a/doc/user/project/issues/img/due_dates_edit_sidebar.png b/doc/user/project/issues/img/due_dates_edit_sidebar.png Binary files differindex d1c7d1eb7e9..d1c7d1eb7e9 100755..100644 --- a/doc/user/project/issues/img/due_dates_edit_sidebar.png +++ b/doc/user/project/issues/img/due_dates_edit_sidebar.png diff --git a/doc/user/project/issues/img/due_dates_issues_index_page.png b/doc/user/project/issues/img/due_dates_issues_index_page.png Binary files differindex 94679436b32..94679436b32 100755..100644 --- a/doc/user/project/issues/img/due_dates_issues_index_page.png +++ b/doc/user/project/issues/img/due_dates_issues_index_page.png diff --git a/doc/user/project/issues/img/due_dates_todos.png b/doc/user/project/issues/img/due_dates_todos.png Binary files differindex 4c124c97f67..4c124c97f67 100755..100644 --- a/doc/user/project/issues/img/due_dates_todos.png +++ b/doc/user/project/issues/img/due_dates_todos.png diff --git a/doc/user/project/issues/img/issue_board.png b/doc/user/project/issues/img/issue_board.png Binary files differindex 1759b28a9ef..1759b28a9ef 100755..100644 --- a/doc/user/project/issues/img/issue_board.png +++ b/doc/user/project/issues/img/issue_board.png diff --git a/doc/user/project/issues/img/issue_template.png b/doc/user/project/issues/img/issue_template.png Binary files differindex c63229a4af2..c63229a4af2 100755..100644 --- a/doc/user/project/issues/img/issue_template.png +++ b/doc/user/project/issues/img/issue_template.png diff --git a/doc/user/project/issues/img/mention_in_issue.png b/doc/user/project/issues/img/mention_in_issue.png Binary files differindex c762a812138..c762a812138 100755..100644 --- a/doc/user/project/issues/img/mention_in_issue.png +++ b/doc/user/project/issues/img/mention_in_issue.png diff --git a/doc/user/project/issues/img/mention_in_merge_request.png b/doc/user/project/issues/img/mention_in_merge_request.png Binary files differindex 681e086d6e0..681e086d6e0 100755..100644 --- a/doc/user/project/issues/img/mention_in_merge_request.png +++ b/doc/user/project/issues/img/mention_in_merge_request.png diff --git a/doc/user/project/issues/img/merge_request_closes_issue.png b/doc/user/project/issues/img/merge_request_closes_issue.png Binary files differindex 6fd27738843..6fd27738843 100755..100644 --- a/doc/user/project/issues/img/merge_request_closes_issue.png +++ b/doc/user/project/issues/img/merge_request_closes_issue.png diff --git a/doc/user/project/issues/img/new_issue.png b/doc/user/project/issues/img/new_issue.png Binary files differindex e72ac49d6b9..e72ac49d6b9 100755..100644 --- a/doc/user/project/issues/img/new_issue.png +++ b/doc/user/project/issues/img/new_issue.png diff --git a/doc/user/project/issues/img/new_issue_from_issue_board.png b/doc/user/project/issues/img/new_issue_from_issue_board.png Binary files differindex 9c2b3ff50fa..9c2b3ff50fa 100755..100644 --- a/doc/user/project/issues/img/new_issue_from_issue_board.png +++ b/doc/user/project/issues/img/new_issue_from_issue_board.png diff --git a/doc/user/project/issues/img/new_issue_from_open_issue.png b/doc/user/project/issues/img/new_issue_from_open_issue.png Binary files differindex 2aed5372830..2aed5372830 100755..100644 --- a/doc/user/project/issues/img/new_issue_from_open_issue.png +++ b/doc/user/project/issues/img/new_issue_from_open_issue.png diff --git a/doc/user/project/issues/img/new_issue_from_projects_dashboard.png b/doc/user/project/issues/img/new_issue_from_projects_dashboard.png Binary files differindex cddf36b7457..cddf36b7457 100755..100644 --- a/doc/user/project/issues/img/new_issue_from_projects_dashboard.png +++ b/doc/user/project/issues/img/new_issue_from_projects_dashboard.png diff --git a/doc/user/project/issues/img/new_issue_from_tracker_list.png b/doc/user/project/issues/img/new_issue_from_tracker_list.png Binary files differindex 7e5413f0b7d..7e5413f0b7d 100755..100644 --- a/doc/user/project/issues/img/new_issue_from_tracker_list.png +++ b/doc/user/project/issues/img/new_issue_from_tracker_list.png diff --git a/doc/user/project/issues/img/sidebar_confidential_issue.png b/doc/user/project/issues/img/sidebar_confidential_issue.png Binary files differindex d99a1ca756e..d99a1ca756e 100755..100644 --- a/doc/user/project/issues/img/sidebar_confidential_issue.png +++ b/doc/user/project/issues/img/sidebar_confidential_issue.png diff --git a/doc/user/project/issues/img/sidebar_not_confidential_issue.png b/doc/user/project/issues/img/sidebar_not_confidential_issue.png Binary files differindex 2e6cbbc5b3a..2e6cbbc5b3a 100755..100644 --- a/doc/user/project/issues/img/sidebar_not_confidential_issue.png +++ b/doc/user/project/issues/img/sidebar_not_confidential_issue.png diff --git a/doc/user/project/repository/img/contributors_graph.png b/doc/user/project/repository/img/contributors_graph.png Binary files differindex c31da7aa1ff..c31da7aa1ff 100755..100644 --- a/doc/user/project/repository/img/contributors_graph.png +++ b/doc/user/project/repository/img/contributors_graph.png diff --git a/doc/user/project/repository/img/repo_graph.png b/doc/user/project/repository/img/repo_graph.png Binary files differindex 28da8ad9589..28da8ad9589 100755..100644 --- a/doc/user/project/repository/img/repo_graph.png +++ b/doc/user/project/repository/img/repo_graph.png diff --git a/doc/user/project/settings/img/general_settings.png b/doc/user/project/settings/img/general_settings.png Binary files differindex 96f5b84871f..96f5b84871f 100755..100644 --- a/doc/user/project/settings/img/general_settings.png +++ b/doc/user/project/settings/img/general_settings.png diff --git a/doc/user/project/settings/img/merge_requests_settings.png b/doc/user/project/settings/img/merge_requests_settings.png Binary files differindex b1f2dfa7376..b1f2dfa7376 100755..100644 --- a/doc/user/project/settings/img/merge_requests_settings.png +++ b/doc/user/project/settings/img/merge_requests_settings.png diff --git a/doc/user/search/img/issues_any_assignee.png b/doc/user/search/img/issues_any_assignee.png Binary files differindex 2f902bcc66c..2f902bcc66c 100755..100644 --- a/doc/user/search/img/issues_any_assignee.png +++ b/doc/user/search/img/issues_any_assignee.png diff --git a/doc/user/search/img/issues_assigned_to_you.png b/doc/user/search/img/issues_assigned_to_you.png Binary files differindex 36c670eedd5..36c670eedd5 100755..100644 --- a/doc/user/search/img/issues_assigned_to_you.png +++ b/doc/user/search/img/issues_assigned_to_you.png diff --git a/doc/user/search/img/issues_author.png b/doc/user/search/img/issues_author.png Binary files differindex 792f9746db6..792f9746db6 100755..100644 --- a/doc/user/search/img/issues_author.png +++ b/doc/user/search/img/issues_author.png diff --git a/doc/user/search/img/issues_mrs_shortcut.png b/doc/user/search/img/issues_mrs_shortcut.png Binary files differindex 6380b337b54..6380b337b54 100755..100644 --- a/doc/user/search/img/issues_mrs_shortcut.png +++ b/doc/user/search/img/issues_mrs_shortcut.png diff --git a/doc/user/search/img/left_menu_bar.png b/doc/user/search/img/left_menu_bar.png Binary files differindex d68a71cba8e..d68a71cba8e 100755..100644 --- a/doc/user/search/img/left_menu_bar.png +++ b/doc/user/search/img/left_menu_bar.png diff --git a/doc/user/search/img/project_search.png b/doc/user/search/img/project_search.png Binary files differindex 3150b40de29..3150b40de29 100755..100644 --- a/doc/user/search/img/project_search.png +++ b/doc/user/search/img/project_search.png diff --git a/doc/user/search/img/search_issues_board.png b/doc/user/search/img/search_issues_board.png Binary files differindex 84048ae6a02..84048ae6a02 100755..100644 --- a/doc/user/search/img/search_issues_board.png +++ b/doc/user/search/img/search_issues_board.png diff --git a/doc/user/search/img/sort_projects.png b/doc/user/search/img/sort_projects.png Binary files differindex 9bf2770b299..9bf2770b299 100755..100644 --- a/doc/user/search/img/sort_projects.png +++ b/doc/user/search/img/sort_projects.png diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature index 4f905674d8c..d6cfa524a3a 100644 --- a/features/project/issues/issues.feature +++ b/features/project/issues/issues.feature @@ -51,36 +51,34 @@ Feature: Project Issues @javascript Scenario: Visiting Issues after being sorted the list Given I visit project "Shop" issues page - And I sort the list by "Oldest updated" + And I sort the list by "Last updated" And I visit my project's home page And I visit project "Shop" issues page - Then The list should be sorted by "Oldest updated" + Then The list should be sorted by "Last updated" @javascript Scenario: Visiting Merge Requests after being sorted the list Given project "Shop" has a "Bugfix MR" merge request open And I visit project "Shop" issues page - And I sort the list by "Oldest updated" + And I sort the list by "Last updated" And I visit project "Shop" merge requests page - Then The list should be sorted by "Oldest updated" + Then The list should be sorted by "Last updated" @javascript Scenario: Visiting Merge Requests from a differente Project after sorting Given project "Shop" has a "Bugfix MR" merge request open And I visit project "Shop" merge requests page - And I sort the list by "Oldest updated" + And I sort the list by "Last updated" And I visit dashboard merge requests page - Then The list should be sorted by "Oldest updated" + Then The list should be sorted by "Last updated" @javascript Scenario: Sort issues by upvotes/downvotes Given project "Shop" have "Bugfix" open issue And issue "Release 0.4" have 2 upvotes and 1 downvote And issue "Tweet control" have 1 upvote and 2 downvotes - And I sort the list by "Most popular" - Then The list should be sorted by "Most popular" - And I sort the list by "Least popular" - Then The list should be sorted by "Least popular" + And I sort the list by "Popularity" + Then The list should be sorted by "Popularity" # Markdown diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 0ebeded7fc5..349fa2663a7 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -91,28 +91,26 @@ Feature: Project Merge Requests @javascript Scenario: Visiting Merge Requests after being sorted the list Given I visit project "Shop" merge requests page - And I sort the list by "Oldest updated" + And I sort the list by "Last updated" And I visit my project's home page And I visit project "Shop" merge requests page - Then The list should be sorted by "Oldest updated" + Then The list should be sorted by "Last updated" @javascript Scenario: Visiting Merge Requests from a different Project after sorting Given I visit project "Shop" merge requests page - And I sort the list by "Oldest updated" + And I sort the list by "Last updated" And I visit dashboard merge requests page - Then The list should be sorted by "Oldest updated" + Then The list should be sorted by "Last updated" @javascript - Scenario: Sort merge requests by upvotes/downvotes + Scenario: Sort merge requests by upvotes Given project "Shop" have "Bug NS-05" open merge request with diffs inside And project "Shop" have "Bug NS-06" open merge request And merge request "Bug NS-04" have 2 upvotes and 1 downvote And merge request "Bug NS-06" have 1 upvote and 2 downvotes - And I sort the list by "Most popular" - Then The list should be sorted by "Most popular" - And I sort the list by "Least popular" - Then The list should be sorted by "Least popular" + And I sort the list by "Popularity" + Then The list should be sorted by "Popularity" @javascript Scenario: I comment on a merge request diff diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb index b9460f5b534..2c3ef2efd52 100644 --- a/features/steps/project/issues/issues.rb +++ b/features/steps/project/issues/issues.rb @@ -223,7 +223,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps end end - step 'The list should be sorted by "Most popular"' do + step 'The list should be sorted by "Popularity"' do page.within '.issues-list' do page.within 'li.issue:nth-child(1)' do expect(page).to have_content 'Release 0.4' diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb index 0d49a4ab90d..dde918e3d41 100644 --- a/features/steps/project/merge_requests.rb +++ b/features/steps/project/merge_requests.rb @@ -222,7 +222,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps end end - step 'The list should be sorted by "Most popular"' do + step 'The list should be sorted by "Popularity"' do page.within '.mr-list' do page.within 'li.merge-request:nth-child(1)' do expect(page).to have_content 'Bug NS-04' diff --git a/features/steps/shared/issuable.rb b/features/steps/shared/issuable.rb index 7c842ba88fb..714985f2051 100644 --- a/features/steps/shared/issuable.rb +++ b/features/steps/shared/issuable.rb @@ -109,10 +109,10 @@ module SharedIssuable edit_issuable end - step 'I sort the list by "Oldest updated"' do + step 'I sort the list by "Last updated"' do find('button.dropdown-toggle').click page.within('.content ul.dropdown-menu.dropdown-menu-align-right li') do - click_link "Oldest updated" + click_link "Last updated" end end @@ -124,16 +124,16 @@ module SharedIssuable end end - step 'I sort the list by "Most popular"' do + step 'I sort the list by "Popularity"' do find('button.dropdown-toggle').click page.within('.content ul.dropdown-menu.dropdown-menu-align-right li') do - click_link 'Most popular' + click_link 'Popularity' end end - step 'The list should be sorted by "Oldest updated"' do - expect(find('.issues-filters')).to have_content('Oldest updated') + step 'The list should be sorted by "Last updated"' do + expect(find('.issues-filters')).to have_content('Last updated') end step 'I click link "Next" in the sidebar' do diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 71253f72533..7f4736a08cb 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -89,6 +89,9 @@ module API expose :ssh_url_to_repo, :http_url_to_repo, :web_url expose :name, :name_with_namespace expose :path, :path_with_namespace + expose :avatar_url do |project, options| + project.avatar_url(only_path: false) + end expose :star_count, :forks_count expose :created_at, :last_activity_at end @@ -146,9 +149,7 @@ module API expose :forked_from_project, using: Entities::BasicProjectDetails, if: lambda { |project, options| project.forked? } expose :import_status expose :import_error, if: lambda { |_project, options| options[:user_can_admin_project] } - expose :avatar_url do |user, options| - user.avatar_url(only_path: false) - end + expose :open_issues_count, if: lambda { |project, options| project.feature_available?(:issues, options[:current_user]) } expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] } expose :public_builds, as: :public_jobs @@ -193,8 +194,8 @@ module API class Group < Grape::Entity expose :id, :name, :path, :description, :visibility expose :lfs_enabled?, as: :lfs_enabled - expose :avatar_url do |user, options| - user.avatar_url(only_path: false) + expose :avatar_url do |group, options| + group.avatar_url(only_path: false) end expose :web_url expose :request_access_enabled @@ -234,6 +235,7 @@ module API class RepoCommitDetail < RepoCommit expose :stats, using: Entities::RepoCommitStats expose :status + expose :last_pipeline, using: 'API::Entities::PipelineBasic' end class RepoBranch < Grape::Entity diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb index 28bbf3b384e..d1979bb7ed3 100644 --- a/lib/gitlab/bitbucket_import/importer.rb +++ b/lib/gitlab/bitbucket_import/importer.rb @@ -149,16 +149,21 @@ module Gitlab description += @formatter.author_line(pull_request.author) unless find_user_id(pull_request.author) description += pull_request.description + source_branch_sha = pull_request.source_branch_sha + target_branch_sha = pull_request.target_branch_sha + source_branch_sha = project.repository.commit(source_branch_sha)&.sha || source_branch_sha + target_branch_sha = project.repository.commit(target_branch_sha)&.sha || target_branch_sha + merge_request = project.merge_requests.create!( iid: pull_request.iid, title: pull_request.title, description: description, source_project: project, source_branch: pull_request.source_branch_name, - source_branch_sha: pull_request.source_branch_sha, + source_branch_sha: source_branch_sha, target_project: project, target_branch: pull_request.target_branch_name, - target_branch_sha: pull_request.target_branch_sha, + target_branch_sha: target_branch_sha, state: pull_request.state, author_id: gitlab_user_id(project, pull_request.author), assignee_id: nil, diff --git a/lib/gitlab/diff/diff_refs.rb b/lib/gitlab/diff/diff_refs.rb index 371cbe04b9b..c98eefbce25 100644 --- a/lib/gitlab/diff/diff_refs.rb +++ b/lib/gitlab/diff/diff_refs.rb @@ -13,9 +13,9 @@ module Gitlab def ==(other) other.is_a?(self.class) && - base_sha == other.base_sha && - start_sha == other.start_sha && - head_sha == other.head_sha + shas_equal?(base_sha, other.base_sha) && + shas_equal?(start_sha, other.start_sha) && + shas_equal?(head_sha, other.head_sha) end alias_method :eql?, :== @@ -47,6 +47,22 @@ module Gitlab CompareService.new(project, head_sha).execute(project, start_sha, straight: straight) end end + + private + + def shas_equal?(sha1, sha2) + return true if sha1 == sha2 + return false if sha1.nil? || sha2.nil? + return false unless sha1.class == sha2.class + + length = [sha1.length, sha2.length].min + + # If either of the shas is below the minimum length, we cannot be sure + # that they actually refer to the same commit because of hash collision. + return false if length < Commit::MIN_SHA_LENGTH + + sha1[0, length] == sha2[0, length] + end end end end diff --git a/lib/gitlab/diff/position.rb b/lib/gitlab/diff/position.rb index f80afb20f0c..b8db3adef0a 100644 --- a/lib/gitlab/diff/position.rb +++ b/lib/gitlab/diff/position.rb @@ -49,12 +49,13 @@ module Gitlab coder['attributes'] = self.to_h end - def key - @key ||= [base_sha, start_sha, head_sha, Digest::SHA1.hexdigest(old_path || ""), Digest::SHA1.hexdigest(new_path || ""), old_line, new_line] - end - def ==(other) - other.is_a?(self.class) && key == other.key + other.is_a?(self.class) && + other.diff_refs == diff_refs && + other.old_path == old_path && + other.new_path == new_path && + other.old_line == old_line && + other.new_line == new_line end def to_h diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 10ba29acbd1..616b075c087 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -386,7 +386,13 @@ module Gitlab options[:limit] ||= 0 options[:offset] ||= 0 - raw_log(options).map { |c| Commit.decorate(self, c) } + gitaly_migrate(:find_commits) do |is_enabled| + if is_enabled + gitaly_commit_client.find_commits(options) + else + raw_log(options).map { |c| Commit.decorate(self, c) } + end + end end # Used in gitaly-ruby diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb index cbd9ff406de..955d2307f88 100644 --- a/lib/gitlab/gitaly_client.rb +++ b/lib/gitlab/gitaly_client.rb @@ -228,10 +228,18 @@ module Gitlab path.read.chomp end + def self.timestamp(t) + Google::Protobuf::Timestamp.new(seconds: t.to_i) + end + def self.encode(s) s.dup.force_encoding(Encoding::ASCII_8BIT) end + def self.encode_repeated(a) + Google::Protobuf::RepeatedField.new(:bytes, a.map { |s| self.encode(s) } ) + end + # Count a stack. Used for n+1 detection def self.count_stack return unless RequestStore.active? diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb index cf3a3554552..36da63fd586 100644 --- a/lib/gitlab/gitaly_client/commit_service.rb +++ b/lib/gitlab/gitaly_client/commit_service.rb @@ -230,6 +230,26 @@ module Gitlab GitalyClient.call(@repository.storage, :commit_service, :commit_stats, request) end + def find_commits(options) + request = Gitaly::FindCommitsRequest.new( + repository: @gitaly_repo, + limit: options[:limit], + offset: options[:offset], + follow: options[:follow], + skip_merges: options[:skip_merges], + disable_walk: options[:disable_walk] + ) + request.after = GitalyClient.timestamp(options[:after]) if options[:after] + request.before = GitalyClient.timestamp(options[:before]) if options[:before] + request.revision = GitalyClient.encode(options[:ref]) if options[:ref] + + request.paths = GitalyClient.encode_repeated(Array(options[:path])) if options[:path].present? + + response = GitalyClient.call(@repository.storage, :commit_service, :find_commits, request) + + consume_commits_response(response) + end + private def call_commit_diff(request_params, options = {}) diff --git a/lib/gitlab/markdown/pipeline.rb b/lib/gitlab/markdown/pipeline.rb deleted file mode 100644 index 306923902e0..00000000000 --- a/lib/gitlab/markdown/pipeline.rb +++ /dev/null @@ -1,32 +0,0 @@ -module Gitlab - module Markdown - class Pipeline - def self.[](name) - name ||= :full - const_get("#{name.to_s.camelize}Pipeline") - end - - def self.filters - [] - end - - def self.transform_context(context) - context - end - - def self.html_pipeline - @html_pipeline ||= HTML::Pipeline.new(filters) - end - - class << self - %i(call to_document to_html).each do |meth| - define_method(meth) do |text, context| - context = transform_context(context) - - html_pipeline.__send__(meth, text, context) # rubocop:disable GitlabSecurity/PublicSend - end - end - end - end - end -end diff --git a/scripts/lint-doc.sh b/scripts/lint-doc.sh index 54c1ef3dfdd..e5242fee32b 100755 --- a/scripts/lint-doc.sh +++ b/scripts/lint-doc.sh @@ -3,15 +3,19 @@ cd "$(dirname "$0")/.." # Use long options (e.g. --header instead of -H) for curl examples in documentation. -grep --extended-regexp --recursive --color=auto 'curl (.+ )?-[^- ].*' doc/ +echo 'Checking for curl short options...' +grep --extended-regexp --recursive --color=auto 'curl (.+ )?-[^- ].*' doc/ >/dev/null 2>&1 if [ $? == 0 ] then - echo '✖ ERROR: Short options should not be used in documentation!' >&2 + echo '✖ ERROR: Short options for curl should not be used in documentation! + Use long options (e.g., --header instead of -H):' >&2 + grep --extended-regexp --recursive --color=auto 'curl (.+ )?-[^- ].*' doc/ exit 1 fi # Ensure that the CHANGELOG.md does not contain duplicate versions DUPLICATE_CHANGELOG_VERSIONS=$(grep --extended-regexp '^## .+' CHANGELOG.md | sed -E 's| \(.+\)||' | sort -r | uniq -d) +echo 'Checking for CHANGELOG.md duplicate entries...' if [ "${DUPLICATE_CHANGELOG_VERSIONS}" != "" ] then echo '✖ ERROR: Duplicate versions in CHANGELOG.md:' >&2 @@ -19,5 +23,15 @@ then exit 1 fi +# Make sure no files in doc/ are executable +EXEC_PERM_COUNT=$(find doc/ app/ -type f -perm 755 | wc -l) +echo 'Checking for executable permissions...' +if [ "${EXEC_PERM_COUNT}" -ne 0 ] +then + echo '✖ ERROR: Executable permissions should not be used in documentation! Use `chmod 644` to the files in question:' >&2 + find doc/ app/ -type f -perm 755 + exit 1 +fi + echo "✔ Linting passed" exit 0 diff --git a/spec/features/dashboard/issues_filter_spec.rb b/spec/features/dashboard/issues_filter_spec.rb index facb67ae787..8759950e013 100644 --- a/spec/features/dashboard/issues_filter_spec.rb +++ b/spec/features/dashboard/issues_filter_spec.rb @@ -90,17 +90,17 @@ feature 'Dashboard Issues filtering', :js do context 'sorting' do it 'shows sorted issues' do - sorting_by('Oldest updated') + sorting_by('Created date') visit_issues - expect(find('.issues-filters')).to have_content('Oldest updated') + expect(find('.issues-filters')).to have_content('Created date') end it 'keeps sorting issues after visiting Projects Issues page' do - sorting_by('Oldest updated') + sorting_by('Created date') visit project_issues_path(project) - expect(find('.issues-filters')).to have_content('Oldest updated') + expect(find('.issues-filters')).to have_content('Created date') end end diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb index b4992dd54a1..8204828b5b9 100644 --- a/spec/features/dashboard/merge_requests_spec.rb +++ b/spec/features/dashboard/merge_requests_spec.rb @@ -112,19 +112,19 @@ feature 'Dashboard Merge Requests' do end it 'shows sorted merge requests' do - sorting_by('Oldest updated') + sorting_by('Created date') visit merge_requests_dashboard_path(assignee_id: current_user.id) - expect(find('.issues-filters')).to have_content('Oldest updated') + expect(find('.issues-filters')).to have_content('Created date') end it 'keeps sorting merge requests after visiting Projects MR page' do - sorting_by('Oldest updated') + sorting_by('Created date') visit project_merge_requests_path(project) - expect(find('.issues-filters')).to have_content('Oldest updated') + expect(find('.issues-filters')).to have_content('Created date') end end end diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb index 9a7b8e3ba6b..4da95ccc169 100644 --- a/spec/features/dashboard/projects_spec.rb +++ b/spec/features/dashboard/projects_spec.rb @@ -50,6 +50,25 @@ feature 'Dashboard Projects' do end end + context 'when on Your projects tab' do + it 'shows all projects by default' do + visit dashboard_projects_path + + expect(page).to have_content(project.name) + end + + it 'shows personal projects on personal projects tab', :js do + project3 = create(:project, namespace: user.namespace) + + visit dashboard_projects_path + + click_link 'Personal' + + expect(page).not_to have_content(project.name) + expect(page).to have_content(project3.name) + end + end + context 'when on Starred projects tab' do it 'shows only starred projects' do user.toggle_star(project2) diff --git a/spec/features/issuables/default_sort_order_spec.rb b/spec/features/issuables/default_sort_order_spec.rb index b72b690110f..925d026ed61 100644 --- a/spec/features/issuables/default_sort_order_spec.rb +++ b/spec/features/issuables/default_sort_order_spec.rb @@ -40,10 +40,10 @@ describe 'Projects > Issuables > Default sort order' do context 'in the "merge requests / open" tab', js: true do let(:issuable_type) { :merge_request } - it 'is "last created"' do + it 'is "created date"' do visit_merge_requests_with_state(project, 'open') - expect(selected_sort_order).to eq('last created') + expect(selected_sort_order).to eq('created date') expect(first_merge_request).to include(last_created_issuable.title) expect(last_merge_request).to include(first_created_issuable.title) end @@ -76,10 +76,10 @@ describe 'Projects > Issuables > Default sort order' do context 'in the "merge requests / all" tab', js: true do let(:issuable_type) { :merge_request } - it 'is "last created"' do + it 'is "created date"' do visit_merge_requests_with_state(project, 'all') - expect(find('.issues-other-filters')).to have_content('Last created') + expect(find('.issues-other-filters')).to have_content('Created date') expect(first_merge_request).to include(last_created_issuable.title) expect(last_merge_request).to include(first_created_issuable.title) end @@ -105,10 +105,10 @@ describe 'Projects > Issuables > Default sort order' do context 'in the "issues" tab', js: true do let(:issuable_type) { :issue } - it 'is "last created"' do + it 'is "created date"' do visit_issues project - expect(find('.issues-other-filters')).to have_content('Last created') + expect(find('.issues-other-filters')).to have_content('Created date') expect(first_issue).to include(last_created_issuable.title) expect(last_issue).to include(first_created_issuable.title) end @@ -117,10 +117,10 @@ describe 'Projects > Issuables > Default sort order' do context 'in the "issues / open" tab', js: true do let(:issuable_type) { :issue } - it 'is "last created"' do + it 'is "created date"' do visit_issues_with_state(project, 'open') - expect(find('.issues-other-filters')).to have_content('Last created') + expect(find('.issues-other-filters')).to have_content('Created date') expect(first_issue).to include(last_created_issuable.title) expect(last_issue).to include(first_created_issuable.title) end @@ -141,10 +141,10 @@ describe 'Projects > Issuables > Default sort order' do context 'in the "issues / all" tab', js: true do let(:issuable_type) { :issue } - it 'is "last created"' do + it 'is "created date"' do visit_issues_with_state(project, 'all') - expect(find('.issues-other-filters')).to have_content('Last created') + expect(find('.issues-other-filters')).to have_content('Created date') expect(first_issue).to include(last_created_issuable.title) expect(last_issue).to include(first_created_issuable.title) end @@ -157,26 +157,12 @@ describe 'Projects > Issuables > Default sort order' do visit_issues(project, sort: 'id_desc') end - it 'shows the sort order as last created' do - expect(find('.issues-other-filters')).to have_content('Last created') + it 'shows the sort order as created date' do + expect(find('.issues-other-filters')).to have_content('Created date') expect(first_issue).to include(last_created_issuable.title) expect(last_issue).to include(first_created_issuable.title) end end - - context 'when the sort in the URL is id_asc' do - let(:issuable_type) { :issue } - - before do - visit_issues(project, sort: 'id_asc') - end - - it 'shows the sort order as oldest created' do - expect(find('.issues-other-filters')).to have_content('Oldest created') - expect(first_issue).to include(first_created_issuable.title) - expect(last_issue).to include(last_created_issuable.title) - end - end end def selected_sort_order diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb index b2229b44f99..a89dcdf41dc 100644 --- a/spec/features/issues/bulk_assignment_labels_spec.rb +++ b/spec/features/issues/bulk_assignment_labels_spec.rb @@ -405,7 +405,7 @@ feature 'Issues > Labels bulk assignment' do end def update_issues - click_button 'Update all' + find('.update-selected-issues').trigger('click') wait_for_requests end diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index 3ea6e1c8863..630d6a10c9c 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -405,20 +405,18 @@ describe 'Filter issues', js: true do end context 'sorting' do - it 'sorts by oldest updated' do - create(:issue, + it 'sorts by created date' do + new_issue = create(:issue, title: '3 days ago', project: project, author: user, - created_at: 3.days.ago, - updated_at: 3.days.ago) + created_at: 3.days.ago) - old_issue = create(:issue, + create(:issue, title: '5 days ago', project: project, author: user, - created_at: 5.days.ago, - updated_at: 5.days.ago) + created_at: 5.days.ago) input_filtered_search('days ago') @@ -427,10 +425,10 @@ describe 'Filter issues', js: true do sort_toggle = find('.filtered-search-wrapper .dropdown-toggle') sort_toggle.click - find('.filtered-search-wrapper .dropdown-menu li a', text: 'Oldest updated').click + find('.filtered-search-wrapper .dropdown-menu li a', text: 'Created date').click wait_for_requests - expect(find('.issues-list .issue:first-of-type .issue-title-text a')).to have_content(old_issue.title) + expect(find('.issues-list .issue:first-of-type .issue-title-text a')).to have_content(new_issue.title) end end end diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb index bcc6e9bab0f..1f57c110c11 100644 --- a/spec/features/issues/update_issues_spec.rb +++ b/spec/features/issues/update_issues_spec.rb @@ -118,7 +118,7 @@ feature 'Multiple issue updating from issues#index', :js do end def click_update_issues_button - find('.update-selected-issues').click + find('.update-selected-issues').trigger('click') wait_for_requests end end diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 5c284a1fe5f..fb763c93c66 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -190,19 +190,12 @@ describe 'Issues' do let(:later_due_milestone) { create(:milestone, due_date: '2013-12-12') } it 'sorts by newest' do - visit project_issues_path(project, sort: sort_value_recently_created) + visit project_issues_path(project, sort: sort_value_created_date) expect(first_issue).to include('foo') expect(last_issue).to include('baz') end - it 'sorts by oldest' do - visit project_issues_path(project, sort: sort_value_oldest_created) - - expect(first_issue).to include('baz') - expect(last_issue).to include('foo') - end - it 'sorts by most recently updated' do baz.updated_at = Time.now + 100 baz.save @@ -211,36 +204,22 @@ describe 'Issues' do expect(first_issue).to include('baz') end - it 'sorts by least recently updated' do - baz.updated_at = Time.now - 100 - baz.save - visit project_issues_path(project, sort: sort_value_oldest_updated) - - expect(first_issue).to include('baz') - end - describe 'sorting by due date' do before do foo.update(due_date: 1.day.from_now) bar.update(due_date: 6.days.from_now) end - it 'sorts by recently due date' do - visit project_issues_path(project, sort: sort_value_due_date_soon) + it 'sorts by due date' do + visit project_issues_path(project, sort: sort_value_due_date) expect(first_issue).to include('foo') end - it 'sorts by least recently due date' do - visit project_issues_path(project, sort: sort_value_due_date_later) - - expect(first_issue).to include('bar') - end - - it 'sorts by least recently due date by excluding nil due dates' do + it 'sorts by due date by excluding nil due dates' do bar.update(due_date: nil) - visit project_issues_path(project, sort: sort_value_due_date_later) + visit project_issues_path(project, sort: sort_value_due_date) expect(first_issue).to include('foo') end @@ -339,19 +318,12 @@ describe 'Issues' do bar.save end - it 'sorts by recently due milestone' do - visit project_issues_path(project, sort: sort_value_milestone_soon) + it 'sorts by milestone' do + visit project_issues_path(project, sort: sort_value_milestone) expect(first_issue).to include('foo') expect(last_issue).to include('baz') end - - it 'sorts by least recently due milestone' do - visit project_issues_path(project, sort: sort_value_milestone_later) - - expect(first_issue).to include('bar') - expect(last_issue).to include('baz') - end end describe 'combine filter and sort' do @@ -365,13 +337,11 @@ describe 'Issues' do end it 'sorts with a filter applied' do - visit project_issues_path(project, - sort: sort_value_oldest_created, - assignee_id: user2.id) + visit project_issues_path(project, sort: sort_value_created_date, assignee_id: user2.id) - expect(first_issue).to include('bar') - expect(last_issue).to include('foo') - expect(page).not_to have_content 'baz' + expect(first_issue).to include('foo') + expect(last_issue).to include('bar') + expect(page).not_to have_content('baz') end end end diff --git a/spec/features/merge_requests/filter_merge_requests_spec.rb b/spec/features/merge_requests/filter_merge_requests_spec.rb index b51ae0890e4..16703bc1c01 100644 --- a/spec/features/merge_requests/filter_merge_requests_spec.rb +++ b/spec/features/merge_requests/filter_merge_requests_spec.rb @@ -277,9 +277,9 @@ describe 'Filter merge requests' do expect_mr_list_count(2) - click_button 'Last created' + click_button 'Created date' page.within '.dropdown-menu-sort' do - click_link 'Oldest created' + click_link 'Priority' end wait_for_requests diff --git a/spec/features/merge_requests/update_merge_requests_spec.rb b/spec/features/merge_requests/update_merge_requests_spec.rb index e6dc284cba7..9cb8a357309 100644 --- a/spec/features/merge_requests/update_merge_requests_spec.rb +++ b/spec/features/merge_requests/update_merge_requests_spec.rb @@ -127,7 +127,7 @@ feature 'Multiple merge requests updating from merge_requests#index' do end def click_update_merge_requests_button - find('.update-selected-issues').click + find('.update-selected-issues').trigger('click') wait_for_requests end end diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb index 20008b4e7f9..416a0f78a45 100644 --- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb @@ -52,21 +52,13 @@ describe 'Projects > Merge requests > User lists merge requests' do end it 'sorts by newest' do - visit_merge_requests(project, sort: sort_value_recently_created) + visit_merge_requests(project, sort: sort_value_created_date) expect(first_merge_request).to include('fix') expect(last_merge_request).to include('merge-test') expect(count_merge_requests).to eq(3) end - it 'sorts by oldest' do - visit_merge_requests(project, sort: sort_value_oldest_created) - - expect(first_merge_request).to include('merge-test') - expect(last_merge_request).to include('fix') - expect(count_merge_requests).to eq(3) - end - it 'sorts by last updated' do visit_merge_requests(project, sort: sort_value_recently_updated) @@ -74,33 +66,19 @@ describe 'Projects > Merge requests > User lists merge requests' do expect(count_merge_requests).to eq(3) end - it 'sorts by oldest updated' do - visit_merge_requests(project, sort: sort_value_oldest_updated) - - expect(first_merge_request).to include('markdown') - expect(count_merge_requests).to eq(3) - end - - it 'sorts by milestone due soon' do - visit_merge_requests(project, sort: sort_value_milestone_soon) + it 'sorts by milestone' do + visit_merge_requests(project, sort: sort_value_milestone) expect(first_merge_request).to include('fix') expect(count_merge_requests).to eq(3) end - it 'sorts by milestone due later' do - visit_merge_requests(project, sort: sort_value_milestone_later) - - expect(first_merge_request).to include('markdown') - expect(count_merge_requests).to eq(3) - end - - it 'filters on one label and sorts by due soon' do + it 'filters on one label and sorts by due date' do label = create(:label, project: project) create(:label_link, label: label, target: @fix) visit_merge_requests(project, label_name: [label.name], - sort: sort_value_due_date_soon) + sort: sort_value_due_date) expect(first_merge_request).to include('fix') expect(count_merge_requests).to eq(1) @@ -115,9 +93,9 @@ describe 'Projects > Merge requests > User lists merge requests' do create(:label_link, label: label2, target: @fix) end - it 'sorts by due soon' do + it 'sorts by due date' do visit_merge_requests(project, label_name: [label.name, label2.name], - sort: sort_value_due_date_soon) + sort: sort_value_due_date) expect(first_merge_request).to include('fix') expect(count_merge_requests).to eq(1) @@ -127,7 +105,7 @@ describe 'Projects > Merge requests > User lists merge requests' do it 'sorts by due soon' do visit_merge_requests(project, label_name: [label.name, label2.name], assignee_id: user.id, - sort: sort_value_due_date_soon) + sort: sort_value_due_date) expect(first_merge_request).to include('fix') expect(count_merge_requests).to eq(1) @@ -137,7 +115,7 @@ describe 'Projects > Merge requests > User lists merge requests' do visit project_merge_requests_path(project, label_name: [label.name, label2.name], assignee_id: user.id, - sort: sort_value_milestone_soon) + sort: sort_value_milestone) expect(first_merge_request).to include('fix') end diff --git a/spec/fixtures/api/schemas/public_api/v4/commit/detail.json b/spec/fixtures/api/schemas/public_api/v4/commit/detail.json index b7b2535c204..88a3cad62f6 100644 --- a/spec/fixtures/api/schemas/public_api/v4/commit/detail.json +++ b/spec/fixtures/api/schemas/public_api/v4/commit/detail.json @@ -5,11 +5,18 @@ { "required" : [ "stats", - "status" + "status", + "last_pipeline" ], "properties": { "stats": { "$ref": "../commit_stats.json" }, - "status": { "type": ["string", "null"] } + "status": { "type": ["string", "null"] }, + "last_pipeline": { + "oneOf": [ + { "type": "null" }, + { "$ref": "../pipeline/basic.json" } + ] + } } } ] diff --git a/spec/fixtures/api/schemas/public_api/v4/pipeline/basic.json b/spec/fixtures/api/schemas/public_api/v4/pipeline/basic.json new file mode 100644 index 00000000000..0d127dc5297 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/pipeline/basic.json @@ -0,0 +1,16 @@ +{ + "type": "object", + "required" : [ + "id", + "sha", + "ref", + "status" + ], + "properties" : { + "id": { "type": "integer" }, + "sha": { "type": "string" }, + "ref": { "type": "string" }, + "status": { "type": "string" } + }, + "additionalProperties": false +} diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb index 4632c679972..f44e7ef6843 100644 --- a/spec/helpers/avatars_helper_spec.rb +++ b/spec/helpers/avatars_helper_spec.rb @@ -26,12 +26,13 @@ describe AvatarsHelper do subject { helper.user_avatar_without_link(options) } it 'displays user avatar' do - is_expected.to eq image_tag( - LazyImageTagHelper.placeholder_image, - class: 'avatar s16 has-tooltip lazy', + is_expected.to eq tag( + :img, alt: "#{user.name}'s avatar", - title: user.name, - data: { container: 'body', src: avatar_icon(user, 16) } + src: avatar_icon(user, 16), + data: { container: 'body' }, + class: 'avatar s16 has-tooltip', + title: user.name ) end @@ -39,12 +40,13 @@ describe AvatarsHelper do let(:options) { { user: user, css_class: '.cat-pics' } } it 'uses provided css_class' do - is_expected.to eq image_tag( - LazyImageTagHelper.placeholder_image, - class: "avatar s16 #{options[:css_class]} has-tooltip lazy", + is_expected.to eq tag( + :img, alt: "#{user.name}'s avatar", - title: user.name, - data: { container: 'body', src: avatar_icon(user, 16) } + src: avatar_icon(user, 16), + data: { container: 'body' }, + class: "avatar s16 #{options[:css_class]} has-tooltip", + title: user.name ) end end @@ -53,12 +55,13 @@ describe AvatarsHelper do let(:options) { { user: user, size: 99 } } it 'uses provided size' do - is_expected.to eq image_tag( - LazyImageTagHelper.placeholder_image, - class: "avatar s#{options[:size]} has-tooltip lazy", + is_expected.to eq tag( + :img, alt: "#{user.name}'s avatar", - title: user.name, - data: { container: 'body', src: avatar_icon(user, options[:size]) } + src: avatar_icon(user, options[:size]), + data: { container: 'body' }, + class: "avatar s#{options[:size]} has-tooltip", + title: user.name ) end end @@ -67,12 +70,28 @@ describe AvatarsHelper do let(:options) { { user: user, url: '/over/the/rainbow.png' } } it 'uses provided url' do - is_expected.to eq image_tag( - LazyImageTagHelper.placeholder_image, - class: 'avatar s16 has-tooltip lazy', + is_expected.to eq tag( + :img, alt: "#{user.name}'s avatar", - title: user.name, - data: { container: 'body', src: options[:url] } + src: options[:url], + data: { container: 'body' }, + class: "avatar s16 has-tooltip", + title: user.name + ) + end + end + + context 'with lazy parameter' do + let(:options) { { user: user, lazy: true } } + + it 'adds `lazy` class to class list, sets `data-src` with avatar URL and `src` with placeholder image' do + is_expected.to eq tag( + :img, + alt: "#{user.name}'s avatar", + src: LazyImageTagHelper.placeholder_image, + data: { container: 'body', src: avatar_icon(user, 16) }, + class: "avatar s16 has-tooltip lazy", + title: user.name ) end end @@ -82,12 +101,13 @@ describe AvatarsHelper do let(:options) { { user: user, has_tooltip: true } } it 'adds has-tooltip' do - is_expected.to eq image_tag( - LazyImageTagHelper.placeholder_image, - class: 'avatar s16 has-tooltip lazy', + is_expected.to eq tag( + :img, alt: "#{user.name}'s avatar", - title: user.name, - data: { container: 'body', src: avatar_icon(user, 16) } + src: avatar_icon(user, 16), + data: { container: 'body' }, + class: "avatar s16 has-tooltip", + title: user.name ) end end @@ -96,12 +116,12 @@ describe AvatarsHelper do let(:options) { { user: user, has_tooltip: false } } it 'does not add has-tooltip or data container' do - is_expected.to eq image_tag( - LazyImageTagHelper.placeholder_image, - class: 'avatar s16 lazy', + is_expected.to eq tag( + :img, alt: "#{user.name}'s avatar", - title: user.name, - data: { src: avatar_icon(user, 16) } + src: avatar_icon(user, 16), + class: "avatar s16", + title: user.name ) end end @@ -114,23 +134,25 @@ describe AvatarsHelper do let(:options) { { user: user, user_name: 'Tinky Winky' } } it 'prefers user parameter' do - is_expected.to eq image_tag( - LazyImageTagHelper.placeholder_image, - class: 'avatar s16 has-tooltip lazy', + is_expected.to eq tag( + :img, alt: "#{user.name}'s avatar", - title: user.name, - data: { container: 'body', src: avatar_icon(user, 16) } + src: avatar_icon(user, 16), + data: { container: 'body' }, + class: "avatar s16 has-tooltip", + title: user.name ) end end it 'uses user_name and user_email parameter if user is not present' do - is_expected.to eq image_tag( - LazyImageTagHelper.placeholder_image, - class: 'avatar s16 has-tooltip lazy', + is_expected.to eq tag( + :img, alt: "#{options[:user_name]}'s avatar", - title: options[:user_name], - data: { container: 'body', src: avatar_icon(options[:user_email], 16) } + src: avatar_icon(options[:user_email], 16), + data: { container: 'body' }, + class: "avatar s16 has-tooltip", + title: options[:user_name] ) end end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index a76c75e0c08..7ded95d01af 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -420,22 +420,26 @@ describe ProjectsHelper do end end - describe '#has_projects_or_name?' do + describe '#show_projects' do let(:projects) do create(:project) Project.all end it 'returns true when there are projects' do - expect(helper.has_projects_or_name?(projects, {})).to eq(true) + expect(helper.show_projects?(projects, {})).to eq(true) end it 'returns true when there are no projects but a name is given' do - expect(helper.has_projects_or_name?(Project.none, name: 'foo')).to eq(true) + expect(helper.show_projects?(Project.none, name: 'foo')).to eq(true) + end + + it 'returns true when there are no projects but personal is present' do + expect(helper.show_projects?(Project.none, personal: 'true')).to eq(true) end it 'returns false when there are no projects and there is no name' do - expect(helper.has_projects_or_name?(Project.none, {})).to eq(false) + expect(helper.show_projects?(Project.none, {})).to eq(false) end end diff --git a/spec/javascripts/cycle_analytics/limit_warning_component_spec.js b/spec/javascripts/cycle_analytics/limit_warning_component_spec.js index 2fb9eb0ca85..13e9fe00a00 100644 --- a/spec/javascripts/cycle_analytics/limit_warning_component_spec.js +++ b/spec/javascripts/cycle_analytics/limit_warning_component_spec.js @@ -1,6 +1,6 @@ import Vue from 'vue'; import Translate from '~/vue_shared/translate'; -import limitWarningComp from '~/cycle_analytics/components/limit_warning_component'; +import limitWarningComp from '~/cycle_analytics/components/limit_warning_component.vue'; Vue.use(Translate); diff --git a/spec/javascripts/fly_out_nav_spec.js b/spec/javascripts/fly_out_nav_spec.js index f4b4d7980a4..4f20e31f511 100644 --- a/spec/javascripts/fly_out_nav_spec.js +++ b/spec/javascripts/fly_out_nav_spec.js @@ -73,6 +73,12 @@ describe('Fly out sidebar navigation', () => { ).toBe(0); }); + it('returns 0 if mousePos is empty', () => { + expect( + getHideSubItemsInterval(), + ).toBe(0); + }); + it('returns 0 when mouse above sub-items', () => { showSubLevelItems(el); documentMouseMove({ diff --git a/spec/javascripts/lib/utils/sticky_spec.js b/spec/javascripts/lib/utils/sticky_spec.js index c3ee3ef9825..b87c836654d 100644 --- a/spec/javascripts/lib/utils/sticky_spec.js +++ b/spec/javascripts/lib/utils/sticky_spec.js @@ -1,52 +1,79 @@ import { isSticky } from '~/lib/utils/sticky'; describe('sticky', () => { - const el = { - offsetTop: 0, - classList: {}, - }; + let el; beforeEach(() => { - el.offsetTop = 0; - el.classList.add = jasmine.createSpy('spy'); - el.classList.remove = jasmine.createSpy('spy'); + document.body.innerHTML += ` + <div class="parent"> + <div id="js-sticky"></div> + </div> + `; + + el = document.getElementById('js-sticky'); }); - describe('classList.remove', () => { - it('does not call classList.remove when stuck', () => { - isSticky(el, 0, 0); + afterEach(() => { + el.parentNode.remove(); + }); + + describe('when stuck', () => { + it('does not remove is-stuck class', () => { + isSticky(el, 0, el.offsetTop); + isSticky(el, 0, el.offsetTop); expect( - el.classList.remove, - ).not.toHaveBeenCalled(); + el.classList.contains('is-stuck'), + ).toBeTruthy(); }); - it('calls classList.remove when not stuck', () => { - el.offsetTop = 10; - isSticky(el, 0, 0); + it('adds is-stuck class', () => { + isSticky(el, 0, el.offsetTop); expect( - el.classList.remove, - ).toHaveBeenCalledWith('is-stuck'); + el.classList.contains('is-stuck'), + ).toBeTruthy(); + }); + + it('inserts placeholder element', () => { + isSticky(el, 0, el.offsetTop, true); + + expect( + document.querySelector('.sticky-placeholder'), + ).not.toBeNull(); }); }); - describe('classList.add', () => { - it('calls classList.add when stuck', () => { + describe('when not stuck', () => { + it('removes is-stuck class', () => { + spyOn(el.classList, 'remove').and.callThrough(); + + isSticky(el, 0, el.offsetTop); isSticky(el, 0, 0); expect( - el.classList.add, + el.classList.remove, ).toHaveBeenCalledWith('is-stuck'); + expect( + el.classList.contains('is-stuck'), + ).toBeFalsy(); }); - it('does not call classList.add when not stuck', () => { - el.offsetTop = 10; + it('does not add is-stuck class', () => { isSticky(el, 0, 0); expect( - el.classList.add, - ).not.toHaveBeenCalled(); + el.classList.contains('is-stuck'), + ).toBeFalsy(); + }); + + it('removes placeholder', () => { + isSticky(el, 0, el.offsetTop, true); + isSticky(el, 0, 0, true); + + expect( + document.querySelector('.sticky-placeholder'), + ).toBeNull(); }); }); }); diff --git a/spec/lib/gitlab/diff/diff_refs_spec.rb b/spec/lib/gitlab/diff/diff_refs_spec.rb index c73708d90a8..f9bfb4c469e 100644 --- a/spec/lib/gitlab/diff/diff_refs_spec.rb +++ b/spec/lib/gitlab/diff/diff_refs_spec.rb @@ -3,6 +3,61 @@ require 'spec_helper' describe Gitlab::Diff::DiffRefs do let(:project) { create(:project, :repository) } + describe '#==' do + let(:commit) { project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863') } + subject { commit.diff_refs } + + context 'when shas are missing' do + let(:other) { described_class.new(base_sha: subject.base_sha, start_sha: subject.start_sha, head_sha: nil) } + + it 'returns false' do + expect(subject).not_to eq(other) + end + end + + context 'when shas are equal' do + let(:other) { described_class.new(base_sha: subject.base_sha, start_sha: subject.start_sha, head_sha: subject.head_sha) } + + it 'returns true' do + expect(subject).to eq(other) + end + end + + context 'when shas are unequal' do + let(:other) { described_class.new(base_sha: subject.base_sha, start_sha: subject.start_sha, head_sha: subject.head_sha.reverse) } + + it 'returns false' do + expect(subject).not_to eq(other) + end + end + + context 'when shas are truncated' do + context 'when sha prefixes are too short' do + let(:other) { described_class.new(base_sha: subject.base_sha[0, 4], start_sha: subject.start_sha[0, 4], head_sha: subject.head_sha[0, 4]) } + + it 'returns false' do + expect(subject).not_to eq(other) + end + end + + context 'when sha prefixes are equal' do + let(:other) { described_class.new(base_sha: subject.base_sha[0, 10], start_sha: subject.start_sha[0, 10], head_sha: subject.head_sha[0, 10]) } + + it 'returns true' do + expect(subject).to eq(other) + end + end + + context 'when sha prefixes are unequal' do + let(:other) { described_class.new(base_sha: subject.base_sha[0, 10], start_sha: subject.start_sha[0, 10], head_sha: subject.head_sha[0, 10].reverse) } + + it 'returns false' do + expect(subject).not_to eq(other) + end + end + end + end + describe '#compare_in' do context 'with diff refs for the initial commit' do let(:commit) { project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863') } diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb index d4a2a852c12..7798736a4dc 100644 --- a/spec/lib/gitlab/diff/position_spec.rb +++ b/spec/lib/gitlab/diff/position_spec.rb @@ -429,6 +429,44 @@ describe Gitlab::Diff::Position do end end + describe '#==' do + let(:commit) { project.commit("570e7b2abdd848b95f2f578043fc23bd6f6fd24d") } + + subject do + described_class.new( + old_path: "files/ruby/popen.rb", + new_path: "files/ruby/popen.rb", + old_line: nil, + new_line: 14, + diff_refs: commit.diff_refs + ) + end + + context 'when positions are equal' do + let(:other) { described_class.new(subject.to_h) } + + it 'returns true' do + expect(subject).to eq(other) + end + end + + context 'when positions are equal, except for truncated shas' do + let(:other) { described_class.new(subject.to_h.merge(start_sha: subject.start_sha[0, 10])) } + + it 'returns true' do + expect(subject).to eq(other) + end + end + + context 'when positions are unequal' do + let(:other) { described_class.new(subject.to_h.merge(start_sha: subject.start_sha.reverse)) } + + it 'returns false' do + expect(subject).not_to eq(other) + end + end + end + describe "#to_json" do let(:hash) do { diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index 46e968cc398..a3dff6d0d4b 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -181,7 +181,7 @@ describe Gitlab::Git::Commit, seed_helper: true do end end - describe '.where' do + shared_examples '.where' do context 'path is empty string' do subject do commits = described_class.where( @@ -279,6 +279,14 @@ describe Gitlab::Git::Commit, seed_helper: true do end end + describe '.where with gitaly' do + it_should_behave_like '.where' + end + + describe '.where without gitaly', skip_gitaly_mock: true do + it_should_behave_like '.where' + end + describe '.between' do subject do commits = described_class.between(repository, SeedRepo::Commit::PARENT_ID, SeedRepo::Commit::ID) diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 2e686e515c5..584dfe9a5c1 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -183,75 +183,42 @@ describe Ci::Runner do end end - context 'when runner is locked' do + context 'when runner is shared' do before do - runner.locked = true + runner.is_shared = true + build.project.runners = [] end - shared_examples 'locked build picker' do - context 'when runner cannot pick untagged jobs' do - before do - runner.run_untagged = false - end + it 'can handle builds' do + expect(runner.can_pick?(build)).to be_truthy + end - it 'cannot handle builds without tags' do - expect(runner.can_pick?(build)).to be_falsey - end + context 'when runner is locked' do + before do + runner.locked = true end - context 'when having runner tags' do - before do - runner.tag_list = %w(bb cc) - end - - it 'cannot handle it for builds without matching tags' do - build.tag_list = ['aa'] - - expect(runner.can_pick?(build)).to be_falsey - end + it 'can handle builds' do + expect(runner.can_pick?(build)).to be_truthy end end + end - context 'when serving the same project' do - it 'can handle it' do + context 'when runner is not shared' do + context 'when runner is assigned to a project' do + it 'can handle builds' do expect(runner.can_pick?(build)).to be_truthy end - - it_behaves_like 'locked build picker' - - context 'when having runner tags' do - before do - runner.tag_list = %w(bb cc) - build.tag_list = ['bb'] - end - - it 'can handle it for matching tags' do - expect(runner.can_pick?(build)).to be_truthy - end - end end - context 'serving a different project' do + context 'when runner is not assigned to a project' do before do - runner.runner_projects.destroy_all + build.project.runners = [] end - it 'cannot handle it' do + it 'cannot handle builds' do expect(runner.can_pick?(build)).to be_falsey end - - it_behaves_like 'locked build picker' - - context 'when having runner tags' do - before do - runner.tag_list = %w(bb cc) - build.tag_list = ['bb'] - end - - it 'cannot handle it for matching tags' do - expect(runner.can_pick?(build)).to be_falsey - end - end end end diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index f663719d28c..94462b4572d 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -491,6 +491,7 @@ describe API::Commits do expect(json_response['stats']['deletions']).to eq(commit.stats.deletions) expect(json_response['stats']['total']).to eq(commit.stats.total) expect(json_response['status']).to be_nil + expect(json_response['last_pipeline']).to be_nil end context 'when ref does not exist' do @@ -573,6 +574,10 @@ describe API::Commits do expect(response).to have_http_status(200) expect(response).to match_response_schema('public_api/v4/commit/detail') expect(json_response['status']).to eq('created') + expect(json_response['last_pipeline']['id']).to eq(pipeline.id) + expect(json_response['last_pipeline']['ref']).to eq(pipeline.ref) + expect(json_response['last_pipeline']['sha']).to eq(pipeline.sha) + expect(json_response['last_pipeline']['status']).to eq(pipeline.status) end context 'when pipeline succeeds' do diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb index 2361809e0e1..f8cd529a06c 100644 --- a/spec/requests/api/environments_spec.rb +++ b/spec/requests/api/environments_spec.rb @@ -20,6 +20,7 @@ describe API::Environments do path path_with_namespace star_count forks_count created_at last_activity_at + avatar_url ) get api("/projects/#{project.id}/environments", user) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 508df990952..18f6f7df1fa 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -193,6 +193,7 @@ describe API::Projects do path path_with_namespace star_count forks_count created_at last_activity_at + avatar_url ) get api('/projects?simple=true', user) diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb index cae2c3118da..e5282c3311f 100644 --- a/spec/requests/api/v3/projects_spec.rb +++ b/spec/requests/api/v3/projects_spec.rb @@ -89,6 +89,7 @@ describe API::V3::Projects do path path_with_namespace star_count forks_count created_at last_activity_at + avatar_url ) get v3_api('/projects?simple=true', user) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 92735336572..dbf05b7f004 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -64,8 +64,16 @@ RSpec.configure do |config| config.infer_spec_type_from_file_location! - config.define_derived_metadata(file_path: %r{/spec/requests/(ci/)?api/}) do |metadata| - metadata[:api] = true + config.define_derived_metadata(file_path: %r{/spec/}) do |metadata| + location = metadata[:location] + + metadata[:api] = true if location =~ %r{/spec/requests/api/} + + # do not overwrite type if it's already set + next if metadata.key?(:type) + + match = location.match(%r{/spec/([^/]+)/}) + metadata[:type] = match[1].singularize.to_sym if match end config.raise_errors_for_deprecations! diff --git a/spec/views/dashboard/projects/_nav.html.haml.rb b/spec/views/dashboard/projects/_nav.html.haml.rb new file mode 100644 index 00000000000..f6a8ca13040 --- /dev/null +++ b/spec/views/dashboard/projects/_nav.html.haml.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe 'dashboard/projects/_nav.html.haml' do + it 'highlights All tab by default' do + render + + expect(rendered).to have_css('li.active a', text: 'All') + end + + it 'highlights Personal tab personal param is present' do + controller.params[:personal] = true + + render + + expect(rendered).to have_css('li.active a', text: 'Personal') + end +end |