diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-16 18:08:22 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-16 18:08:22 +0000 |
commit | 123c68a7cf788ace140e57e478a12c5b7ac893ae (patch) | |
tree | b36e565ecd895ee46c1713f3734308cfce0e6ba9 /app | |
parent | 862d225ca0d8eb452e56b8fe5a0109aac796e872 (diff) | |
download | gitlab-ce-123c68a7cf788ace140e57e478a12c5b7ac893ae.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
21 files changed, 142 insertions, 130 deletions
diff --git a/app/assets/javascripts/error_tracking/components/error_tracking_list.vue b/app/assets/javascripts/error_tracking/components/error_tracking_list.vue index 23e251e4201..8e2128ac713 100644 --- a/app/assets/javascripts/error_tracking/components/error_tracking_list.vue +++ b/app/assets/javascripts/error_tracking/components/error_tracking_list.vue @@ -12,13 +12,18 @@ import { GlDropdownItem, GlDropdownDivider, GlTooltipDirective, + GlPagination, } from '@gitlab/ui'; import AccessorUtils from '~/lib/utils/accessor'; import Icon from '~/vue_shared/components/icon.vue'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import { __ } from '~/locale'; +import _ from 'underscore'; export default { + FIRST_PAGE: 1, + PREV_PAGE: 1, + NEXT_PAGE: 2, fields: [ { key: 'error', label: __('Open errors'), thClass: 'w-70p' }, { key: 'events', label: __('Events') }, @@ -42,6 +47,7 @@ export default { GlTable, GlFormInput, Icon, + GlPagination, TimeAgo, }, directives: { @@ -73,10 +79,28 @@ export default { data() { return { errorSearchQuery: '', + pageValue: this.$options.FIRST_PAGE, }; }, computed: { - ...mapState('list', ['errors', 'loading', 'searchQuery', 'sortField', 'recentSearches']), + ...mapState('list', [ + 'errors', + 'loading', + 'searchQuery', + 'sortField', + 'recentSearches', + 'pagination', + ]), + paginationRequired() { + return !_.isEmpty(this.pagination); + }, + }, + watch: { + pagination() { + if (typeof this.pagination.previous === 'undefined') { + this.pageValue = this.$options.FIRST_PAGE; + } + }, }, created() { if (this.errorTrackingEnabled) { @@ -103,6 +127,17 @@ export default { getDetailsLink(errorId) { return `error_tracking/${errorId}/details`; }, + goToNextPage() { + this.pageValue = this.$options.NEXT_PAGE; + this.startPolling(`${this.indexPath}?cursor=${this.pagination.next.cursor}`); + }, + goToPrevPage() { + this.startPolling(`${this.indexPath}?cursor=${this.pagination.previous.cursor}`); + }, + goToPage(page) { + window.scrollTo(0, 0); + return page === this.$options.PREV_PAGE ? this.goToPrevPage() : this.goToNextPage(); + }, isCurrentSortField(field) { return field === this.sortField; }, @@ -217,7 +252,6 @@ export default { </span> </div> </template> - <template slot="events" slot-scope="errors"> <div class="text-md-right">{{ errors.item.count }}</div> </template> @@ -240,6 +274,15 @@ export default { </div> </template> </gl-table> + <gl-pagination + v-show="!loading" + v-if="paginationRequired" + :prev-page="$options.PREV_PAGE" + :next-page="$options.NEXT_PAGE" + :value="pageValue" + align="center" + @input="goToPage" + /> </div> <div v-else-if="userCanEnableErrorTracking"> <gl-empty-state diff --git a/app/assets/javascripts/error_tracking/store/list/actions.js b/app/assets/javascripts/error_tracking/store/list/actions.js index b1c81b55e58..c9e882c4ed2 100644 --- a/app/assets/javascripts/error_tracking/store/list/actions.js +++ b/app/assets/javascripts/error_tracking/store/list/actions.js @@ -23,6 +23,7 @@ export function startPolling({ state, commit, dispatch }) { if (!data) { return; } + commit(types.SET_PAGINATION, data.pagination); commit(types.SET_ERRORS, data.errors); commit(types.SET_LOADING, false); dispatch('stopPolling'); diff --git a/app/assets/javascripts/error_tracking/store/list/mutation_types.js b/app/assets/javascripts/error_tracking/store/list/mutation_types.js index 3ebfef76324..301984a1ee0 100644 --- a/app/assets/javascripts/error_tracking/store/list/mutation_types.js +++ b/app/assets/javascripts/error_tracking/store/list/mutation_types.js @@ -4,6 +4,7 @@ export const SET_LOADING = 'SET_LOADING'; export const ADD_RECENT_SEARCH = 'ADD_RECENT_SEARCH'; export const CLEAR_RECENT_SEARCHES = 'CLEAR_RECENT_SEARCHES'; export const LOAD_RECENT_SEARCHES = 'LOAD_RECENT_SEARCHES'; +export const SET_PAGINATION = 'SET_PAGINATION'; export const SET_ENDPOINT = 'SET_ENDPOINT'; export const SET_SORT_FIELD = 'SET_SORT_FIELD'; export const SET_SEARCH_QUERY = 'SET_SEARCH_QUERY'; diff --git a/app/assets/javascripts/error_tracking/store/list/mutations.js b/app/assets/javascripts/error_tracking/store/list/mutations.js index 048660eaeeb..5648013bb89 100644 --- a/app/assets/javascripts/error_tracking/store/list/mutations.js +++ b/app/assets/javascripts/error_tracking/store/list/mutations.js @@ -44,6 +44,9 @@ export default { throw e; } }, + [types.SET_PAGINATION](state, pagination) { + state.pagination = pagination; + }, [types.SET_SORT_FIELD](state, field) { state.sortField = field; }, diff --git a/app/assets/javascripts/error_tracking/store/list/state.js b/app/assets/javascripts/error_tracking/store/list/state.js index f20b707142e..93dc1040fde 100644 --- a/app/assets/javascripts/error_tracking/store/list/state.js +++ b/app/assets/javascripts/error_tracking/store/list/state.js @@ -6,4 +6,5 @@ export default () => ({ searchQuery: null, indexPath: '', recentSearches: [], + pagination: {}, }); diff --git a/app/assets/javascripts/ide/stores/utils.js b/app/assets/javascripts/ide/stores/utils.js index be7ee80656f..a29d9bf3b40 100644 --- a/app/assets/javascripts/ide/stores/utils.js +++ b/app/assets/javascripts/ide/stores/utils.js @@ -162,7 +162,7 @@ export const createCommitPayload = ({ }); export const createNewMergeRequestUrl = (projectUrl, source, target) => - `${projectUrl}/merge_requests/new?merge_request[source_branch]=${source}&merge_request[target_branch]=${target}&nav_source=webide`; + `${projectUrl}/-/merge_requests/new?merge_request[source_branch]=${source}&merge_request[target_branch]=${target}&nav_source=webide`; const sortTreesByTypeAndName = (a, b) => { if (a.type === 'tree' && b.type === 'blob') { diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index 52674107df2..8d09e88e772 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -32,17 +32,17 @@ import { __ } from './locale'; // // <ul class="nav-links merge-request-tabs"> // <li class="notes-tab active"> -// <a data-action="notes" data-target="#notes" data-toggle="tab" href="/foo/bar/merge_requests/1"> +// <a data-action="notes" data-target="#notes" data-toggle="tab" href="/foo/bar/-/merge_requests/1"> // Discussion // </a> // </li> // <li class="commits-tab"> -// <a data-action="commits" data-target="#commits" data-toggle="tab" href="/foo/bar/merge_requests/1/commits"> +// <a data-action="commits" data-target="#commits" data-toggle="tab" href="/foo/bar/-/merge_requests/1/commits"> // Commits // </a> // </li> // <li class="diffs-tab"> -// <a data-action="diffs" data-target="#diffs" data-toggle="tab" href="/foo/bar/merge_requests/1/diffs"> +// <a data-action="diffs" data-target="#diffs" data-toggle="tab" href="/foo/bar/-/merge_requests/1/diffs"> // Diffs // </a> // </li> @@ -260,17 +260,17 @@ export default class MergeRequestTabs { // // Examples: // - // location.pathname # => "/namespace/project/merge_requests/1" + // location.pathname # => "/namespace/project/-/merge_requests/1" // setCurrentAction('diffs') - // location.pathname # => "/namespace/project/merge_requests/1/diffs" + // location.pathname # => "/namespace/project/-/merge_requests/1/diffs" // - // location.pathname # => "/namespace/project/merge_requests/1/diffs" + // location.pathname # => "/namespace/project/-/merge_requests/1/diffs" // setCurrentAction('show') - // location.pathname # => "/namespace/project/merge_requests/1" + // location.pathname # => "/namespace/project/-/merge_requests/1" // - // location.pathname # => "/namespace/project/merge_requests/1/diffs" + // location.pathname # => "/namespace/project/-/merge_requests/1/diffs" // setCurrentAction('commits') - // location.pathname # => "/namespace/project/merge_requests/1/commits" + // location.pathname # => "/namespace/project/-/merge_requests/1/commits" // // Returns the new URL String setCurrentAction(action) { diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb index 9b3b2c4a482..655575e0944 100644 --- a/app/controllers/concerns/uploads_actions.rb +++ b/app/controllers/concerns/uploads_actions.rb @@ -44,15 +44,14 @@ module UploadsActions expires_in ttl, directives - disposition = uploader.embeddable? ? 'inline' : 'attachment' - - uploaders = [uploader, *uploader.versions.values] - uploader = uploaders.find { |version| version.filename == params[:filename] } + file_uploader = [uploader, *uploader.versions.values].find do |version| + version.filename == params[:filename] + end - return render_404 unless uploader + return render_404 unless file_uploader workhorse_set_content_type! - send_upload(uploader, attachment: uploader.filename, disposition: disposition) + send_upload(file_uploader, attachment: file_uploader.filename, disposition: content_disposition) end def authorize @@ -83,6 +82,14 @@ module UploadsActions end end + def content_disposition + if uploader.embeddable? || uploader.pdf? + 'inline' + else + 'attachment' + end + end + def uploader_class raise NotImplementedError end diff --git a/app/graphql/types/permission_types/snippet.rb b/app/graphql/types/permission_types/snippet.rb index 1e21efe790a..0fc13c60983 100644 --- a/app/graphql/types/permission_types/snippet.rb +++ b/app/graphql/types/permission_types/snippet.rb @@ -10,6 +10,7 @@ module Types permission_field :read_snippet, method: :can_read_snippet? permission_field :update_snippet, method: :can_update_snippet? permission_field :admin_snippet, method: :can_admin_snippet? + permission_field :report_snippet, method: :can_report_as_spam? end end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index c7fdd009edb..d683faf6a20 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -686,6 +686,7 @@ module ProjectsHelper error_tracking user gcp + logs ] end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 4077a868373..b6c71f81a49 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -23,7 +23,6 @@ module Ci belongs_to :runner belongs_to :trigger_request belongs_to :erased_by, class_name: 'User' - belongs_to :resource_group, class_name: 'Ci::ResourceGroup', inverse_of: :builds RUNNER_FEATURES = { upload_multiple_artifacts: -> (build) { build.publishes_artifacts_reports? }, @@ -35,7 +34,6 @@ module Ci }.freeze has_one :deployment, as: :deployable, class_name: 'Deployment' - has_one :resource, class_name: 'Ci::Resource', inverse_of: :build has_many :trace_sections, class_name: 'Ci::BuildTraceSection' has_many :trace_chunks, class_name: 'Ci::BuildTraceChunk', foreign_key: :build_id @@ -443,15 +441,6 @@ module Ci environment.present? end - def requires_resource? - Feature.enabled?(:ci_resource_group, project) && - self.resource_group_id.present? && resource.nil? - end - - def retains_resource? - self.resource_group_id.present? && resource.present? - end - def starts_environment? has_environment? && self.environment_action == 'start' end diff --git a/app/models/ci/resource.rb b/app/models/ci/resource.rb deleted file mode 100644 index ee5b6546165..00000000000 --- a/app/models/ci/resource.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module Ci - class Resource < ApplicationRecord - extend Gitlab::Ci::Model - - belongs_to :resource_group, class_name: 'Ci::ResourceGroup', inverse_of: :resources - belongs_to :build, class_name: 'Ci::Build', inverse_of: :resource - - scope :free, -> { where(build: nil) } - scope :retained_by, -> (build) { where(build: build) } - end -end diff --git a/app/models/ci/resource_group.rb b/app/models/ci/resource_group.rb deleted file mode 100644 index fb562783d3d..00000000000 --- a/app/models/ci/resource_group.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -module Ci - class ResourceGroup < ApplicationRecord - extend Gitlab::Ci::Model - - belongs_to :project, inverse_of: :resource_groups - - has_many :resources, class_name: 'Ci::Resource', inverse_of: :resource_group - has_many :builds, class_name: 'Ci::Build', inverse_of: :resource_group - - validates :key, - length: { maximum: 255 }, - format: { with: Gitlab::Regex.environment_name_regex, - message: Gitlab::Regex.environment_name_regex_message } - - before_create :ensure_resource - - def retain_resource_for(build) - resources.free.limit(1).update_all(build_id: build.id) > 0 - end - - def release_resource_from(build) - resources.retained_by(build).update_all(build_id: nil) > 0 - end - - private - - def ensure_resource - # Currently we only support one resource per group, which means - # maximum one build can be set to the resource group, thus builds - # belong to the same resource group are executed once at time. - self.resources.build if self.resources.empty? - end - end -end diff --git a/app/models/project.rb b/app/models/project.rb index bc7aebee9e6..5ed47032dab 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -285,7 +285,6 @@ class Project < ApplicationRecord has_many :pipeline_schedules, class_name: 'Ci::PipelineSchedule' has_many :project_deploy_tokens has_many :deploy_tokens, through: :project_deploy_tokens - has_many :resource_groups, class_name: 'Ci::ResourceGroup', inverse_of: :project has_one :auto_devops, class_name: 'ProjectAutoDevops', inverse_of: :project, autosave: true has_many :custom_attributes, class_name: 'ProjectCustomAttribute' @@ -741,7 +740,7 @@ class Project < ApplicationRecord end def unlink_forks_upon_visibility_decrease_enabled? - Feature.enabled?(:unlink_fork_network_upon_visibility_decrease, self) + Feature.enabled?(:unlink_fork_network_upon_visibility_decrease, self, default_enabled: true) end def empty_repo? diff --git a/app/models/project_services/chat_message/merge_message.rb b/app/models/project_services/chat_message/merge_message.rb index 46313ba7bec..dc62a4c8908 100644 --- a/app/models/project_services/chat_message/merge_message.rb +++ b/app/models/project_services/chat_message/merge_message.rb @@ -62,7 +62,7 @@ module ChatMessage end def merge_request_url - "#{project_url}/merge_requests/#{merge_request_iid}" + "#{project_url}/-/merge_requests/#{merge_request_iid}" end # overridden in EE diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 019bd54f48c..c92e8ecb31c 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -184,7 +184,7 @@ class HipchatService < Service description = obj_attr[:description] title = render_line(obj_attr[:title]) - merge_request_url = "#{project_url}/merge_requests/#{merge_request_id}" + merge_request_url = "#{project_url}/-/merge_requests/#{merge_request_id}" merge_request_link = "<a href=\"#{merge_request_url}\">merge request !#{merge_request_id}</a>" message = ["#{user_name} #{state} #{merge_request_link} in " \ "#{project_link}: <b>#{title}</b>"] diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb index e1efd84e510..d092a2de882 100644 --- a/app/policies/user_policy.rb +++ b/app/policies/user_policy.rb @@ -10,6 +10,9 @@ class UserPolicy < BasePolicy desc "The profile is private" condition(:private_profile, scope: :subject, score: 0) { @subject.private_profile? } + desc "The user is blocked" + condition(:blocked_user, scope: :subject, score: 0) { @subject.blocked? } + rule { ~restricted_public_level }.enable :read_user rule { ~anonymous }.enable :read_user @@ -20,5 +23,5 @@ class UserPolicy < BasePolicy end rule { default }.enable :read_user_profile - rule { private_profile & ~(user_is_self | admin) }.prevent :read_user_profile + rule { (private_profile | blocked_user) & ~(user_is_self | admin) }.prevent :read_user_profile end diff --git a/app/presenters/snippet_presenter.rb b/app/presenters/snippet_presenter.rb index 37c9ebd3305..a453be18b95 100644 --- a/app/presenters/snippet_presenter.rb +++ b/app/presenters/snippet_presenter.rb @@ -23,6 +23,10 @@ class SnippetPresenter < Gitlab::View::Presenter::Delegated can_access_resource?("admin") end + def can_report_as_spam? + snippet.submittable_as_spam_by?(current_user) + end + private def can_access_resource?(ability_prefix) diff --git a/app/services/ci/retry_build_service.rb b/app/services/ci/retry_build_service.rb index 5abfbd26641..7a5e33c61ba 100644 --- a/app/services/ci/retry_build_service.rb +++ b/app/services/ci/retry_build_service.rb @@ -5,7 +5,7 @@ module Ci CLONE_ACCESSORS = %i[pipeline project ref tag options name allow_failure stage stage_id stage_idx trigger_request yaml_variables when environment coverage_regex - description tag_list protected needs resource_group].freeze + description tag_list protected needs].freeze def execute(build) reprocess!(build).tap do |new_build| diff --git a/app/views/users/_profile_basic_info.html.haml b/app/views/users/_profile_basic_info.html.haml new file mode 100644 index 00000000000..af0a766bab0 --- /dev/null +++ b/app/views/users/_profile_basic_info.html.haml @@ -0,0 +1,6 @@ +%p + %span.middle-dot-divider + @#{@user.username} + - if can?(current_user, :read_user_profile, @user) + %span.middle-dot-divider + = s_('Member since %{date}') % { date: @user.created_at.to_date.to_s(:long) } diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index e1c75d5d0f4..e10dad8aa8d 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -1,7 +1,7 @@ - @hide_top_links = true - @hide_breadcrumbs = true - @no_container = true -- page_title @user.name +- page_title @user.blocked? ? s_('UserProfile|Blocked user') : @user.name - page_description @user.bio - header_title @user.name, user_path(@user) @@ -36,50 +36,48 @@ = link_to avatar_icon_for_user(@user, 400), target: '_blank', rel: 'noopener noreferrer' do = image_tag avatar_icon_for_user(@user, 90), class: "avatar s90", alt: '' - .user-info - .cover-title - = @user.name - - - if @user.status - .cover-status - = emoji_icon(@user.status.emoji) - = markdown_field(@user.status, :message) - - .cover-desc.member-date.cgray - %p - %span.middle-dot-divider - @#{@user.username} - - if can?(current_user, :read_user_profile, @user) - %span.middle-dot-divider - = s_('Member since %{date}') % { date: @user.created_at.to_date.to_s(:long) } - - .cover-desc.cgray - - unless @user.public_email.blank? - .profile-link-holder.middle-dot-divider - = link_to @user.public_email, "mailto:#{@user.public_email}", class: 'text-link' - - unless @user.skype.blank? - .profile-link-holder.middle-dot-divider - = link_to "skype:#{@user.skype}", title: "Skype" do - = icon('skype') - - unless @user.linkedin.blank? - .profile-link-holder.middle-dot-divider - = link_to linkedin_url(@user), title: "LinkedIn", target: '_blank', rel: 'noopener noreferrer nofollow' do - = icon('linkedin-square') - - unless @user.twitter.blank? - .profile-link-holder.middle-dot-divider - = link_to twitter_url(@user), title: "Twitter", target: '_blank', rel: 'noopener noreferrer nofollow' do - = icon('twitter-square') - - unless @user.website_url.blank? - .profile-link-holder.middle-dot-divider - = link_to @user.short_website_url, @user.full_website_url, class: 'text-link', target: '_blank', rel: 'me noopener noreferrer nofollow' - - unless @user.location.blank? - .profile-link-holder.middle-dot-divider - = sprite_icon('location', size: 16, css_class: 'vertical-align-sub') - = @user.location - - unless @user.organization.blank? - .profile-link-holder.middle-dot-divider - = sprite_icon('work', size: 16, css_class: 'vertical-align-sub') - = @user.organization + - if @user.blocked? + .user-info + .cover-title + = s_('UserProfile|Blocked user') + = render "users/profile_basic_info" + - else + .user-info + .cover-title + = @user.name + + - if @user.status + .cover-status + = emoji_icon(@user.status.emoji) + = markdown_field(@user.status, :message) + = render "users/profile_basic_info" + .cover-desc.cgray + - unless @user.public_email.blank? + .profile-link-holder.middle-dot-divider + = link_to @user.public_email, "mailto:#{@user.public_email}", class: 'text-link' + - unless @user.skype.blank? + .profile-link-holder.middle-dot-divider + = link_to "skype:#{@user.skype}", title: "Skype" do + = icon('skype') + - unless @user.linkedin.blank? + .profile-link-holder.middle-dot-divider + = link_to linkedin_url(@user), title: "LinkedIn", target: '_blank', rel: 'noopener noreferrer nofollow' do + = icon('linkedin-square') + - unless @user.twitter.blank? + .profile-link-holder.middle-dot-divider + = link_to twitter_url(@user), title: "Twitter", target: '_blank', rel: 'noopener noreferrer nofollow' do + = icon('twitter-square') + - unless @user.website_url.blank? + .profile-link-holder.middle-dot-divider + = link_to @user.short_website_url, @user.full_website_url, class: 'text-link', target: '_blank', rel: 'me noopener noreferrer nofollow' + - unless @user.location.blank? + .profile-link-holder.middle-dot-divider + = sprite_icon('location', size: 16, css_class: 'vertical-align-sub') + = @user.location + - unless @user.organization.blank? + .profile-link-holder.middle-dot-divider + = sprite_icon('work', size: 16, css_class: 'vertical-align-sub') + = @user.organization - if @user.bio.present? .cover-desc.cgray @@ -165,4 +163,8 @@ .col-12.text-center .text-content %h4 - = s_('UserProfile|This user has a private profile') + - if @user.blocked? + = s_('UserProfile|This user is blocked') + - else + = s_('UserProfile|This user has a private profile') + |