Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorLuke Bennett <lukeeeebennettplus@gmail.com>2018-06-06 10:50:13 +0300
committerLuke Bennett <lukeeeebennettplus@gmail.com>2018-06-06 10:50:13 +0300
commit0af7333ef9bea81f2a9d45f14a2ed4518b383d6d (patch)
treeeda1fc06f17a7a3f657f6d52449a0bbc3cc664fd /app
parentbb7f44aa8cf61d590bf45efb20c4ce19234ce03d (diff)
parenta93e34acc3e52ccf81369d3345faaa48fee08581 (diff)
Merge remote-tracking branch 'origin/master' into 39549-label-list-page-redesign-with-draggable-labels
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/importer_status.js4
-rw-r--r--app/assets/javascripts/performance_bar/components/detailed_metric.vue3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/gl_modal.vue15
-rw-r--r--app/assets/javascripts/vue_shared/components/table_pagination.vue16
-rw-r--r--app/assets/stylesheets/bootstrap_migration.scss65
-rw-r--r--app/assets/stylesheets/framework/common.scss4
-rw-r--r--app/assets/stylesheets/framework/pagination.scss91
-rw-r--r--app/assets/stylesheets/pages/issuable.scss9
-rw-r--r--app/assets/stylesheets/pages/settings.scss4
-rw-r--r--app/controllers/application_controller.rb9
-rw-r--r--app/controllers/groups/group_members_controller.rb6
-rw-r--r--app/controllers/groups/milestones_controller.rb5
-rw-r--r--app/controllers/projects/merge_requests/application_controller.rb2
-rw-r--r--app/controllers/projects/pipelines_controller.rb4
-rw-r--r--app/controllers/users/terms_controller.rb4
-rw-r--r--app/helpers/merge_requests_helper.rb4
-rw-r--r--app/helpers/projects_helper.rb11
-rw-r--r--app/helpers/workhorse_helper.rb2
-rw-r--r--app/models/application_setting/term.rb6
-rw-r--r--app/models/ci/group.rb8
-rw-r--r--app/models/ci/legacy_stage.rb6
-rw-r--r--app/models/ci/pipeline.rb24
-rw-r--r--app/models/ci/runner.rb6
-rw-r--r--app/models/ci/stage.rb32
-rw-r--r--app/models/concerns/avatarable.rb47
-rw-r--r--app/models/concerns/has_status.rb2
-rw-r--r--app/models/concerns/with_uploads.rb4
-rw-r--r--app/models/merge_request.rb12
-rw-r--r--app/models/note.rb4
-rw-r--r--app/models/personal_snippet.rb1
-rw-r--r--app/models/project.rb23
-rw-r--r--app/models/repository.rb10
-rw-r--r--app/models/term_agreement.rb2
-rw-r--r--app/policies/ci/build_policy.rb6
-rw-r--r--app/policies/ci/pipeline_policy.rb6
-rw-r--r--app/serializers/merge_request_widget_entity.rb2
-rw-r--r--app/serializers/pipeline_details_entity.rb2
-rw-r--r--app/serializers/pipeline_serializer.rb17
-rw-r--r--app/services/application_settings/update_service.rb2
-rw-r--r--app/services/applications/create_service.rb3
-rw-r--r--app/services/merge_requests/base_service.rb4
-rw-r--r--app/services/test_hooks/project_service.rb4
-rw-r--r--app/uploaders/object_storage.rb4
-rw-r--r--app/views/admin/projects/show.html.haml6
-rw-r--r--app/views/admin/runners/index.html.haml2
-rw-r--r--app/views/groups/_activities.html.haml2
-rw-r--r--app/views/help/_shortcuts.html.haml164
-rw-r--r--app/views/kaminari/gitlab/_first_page.html.haml2
-rw-r--r--app/views/kaminari/gitlab/_gap.html.haml2
-rw-r--r--app/views/kaminari/gitlab/_last_page.html.haml2
-rw-r--r--app/views/kaminari/gitlab/_next_page.html.haml2
-rw-r--r--app/views/kaminari/gitlab/_page.html.haml2
-rw-r--r--app/views/kaminari/gitlab/_paginator.html.haml2
-rw-r--r--app/views/kaminari/gitlab/_prev_page.html.haml2
-rw-r--r--app/views/kaminari/gitlab/_without_count.html.haml4
-rw-r--r--app/views/projects/new.html.haml12
-rw-r--r--app/views/projects/pages/_destroy.haml2
-rw-r--r--app/views/shared/issuable/form/_contribution.html.haml10
-rw-r--r--app/views/shared/projects/_edit_information.html.haml2
-rw-r--r--app/views/users/terms/index.html.haml4
62 files changed, 440 insertions, 283 deletions
diff --git a/app/assets/javascripts/importer_status.js b/app/assets/javascripts/importer_status.js
index b469e1e2adc..52455885248 100644
--- a/app/assets/javascripts/importer_status.js
+++ b/app/assets/javascripts/importer_status.js
@@ -58,7 +58,7 @@ class ImporterStatus {
job.find('.import-target').html(`<a href="${data.full_path}">${data.full_path}</a>`);
$('table.import-jobs tbody').prepend(job);
- job.addClass('active');
+ job.addClass('table-active');
const connectingVerb = this.ciCdOnly ? __('connecting') : __('importing');
job.find('.import-actions').html(sprintf(
_.escape(__('%{loadingIcon} Started')), {
@@ -81,7 +81,7 @@ class ImporterStatus {
switch (job.import_status) {
case 'finished':
- jobItem.removeClass('active').addClass('success');
+ jobItem.removeClass('table-active').addClass('table-success');
statusField.html(`<span><i class="fa fa-check"></i> ${__('Done')}</span>`);
break;
case 'scheduled':
diff --git a/app/assets/javascripts/performance_bar/components/detailed_metric.vue b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
index db8a0055acd..96189e7033a 100644
--- a/app/assets/javascripts/performance_bar/components/detailed_metric.vue
+++ b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
@@ -56,6 +56,7 @@ export default {
<gl-modal
:id="`modal-peek-${metric}-details`"
:header-title-text="header"
+ modal-size="lg"
class="performance-bar-modal"
>
<table
@@ -70,7 +71,7 @@ export default {
<td
v-for="key in keys"
:key="key"
- class="break-word"
+ class="break-word all-words"
>
{{ item[key] }}
</td>
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index f69fe03fcb3..c20d07a169d 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -265,10 +265,10 @@ export default {
/>
<section
- v-if="mr.maintainerEditAllowed"
+ v-if="mr.allowCollaboration"
class="mr-info-list mr-links"
>
- {{ s__("mrWidget|Allows edits from maintainers") }}
+ {{ s__("mrWidget|Allows commits from members who can merge to the target branch") }}
</section>
<mr-widget-related-links
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index e5b7e1f1c68..134aaacf9d2 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -83,7 +83,7 @@ export default class MergeRequestStore {
this.canBeMerged = data.can_be_merged || false;
this.isMergeAllowed = data.mergeable || false;
this.mergeOngoing = data.merge_ongoing;
- this.maintainerEditAllowed = data.allow_maintainer_to_push;
+ this.allowCollaboration = data.allow_collaboration;
// Cherry-pick and Revert actions related
this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false;
diff --git a/app/assets/javascripts/vue_shared/components/gl_modal.vue b/app/assets/javascripts/vue_shared/components/gl_modal.vue
index d5d5a7d3798..7ba58bd5959 100644
--- a/app/assets/javascripts/vue_shared/components/gl_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/gl_modal.vue
@@ -1,15 +1,21 @@
<script>
const buttonVariants = ['danger', 'primary', 'success', 'warning'];
+const sizeVariants = ['sm', 'md', 'lg'];
export default {
name: 'GlModal',
-
props: {
id: {
type: String,
required: false,
default: null,
},
+ modalSize: {
+ type: String,
+ required: false,
+ default: 'md',
+ validator: value => sizeVariants.includes(value),
+ },
headerTitleText: {
type: String,
required: false,
@@ -27,7 +33,11 @@ export default {
default: '',
},
},
-
+ computed: {
+ modalSizeClass() {
+ return this.modalSize === 'md' ? '' : `modal-${this.modalSize}`;
+ },
+ },
methods: {
emitCancel(event) {
this.$emit('cancel', event);
@@ -48,6 +58,7 @@ export default {
>
<div
class="modal-dialog"
+ :class="modalSizeClass"
role="document"
>
<div class="modal-content">
diff --git a/app/assets/javascripts/vue_shared/components/table_pagination.vue b/app/assets/javascripts/vue_shared/components/table_pagination.vue
index 22fc5757447..6f231619f26 100644
--- a/app/assets/javascripts/vue_shared/components/table_pagination.vue
+++ b/app/assets/javascripts/vue_shared/components/table_pagination.vue
@@ -124,15 +124,18 @@
break;
}
},
+ hideOnSmallScreen(item) {
+ return !item.first && !item.last && !item.next && !item.prev && !item.active;
+ },
},
};
</script>
<template>
<div
v-if="showPagination"
- class="gl-pagination"
+ class="gl-pagination prepend-top-default"
>
- <ul class="pagination clearfix">
+ <ul class="pagination justify-content-center">
<li
v-for="(item, index) in getItems"
:key="index"
@@ -142,12 +145,17 @@
'js-next-button': item.next,
'js-last-button': item.last,
'js-first-button': item.first,
+ 'd-none d-md-block': hideOnSmallScreen(item),
separator: item.separator,
active: item.active,
- disabled: item.disabled
+ disabled: item.disabled || item.separator
}"
+ class="page-item"
>
- <a @click.prevent="changePage(item.title, item.disabled)">
+ <a
+ @click.prevent="changePage(item.title, item.disabled)"
+ class="page-link"
+ >
{{ item.title }}
</a>
</li>
diff --git a/app/assets/stylesheets/bootstrap_migration.scss b/app/assets/stylesheets/bootstrap_migration.scss
index d5679177f8f..3785aaa43f0 100644
--- a/app/assets/stylesheets/bootstrap_migration.scss
+++ b/app/assets/stylesheets/bootstrap_migration.scss
@@ -24,16 +24,54 @@ html {
font-size: 14px;
}
+legend {
+ border-bottom: 1px solid $border-color;
+ margin-bottom: 20px;
+}
+
button,
html [type="button"],
[type="reset"],
-[type="submit"] {
+[type="submit"],
+[role="button"] {
// Override bootstrap reboot
-webkit-appearance: inherit;
+ cursor: pointer;
}
-[role="button"] {
- cursor: pointer;
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ color: $gl-text-color;
+ font-weight: 600;
+}
+
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3 {
+ margin-top: 20px;
+ margin-bottom: 10px;
+}
+
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6 {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+
+h5,
+.h5 {
+ font-size: $gl-font-size;
}
input[type="file"] {
@@ -59,6 +97,10 @@ a {
}
}
+kbd {
+ display: inline-block;
+}
+
code {
padding: 2px 4px;
color: $red-600;
@@ -108,6 +150,16 @@ table {
color: $gl-text-color-secondary !important;
}
+.bg-success,
+.bg-primary,
+.bg-info,
+.bg-danger,
+.bg-warning {
+ .card-header {
+ color: $white-light;
+ }
+}
+
// Polyfill deprecated selectors
.hidden {
@@ -182,8 +234,13 @@ table {
}
.nav-tabs {
+ // Override bootstrap's default border
+ border-bottom: 0;
+
.nav-link {
- border: 0;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
}
.nav-item {
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 1e7b9534275..996e5c1512d 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -448,6 +448,10 @@ img.emoji {
.break-word {
word-wrap: break-word;
+
+ &.all-words {
+ word-break: break-word;
+ }
}
/** COMMON CLASSES **/
diff --git a/app/assets/stylesheets/framework/pagination.scss b/app/assets/stylesheets/framework/pagination.scss
index d3e013590b6..50a1b1c446d 100644
--- a/app/assets/stylesheets/framework/pagination.scss
+++ b/app/assets/stylesheets/framework/pagination.scss
@@ -1,91 +1,6 @@
.gl-pagination {
- text-align: center;
- border-top: 1px solid $border-color;
- margin: 0;
- margin-top: 0;
-
- .pagination {
- padding: 0;
- margin: 20px 0;
-
- a {
- cursor: pointer;
- }
-
- .separator,
- .separator:hover {
- a {
- cursor: default;
- background-color: $gray-light;
- padding: $gl-vert-padding;
- }
- }
- }
-
-
- .gap,
- .gap:hover {
- background-color: $gray-light;
- padding: $gl-vert-padding;
- cursor: default;
- }
-}
-
-.card > .gl-pagination {
- margin: 0;
-}
-
-/**
- * Extra-small screen pagination.
- */
-@media (max-width: 320px) {
- .gl-pagination {
- .first,
- .last {
- display: none;
- }
-
- .page-item {
- display: none;
-
- &.active {
- display: inline;
- }
- }
- }
-}
-
-/**
- * Small screen pagination
- */
-@include media-breakpoint-down(xs) {
- .gl-pagination {
- .pagination li a {
- padding: 6px 10px;
- }
-
- .page-item {
- display: none;
-
- &.active {
- display: inline;
- }
- }
- }
-}
-
-/**
- * Medium screen pagination
- */
-@media (min-width: map-get($grid-breakpoints, xs)) and (max-width: map-get($grid-breakpoints, sm)) {
- .gl-pagination {
- .page-item {
- display: none;
-
- &.active,
- &.sibling {
- display: inline;
- }
- }
+ a {
+ color: inherit;
+ text-decoration: none;
}
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 4aea9740735..b42c232fd91 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -485,6 +485,15 @@
.sidebar-collapsed-user {
padding-bottom: 0;
margin-bottom: 10px;
+
+ .author_link {
+ padding-left: 0;
+
+ .avatar {
+ position: static;
+ margin: 0;
+ }
+ }
}
.issuable-header-btn {
diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss
index 43c39c43bc1..16e999341da 100644
--- a/app/assets/stylesheets/pages/settings.scss
+++ b/app/assets/stylesheets/pages/settings.scss
@@ -102,10 +102,6 @@
.form-text.text-muted {
margin-top: 0;
}
-
- .label-light {
- margin-bottom: 0;
- }
}
.settings-list-icon {
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index db8a8cdc0d2..bc60a0a02e8 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -130,12 +130,17 @@ class ApplicationController < ActionController::Base
end
def access_denied!(message = nil)
+ # If we display a custom access denied message to the user, we don't want to
+ # hide existence of the resource, rather tell them they cannot access it using
+ # the provided message
+ status = message.present? ? :forbidden : :not_found
+
respond_to do |format|
- format.any { head :not_found }
+ format.any { head status }
format.html do
render "errors/access_denied",
layout: "errors",
- status: 404,
+ status: status,
locals: { message: message }
end
end
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index ef3eba80154..ef5d5e5c742 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -3,8 +3,12 @@ class Groups::GroupMembersController < Groups::ApplicationController
include MembersPresentation
include SortingHelper
+ def self.admin_not_required_endpoints
+ %i[index leave request_access]
+ end
+
# Authorize
- before_action :authorize_admin_group_member!, except: [:index, :leave, :request_access]
+ before_action :authorize_admin_group_member!, except: admin_not_required_endpoints
skip_cross_project_access_check :index, :create, :update, :destroy, :request_access,
:approve_access_request, :leave, :resend_invite,
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb
index 5903689dc62..9bd51de7e97 100644
--- a/app/controllers/groups/milestones_controller.rb
+++ b/app/controllers/groups/milestones_controller.rb
@@ -76,12 +76,15 @@ class Groups::MilestonesController < Groups::ApplicationController
def milestones
milestones = MilestonesFinder.new(search_params).execute
- legacy_milestones = GroupMilestone.build_collection(group, group_projects, params)
@sort = params[:sort] || 'due_date_asc'
MilestoneArray.sort(milestones + legacy_milestones, @sort)
end
+ def legacy_milestones
+ GroupMilestone.build_collection(group, group_projects, params)
+ end
+
def milestone
@milestone =
if params[:title]
diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb
index 29632bef7e5..8e4aeec16dc 100644
--- a/app/controllers/projects/merge_requests/application_controller.rb
+++ b/app/controllers/projects/merge_requests/application_controller.rb
@@ -15,7 +15,7 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
def merge_request_params_attributes
[
- :allow_maintainer_to_push,
+ :allow_collaboration,
:assignee_id,
:description,
:force_remove_source_branch,
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 6b40fc2fe68..768595ceeb4 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -23,8 +23,6 @@ class Projects::PipelinesController < Projects::ApplicationController
@finished_count = limited_pipelines_count(project, 'finished')
@pipelines_count = limited_pipelines_count(project)
- Gitlab::Ci::Pipeline::Preloader.preload(@pipelines)
-
respond_to do |format|
format.html
format.json do
@@ -34,7 +32,7 @@ class Projects::PipelinesController < Projects::ApplicationController
pipelines: PipelineSerializer
.new(project: @project, current_user: @current_user)
.with_pagination(request, response)
- .represent(@pipelines, disable_coverage: true),
+ .represent(@pipelines, disable_coverage: true, preload: true),
count: {
all: @pipelines_count,
running: @running_count,
diff --git a/app/controllers/users/terms_controller.rb b/app/controllers/users/terms_controller.rb
index ab685b9106e..f7c6d1d59db 100644
--- a/app/controllers/users/terms_controller.rb
+++ b/app/controllers/users/terms_controller.rb
@@ -13,6 +13,10 @@ module Users
def index
@redirect = redirect_path
+
+ if @term.accepted_by_user?(current_user)
+ flash.now[:notice] = "You have already accepted the Terms of Service as #{current_user.to_reference}"
+ end
end
def accept
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 74251c260f0..5ff06b3e0fc 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -126,8 +126,8 @@ module MergeRequestsHelper
link_to(url[merge_request.project, merge_request], data: data_attrs, &block)
end
- def allow_maintainer_push_unavailable_reason(merge_request)
- return if merge_request.can_allow_maintainer_to_push?(current_user)
+ def allow_collaboration_unavailable_reason(merge_request)
+ return if merge_request.can_allow_collaboration?(current_user)
minimum_visibility = [merge_request.target_project.visibility_level,
merge_request.source_project.visibility_level].min
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index dfca799a53d..cdbb572f80a 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -389,11 +389,11 @@ module ProjectsHelper
def project_status_css_class(status)
case status
when "started"
- "active"
+ "table-active"
when "failed"
- "danger"
+ "table-danger"
when "finished"
- "success"
+ "table-success"
end
end
@@ -412,7 +412,10 @@ module ProjectsHelper
exports_path = File.join(Settings.shared['path'], 'tmp/project_exports')
filtered_message = message.strip.gsub(exports_path, "[REPO EXPORT PATH]")
- disk_path = Gitlab.config.repositories.storages[project.repository_storage].legacy_disk_path
+ disk_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ Gitlab.config.repositories.storages[project.repository_storage].legacy_disk_path
+ end
+
filtered_message.gsub(disk_path.chomp('/'), "[REPOS PATH]")
end
diff --git a/app/helpers/workhorse_helper.rb b/app/helpers/workhorse_helper.rb
index 9f78b80c71d..a82271ce0ee 100644
--- a/app/helpers/workhorse_helper.rb
+++ b/app/helpers/workhorse_helper.rb
@@ -6,7 +6,7 @@ module WorkhorseHelper
headers.store(*Gitlab::Workhorse.send_git_blob(repository, blob))
headers['Content-Disposition'] = 'inline'
headers['Content-Type'] = safe_content_type(blob)
- head :ok # 'render nothing: true' messes up the Content-Type
+ render plain: ""
end
# Send a Git diff through Workhorse
diff --git a/app/models/application_setting/term.rb b/app/models/application_setting/term.rb
index e8ce0ccbb71..3b1dfe7e4ef 100644
--- a/app/models/application_setting/term.rb
+++ b/app/models/application_setting/term.rb
@@ -1,6 +1,7 @@
class ApplicationSetting
class Term < ActiveRecord::Base
include CacheMarkdownField
+ has_many :term_agreements
validates :terms, presence: true
@@ -9,5 +10,10 @@ class ApplicationSetting
def self.latest
order(:id).last
end
+
+ def accepted_by_user?(user)
+ user.accepted_term_id == id ||
+ term_agreements.accepted.where(user: user).exists?
+ end
end
end
diff --git a/app/models/ci/group.rb b/app/models/ci/group.rb
index 87898b086c6..9c1046e8715 100644
--- a/app/models/ci/group.rb
+++ b/app/models/ci/group.rb
@@ -31,6 +31,14 @@ module Ci
end
end
+ def self.fabricate(stage)
+ stage.statuses.ordered.latest
+ .sort_by(&:sortable_name).group_by(&:group_name)
+ .map do |group_name, grouped_statuses|
+ self.new(stage, name: group_name, jobs: grouped_statuses)
+ end
+ end
+
private
def commit_statuses
diff --git a/app/models/ci/legacy_stage.rb b/app/models/ci/legacy_stage.rb
index 9b536af672b..ce691875e42 100644
--- a/app/models/ci/legacy_stage.rb
+++ b/app/models/ci/legacy_stage.rb
@@ -16,11 +16,7 @@ module Ci
end
def groups
- @groups ||= statuses.ordered.latest
- .sort_by(&:sortable_name).group_by(&:group_name)
- .map do |group_name, grouped_statuses|
- Ci::Group.new(self, name: group_name, jobs: grouped_statuses)
- end
+ @groups ||= Ci::Group.fabricate(self)
end
def to_param
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 5eb30f4aaa0..eecd86349e4 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -18,7 +18,7 @@ module Ci
s&.project&.pipelines&.maximum(:iid) || s&.project&.pipelines&.count
end
- has_many :stages
+ has_many :stages, -> { order(position: :asc) }, inverse_of: :pipeline
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent
@@ -254,6 +254,20 @@ module Ci
stage unless stage.statuses_count.zero?
end
+ ##
+ # TODO We do not completely switch to persisted stages because of
+ # race conditions with setting statuses gitlab-ce#23257.
+ #
+ def ordered_stages
+ return legacy_stages unless complete?
+
+ if Feature.enabled?('ci_pipeline_persisted_stages')
+ stages
+ else
+ legacy_stages
+ end
+ end
+
def legacy_stages
# TODO, this needs refactoring, see gitlab-ce#26481.
@@ -416,7 +430,7 @@ module Ci
def number_of_warnings
BatchLoader.for(id).batch(default_value: 0) do |pipeline_ids, loader|
- Build.where(commit_id: pipeline_ids)
+ ::Ci::Build.where(commit_id: pipeline_ids)
.latest
.failed_but_allowed
.group(:commit_id)
@@ -508,7 +522,8 @@ module Ci
def update_status
retry_optimistic_lock(self) do
- case latest_builds_status
+ case latest_builds_status.to_s
+ when 'created' then nil
when 'pending' then enqueue
when 'running' then run
when 'success' then succeed
@@ -516,6 +531,9 @@ module Ci
when 'canceled' then cancel
when 'skipped' then skip
when 'manual' then block
+ else
+ raise HasStatus::UnknownStatusError,
+ "Unknown status `#{latest_builds_status}`"
end
end
end
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 57edd6a4956..8c9aacca8de 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -219,10 +219,8 @@ module Ci
cache_attributes(values)
- if persist_cached_data?
- self.assign_attributes(values)
- self.save if self.changed?
- end
+ # We save data without validation, it will always change due to `contacted_at`
+ self.update_columns(values) if persist_cached_data?
end
def pick_build!(build)
diff --git a/app/models/ci/stage.rb b/app/models/ci/stage.rb
index 5a1eeb966aa..ea07f37e6c1 100644
--- a/app/models/ci/stage.rb
+++ b/app/models/ci/stage.rb
@@ -68,16 +68,44 @@ module Ci
def update_status
retry_optimistic_lock(self) do
case statuses.latest.status
+ when 'created' then nil
when 'pending' then enqueue
when 'running' then run
when 'success' then succeed
when 'failed' then drop
when 'canceled' then cancel
when 'manual' then block
- when 'skipped' then skip
- else skip
+ when 'skipped', nil then skip
+ else
+ raise HasStatus::UnknownStatusError,
+ "Unknown status `#{statuses.latest.status}`"
end
end
end
+
+ def groups
+ @groups ||= Ci::Group.fabricate(self)
+ end
+
+ def has_warnings?
+ number_of_warnings.positive?
+ end
+
+ def number_of_warnings
+ BatchLoader.for(id).batch(default_value: 0) do |stage_ids, loader|
+ ::Ci::Build.where(stage_id: stage_ids)
+ .latest
+ .failed_but_allowed
+ .group(:stage_id)
+ .count
+ .each { |id, amount| loader.call(id, amount) }
+ end
+ end
+
+ def detailed_status(current_user)
+ Gitlab::Ci::Status::Stage::Factory
+ .new(self, current_user)
+ .fabricate!
+ end
end
end
diff --git a/app/models/concerns/avatarable.rb b/app/models/concerns/avatarable.rb
index 13246a774e3..095897b08e3 100644
--- a/app/models/concerns/avatarable.rb
+++ b/app/models/concerns/avatarable.rb
@@ -4,11 +4,14 @@ module Avatarable
included do
prepend ShadowMethods
include ObjectStorage::BackgroundMove
+ include Gitlab::Utils::StrongMemoize
validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
mount_uploader :avatar, AvatarUploader
+
+ after_initialize :add_avatar_to_batch
end
module ShadowMethods
@@ -18,6 +21,17 @@ module Avatarable
avatar_path(only_path: args.fetch(:only_path, true)) || super
end
+
+ def retrieve_upload(identifier, paths)
+ upload = retrieve_upload_from_batch(identifier)
+
+ # This fallback is needed when deleting an upload, because we may have
+ # already been removed from the DB. We have to check an explicit `#nil?`
+ # because it's a BatchLoader instance.
+ upload = super if upload.nil?
+
+ upload
+ end
end
def avatar_type
@@ -52,4 +66,37 @@ module Avatarable
url_base + avatar.local_url
end
+
+ # Path that is persisted in the tracking Upload model. Used to fetch the
+ # upload from the model.
+ def upload_paths(identifier)
+ avatar_mounter.blank_uploader.store_dirs.map { |store, path| File.join(path, identifier) }
+ end
+
+ private
+
+ def retrieve_upload_from_batch(identifier)
+ BatchLoader.for(identifier: identifier, model: self).batch(key: self.class) do |upload_params, loader, args|
+ model_class = args[:key]
+ paths = upload_params.flat_map do |params|
+ params[:model].upload_paths(params[:identifier])
+ end
+
+ Upload.where(uploader: AvatarUploader, path: paths).find_each do |upload|
+ model = model_class.instantiate('id' => upload.model_id)
+
+ loader.call({ model: model, identifier: File.basename(upload.path) }, upload)
+ end
+ end
+ end
+
+ def add_avatar_to_batch
+ return unless avatar_mounter
+
+ avatar_mounter.read_identifiers.each { |identifier| retrieve_upload_from_batch(identifier) }
+ end
+
+ def avatar_mounter
+ strong_memoize(:avatar_mounter) { _mounter(:avatar) }
+ end
end
diff --git a/app/models/concerns/has_status.rb b/app/models/concerns/has_status.rb
index 7c3ed96bc28..72c236a0fc7 100644
--- a/app/models/concerns/has_status.rb
+++ b/app/models/concerns/has_status.rb
@@ -11,6 +11,8 @@ module HasStatus
STATUSES_ENUM = { created: 0, pending: 1, running: 2, success: 3,
failed: 4, canceled: 5, skipped: 6, manual: 7 }.freeze
+ UnknownStatusError = Class.new(StandardError)
+
class_methods do
def status_sql
scope_relevant = respond_to?(:exclude_ignored) ? exclude_ignored : all
diff --git a/app/models/concerns/with_uploads.rb b/app/models/concerns/with_uploads.rb
index e7cfffb775b..4245d083a49 100644
--- a/app/models/concerns/with_uploads.rb
+++ b/app/models/concerns/with_uploads.rb
@@ -36,4 +36,8 @@ module WithUploads
upload.destroy
end
end
+
+ def retrieve_upload(_identifier, paths)
+ uploads.find_by(path: paths)
+ end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 4c1628d2bdb..535a2c362f2 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -1125,21 +1125,21 @@ class MergeRequest < ActiveRecord::Base
project.merge_requests.merged.where(author_id: author_id).empty?
end
- def allow_maintainer_to_push
- maintainer_push_possible? && super
+ def allow_collaboration
+ collaborative_push_possible? && super
end
- alias_method :allow_maintainer_to_push?, :allow_maintainer_to_push
+ alias_method :allow_collaboration?, :allow_collaboration
- def maintainer_push_possible?
+ def collaborative_push_possible?
source_project.present? && for_fork? &&
target_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE &&
source_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE &&
!ProtectedBranch.protected?(source_project, source_branch)
end
- def can_allow_maintainer_to_push?(user)
- maintainer_push_possible? &&
+ def can_allow_collaboration?(user)
+ collaborative_push_possible? &&
Ability.allowed?(user, :push_code, source_project)
end
diff --git a/app/models/note.rb b/app/models/note.rb
index 02f7a9b1e4f..41c04ae0571 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -435,6 +435,10 @@ class Note < ActiveRecord::Base
super.merge(noteable: noteable)
end
+ def retrieve_upload(_identifier, paths)
+ Upload.find_by(model: self, path: paths)
+ end
+
private
def keep_around_commit
diff --git a/app/models/personal_snippet.rb b/app/models/personal_snippet.rb
index 82c1c4de3a0..355624fd552 100644
--- a/app/models/personal_snippet.rb
+++ b/app/models/personal_snippet.rb
@@ -1,2 +1,3 @@
class PersonalSnippet < Snippet
+ include WithUploads
end
diff --git a/app/models/project.rb b/app/models/project.rb
index a094dbcb747..562198e2369 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -228,6 +228,7 @@ class Project < ActiveRecord::Base
has_many :commit_statuses
has_many :pipelines, class_name: 'Ci::Pipeline', inverse_of: :project
+ has_many :stages, class_name: 'Ci::Stage', inverse_of: :project
# Ci::Build objects store data on the file system such as artifact files and
# build traces. Currently there's no efficient way of removing this data in
@@ -1425,8 +1426,14 @@ class Project < ActiveRecord::Base
Ci::Runner.from("(#{union.to_sql}) ci_runners")
end
+ def active_runners
+ strong_memoize(:active_runners) do
+ all_runners.active
+ end
+ end
+
def any_runners?(&block)
- all_runners.active.any?(&block)
+ active_runners.any?(&block)
end
def valid_runners_token?(token)
@@ -1968,18 +1975,18 @@ class Project < ActiveRecord::Base
.limit(1)
.select(1)
source_of_merge_requests.opened
- .where(allow_maintainer_to_push: true)
+ .where(allow_collaboration: true)
.where('EXISTS (?)', developer_access_exists)
end
- def branch_allows_maintainer_push?(user, branch_name)
+ def branch_allows_collaboration?(user, branch_name)
return false unless user
cache_key = "user:#{user.id}:#{branch_name}:branch_allows_push"
- memoized_results = strong_memoize(:branch_allows_maintainer_push) do
+ memoized_results = strong_memoize(:branch_allows_collaboration) do
Hash.new do |result, cache_key|
- result[cache_key] = fetch_branch_allows_maintainer_push?(user, branch_name)
+ result[cache_key] = fetch_branch_allows_collaboration?(user, branch_name)
end
end
@@ -2121,18 +2128,18 @@ class Project < ActiveRecord::Base
raise ex
end
- def fetch_branch_allows_maintainer_push?(user, branch_name)
+ def fetch_branch_allows_collaboration?(user, branch_name)
check_access = -> do
next false if empty_repo?
merge_request = source_of_merge_requests.opened
- .where(allow_maintainer_to_push: true)
+ .where(allow_collaboration: true)
.find_by(source_branch: branch_name)
merge_request&.can_be_merged_by?(user)
end
if RequestStore.active?
- RequestStore.fetch("project-#{id}:branch-#{branch_name}:user-#{user.id}:branch_allows_maintainer_push") do
+ RequestStore.fetch("project-#{id}:branch-#{branch_name}:user-#{user.id}:branch_allows_collaboration") do
check_access.call
end
else
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 82cf47ba04e..0784891d1bf 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -270,6 +270,16 @@ class Repository
end
end
+ def archive_metadata(ref, storage_path, format = "tar.gz", append_sha:)
+ raw_repository.archive_metadata(
+ ref,
+ storage_path,
+ project.path,
+ format,
+ append_sha: append_sha
+ )
+ end
+
def expire_tags_cache
expire_method_caches(%i(tag_names tag_count))
@tags = nil
diff --git a/app/models/term_agreement.rb b/app/models/term_agreement.rb
index 8458a231bbd..c317bd0c90b 100644
--- a/app/models/term_agreement.rb
+++ b/app/models/term_agreement.rb
@@ -2,5 +2,7 @@ class TermAgreement < ActiveRecord::Base
belongs_to :term, class_name: 'ApplicationSetting::Term'
belongs_to :user
+ scope :accepted, -> { where(accepted: true) }
+
validates :user, :term, presence: true
end
diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb
index 8b65758f3e8..1c0cc7425ec 100644
--- a/app/policies/ci/build_policy.rb
+++ b/app/policies/ci/build_policy.rb
@@ -14,8 +14,8 @@ module Ci
@subject.triggered_by?(@user)
end
- condition(:branch_allows_maintainer_push) do
- @subject.project.branch_allows_maintainer_push?(@user, @subject.ref)
+ condition(:branch_allows_collaboration) do
+ @subject.project.branch_allows_collaboration?(@user, @subject.ref)
end
rule { protected_ref }.policy do
@@ -25,7 +25,7 @@ module Ci
rule { can?(:admin_build) | (can?(:update_build) & owner_of_job) }.enable :erase_build
- rule { can?(:public_access) & branch_allows_maintainer_push }.policy do
+ rule { can?(:public_access) & branch_allows_collaboration }.policy do
enable :update_build
enable :update_commit_status
end
diff --git a/app/policies/ci/pipeline_policy.rb b/app/policies/ci/pipeline_policy.rb
index 540e4235299..b81329d0625 100644
--- a/app/policies/ci/pipeline_policy.rb
+++ b/app/policies/ci/pipeline_policy.rb
@@ -4,13 +4,13 @@ module Ci
condition(:protected_ref) { ref_protected?(@user, @subject.project, @subject.tag?, @subject.ref) }
- condition(:branch_allows_maintainer_push) do
- @subject.project.branch_allows_maintainer_push?(@user, @subject.ref)
+ condition(:branch_allows_collaboration) do
+ @subject.project.branch_allows_collaboration?(@user, @subject.ref)
end
rule { protected_ref }.prevent :update_pipeline
- rule { can?(:public_access) & branch_allows_maintainer_push }.policy do
+ rule { can?(:public_access) & branch_allows_collaboration }.policy do
enable :update_pipeline
end
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index 141070aef45..8260c6c7b84 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -13,7 +13,7 @@ class MergeRequestWidgetEntity < IssuableEntity
expose :squash
expose :target_branch
expose :target_project_id
- expose :allow_maintainer_to_push
+ expose :allow_collaboration
expose :should_be_rebased?, as: :should_be_rebased
expose :ff_only_enabled do |merge_request|
diff --git a/app/serializers/pipeline_details_entity.rb b/app/serializers/pipeline_details_entity.rb
index 130968a44c1..8ba9cac53c4 100644
--- a/app/serializers/pipeline_details_entity.rb
+++ b/app/serializers/pipeline_details_entity.rb
@@ -1,6 +1,6 @@
class PipelineDetailsEntity < PipelineEntity
expose :details do
- expose :legacy_stages, as: :stages, using: StageEntity
+ expose :ordered_stages, as: :stages, using: StageEntity
expose :artifacts, using: BuildArtifactEntity
expose :manual_actions, using: BuildActionEntity
end
diff --git a/app/serializers/pipeline_serializer.rb b/app/serializers/pipeline_serializer.rb
index 7181f8a6b04..17a022539bb 100644
--- a/app/serializers/pipeline_serializer.rb
+++ b/app/serializers/pipeline_serializer.rb
@@ -1,14 +1,11 @@
class PipelineSerializer < BaseSerializer
include WithPagination
-
- InvalidResourceError = Class.new(StandardError)
-
entity PipelineDetailsEntity
def represent(resource, opts = {})
if resource.is_a?(ActiveRecord::Relation)
-
resource = resource.preload([
+ :stages,
:retryable_builds,
:cancelable_statuses,
:trigger_requests,
@@ -20,10 +17,14 @@ class PipelineSerializer < BaseSerializer
end
if paginated?
- super(@paginator.paginate(resource), opts)
- else
- super(resource, opts)
+ resource = paginator.paginate(resource)
end
+
+ if opts.delete(:preload)
+ resource = Gitlab::Ci::Pipeline::Preloader.preload!(resource)
+ end
+
+ super(resource, opts)
end
def represent_status(resource)
@@ -36,7 +37,7 @@ class PipelineSerializer < BaseSerializer
def represent_stages(resource)
return {} unless resource.present?
- data = represent(resource, { only: [{ details: [:stages] }] })
+ data = represent(resource, { only: [{ details: [:stages] }], preload: true })
data.dig(:details, :stages) || []
end
end
diff --git a/app/services/application_settings/update_service.rb b/app/services/application_settings/update_service.rb
index e70445cfb67..7bcb8f49d0d 100644
--- a/app/services/application_settings/update_service.rb
+++ b/app/services/application_settings/update_service.rb
@@ -1,5 +1,7 @@
module ApplicationSettings
class UpdateService < ApplicationSettings::BaseService
+ attr_reader :params, :application_setting
+
def execute
update_terms(@params.delete(:terms))
diff --git a/app/services/applications/create_service.rb b/app/services/applications/create_service.rb
index 35d45f25a71..e67af929954 100644
--- a/app/services/applications/create_service.rb
+++ b/app/services/applications/create_service.rb
@@ -2,8 +2,7 @@ module Applications
class CreateService
def initialize(current_user, params)
@current_user = current_user
- @params = params
- @ip_address = @params.delete(:ip_address)
+ @params = params.except(:ip_address)
end
def execute(request = nil)
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index 231ab76fde4..4c420b38258 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -38,8 +38,8 @@ module MergeRequests
def filter_params(merge_request)
super
- unless merge_request.can_allow_maintainer_to_push?(current_user)
- params.delete(:allow_maintainer_to_push)
+ unless merge_request.can_allow_collaboration?(current_user)
+ params.delete(:allow_collaboration)
end
end
diff --git a/app/services/test_hooks/project_service.rb b/app/services/test_hooks/project_service.rb
index 01d5d774cd5..65183e84cce 100644
--- a/app/services/test_hooks/project_service.rb
+++ b/app/services/test_hooks/project_service.rb
@@ -1,11 +1,13 @@
module TestHooks
class ProjectService < TestHooks::BaseService
- private
+ attr_writer :project
def project
@project ||= hook.project
end
+ private
+
def push_events_data
throw(:validation_error, 'Ensure the project has at least one commit.') if project.empty_repo?
diff --git a/app/uploaders/object_storage.rb b/app/uploaders/object_storage.rb
index 3bb2e1ea63a..5aa1bc7227c 100644
--- a/app/uploaders/object_storage.rb
+++ b/app/uploaders/object_storage.rb
@@ -33,7 +33,7 @@ module ObjectStorage
unless current_upload_satisfies?(paths, model)
# the upload we already have isn't right, find the correct one
- self.upload = uploads.find_by(model: model, path: paths)
+ self.upload = model&.retrieve_upload(identifier, paths)
end
super
@@ -46,7 +46,7 @@ module ObjectStorage
end
def upload=(upload)
- return unless upload
+ return if upload.nil?
self.object_store = upload.store
super
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 0a22a142858..ccba1c461fc 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -116,8 +116,8 @@
.card-body
= form_for @project, url: transfer_admin_project_path(@project), method: :put do |f|
.form-group.row
- = f.label :new_namespace_id, "Namespace", class: 'col-form-label col-sm-2'
- .col-sm-10
+ = f.label :new_namespace_id, "Namespace", class: 'col-form-label col-sm-3'
+ .col-sm-9
.dropdown
= dropdown_toggle('Search for Namespace', { toggle: 'dropdown', field_name: 'new_namespace_id' }, { toggle_class: 'js-namespace-select large' })
.dropdown-menu.dropdown-select
@@ -127,7 +127,7 @@
= dropdown_loading
.form-group.row
- .offset-sm-2.col-sm-10
+ .offset-sm-3.col-sm-9
= f.submit 'Transfer', class: 'btn btn-primary'
.card.repository-check
diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index f38aeb151df..8dfd176f1b7 100644
--- a/app/views/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -67,7 +67,7 @@
%th Projects
%th Jobs
%th Tags
- %th= link_to 'Last contact', admin_runners_path(params.slice(:search).merge(sort: 'contacted_asc'))
+ %th= link_to 'Last contact', admin_runners_path(safe_params.slice(:search).merge(sort: 'contacted_asc'))
%th
- @runners.each do |runner|
diff --git a/app/views/groups/_activities.html.haml b/app/views/groups/_activities.html.haml
index fd6e7111f38..577c63503a8 100644
--- a/app/views/groups/_activities.html.haml
+++ b/app/views/groups/_activities.html.haml
@@ -1,4 +1,4 @@
-.nav-block
+.nav-block.activities
.controls
= link_to group_path(@group, rss_url_options), class: 'btn rss-btn has-tooltip' , title: 'Subscribe' do
%i.fa.fa-rss
diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml
index 29db29235c1..c23fe0b5c49 100644
--- a/app/views/help/_shortcuts.html.haml
+++ b/app/views/help/_shortcuts.html.haml
@@ -18,71 +18,71 @@
%th Global Shortcuts
%tr
%td.shortcut
- .key s
+ %kbd s
%td Focus Search
%tr
%td.shortcut
- .key f
+ %kbd f
%td Focus Filter
- if performance_bar_enabled?
%tr
%td.shortcut
- .key p b
+ %kbd p b
%td Show/hide the Performance Bar
%tr
%td.shortcut
- .key ?
+ %kbd ?
%td Show/hide this dialog
%tr
%td.shortcut
- if browser.platform.mac?
- .key &#8984; shift p
+ %kbd &#8984; shift p
- else
- .key ctrl shift p
+ %kbd ctrl shift p
%td Toggle Markdown preview
%tr
%td.shortcut
- .key
+ %kbd
%i.fa.fa-arrow-up
%td Edit last comment (when focused on an empty textarea)
%tr
%td.shortcut
- .key shift t
+ %kbd shift t
%td
Go to todos
%tr
%td.shortcut
- .key shift a
+ %kbd shift a
%td
Go to the activity feed
%tr
%td.shortcut
- .key shift p
+ %kbd shift p
%td
Go to projects
%tr
%td.shortcut
- .key shift i
+ %kbd shift i
%td
Go to issues
%tr
%td.shortcut
- .key shift m
+ %kbd shift m
%td
Go to merge requests
%tr
%td.shortcut
- .key shift g
+ %kbd shift g
%td
Go to groups
%tr
%td.shortcut
- .key shift l
+ %kbd shift l
%td
Go to milestones
%tr
%td.shortcut
- .key shift s
+ %kbd shift s
%td
Go to snippets
%tbody
@@ -91,21 +91,21 @@
%th Finding Project File
%tr
%td.shortcut
- .key
+ %kbd
%i.fa.fa-arrow-up
%td Move selection up
%tr
%td.shortcut
- .key
+ %kbd
%i.fa.fa-arrow-down
%td Move selection down
%tr
%td.shortcut
- .key enter
+ %kbd enter
%td Open Selection
%tr
%td.shortcut
- .key esc
+ %kbd esc
%td Go back
.col-lg-4
%table.shortcut-mappings
@@ -115,95 +115,95 @@
%th Project
%tr
%td.shortcut
- .key g
- .key p
+ %kbd g
+ %kbd p
%td
Go to the project's overview page
%tr
%td.shortcut
- .key g
- .key v
+ %kbd g
+ %kbd v
%td
Go to the project's activity feed
%tr
%td.shortcut
- .key g
- .key f
+ %kbd g
+ %kbd f
%td
Go to files
%tr
%td.shortcut
- .key g
- .key c
+ %kbd g
+ %kbd c
%td
Go to commits
%tr
%td.shortcut
- .key g
- .key j
+ %kbd g
+ %kbd j
%td
Go to jobs
%tr
%td.shortcut
- .key g
- .key n
+ %kbd g
+ %kbd n
%td
Go to network graph
%tr
%td.shortcut
- .key g
- .key d
+ %kbd g
+ %kbd d
%td
Go to repository charts
%tr
%td.shortcut
- .key g
- .key i
+ %kbd g
+ %kbd i
%td
Go to issues
%tr
%td.shortcut
- .key g
- .key b
+ %kbd g
+ %kbd b
%td
Go to issue boards
%tr
%td.shortcut
- .key g
- .key m
+ %kbd g
+ %kbd m
%td
Go to merge requests
%tr
%td.shortcut
- .key g
- .key e
+ %kbd g
+ %kbd e
%td
Go to environments
%tr
%td.shortcut
- .key g
- .key k
+ %kbd g
+ %kbd k
%td
Go to kubernetes
%tr
%td.shortcut
- .key g
- .key s
+ %kbd g
+ %kbd s
%td
Go to snippets
%tr
%td.shortcut
- .key g
- .key w
+ %kbd g
+ %kbd w
%td
Go to wiki
%tr
%td.shortcut
- .key t
+ %kbd t
%td Go to finding file
%tr
%td.shortcut
- .key i
+ %kbd i
%td New issue
%tbody
@@ -212,17 +212,17 @@
%th Project Files browsing
%tr
%td.shortcut
- .key
+ %kbd
%i.fa.fa-arrow-up
%td Move selection up
%tr
%td.shortcut
- .key
+ %kbd
%i.fa.fa-arrow-down
%td Move selection down
%tr
%td.shortcut
- .key enter
+ %kbd enter
%td Open Selection
%tbody
%tr
@@ -230,7 +230,7 @@
%th Project File
%tr
%td.shortcut
- .key y
+ %kbd y
%td Go to file permalink
%tbody
%tr
@@ -239,115 +239,115 @@
%tr
%td.shortcut
- if browser.platform.mac?
- .key &#8984; p
+ %kbd &#8984; p
- else
- .key ctrl p
+ %kbd ctrl p
%td Go to file
.col-lg-4
%table.shortcut-mappings
- %tbody.hidden-shortcut.network{ style: 'display:none' }
+ %tbody.hidden-shortcut{ style: 'display:none' }
%tr
%th
%th Network Graph
%tr
%td.shortcut
- .key
+ %kbd
%i.fa.fa-arrow-left
\/
- .key h
+ %kbd h
%td Scroll left
%tr
%td.shortcut
- .key
+ %kbd
%i.fa.fa-arrow-right
\/
- .key l
+ %kbd l
%td Scroll right
%tr
%td.shortcut
- .key
+ %kbd
%i.fa.fa-arrow-up
\/
- .key k
+ %kbd k
%td Scroll up
%tr
%td.shortcut
- .key
+ %kbd
%i.fa.fa-arrow-down
\/
- .key j
+ %kbd j
%td Scroll down
%tr
%td.shortcut
- .key
+ %kbd
shift
%i.fa.fa-arrow-up
\/
- .key
+ %kbd
shift k
%td Scroll to top
%tr
%td.shortcut
- .key
+ %kbd
shift
%i.fa.fa-arrow-down
\/
- .key
+ %kbd
shift j
%td Scroll to bottom
- %tbody.hidden-shortcut.issues{ style: 'display:none' }
+ %tbody.hidden-shortcut{ style: 'display:none' }
%tr
%th
%th Issues
%tr
%td.shortcut
- .key a
+ %kbd a
%td Change assignee
%tr
%td.shortcut
- .key m
+ %kbd m
%td Change milestone
%tr
%td.shortcut
- .key r
+ %kbd r
%td Reply (quoting selected text)
%tr
%td.shortcut
- .key e
+ %kbd e
%td Edit issue
%tr
%td.shortcut
- .key l
+ %kbd l
%td Change Label
- %tbody.hidden-shortcut.merge_requests{ style: 'display:none' }
+ %tbody.hidden-shortcut{ style: 'display:none' }
%tr
%th
%th Merge Requests
%tr
%td.shortcut
- .key a
+ %kbd a
%td Change assignee
%tr
%td.shortcut
- .key m
+ %kbd m
%td Change milestone
%tr
%td.shortcut
- .key r
+ %kbd r
%td Reply (quoting selected text)
%tr
%td.shortcut
- .key e
+ %kbd e
%td Edit merge request
%tr
%td.shortcut
- .key l
+ %kbd l
%td Change Label
- %tbody.hidden-shortcut.wiki{ style: 'display:none' }
+ %tbody.hidden-shortcut{ style: 'display:none' }
%tr
%th
%th Wiki pages
%tr
%td.shortcut
- .key e
+ %kbd e
%td Edit wiki page
diff --git a/app/views/kaminari/gitlab/_first_page.html.haml b/app/views/kaminari/gitlab/_first_page.html.haml
index 369165da02a..3b7d4a1c578 100644
--- a/app/views/kaminari/gitlab/_first_page.html.haml
+++ b/app/views/kaminari/gitlab/_first_page.html.haml
@@ -5,5 +5,5 @@
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
-%li.first.page-item
+%li.page-item.js-first-button
= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote, class: 'page-link'
diff --git a/app/views/kaminari/gitlab/_gap.html.haml b/app/views/kaminari/gitlab/_gap.html.haml
index 6eec30212d1..849f92fdc95 100644
--- a/app/views/kaminari/gitlab/_gap.html.haml
+++ b/app/views/kaminari/gitlab/_gap.html.haml
@@ -4,5 +4,5 @@
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
-%li.page-item.disabled
+%li.page-item.disabled.d-none.d-md-block
= link_to raw(t 'views.pagination.truncate'), '#', class: 'page-link'
diff --git a/app/views/kaminari/gitlab/_last_page.html.haml b/app/views/kaminari/gitlab/_last_page.html.haml
index 8b49db58281..7836e17f877 100644
--- a/app/views/kaminari/gitlab/_last_page.html.haml
+++ b/app/views/kaminari/gitlab/_last_page.html.haml
@@ -5,5 +5,5 @@
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
-%li.last.page-item
+%li.page-item.js-last-button
= link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {remote: remote, class: 'page-link'}
diff --git a/app/views/kaminari/gitlab/_next_page.html.haml b/app/views/kaminari/gitlab/_next_page.html.haml
index 05f151555ad..a7fa1a21a6c 100644
--- a/app/views/kaminari/gitlab/_next_page.html.haml
+++ b/app/views/kaminari/gitlab/_next_page.html.haml
@@ -8,5 +8,5 @@
- page_url = current_page.last? ? '#' : url
-%li.page-item{ class: ('disabled' if current_page.last?) }
+%li.page-item.js-next-button{ class: ('disabled' if current_page.last?) }
= link_to raw(t 'views.pagination.next'), page_url, rel: 'next', remote: remote, class: 'page-link'
diff --git a/app/views/kaminari/gitlab/_page.html.haml b/app/views/kaminari/gitlab/_page.html.haml
index 8a40e13a537..d0dc1784540 100644
--- a/app/views/kaminari/gitlab/_page.html.haml
+++ b/app/views/kaminari/gitlab/_page.html.haml
@@ -6,5 +6,5 @@
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
-%li.page-item.js-pagination-page{ class: [active_when(page.current?), ('sibling' if page.next? || page.prev?)] }
+%li.page-item.js-pagination-page{ class: [active_when(page.current?), ('sibling' if page.next? || page.prev?), ('d-none d-md-block' if !page.current?) ] }
= link_to page, url, { remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil, class: 'page-link' }
diff --git a/app/views/kaminari/gitlab/_paginator.html.haml b/app/views/kaminari/gitlab/_paginator.html.haml
index a6435deb4bf..ac9e274dbc7 100644
--- a/app/views/kaminari/gitlab/_paginator.html.haml
+++ b/app/views/kaminari/gitlab/_paginator.html.haml
@@ -6,7 +6,7 @@
-# remote: data-remote
-# paginator: the paginator that renders the pagination tags inside
= paginator.render do
- .gl-pagination
+ .gl-pagination.prepend-top-default
%ul.pagination.justify-content-center
- unless current_page.first?
= first_page_tag unless total_pages < 5 # As kaminari will always show the first 5 pages
diff --git a/app/views/kaminari/gitlab/_prev_page.html.haml b/app/views/kaminari/gitlab/_prev_page.html.haml
index f4a11a449b7..12b0e106a62 100644
--- a/app/views/kaminari/gitlab/_prev_page.html.haml
+++ b/app/views/kaminari/gitlab/_prev_page.html.haml
@@ -8,5 +8,5 @@
- page_url = current_page.first? ? '#' : url
-%li.page-item{ class: ('disabled' if current_page.first?) }
+%li.page-item.js-previous-button{ class: ('disabled' if current_page.first?) }
= link_to raw(t 'views.pagination.previous'), page_url, rel: 'prev', remote: remote, class: 'page-link'
diff --git a/app/views/kaminari/gitlab/_without_count.html.haml b/app/views/kaminari/gitlab/_without_count.html.haml
index 1425a809052..f780400ebcb 100644
--- a/app/views/kaminari/gitlab/_without_count.html.haml
+++ b/app/views/kaminari/gitlab/_without_count.html.haml
@@ -1,5 +1,5 @@
-.gl-pagination
- %ul.pagination.clearfix
+.gl-pagination.prepend-top-default
+ %ul.pagination.justify-content-center
- if previous_path
%li.page-item.prev
= link_to(t('views.pagination.previous'), previous_path, rel: 'prev', class: 'page-link')
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 35a09f06bfa..5bb1bfb7059 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -29,16 +29,16 @@
.col-lg-9.js-toggle-container
%ul.nav.nav-tabs.nav-links.gitlab-tabs{ role: 'tablist' }
- %li{ class: active_when(active_tab == 'blank'), role: 'presentation' }
- %a{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' }
+ %li.nav-item{ role: 'presentation' }
+ %a.nav-link.active{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.d-none.d-sm-block Blank project
%span.d-block.d-sm-none Blank
- %li{ class: active_when(active_tab == 'template'), role: 'presentation' }
- %a{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' }
+ %li.nav-item{ role: 'presentation' }
+ %a.nav-link{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.d-none.d-sm-block Create from template
%span.d-block.d-sm-none Template
- %li{ class: active_when(active_tab == 'import'), role: 'presentation' }
- %a{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' }
+ %li.nav-item{ role: 'presentation' }
+ %a.nav-link{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.d-none.d-sm-block Import project
%span.d-block.d-sm-none Import
diff --git a/app/views/projects/pages/_destroy.haml b/app/views/projects/pages/_destroy.haml
index 4ada19a1368..9b77c4e3494 100644
--- a/app/views/projects/pages/_destroy.haml
+++ b/app/views/projects/pages/_destroy.haml
@@ -5,7 +5,7 @@
.errors-holder
.card-body
%p
- Removing the pages will prevent from exposing them to outside world.
+ Removing pages will prevent them from being exposed to the outside world.
.form-actions
= link_to 'Remove pages', project_pages_path(@project), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove"
- else
diff --git a/app/views/shared/issuable/form/_contribution.html.haml b/app/views/shared/issuable/form/_contribution.html.haml
index b34549240e0..519b5fae846 100644
--- a/app/views/shared/issuable/form/_contribution.html.haml
+++ b/app/views/shared/issuable/form/_contribution.html.haml
@@ -12,9 +12,9 @@
= _('Contribution')
.col-sm-10
.form-check
- = form.check_box :allow_maintainer_to_push, disabled: !issuable.can_allow_maintainer_to_push?(current_user), class: 'form-check-input'
- = form.label :allow_maintainer_to_push, class: 'form-check-label' do
- = _('Allow edits from maintainers.')
- = link_to 'About this feature', help_page_path('user/project/merge_requests/maintainer_access')
+ = form.check_box :allow_collaboration, disabled: !issuable.can_allow_collaboration?(current_user), class: 'form-check-input'
+ = form.label :allow_collaboration, class: 'form-check-label' do
+ = _('Allow commits from members who can merge to the target branch.')
+ = link_to 'About this feature', help_page_path('user/project/merge_requests/allow_collaboration')
.form-text.text-muted
- = allow_maintainer_push_unavailable_reason(issuable)
+ = allow_collaboration_unavailable_reason(issuable)
diff --git a/app/views/shared/projects/_edit_information.html.haml b/app/views/shared/projects/_edit_information.html.haml
index ec9dc8f62c2..9230e045a81 100644
--- a/app/views/shared/projects/_edit_information.html.haml
+++ b/app/views/shared/projects/_edit_information.html.haml
@@ -1,6 +1,6 @@
- unless can?(current_user, :push_code, @project)
.inline.prepend-left-10
- - if @project.branch_allows_maintainer_push?(current_user, selected_branch)
+ - if @project.branch_allows_collaboration?(current_user, selected_branch)
= commit_in_single_accessible_branch
- else
= commit_in_fork_help
diff --git a/app/views/users/terms/index.html.haml b/app/views/users/terms/index.html.haml
index b9f25a71170..33cddf63952 100644
--- a/app/views/users/terms/index.html.haml
+++ b/app/views/users/terms/index.html.haml
@@ -7,6 +7,10 @@
.float-right
= button_to accept_term_path(@term, redirect_params), class: 'btn btn-success prepend-left-8' do
= _('Accept terms')
+ - else
+ .pull-right
+ = link_to root_path, class: 'btn btn-success prepend-left-8' do
+ = _('Continue')
- if can?(current_user, :decline_terms, @term)
.float-right
= button_to decline_term_path(@term, redirect_params), class: 'btn btn-default prepend-left-8' do