diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-15 18:09:53 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-15 18:09:53 +0300 |
commit | 977720d7565377672df302ecb82b1e7a221cfba6 (patch) | |
tree | f258b65ed376a3075e0a76971a9360083ee6a059 /app | |
parent | 717436a767395d0ed850a16d07f19cd51c3d4551 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
17 files changed, 339 insertions, 113 deletions
diff --git a/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js b/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js index 43ff617dabe..ce36ff6a230 100644 --- a/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js +++ b/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js @@ -1,7 +1,15 @@ import Vue from 'vue'; +import VueApollo from 'vue-apollo'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { joinPaths, webIDEUrl } from '~/lib/utils/url_utility'; import WebIdeButton from '~/vue_shared/components/web_ide_link.vue'; +import createDefaultClient from '~/lib/graphql'; + +Vue.use(VueApollo); + +const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), +}); export default ({ el, router }) => { if (!el) return; @@ -15,6 +23,10 @@ export default ({ el, router }) => { new Vue({ el, router, + apolloProvider, + provide: { + projectPath, + }, render(h) { return h(WebIdeButton, { props: { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue index 5db5f1f8dcf..334fc01c9f7 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue @@ -14,9 +14,7 @@ export default { }, computed: { widgets() { - return [window.gon?.features?.refactorSecurityExtension && 'MrSecurityWidget'].filter( - (w) => w, - ); + return ['MrSecurityWidget']; }, }, }; 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 e9efc8e75be..9dc5bf77da7 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 @@ -98,7 +98,6 @@ export default { MrWidgetRebase: RebaseState, SourceBranchRemovalStatus, MrWidgetApprovals, - SecurityReportsApp: () => import('~/vue_shared/security_reports/security_reports_app.vue'), MergeChecksFailed: () => import('./components/states/merge_checks_failed.vue'), ReadyToMerge: ReadyToMergeState, ReportWidgetContainer, @@ -239,9 +238,6 @@ export default { this.mr.mergePipelinesEnabled && this.mr.sourceProjectId !== this.mr.targetProjectId, ); }, - shouldRenderSecurityReport() { - return Boolean(this.mr?.pipeline?.id); - }, shouldRenderTerraformPlans() { return Boolean(this.mr?.terraformReportsPath); }, @@ -275,9 +271,6 @@ export default { hasAlerts() { return this.hasMergeError || this.showMergePipelineForkWarning; }, - shouldShowSecurityExtension() { - return window.gon?.features?.refactorSecurityExtension; - }, shouldShowMergeDetails() { if (this.mr.state === 'readyToMerge') return true; @@ -601,15 +594,7 @@ export default { <mr-widget-approvals v-if="shouldRenderApprovals" :mr="mr" :service="service" /> <report-widget-container> <extensions-container v-if="hasExtensions" :mr="mr" /> - <widget-container v-if="mr && shouldShowSecurityExtension" :mr="mr" /> - <security-reports-app - v-if="shouldRenderSecurityReport && !shouldShowSecurityExtension" - :pipeline-id="mr.pipeline.id" - :project-id="mr.sourceProjectId" - :security-reports-docs-path="mr.securityReportsDocsPath" - :target-project-full-path="mr.targetProjectFullPath" - :mr-iid="mr.iid" - /> + <widget-container :mr="mr" /> </report-widget-container> <div class="mr-section-container mr-widget-workflow"> <div v-if="hasAlerts" class="gl-overflow-hidden mr-widget-alert-container"> diff --git a/app/assets/javascripts/vue_shared/components/confirm_fork_modal.vue b/app/assets/javascripts/vue_shared/components/confirm_fork_modal.vue deleted file mode 100644 index 64e3b5d0bae..00000000000 --- a/app/assets/javascripts/vue_shared/components/confirm_fork_modal.vue +++ /dev/null @@ -1,68 +0,0 @@ -<script> -import { GlModal } from '@gitlab/ui'; -import { __ } from '~/locale'; - -export const i18n = { - btnText: __('Fork project'), - title: __('Fork project?'), - message: __( - 'You can’t edit files directly in this project. Fork this project and submit a merge request with your changes.', - ), -}; - -export default { - name: 'ConfirmForkModal', - components: { - GlModal, - }, - model: { - prop: 'visible', - event: 'change', - }, - props: { - visible: { - type: Boolean, - required: false, - default: false, - }, - modalId: { - type: String, - required: true, - }, - forkPath: { - type: String, - required: true, - }, - }, - computed: { - btnActions() { - return { - cancel: { text: __('Cancel') }, - primary: { - text: this.$options.i18n.btnText, - attributes: { - href: this.forkPath, - variant: 'confirm', - 'data-qa-selector': 'fork_project_button', - 'data-method': 'post', - }, - }, - }; - }, - }, - i18n, -}; -</script> -<template> - <gl-modal - :visible="visible" - data-qa-selector="confirm_fork_modal" - :modal-id="modalId" - :title="$options.i18n.title" - :action-primary="btnActions.primary" - :action-cancel="btnActions.cancel" - @change="$emit('change', $event)" - > - <p>{{ $options.i18n.message }}</p> - </gl-modal> -</template> diff --git a/app/assets/javascripts/vue_shared/components/web_ide/confirm_fork_modal.vue b/app/assets/javascripts/vue_shared/components/web_ide/confirm_fork_modal.vue new file mode 100644 index 00000000000..b4afb27c497 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/web_ide/confirm_fork_modal.vue @@ -0,0 +1,114 @@ +<script> +import { GlModal, GlLoadingIcon, GlLink } from '@gitlab/ui'; +import { __ } from '~/locale'; +import getWritableForksQuery from './get_writable_forks.query.graphql'; + +export const i18n = { + btnText: __('Create a new fork'), + title: __('Fork project?'), + message: __('You can’t edit files directly in this project.'), + existingForksMessage: __( + 'To submit your changes in a merge request, switch to one of these forks or create a new fork.', + ), + newForkMessage: __('To submit your changes in a merge request, create a new fork.'), +}; + +export default { + name: 'ConfirmForkModal', + components: { + GlModal, + GlLoadingIcon, + GlLink, + }, + inject: { + projectPath: { + default: '', + }, + }, + model: { + prop: 'visible', + event: 'change', + }, + props: { + visible: { + type: Boolean, + required: false, + default: false, + }, + modalId: { + type: String, + required: true, + }, + forkPath: { + type: String, + required: true, + }, + }, + data() { + return { + forks: [], + }; + }, + apollo: { + forks: { + query: getWritableForksQuery, + variables() { + return { + projectPath: this.projectPath, + }; + }, + update({ project } = {}) { + return project?.visibleForks?.nodes.map((node) => { + return { + text: node.fullPath, + href: node.webUrl, + }; + }); + }, + }, + }, + computed: { + isLoading() { + return this.$apollo.queries.forks.loading; + }, + hasWritableForks() { + return this.forks.length; + }, + btnActions() { + return { + cancel: { text: __('Cancel') }, + primary: { + text: this.$options.i18n.btnText, + attributes: { + href: this.forkPath, + variant: 'confirm', + 'data-qa-selector': 'fork_project_button', + }, + }, + }; + }, + }, + i18n, +}; +</script> +<template> + <gl-modal + :visible="visible" + data-qa-selector="confirm_fork_modal" + :modal-id="modalId" + :title="$options.i18n.title" + :action-primary="btnActions.primary" + :action-cancel="btnActions.cancel" + @change="$emit('change', $event)" + > + <p>{{ $options.i18n.message }}</p> + <gl-loading-icon v-if="isLoading" /> + <template v-else-if="hasWritableForks"> + <p>{{ $options.i18n.existingForksMessage }}</p> + <div v-for="fork in forks" :key="fork.text"> + <gl-link :href="fork.href">{{ fork.text }}</gl-link> + </div> + </template> + <p v-else>{{ $options.i18n.newForkMessage }}</p> + </gl-modal> +</template> diff --git a/app/assets/javascripts/vue_shared/components/web_ide/get_writable_forks.query.graphql b/app/assets/javascripts/vue_shared/components/web_ide/get_writable_forks.query.graphql new file mode 100644 index 00000000000..044b79e64f3 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/web_ide/get_writable_forks.query.graphql @@ -0,0 +1,12 @@ +query getWritableForks($projectPath: ID!) { + project(fullPath: $projectPath) { + id + visibleForks(minimumAccessLevel: DEVELOPER) { + nodes { + id + fullPath + webUrl + } + } + } +} diff --git a/app/assets/javascripts/vue_shared/components/web_ide_link.vue b/app/assets/javascripts/vue_shared/components/web_ide_link.vue index 96944877f61..82f4edcbd5f 100644 --- a/app/assets/javascripts/vue_shared/components/web_ide_link.vue +++ b/app/assets/javascripts/vue_shared/components/web_ide_link.vue @@ -3,7 +3,7 @@ import { GlModal, GlSprintf, GlLink } from '@gitlab/ui'; import { s__, __ } from '~/locale'; import { visitUrl } from '~/lib/utils/url_utility'; import ActionsButton from '~/vue_shared/components/actions_button.vue'; -import ConfirmForkModal from '~/vue_shared/components/confirm_fork_modal.vue'; +import ConfirmForkModal from '~/vue_shared/components/web_ide/confirm_fork_modal.vue'; import { KEY_EDIT, KEY_WEB_IDE, KEY_GITPOD, KEY_PIPELINE_EDITOR } from './constants'; export const i18n = { @@ -152,9 +152,7 @@ export default { return this.actions.length > 0; }, editAction() { - if (!this.showEditButton) { - return null; - } + if (!this.showEditButton) return null; const handleOptions = this.needsToFork ? { @@ -194,9 +192,7 @@ export default { return __('Web IDE'); }, webIdeAction() { - if (!this.showWebIdeButton) { - return null; - } + if (!this.showWebIdeButton) return null; const handleOptions = this.needsToFork ? { @@ -298,6 +294,12 @@ export default { }, }; }, + mountForkModal() { + const { disableForkModal, showWebIdeButton, showEditButton } = this; + if (disableForkModal) return false; + + return showWebIdeButton || showEditButton; + }, }, methods: { showModal(dataKey) { @@ -330,7 +332,7 @@ export default { </gl-sprintf> </gl-modal> <confirm-fork-modal - v-if="showWebIdeButton || showEditButton" + v-if="mountForkModal" v-model="showForkModal" :modal-id="forkModalId" :fork-path="forkPath" diff --git a/app/controllers/concerns/search_rate_limitable.rb b/app/controllers/concerns/search_rate_limitable.rb index 7cce30dbb3c..1105e9bbbfd 100644 --- a/app/controllers/concerns/search_rate_limitable.rb +++ b/app/controllers/concerns/search_rate_limitable.rb @@ -20,9 +20,7 @@ module SearchRateLimitable def safe_search_scope # Sometimes search scope can have abusive length or invalid keyword. We don't want # to send those to redis for rate limit checks, so we guard against that here. - return if Feature.disabled?(:search_rate_limited_scopes) || abuse_detected? - - params[:scope] + params[:scope] unless abuse_detected? end def abuse_detected? diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 6558dc10994..77ff69c669d 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -41,7 +41,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo push_force_frontend_feature_flag(:content_editor_on_issues, project&.content_editor_on_issues_feature_flag_enabled?) push_frontend_feature_flag(:core_security_mr_widget_counts, project) push_frontend_feature_flag(:issue_assignees_widget, @project) - push_frontend_feature_flag(:refactor_security_extension, @project) push_frontend_feature_flag(:deprecate_vulnerabilities_feedback, @project) push_frontend_feature_flag(:moved_mr_sidebar, project) push_frontend_feature_flag(:mr_experience_survey, project) diff --git a/app/graphql/types/user_interface.rb b/app/graphql/types/user_interface.rb index b4950cc60e3..5357f2f8e66 100644 --- a/app/graphql/types/user_interface.rb +++ b/app/graphql/types/user_interface.rb @@ -162,6 +162,41 @@ module Types extras: [:lookahead], resolver: ::Resolvers::Achievements::UserAchievementsResolver + field :bio, + type: ::GraphQL::Types::String, + null: true, + description: 'Bio of the user.' + + field :linkedin, + type: ::GraphQL::Types::String, + null: true, + description: 'LinkedIn profile name of the user.' + + field :twitter, + type: ::GraphQL::Types::String, + null: true, + description: 'Twitter username of the user.' + + field :discord, + type: ::GraphQL::Types::String, + null: true, + description: 'Discord ID of the user.' + + field :organization, + type: ::GraphQL::Types::String, + null: true, + description: 'Who the user represents or works for.' + + field :job_title, + type: ::GraphQL::Types::String, + null: true, + description: 'Job title of the user.' + + field :created_at, + type: Types::TimeType, + null: true, + description: 'Timestamp of when the user was created.' + definition_methods do def resolve_type(object, context) # in the absence of other information, we cannot tell - just default to diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index 0aeea323ddb..84512453b7c 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -157,17 +157,15 @@ module TreeHelper } end - def fork_modal_options(project, ref, path, blob) + def fork_modal_options(project, blob) if show_edit_button?({ blob: blob }) - fork_path = fork_and_edit_path(project, ref, path) fork_modal_id = "modal-confirm-fork-edit" elsif show_web_ide_button? - fork_path = ide_fork_and_edit_path(project, ref, path) fork_modal_id = "modal-confirm-fork-webide" end { - fork_path: fork_path, + fork_path: new_namespace_project_fork_path(project_id: project.path, namespace_id: project.namespace.full_path), fork_modal_id: fork_modal_id } end diff --git a/app/models/plan_limits.rb b/app/models/plan_limits.rb index 09cac87ce01..6795e7a3049 100644 --- a/app/models/plan_limits.rb +++ b/app/models/plan_limits.rb @@ -6,6 +6,9 @@ class PlanLimits < ApplicationRecord ignore_column :web_hook_calls_high, remove_with: '15.10', remove_after: '2022-02-22' ignore_column :ci_active_pipelines, remove_with: '16.3', remove_after: '2022-07-22' + attribute :limits_history, :ind_jsonb, default: -> { {} } + validates :limits_history, json_schema: { filename: 'plan_limits_history' } + LimitUndefinedError = Class.new(StandardError) belongs_to :plan @@ -46,6 +49,34 @@ class PlanLimits < ApplicationRecord def dashboard_storage_limit_enabled? false end + + def log_limits_changes(user, new_limits) + new_limits.each do |attribute, value| + limits_history[attribute] ||= [] + limits_history[attribute] << { + user_id: user&.id, + username: user&.username, + timestamp: Time.current.utc.to_i, + value: value + } + end + + update(limits_history: limits_history) + end + + def limit_attribute_changes(attribute) + limit_history = limits_history[attribute] + return [] unless limit_history + + limit_history.map do |entry| + { + timestamp: entry[:timestamp], + value: entry[:value], + username: entry[:username], + user_id: entry[:user_id] + } + end + end end PlanLimits.prepend_mod_with('PlanLimits') diff --git a/app/models/user_detail.rb b/app/models/user_detail.rb index 293a20fcc5a..5c9a73571c0 100644 --- a/app/models/user_detail.rb +++ b/app/models/user_detail.rb @@ -5,6 +5,7 @@ class UserDetail < ApplicationRecord extend ::Gitlab::Utils::Override ignore_column :requires_credit_card_verification, remove_with: '16.1', remove_after: '2023-06-22' + ignore_column :provisioned_by_group_at, remove_with: '16.3', remove_after: '2023-07-22' REGISTRATION_OBJECTIVE_PAIRS = { basics: 0, move_repository: 1, code_storage: 2, exploring: 3, ci: 4, other: 5, joining_team: 6 }.freeze diff --git a/app/models/vulnerability.rb b/app/models/vulnerability.rb index 700e4e0e0ec..650e8942132 100644 --- a/app/models/vulnerability.rb +++ b/app/models/vulnerability.rb @@ -9,12 +9,6 @@ class Vulnerability < ApplicationRecord scope :with_projects, -> { includes(:project) } - # Policy class inferring logic is causing performance - # issues therefore we need to explicitly set it. - def self.declarative_policy_class - :VulnerabilityPolicy - end - def self.link_reference_pattern nil end diff --git a/app/validators/json_schemas/plan_limits_history.json b/app/validators/json_schemas/plan_limits_history.json new file mode 100644 index 00000000000..80d4165018a --- /dev/null +++ b/app/validators/json_schemas/plan_limits_history.json @@ -0,0 +1,115 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "enforcement_limit": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "integer" + }, + "username": { + "type": "string" + }, + "timestamp": { + "type": "integer" + }, + "value": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "user_id", + "username", + "timestamp", + "value" + ] + } + }, + "notification_limit": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "integer" + }, + "username": { + "type": "string" + }, + "timestamp": { + "type": "integer" + }, + "value": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "user_id", + "username", + "timestamp", + "value" + ] + } + }, + "storage_size_limit": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "integer" + }, + "username": { + "type": "string" + }, + "timestamp": { + "type": "integer" + }, + "value": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "user_id", + "username", + "timestamp", + "value" + ] + } + }, + "dashboard_limit_enabled_at": { + "type": "array", + "items": { + "type": "object", + "properties": { + "user_id": { + "type": "integer" + }, + "username": { + "type": "string" + }, + "timestamp": { + "type": "integer" + }, + "value": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "user_id", + "username", + "timestamp", + "value" + ] + } + } + }, + "additionalProperties": false +} diff --git a/app/views/admin/application_settings/_performance.html.haml b/app/views/admin/application_settings/_performance.html.haml index 86a01e1785e..bfa548b70e5 100644 --- a/app/views/admin/application_settings/_performance.html.haml +++ b/app/views/admin/application_settings/_performance.html.haml @@ -11,16 +11,16 @@ = f.label :raw_blob_request_limit, _('Raw blob request rate limit per minute'), class: 'label-bold' = f.number_field :raw_blob_request_limit, class: 'form-control gl-form-input' .form-text.text-muted - = _('Maximum number of requests per minute for each raw path (default is 300). Set to 0 to disable throttling.') + = _('Maximum number of requests per minute for each raw path (default is `300`). Set to `0` to disable throttling.') .form-group = f.label :push_event_hooks_limit, class: 'label-bold' = f.number_field :push_event_hooks_limit, class: 'form-control gl-form-input' .form-text.text-muted - = _('Maximum number of changes (branches or tags) in a single push for which webhooks and services trigger (default is 3).') + = _('Maximum number of changes (branches or tags) in a single push above which webhooks and integrations are not triggered (default is `3`). Setting to `0` does not disable throttling.') .form-group = f.label :push_event_activities_limit, class: 'label-bold' = f.number_field :push_event_activities_limit, class: 'form-control gl-form-input' .form-text.text-muted - = _('Threshold number of changes (branches or tags) in a single push above which a bulk push event is created (default is 3).') + = _('Maximum number of changes (branches or tags) in a single push above which a bulk push event is created (default is `3`). Setting to `0` does not disable throttling.') = f.submit _('Save changes'), pajamas_button: true diff --git a/app/views/shared/_web_ide_button.html.haml b/app/views/shared/_web_ide_button.html.haml index aeaccdfa54b..803f6f9efce 100644 --- a/app/views/shared/_web_ide_button.html.haml +++ b/app/views/shared/_web_ide_button.html.haml @@ -1,5 +1,5 @@ - type = blob ? 'blob' : 'tree' - button_data = web_ide_button_data({ blob: blob }) -- fork_options = fork_modal_options(@project, @ref, @path, blob) +- fork_options = fork_modal_options(@project, blob) .gl-display-inline-block{ data: { options: button_data.merge(fork_options).to_json, web_ide_promo_popover_img: image_path('web-ide-promo-popover.svg') }, id: "js-#{type}-web-ide-link" } |