diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue | 28 | ||||
-rw-r--r-- | app/assets/javascripts/vue_shared/constants.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/work_items/components/work_item_created_updated.vue | 23 | ||||
-rw-r--r-- | app/assets/javascripts/work_items/components/work_item_detail.vue | 39 | ||||
-rw-r--r-- | app/models/ci/job_artifact.rb | 10 | ||||
-rw-r--r-- | app/models/ci/runner.rb | 19 | ||||
-rw-r--r-- | app/models/commit_status.rb | 8 | ||||
-rw-r--r-- | app/models/concerns/ci/partitionable.rb | 1 | ||||
-rw-r--r-- | app/models/concerns/ci/partitionable/switch.rb | 44 | ||||
-rw-r--r-- | app/models/repository.rb | 4 | ||||
-rw-r--r-- | app/services/metrics/users_starred_dashboards/create_service.rb | 76 | ||||
-rw-r--r-- | app/services/metrics/users_starred_dashboards/delete_service.rb | 35 |
12 files changed, 116 insertions, 173 deletions
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue index bca43d0b20a..a545ad1d09c 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue @@ -1,7 +1,7 @@ <script> import { - GlDropdown, - GlDropdownItem, + GlDisclosureDropdown, + GlDisclosureDropdownItem, GlFormCheckbox, GlIcon, GlSprintf, @@ -28,8 +28,8 @@ import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; export default { name: 'PackageListRow', components: { - GlDropdown, - GlDropdownItem, + GlDisclosureDropdown, + GlDisclosureDropdownItem, GlFormCheckbox, GlIcon, GlSprintf, @@ -194,18 +194,22 @@ export default { </template> <template v-if="packageEntity.canDestroy" #right-action> - <gl-dropdown + <gl-disclosure-dropdown + category="tertiary" data-testid="delete-dropdown" icon="ellipsis_v" - :text="$options.i18n.moreActions" - :text-sr-only="true" - category="tertiary" + :toggle-text="$options.i18n.moreActions" + text-sr-only no-caret > - <gl-dropdown-item data-testid="action-delete" variant="danger" @click="$emit('delete')">{{ - $options.i18n.deletePackage - }}</gl-dropdown-item> - </gl-dropdown> + <gl-disclosure-dropdown-item data-testid="action-delete" @action="$emit('delete')"> + <template #list-item> + <span class="gl-text-red-500"> + {{ $options.i18n.deletePackage }} + </span> + </template> + </gl-disclosure-dropdown-item> + </gl-disclosure-dropdown> </template> </list-item> </template> diff --git a/app/assets/javascripts/vue_shared/constants.js b/app/assets/javascripts/vue_shared/constants.js index 8946a02e663..d9bc2c82688 100644 --- a/app/assets/javascripts/vue_shared/constants.js +++ b/app/assets/javascripts/vue_shared/constants.js @@ -86,7 +86,7 @@ export const confidentialityInfoText = (workspaceType, issuableType) => ), { workspaceType: workspaceType === WORKSPACE_PROJECT ? __('project') : __('group'), - issuableType: issuableType === TYPE_ISSUE ? __('issue') : __('epic'), + issuableType: issuableType.toLowerCase(), permissions: issuableType === TYPE_ISSUE ? __('at least the Reporter role, the author, and assignees') diff --git a/app/assets/javascripts/work_items/components/work_item_created_updated.vue b/app/assets/javascripts/work_items/components/work_item_created_updated.vue index a6cc37290fb..f93ea4a0753 100644 --- a/app/assets/javascripts/work_items/components/work_item_created_updated.vue +++ b/app/assets/javascripts/work_items/components/work_item_created_updated.vue @@ -1,8 +1,10 @@ <script> -import { GlAvatarLink, GlSprintf } from '@gitlab/ui'; +import { GlAvatarLink, GlSprintf, GlLoadingIcon } from '@gitlab/ui'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import { WORKSPACE_PROJECT } from '~/issues/constants'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import WorkItemStateBadge from '~/work_items/components/work_item_state_badge.vue'; +import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue'; import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue'; import workItemByIidQuery from '../graphql/work_item_by_iid.query.graphql'; @@ -13,6 +15,8 @@ export default { TimeAgoTooltip, WorkItemStateBadge, WorkItemTypeIcon, + ConfidentialityBadge, + GlLoadingIcon, }, inject: ['fullPath'], props: { @@ -21,6 +25,11 @@ export default { required: false, default: null, }, + updateInProgress: { + type: Boolean, + required: false, + default: false, + }, }, computed: { createdAt() { @@ -44,6 +53,9 @@ export default { workItemIconName() { return this.workItem?.workItemType?.iconName; }, + isWorkItemConfidential() { + return this.workItem?.confidential; + }, }, apollo: { workItem: { @@ -62,12 +74,21 @@ export default { }, }, }, + WORKSPACE_PROJECT, }; </script> <template> <div class="gl-mb-3 gl-text-gray-700"> <work-item-state-badge v-if="workItemState" :work-item-state="workItemState" /> + <gl-loading-icon v-if="updateInProgress" :inline="true" class="gl-mr-3" /> + <confidentiality-badge + v-if="isWorkItemConfidential" + class="gl-vertical-align-middle gl-display-inline-flex!" + data-testid="confidential" + :workspace-type="$options.WORKSPACE_PROJECT" + :issuable-type="workItemType" + /> <work-item-type-icon class="gl-vertical-align-middle gl-mr-0!" :work-item-icon-name="workItemIconName" diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue index 24fcc85dabf..d826ef9cbe7 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -5,7 +5,6 @@ import { GlSkeletonLoader, GlLoadingIcon, GlIcon, - GlBadge, GlButton, GlTooltipDirective, GlEmptyState, @@ -19,8 +18,9 @@ import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { isLoggedIn } from '~/lib/utils/common_utils'; import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue'; import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue'; +import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue'; +import { WORKSPACE_PROJECT } from '~/issues/constants'; import { - sprintfWorkItem, i18n, WIDGET_TYPE_ASSIGNEES, WIDGET_TYPE_NOTIFICATIONS, @@ -60,7 +60,6 @@ export default { components: { WorkItemStateToggleButton, GlAlert, - GlBadge, GlButton, GlLoadingIcon, GlSkeletonLoader, @@ -79,6 +78,7 @@ export default { WorkItemDetailModal, AbuseCategorySelector, GlIntersectionObserver, + ConfidentialityBadge, }, mixins: [glFeatureFlagMixin()], inject: ['fullPath', 'reportAbusePath'], @@ -186,9 +186,6 @@ export default { canAssignUnassignUser() { return this.workItemAssignees && this.canSetWorkItemMetadata; }, - confidentialTooltip() { - return sprintfWorkItem(this.$options.i18n.confidentialTooltip, this.workItemType); - }, fullPath() { return this.workItem?.project.fullPath; }, @@ -377,8 +374,8 @@ export default { } }, }, - WORK_ITEM_TYPE_VALUE_OBJECTIVE, + WORKSPACE_PROJECT, }; </script> @@ -439,16 +436,6 @@ export default { /> {{ workItemBreadcrumbReference }} </div> - <gl-loading-icon v-if="updateInProgress" :inline="true" class="gl-mr-3" /> - <gl-badge - v-if="workItem.confidential" - v-gl-tooltip.bottom - :title="confidentialTooltip" - variant="warning" - icon="eye-slash" - class="gl-mr-3 gl-cursor-help" - >{{ __('Confidential') }}</gl-badge - > <work-item-state-toggle-button v-if="canUpdate" :work-item-id="workItem.id" @@ -503,7 +490,10 @@ export default { :can-update="canUpdate" @error="updateError = $event" /> - <work-item-created-updated :work-item-iid="workItemIid" /> + <work-item-created-updated + :work-item-iid="workItemIid" + :update-in-progress="updateInProgress" + /> </div> <gl-intersection-observer v-if="showIntersectionObserver" @@ -523,15 +513,12 @@ export default { {{ workItem.title }} </span> <gl-loading-icon v-if="updateInProgress" class="gl-mr-3" /> - <gl-badge + <confidentiality-badge v-if="workItem.confidential" - v-gl-tooltip.bottom - :title="confidentialTooltip" - variant="warning" - icon="eye-slash" - class="gl-mr-3 gl-cursor-help" - >{{ __('Confidential') }}</gl-badge - > + data-testid="confidential" + :workspace-type="$options.WORKSPACE_PROJECT" + :issuable-type="workItemType" + /> <work-item-todos v-if="showWorkItemCurrentUserTodos" :work-item-id="workItem.id" diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb index 483386f1f1b..11d70e088e9 100644 --- a/app/models/ci/job_artifact.rb +++ b/app/models/ci/job_artifact.rb @@ -341,16 +341,10 @@ module Ci end def to_deleted_object_attrs(pick_up_at = nil) - final_path_store_dir, final_path_filename = nil - if file_final_path.present? - final_path_store_dir = File.dirname(file_final_path) - final_path_filename = File.basename(file_final_path) - end - { file_store: file_store, - store_dir: final_path_store_dir || file.store_dir.to_s, - file: final_path_filename || file_identifier, + store_dir: file.store_dir.to_s, + file: file_identifier, pick_up_at: pick_up_at || expire_at || Time.current } end diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index 4eb5c3c9ed2..0413bb480d4 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -87,19 +87,23 @@ module Ci scope :active, -> (value = true) { where(active: value) } scope :paused, -> { active(false) } - scope :online, -> { where('contacted_at > ?', online_contact_time_deadline) } + scope :online, -> { where(arel_table[:contacted_at].gt(online_contact_time_deadline)) } scope :recent, -> do - where('ci_runners.created_at >= :datetime OR ci_runners.contacted_at >= :datetime', datetime: stale_deadline) + timestamp = stale_deadline + + where(arel_table[:created_at].gteq(timestamp).or(arel_table[:contacted_at].gteq(timestamp))) end scope :stale, -> do - where('ci_runners.created_at <= :datetime AND ' \ - '(ci_runners.contacted_at IS NULL OR ci_runners.contacted_at <= :datetime)', datetime: stale_deadline) + timestamp = stale_deadline + + where(arel_table[:created_at].lteq(timestamp)) + .where(arel_table[:contacted_at].eq(nil).or(arel_table[:contacted_at].lteq(timestamp))) end scope :offline, -> { where(arel_table[:contacted_at].lteq(online_contact_time_deadline)) } scope :never_contacted, -> { where(contacted_at: nil) } scope :ordered, -> { order(id: :desc) } - scope :with_recent_runner_queue, -> { where('contacted_at > ?', recent_queue_deadline) } + scope :with_recent_runner_queue, -> { where(arel_table[:contacted_at].gt(recent_queue_deadline)) } scope :with_running_builds, -> do where('EXISTS(?)', ::Ci::Build.running.select(1) @@ -513,7 +517,10 @@ module Ci private scope :with_upgrade_status, ->(upgrade_status) do - joins(:runner_version).where(runner_version: { status: upgrade_status }) + joins(:runner_managers) + .joins("INNER JOIN #{RunnerVersion.quoted_table_name} runner_version " \ + "ON runner_version.version = #{RunnerManager.quoted_table_name}.version") + .where(runner_version: { status: upgrade_status }) end EXECUTOR_NAME_TO_TYPES = { diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 3f631f583b6..c2425e9460a 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -9,10 +9,16 @@ class CommitStatus < Ci::ApplicationRecord include BulkInsertableAssociations include TaggableQueries + ROUTING_FEATURE_FLAG = :ci_partitioning_use_ci_builds_routing_table + self.table_name = 'ci_builds' self.sequence_name = 'ci_builds_id_seq' self.primary_key = :id - partitionable scope: :pipeline + + partitionable scope: :pipeline, through: { + table: :p_ci_builds, + flag: ROUTING_FEATURE_FLAG + } belongs_to :user belongs_to :project diff --git a/app/models/concerns/ci/partitionable.rb b/app/models/concerns/ci/partitionable.rb index a3bcc7bcbbc..ec6c85d888d 100644 --- a/app/models/concerns/ci/partitionable.rb +++ b/app/models/concerns/ci/partitionable.rb @@ -80,6 +80,7 @@ module Ci def handle_partitionable_through(options) return unless options + return if Gitlab::Utils.to_boolean(ENV['DISABLE_PARTITIONABLE_SWITCH'], default: false) define_singleton_method(:routing_table_name) { options[:table] } define_singleton_method(:routing_table_name_flag) { options[:flag] } diff --git a/app/models/concerns/ci/partitionable/switch.rb b/app/models/concerns/ci/partitionable/switch.rb index c1bbd107e9f..6195f92114f 100644 --- a/app/models/concerns/ci/partitionable/switch.rb +++ b/app/models/concerns/ci/partitionable/switch.rb @@ -2,6 +2,8 @@ module Ci module Partitionable + MUTEX = Mutex.new + module Switch extend ActiveSupport::Concern @@ -14,18 +16,39 @@ module Ci predicate_builder cached_find_by_statement].freeze included do |base| - partitioned = Class.new(base) do - self.table_name = base.routing_table_name + install_partitioned_class(base) + end + + class_methods do + # `Class.new(partitionable_model)` triggers `partitionable_model.inherited` + # and we need the mutex to break the recursion without adding extra accessors + # on the model. This will be used during code loading, not runtime. + # + def install_partitioned_class(partitionable_model) + Partitionable::MUTEX.synchronize do + partitioned = Class.new(partitionable_model) do + self.table_name = partitionable_model.routing_table_name + + def self.routing_class? + true + end + + def self.sti_name + superclass.sti_name + end + end - def self.routing_class? - true + partitionable_model.const_set(:Partitioned, partitioned) end end - base.const_set(:Partitioned, partitioned) - end + def inherited(child_class) + super + return if Partitionable::MUTEX.owned? + + install_partitioned_class(child_class) + end - class_methods do def routing_class? false end @@ -51,6 +74,13 @@ module Ci end end end + + def type_condition(table = arel_table) + sti_column = table[inheritance_column] + sti_names = ([self] + descendants).map(&:sti_name).uniq + + predicate_builder.build(sti_column, sti_names) + end end end end diff --git a/app/models/repository.rb b/app/models/repository.rb index cd269f928b5..6113f54367d 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1248,6 +1248,10 @@ class Repository prohibited_branches.each { |name| raw_repository.delete_branch(name) } end + def get_patch_id(old_revision, new_revision) + raw_repository.get_patch_id(old_revision, new_revision) + end + private def ancestor_cache_key(ancestor_id, descendant_id) diff --git a/app/services/metrics/users_starred_dashboards/create_service.rb b/app/services/metrics/users_starred_dashboards/create_service.rb deleted file mode 100644 index 0d028f120d3..00000000000 --- a/app/services/metrics/users_starred_dashboards/create_service.rb +++ /dev/null @@ -1,76 +0,0 @@ -# frozen_string_literal: true - -# Create Metrics::UsersStarredDashboard entry for given user based on matched dashboard_path, project -module Metrics - module UsersStarredDashboards - class CreateService < ::BaseService - include Stepable - - steps :authorize_create_action, - :parse_dashboard_path, - :create - - def initialize(user, project, dashboard_path) - @user = user - @project = project - @dashboard_path = dashboard_path - end - - def execute - keys = %i[status message starred_dashboard] - status, message, dashboards = execute_steps.values_at(*keys) - - if status != :success - ServiceResponse.error(message: message) - else - ServiceResponse.success(payload: dashboards) - end - end - - private - - attr_reader :user, :project, :dashboard_path - - def authorize_create_action(_options) - if Ability.allowed?(user, :create_metrics_user_starred_dashboard, project) - success(user: user, project: project) - else - error(s_('MetricsUsersStarredDashboards|You are not authorized to add star to this dashboard')) - end - end - - def parse_dashboard_path(options) - if dashboard_path_exists? - options[:dashboard_path] = dashboard_path - success(options) - else - error(s_('MetricsUsersStarredDashboards|Dashboard with requested path can not be found')) - end - end - - def create(options) - starred_dashboard = build_starred_dashboard_from(options) - - if starred_dashboard.save - success(starred_dashboard: starred_dashboard) - else - error(starred_dashboard.errors.messages) - end - end - - def build_starred_dashboard_from(options) - Metrics::UsersStarredDashboard.new( - user: options.fetch(:user), - project: options.fetch(:project), - dashboard_path: options.fetch(:dashboard_path) - ) - end - - def dashboard_path_exists? - Gitlab::Metrics::Dashboard::Finder - .find_all_paths(project) - .any? { |dashboard| dashboard[:path] == dashboard_path } - end - end - end -end diff --git a/app/services/metrics/users_starred_dashboards/delete_service.rb b/app/services/metrics/users_starred_dashboards/delete_service.rb deleted file mode 100644 index 229c0e8cfc0..00000000000 --- a/app/services/metrics/users_starred_dashboards/delete_service.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -# Delete all matching Metrics::UsersStarredDashboard entries for given user based on matched dashboard_path, project -module Metrics - module UsersStarredDashboards - class DeleteService < ::BaseService - def initialize(user, project, dashboard_path = nil) - @user = user - @project = project - @dashboard_path = dashboard_path - end - - def execute - ServiceResponse.success(payload: { deleted_rows: starred_dashboards.delete_all }) - end - - private - - attr_reader :user, :project, :dashboard_path - - def starred_dashboards - # since deleted records are scoped to their owner there is no need to - # check if that user can delete them, also if user lost access to - # project it shouldn't block that user from removing them - dashboards = user.metrics_users_starred_dashboards - - if dashboard_path.present? - dashboards.for_project_dashboard(project, dashboard_path) - else - dashboards.for_project(project) - end - end - end - end -end |