diff options
21 files changed, 429 insertions, 99 deletions
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index b7c771a3959..4a93c49ca4c 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -369,10 +369,3 @@ Style/StringConcatenation: # SupportedStyles: single_quotes, double_quotes Style/StringLiteralsInInterpolation: Enabled: false - -# Offense count: 293 -# Cop supports --auto-correct. -# Configuration parameters: IgnoredMethods. -# IgnoredMethods: respond_to, define_method -Style/SymbolProc: - Enabled: false diff --git a/.rubocop_todo/style/symbol_proc.yml b/.rubocop_todo/style/symbol_proc.yml new file mode 100644 index 00000000000..12e20553e1a --- /dev/null +++ b/.rubocop_todo/style/symbol_proc.yml @@ -0,0 +1,280 @@ +--- +# Cop supports --auto-correct. +Style/SymbolProc: + # Offense count: 341 + # Temporarily disabled due to too many offenses + Enabled: false + Exclude: + - 'app/controllers/admin/users_controller.rb' + - 'app/controllers/concerns/renders_blob.rb' + - 'app/controllers/import/bitbucket_controller.rb' + - 'app/controllers/import/bitbucket_server_controller.rb' + - 'app/controllers/profiles/avatars_controller.rb' + - 'app/controllers/profiles/two_factor_auths_controller.rb' + - 'app/controllers/profiles_controller.rb' + - 'app/finders/packages/go/version_finder.rb' + - 'app/graphql/mutations/commits/create.rb' + - 'app/graphql/mutations/jira_import/start.rb' + - 'app/helpers/graph_helper.rb' + - 'app/models/ci/build_metadata.rb' + - 'app/models/ci/build_trace_chunk.rb' + - 'app/models/ci/pipeline.rb' + - 'app/models/clusters/concerns/provider_status.rb' + - 'app/models/commit.rb' + - 'app/models/concerns/board_recent_visit.rb' + - 'app/models/concerns/resolvable_discussion.rb' + - 'app/models/container_repository.rb' + - 'app/models/discussion.rb' + - 'app/models/environment.rb' + - 'app/models/integrations/prometheus.rb' + - 'app/models/label_note.rb' + - 'app/models/members/project_member.rb' + - 'app/models/namespace.rb' + - 'app/models/preloaders/merge_request_diff_preloader.rb' + - 'app/models/project_team.rb' + - 'app/models/release.rb' + - 'app/models/remote_mirror.rb' + - 'app/models/snippet_input_action_collection.rb' + - 'app/models/user.rb' + - 'app/policies/group_policy.rb' + - 'app/presenters/project_presenter.rb' + - 'app/serializers/analytics/cycle_analytics/value_stream_entity.rb' + - 'app/serializers/build_action_entity.rb' + - 'app/serializers/build_details_entity.rb' + - 'app/serializers/ci/pipeline_entity.rb' + - 'app/serializers/ci/trigger_entity.rb' + - 'app/serializers/cluster_entity.rb' + - 'app/serializers/deployment_cluster_entity.rb' + - 'app/serializers/deployment_entity.rb' + - 'app/serializers/draft_note_entity.rb' + - 'app/serializers/environment_entity.rb' + - 'app/serializers/import/bitbucket_provider_repo_entity.rb' + - 'app/serializers/import/fogbugz_provider_repo_entity.rb' + - 'app/serializers/issuable_sidebar_basic_entity.rb' + - 'app/serializers/issue_board_entity.rb' + - 'app/serializers/linked_project_issue_entity.rb' + - 'app/serializers/member_entity.rb' + - 'app/serializers/member_user_entity.rb' + - 'app/serializers/merge_request_widget_entity.rb' + - 'app/serializers/project_entity.rb' + - 'app/serializers/project_mirror_entity.rb' + - 'app/serializers/project_note_entity.rb' + - 'app/serializers/prometheus_alert_entity.rb' + - 'app/serializers/review_app_setup_entity.rb' + - 'app/serializers/test_suite_summary_entity.rb' + - 'app/services/badges/create_service.rb' + - 'app/services/ci/change_variable_service.rb' + - 'app/services/ci/find_exposed_artifacts_service.rb' + - 'app/services/ci/resource_groups/assign_resource_from_resource_group_service.rb' + - 'app/services/ci/update_build_state_service.rb' + - 'app/services/clusters/agents/delete_expired_events_service.rb' + - 'app/services/feature_flags/update_service.rb' + - 'app/services/google_cloud/enable_cloud_run_service.rb' + - 'app/services/merge_requests/base_service.rb' + - 'app/services/merge_requests/bulk_remove_attention_requested_service.rb' + - 'app/services/merge_requests/reopen_service.rb' + - 'app/services/notes/destroy_service.rb' + - 'app/services/packages/debian/generate_distribution_service.rb' + - 'app/services/resource_events/synthetic_label_notes_builder_service.rb' + - 'app/services/two_factor/destroy_service.rb' + - 'app/workers/bulk_import_worker.rb' + - 'app/workers/bulk_imports/stuck_import_worker.rb' + - 'app/workers/ci/build_trace_chunk_flush_worker.rb' + - 'app/workers/gitlab/import/stuck_import_job.rb' + - 'app/workers/namespaces/prune_aggregation_schedules_worker.rb' + - 'app/workers/stuck_export_jobs_worker.rb' + - 'app/workers/update_head_pipeline_for_merge_request_worker.rb' + - 'config/initializers/01_active_record_database_tasks_configuration_flag.rb' + - 'config/initializers/doorkeeper_openid_connect.rb' + - 'config/initializers/mail_encoding_patch.rb' + - 'config/initializers/wikicloth_redos_patch.rb' + - 'config/settings.rb' + - 'db/migrate/20210318134427_delete_security_findings_without_uuid.rb' + - 'db/migrate/20210503105845_add_project_value_stream_id_to_project_stages.rb' + - 'db/post_migrate/20220119094503_populate_audit_event_streaming_verification_token.rb' + - 'ee/app/helpers/ee/mirror_helper.rb' + - 'ee/app/helpers/ee/registrations_helper.rb' + - 'ee/app/models/concerns/epic_tree_sorting.rb' + - 'ee/app/models/ee/integrations/jira.rb' + - 'ee/app/models/ee/issue.rb' + - 'ee/app/serializers/ee/fork_namespace_entity.rb' + - 'ee/app/serializers/ee/group_child_entity.rb' + - 'ee/app/serializers/ee/issue_sidebar_basic_entity.rb' + - 'ee/app/serializers/ee/member_entity.rb' + - 'ee/app/serializers/ee/merge_request_widget_entity.rb' + - 'ee/app/serializers/epics/related_epic_entity.rb' + - 'ee/app/serializers/integrations/jira_serializers/issue_entity.rb' + - 'ee/app/serializers/linked_epic_entity.rb' + - 'ee/app/services/analytics/cycle_analytics/data_loader_service.rb' + - 'ee/app/services/geo/verification_state_backfill_service.rb' + - 'ee/app/services/security/scanned_resources_counting_service.rb' + - 'ee/app/services/timebox_report_service.rb' + - 'ee/app/services/vulnerabilities/historical_statistics/deletion_service.rb' + - 'ee/app/workers/geo/batch/project_registry_worker.rb' + - 'ee/app/workers/geo/sync_timeout_cron_worker.rb' + - 'ee/app/workers/geo/verification_cron_worker.rb' + - 'ee/app/workers/repository_push_audit_event_worker.rb' + - 'ee/lib/api/entities/pending_member.rb' + - 'ee/lib/api/related_epic_links.rb' + - 'ee/lib/ee/api/entities/audit_event.rb' + - 'ee/lib/ee/api/entities/geo_node.rb' + - 'ee/lib/ee/api/entities/merge_request_approval_state.rb' + - 'ee/lib/ee/gitlab/auth/ldap/access.rb' + - 'ee/lib/ee/gitlab/background_migration/drop_invalid_remediations.rb' + - 'ee/lib/ee/gitlab/background_migration/fix_incorrect_max_seats_used.rb' + - 'ee/lib/ee/gitlab/background_migration/populate_uuids_for_security_findings.rb' + - 'ee/lib/gitlab/ci/parsers/security/formatters/dependency_list.rb' + - 'ee/lib/gitlab/contribution_analytics/data_collector.rb' + - 'ee/lib/gitlab/custom_file_templates.rb' + - 'ee/lib/gitlab/geo/oauth/logout_state.rb' + - 'ee/spec/factories/issues.rb' + - 'ee/spec/features/billings/extend_reactivate_trial_spec.rb' + - 'ee/spec/features/billings/qrtly_reconciliation_alert_spec.rb' + - 'ee/spec/helpers/ee/geo_helper_spec.rb' + - 'ee/spec/helpers/ee/registrations_helper_spec.rb' + - 'ee/spec/lib/ee/gitlab/search_results_spec.rb' + - 'ee/spec/lib/gitlab/elastic/document_reference_spec.rb' + - 'ee/spec/lib/gitlab/graphql/aggregations/issues/lazy_block_aggregate_spec.rb' + - 'ee/spec/models/ee/iterations/cadence_spec.rb' + - 'ee/spec/services/groups/participants_service_spec.rb' + - 'ee/spec/support/helpers/subscription_portal_helpers.rb' + - 'lib/api/api_guard.rb' + - 'lib/api/entities/board.rb' + - 'lib/api/entities/environment.rb' + - 'lib/api/entities/issuable_references.rb' + - 'lib/api/entities/merge_request_approvals.rb' + - 'lib/api/entities/package.rb' + - 'lib/api/entities/protected_ref_access.rb' + - 'lib/api/github/entities.rb' + - 'lib/api/go_proxy.rb' + - 'lib/api/helpers/internal_helpers.rb' + - 'lib/api/package_files.rb' + - 'lib/api/terraform/state.rb' + - 'lib/atlassian/jira_connect/serializers/base_entity.rb' + - 'lib/banzai/filter/inline_cluster_metrics_filter.rb' + - 'lib/banzai/filter/inline_embeds_filter.rb' + - 'lib/bulk_imports/common/pipelines/entity_finisher.rb' + - 'lib/bulk_imports/ndjson_pipeline.rb' + - 'lib/container_registry/client.rb' + - 'lib/container_registry/gitlab_api_client.rb' + - 'lib/gitlab/analytics/cycle_analytics/stage_events.rb' + - 'lib/gitlab/background_migration/cleanup_orphaned_lfs_objects_projects.rb' + - 'lib/gitlab/background_migration/recalculate_vulnerabilities_occurrences_uuid.rb' + - 'lib/gitlab/background_migration/remove_occurrence_pipelines_and_duplicate_vulnerabilities_findings.rb' + - 'lib/gitlab/blob_helper.rb' + - 'lib/gitlab/cache/ci/project_pipeline_status.rb' + - 'lib/gitlab/checks/changes_access.rb' + - 'lib/gitlab/ci/pipeline/preloader.rb' + - 'lib/gitlab/ci/runner_upgrade_check.rb' + - 'lib/gitlab/ci/trace.rb' + - 'lib/gitlab/config/entry/node.rb' + - 'lib/gitlab/database/async_indexes/migration_helpers.rb' + - 'lib/gitlab/database/consistency_checker.rb' + - 'lib/gitlab/database/migrations/background_migration_helpers.rb' + - 'lib/gitlab/database/migrations/instrumentation.rb' + - 'lib/gitlab/diff/file_collection/base.rb' + - 'lib/gitlab/git/diff_stats_collection.rb' + - 'lib/gitlab/gitaly_client/commit_service.rb' + - 'lib/gitlab/gitaly_client/wiki_service.rb' + - 'lib/gitlab/import_export/attributes_finder.rb' + - 'lib/gitlab/import_export/base/relation_object_saver.rb' + - 'lib/gitlab/import_export/fast_hash_serializer.rb' + - 'lib/gitlab/import_export/group/relation_tree_restorer.rb' + - 'lib/gitlab/manifest_import/manifest.rb' + - 'lib/gitlab/metrics/dashboard/importers/prometheus_metrics.rb' + - 'lib/gitlab/metrics/dashboard/url.rb' + - 'lib/gitlab/quick_actions/extractor.rb' + - 'lib/gitlab/quick_actions/merge_request_actions.rb' + - 'lib/gitlab/search/found_blob.rb' + - 'lib/gitlab/seeder.rb' + - 'lib/gitlab/sidekiq_config.rb' + - 'lib/gitlab/slash_commands/deploy.rb' + - 'lib/gitlab/ssh_public_key.rb' + - 'lib/gitlab/suggestions/suggestion_set.rb' + - 'lib/gitlab/task_helpers.rb' + - 'lib/tasks/gitlab/praefect.rake' + - 'qa/qa/ee/page/group/settings/general.rb' + - 'qa/qa/ee/page/operations_dashboard.rb' + - 'qa/qa/page/group/settings/package_registries.rb' + - 'qa/qa/page/profile/two_factor_auth.rb' + - 'qa/qa/resource/project_snippet.rb' + - 'qa/qa/runtime/ip_address.rb' + - 'qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb' + - 'qa/qa/specs/features/browser_ui/3_create/jenkins/jenkins_build_status_spec.rb' + - 'qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb' + - 'qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb' + - 'qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/12_geo/attachment_replication_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/12_geo/http_push_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/12_geo/rename_replication_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/12_geo/ssh_push_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/12_geo/wiki_http_push_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/13_secure/enable_scanning_from_configuration_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/3_create/merge_request/approval_rules_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/3_create/repository/file_locking_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/4_verify/pipeline_status_on_operation_dashboard_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/4_verify/pipeline_subscription_with_group_owned_project_spec.rb' + - 'rubocop/cop/gitlab/mark_used_feature_flags.rb' + - 'scripts/qa/testcases-check' + - 'scripts/static-analysis' + - 'spec/controllers/concerns/product_analytics_tracking_spec.rb' + - 'spec/controllers/concerns/redis_tracking_spec.rb' + - 'spec/controllers/projects/merge_requests/conflicts_controller_spec.rb' + - 'spec/factories/ci/builds.rb' + - 'spec/factories/clusters/providers/aws.rb' + - 'spec/factories/oauth_openid_requests.rb' + - 'spec/factories/personal_access_tokens.rb' + - 'spec/factories/pool_repositories.rb' + - 'spec/features/merge_request/user_creates_image_diff_notes_spec.rb' + - 'spec/features/merge_request/user_resolves_conflicts_spec.rb' + - 'spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb' + - 'spec/features/merge_request/user_sees_pipelines_spec.rb' + - 'spec/features/projects/commit/user_comments_on_commit_spec.rb' + - 'spec/features/projects/environments/environment_spec.rb' + - 'spec/features/projects/labels/update_prioritization_spec.rb' + - 'spec/finders/license_template_finder_spec.rb' + - 'spec/finders/packages/go/version_finder_spec.rb' + - 'spec/graphql/mutations/releases/create_spec.rb' + - 'spec/helpers/instance_configuration_helper_spec.rb' + - 'spec/helpers/learn_gitlab_helper_spec.rb' + - 'spec/helpers/members_helper_spec.rb' + - 'spec/lib/backup/gitaly_backup_spec.rb' + - 'spec/lib/gitlab/database/dynamic_model_helpers_spec.rb' + - 'spec/lib/gitlab/database/migration_helpers/loose_foreign_key_helpers_spec.rb' + - 'spec/lib/gitlab/git/commit_spec.rb' + - 'spec/lib/gitlab/git/repository_spec.rb' + - 'spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb' + - 'spec/lib/gitlab/graphql/lazy_spec.rb' + - 'spec/lib/gitlab/instrumentation/redis_spec.rb' + - 'spec/lib/gitlab/optimistic_locking_spec.rb' + - 'spec/lib/gitlab/pagination/keyset/in_operator_optimization/query_builder_spec.rb' + - 'spec/lib/gitlab/quick_actions/dsl_spec.rb' + - 'spec/lib/gitlab/relative_positioning/item_context_spec.rb' + - 'spec/lib/gitlab/usage/metrics/instrumentations/database_metric_spec.rb' + - 'spec/lib/omni_auth/strategies/jwt_spec.rb' + - 'spec/models/member_spec.rb' + - 'spec/models/namespace/root_storage_statistics_spec.rb' + - 'spec/models/operations/feature_flags/strategy_spec.rb' + - 'spec/models/project_statistics_spec.rb' + - 'spec/models/repository_spec.rb' + - 'spec/models/user_spec.rb' + - 'spec/presenters/projects/import_export/project_export_presenter_spec.rb' + - 'spec/requests/api/snippet_repository_storage_moves_spec.rb' + - 'spec/requests/api/tags_spec.rb' + - 'spec/services/ci/pipelines/add_job_service_spec.rb' + - 'spec/services/groups/transfer_service_spec.rb' + - 'spec/services/merge_requests/conflicts/list_service_spec.rb' + - 'spec/services/notification_recipients/builder/default_spec.rb' + - 'spec/services/packages/go/create_package_service_spec.rb' + - 'spec/services/suggestions/apply_service_spec.rb' + - 'spec/support/generate-seed-repo-rb' + - 'spec/support/helpers/filter_spec_helper.rb' + - 'spec/support/helpers/migrations_helpers.rb' + - 'spec/support/shared_contexts/finders/users_finder_shared_contexts.rb' + - 'spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb' + - 'spec/support/shared_examples/lib/gitlab/import_export/attributes_permitter_shared_examples.rb' + - 'spec/support/shared_examples/models/label_note_shared_examples.rb' + - 'spec/views/layouts/_published_experiments.html.haml_spec.rb' + - 'spec/workers/snippets/schedule_bulk_repository_shard_moves_worker_spec.rb' + - 'tooling/lib/tooling/test_map_generator.rb' + - 'tooling/rspec_flaky/flaky_examples_collection.rb' diff --git a/app/assets/javascripts/work_items/components/work_item_actions.vue b/app/assets/javascripts/work_items/components/work_item_actions.vue index 40b6fcdd204..701cb84df59 100644 --- a/app/assets/javascripts/work_items/components/work_item_actions.vue +++ b/app/assets/javascripts/work_items/components/work_item_actions.vue @@ -21,7 +21,7 @@ export default { required: false, default: null, }, - canUpdate: { + canDelete: { type: Boolean, required: false, default: false, @@ -63,7 +63,7 @@ export default { </script> <template> - <div v-if="canUpdate"> + <div v-if="canDelete"> <gl-dropdown icon="ellipsis_v" text-sr-only 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 449e17e155c..29d61ec6091 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -3,6 +3,7 @@ import { GlAlert } from '@gitlab/ui'; import { i18n } from '../constants'; import workItemQuery from '../graphql/work_item.query.graphql'; import workItemTitleSubscription from '../graphql/work_item_title.subscription.graphql'; +import WorkItemActions from './work_item_actions.vue'; import WorkItemState from './work_item_state.vue'; import WorkItemTitle from './work_item_title.vue'; @@ -10,6 +11,7 @@ export default { i18n, components: { GlAlert, + WorkItemActions, WorkItemTitle, WorkItemState, }, @@ -57,6 +59,17 @@ export default { workItemType() { return this.workItem.workItemType?.name; }, + canUpdate() { + return this.workItem?.userPermissions?.updateWorkItem; + }, + canDelete() { + return this.workItem?.userPermissions?.deleteWorkItem; + }, + }, + methods: { + handleWorkItemDeleted() { + this.$emit('workItemDeleted'); + }, }, }; </script> @@ -67,13 +80,23 @@ export default { {{ error }} </gl-alert> - <work-item-title - :loading="workItemLoading" - :work-item-id="workItem.id" - :work-item-title="workItem.title" - :work-item-type="workItemType" - @error="error = $event" - /> + <div class="gl-display-flex"> + <work-item-title + :loading="workItemLoading" + :work-item-id="workItem.id" + :work-item-title="workItem.title" + :work-item-type="workItemType" + class="gl-mr-5" + @error="error = $event" + /> + <work-item-actions + :work-item-id="workItem.id" + :can-delete="canDelete" + class="gl-ml-auto gl-mt-5" + @workItemDeleted="handleWorkItemDeleted" + @error="error = $event" + /> + </div> <work-item-state :loading="workItemLoading" :work-item="workItem" @error="error = $event" /> </section> </template> diff --git a/app/assets/javascripts/work_items/components/work_item_detail_modal.vue b/app/assets/javascripts/work_items/components/work_item_detail_modal.vue index a79091fb8b2..0a35abfa5b9 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail_modal.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail_modal.vue @@ -1,22 +1,14 @@ <script> -import { GlAlert, GlButton, GlModal } from '@gitlab/ui'; -import WorkItemActions from './work_item_actions.vue'; +import { GlAlert, GlModal } from '@gitlab/ui'; import WorkItemDetail from './work_item_detail.vue'; export default { components: { GlAlert, - GlButton, GlModal, WorkItemDetail, - WorkItemActions, }, props: { - canUpdate: { - type: Boolean, - required: false, - default: false, - }, visible: { type: Boolean, required: true, @@ -50,32 +42,25 @@ export default { </script> <template> - <gl-modal hide-footer modal-id="work-item-detail-modal" :visible="visible" @hide="closeModal"> - <template #modal-header> - <div class="gl-w-full gl-display-flex gl-align-items-center gl-justify-content-end"> - <h2 class="modal-title gl-mr-auto">{{ s__('WorkItem|Work Item') }}</h2> - <work-item-actions - :work-item-id="workItemId" - :can-update="canUpdate" - @workItemDeleted="handleWorkItemDeleted" - @error="setErrorMessage" - /> - <gl-button category="tertiary" icon="close" :aria-label="__('Close')" @click="closeModal" /> - </div> - </template> + <gl-modal + hide-footer + size="lg" + modal-id="work-item-detail-modal" + :visible="visible" + @hide="closeModal" + > <gl-alert v-if="error" variant="danger" @dismiss="error = false"> {{ error }} </gl-alert> - <work-item-detail :work-item-id="workItemId" /> + <work-item-detail :work-item-id="workItemId" @workItemDeleted="handleWorkItemDeleted" /> </gl-modal> </template> <style> -/* hide the existing close button until we can do it - * with https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/2710 +/* hide the existing modal header */ -#work-item-detail-modal .modal-header > .gl-button { +#work-item-detail-modal .modal-header { display: none; } </style> diff --git a/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql b/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql index 4ad75425893..ca5ba7a7d8e 100644 --- a/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql +++ b/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql @@ -6,4 +6,8 @@ fragment WorkItem on WorkItem { id name } + userPermissions { + deleteWorkItem + updateWorkItem + } } diff --git a/app/assets/javascripts/work_items/pages/create_work_item.vue b/app/assets/javascripts/work_items/pages/create_work_item.vue index 2e59912e640..58a4d2cdba3 100644 --- a/app/assets/javascripts/work_items/pages/create_work_item.vue +++ b/app/assets/javascripts/work_items/pages/create_work_item.vue @@ -115,21 +115,15 @@ export default { }, }, update(store, { data: { workItemCreate } }) { - const { id, title, workItemType, state } = workItemCreate.workItem; + const { workItem } = workItemCreate; store.writeQuery({ query: workItemQuery, variables: { - id, + id: workItem.id, }, data: { - workItem: { - __typename: 'WorkItem', - id, - title, - state, - workItemType, - }, + workItem, }, }); }, diff --git a/app/assets/javascripts/work_items/pages/work_item_root.vue b/app/assets/javascripts/work_items/pages/work_item_root.vue index b8f2bcff25d..b8ce6d641a9 100644 --- a/app/assets/javascripts/work_items/pages/work_item_root.vue +++ b/app/assets/javascripts/work_items/pages/work_item_root.vue @@ -1,6 +1,7 @@ <script> import { TYPE_WORK_ITEM } from '~/graphql_shared/constants'; import { convertToGraphQLId } from '~/graphql_shared/utils'; +import { s__ } from '~/locale'; import WorkItemDetail from '../components/work_item_detail.vue'; export default { @@ -18,9 +19,15 @@ export default { return convertToGraphQLId(TYPE_WORK_ITEM, this.id); }, }, + methods: { + handleWorkItemDeleted() { + this.$root.$toast.show(s__('WorkItem|Work item deleted')); + this.$router.push('/'); + }, + }, }; </script> <template> - <work-item-detail :work-item-id="gid" /> + <work-item-detail :work-item-id="gid" @workItemDeleted="handleWorkItemDeleted" /> </template> diff --git a/app/assets/javascripts/work_items/router/index.js b/app/assets/javascripts/work_items/router/index.js index 142fab8cfa6..2b39a298720 100644 --- a/app/assets/javascripts/work_items/router/index.js +++ b/app/assets/javascripts/work_items/router/index.js @@ -1,8 +1,10 @@ +import { GlToast } from '@gitlab/ui'; import Vue from 'vue'; import VueRouter from 'vue-router'; import { joinPaths } from '~/lib/utils/url_utility'; import { routes } from './routes'; +Vue.use(GlToast); Vue.use(VueRouter); export function createRouter(fullPath) { diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index f9e7f2f68f4..61eb7f52a8d 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -40,6 +40,7 @@ class ProjectsController < Projects::ApplicationController push_frontend_feature_flag(:highlight_js, @project, default_enabled: :yaml) push_frontend_feature_flag(:increase_page_size_exponentially, @project, default_enabled: :yaml) push_licensed_feature(:file_locks) if @project.present? && @project.licensed_feature_available?(:file_locks) + push_licensed_feature(:security_orchestration_policies) if @project.present? && @project.licensed_feature_available?(:security_orchestration_policies) push_force_frontend_feature_flag(:work_items, @project&.work_items_feature_flag_enabled?) end diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb index 9fd35faf0b7..5f72259f34a 100644 --- a/app/serializers/build_details_entity.rb +++ b/app/serializers/build_details_entity.rb @@ -148,12 +148,14 @@ class BuildDetailsEntity < Ci::JobEntity end def failure_message - _("This job depends on other jobs with expired/erased artifacts: %{invalid_dependencies}") % - { invalid_dependencies: invalid_dependencies } + # We do not return the invalid_dependencies for all scenarios see https://gitlab.com/gitlab-org/gitlab/-/issues/287772#note_914406387 + punctuation = invalid_dependencies.empty? ? '.' : ': ' + _("This job could not start because it could not retrieve the needed artifacts%{punctuation}%{invalid_dependencies}") % + { invalid_dependencies: invalid_dependencies, punctuation: punctuation } end def help_message(docs_url) - html_escape(_("Please refer to %{docs_url}")) % { docs_url: "<a href=\"#{docs_url}\">#{html_escape(docs_url)}</a>".html_safe } + html_escape(_("<a href=\"#{docs_url}\">Learn more.</a>".html_safe)) end end diff --git a/doc/development/service_ping/index.md b/doc/development/service_ping/index.md index 53e0048e831..8ba418767cb 100644 --- a/doc/development/service_ping/index.md +++ b/doc/development/service_ping/index.md @@ -413,6 +413,10 @@ To generate Service Ping, use [Teleport](https://goteleport.com/docs/) or a deta exit ``` +1. Get the metrics duration from logs: + +Search in Google Console logs for `time_elapsed`. Query example [here](https://cloudlogging.app.goo.gl/nWheZvD8D3nWazNe6). + ### Verification (After approx 30 hours) #### Verify with Teleport diff --git a/locale/gitlab.pot b/locale/gitlab.pot index da7adac4bc2..79f2e8ddae9 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -5805,6 +5805,9 @@ msgstr "" msgid "Billings|Reactivate trial" msgstr "" +msgid "Billings|Seats in use / Seats available" +msgstr "" + msgid "Billings|Seats in use / Seats in subscription" msgstr "" @@ -5871,12 +5874,21 @@ msgstr "" msgid "Billing|Enter at least three characters to search." msgstr "" +msgid "Billing|Explore all plans" +msgstr "" + msgid "Billing|Export list" msgstr "" +msgid "Billing|Free groups on GitLab are limited to %{maxNamespaceSeats} seats" +msgstr "" + msgid "Billing|Group invite" msgstr "" +msgid "Billing|If the group has over %{maxNamespaceSeats} members, only those occupying a seat can access the namespace. To ensure all members (active and %{linkStart}over limit%{linkEnd}) can access the namespace, you can start a trial or upgrade to a paid tier." +msgstr "" + msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member." msgstr "" @@ -28334,9 +28346,6 @@ msgstr "" msgid "Please reach out if you have any questions and we'll be happy to assist." msgstr "" -msgid "Please refer to %{docs_url}" -msgstr "" - msgid "Please review the updated escalation policies for %{project_link}. It is recommended that you reach out to the current on-call responder to ensure continuity of on-call coverage." msgstr "" @@ -38668,7 +38677,7 @@ msgstr "" msgid "This issue is in a child epic of the filtered epic" msgstr "" -msgid "This job depends on other jobs with expired/erased artifacts: %{invalid_dependencies}" +msgid "This job could not start because it could not retrieve the needed artifacts%{punctuation}%{invalid_dependencies}" msgstr "" msgid "This job depends on upstream jobs that need to succeed in order for this job to be triggered" @@ -42826,9 +42835,6 @@ msgstr "" msgid "WorkItem|Type" msgstr "" -msgid "WorkItem|Work Item" -msgstr "" - msgid "WorkItem|Work Items" msgstr "" diff --git a/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb index 79bba484bea..705bc20202e 100644 --- a/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb +++ b/qa/qa/specs/features/api/1_manage/import_github_repo_spec.rb @@ -3,7 +3,7 @@ module QA # Spec uses real github.com, which means outage of github.com can actually block deployment # Keep spec in reliable bucket but don't run in blocking pipelines - RSpec.describe 'Manage', :github, :reliable, :skip_live_env, :requires_admin do + RSpec.describe 'Manage', :github, :skip_live_env, :requires_admin do describe 'Project import', issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/353583' do let!(:api_client) { Runtime::API::Client.as_admin } let!(:group) { Resource::Group.fabricate_via_api! { |resource| resource.api_client = api_client } } diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb index 3bf5a11b074..4621c540eb3 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb @@ -3,7 +3,7 @@ module QA # Spec uses real github.com, which means outage of github can actually block deployment # Keep spec in reliable bucket but don't run in blocking pipelines - RSpec.describe 'Manage', :github, :reliable, :skip_live_env, :requires_admin do + RSpec.describe 'Manage', :github, :skip_live_env, :requires_admin do describe 'Project import' do let(:github_repo) { 'gitlab-qa-github/import-test' } let(:api_client) { Runtime::API::Client.as_admin } diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb index fa79c4ee98a..f4ed9f28dac 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb @@ -37,7 +37,7 @@ module QA 'creates a merge request with a milestone and label', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347762' ) do - gitlab_account_username = "@#{Runtime::User.username}" + gitlab_account_user_name = Resource::User.default.reload!.name milestone = Resource::ProjectMilestone.fabricate_via_api! do |milestone| milestone.project = project @@ -59,7 +59,7 @@ module QA Page::MergeRequest::Show.perform do |merge_request| expect(merge_request).to have_title(merge_request_title) expect(merge_request).to have_description(merge_request_description) - expect(merge_request).to have_assignee(gitlab_account_username) + expect(merge_request).to have_assignee(gitlab_account_user_name) expect(merge_request).to have_label(label.title) expect(merge_request).to have_milestone(milestone.title) end diff --git a/spec/frontend/work_items/components/work_item_actions_spec.js b/spec/frontend/work_items/components/work_item_actions_spec.js index d0e9cfee353..286c8180e16 100644 --- a/spec/frontend/work_items/components/work_item_actions_spec.js +++ b/spec/frontend/work_items/components/work_item_actions_spec.js @@ -18,13 +18,13 @@ describe('WorkItemActions component', () => { const findDeleteButton = () => wrapper.findComponent(GlDropdownItem); const createComponent = ({ - canUpdate = true, + canDelete = true, deleteWorkItemHandler = jest.fn().mockResolvedValue(deleteWorkItemResponse), } = {}) => { glModalDirective = jest.fn(); wrapper = shallowMount(WorkItemActions, { apolloProvider: createMockApollo([[deleteWorkItem, deleteWorkItemHandler]]), - propsData: { workItemId: '123', canUpdate }, + propsData: { workItemId: '123', canDelete }, directives: { glModal: { bind(_, { value }) { @@ -93,9 +93,9 @@ describe('WorkItemActions component', () => { expect(wrapper.emitted('workItemDeleted')).toBeUndefined(); }); - it('does not render when canUpdate is false', () => { + it('does not render when canDelete is false', () => { createComponent({ - canUpdate: false, + canDelete: false, }); expect(wrapper.html()).toBe(''); diff --git a/spec/frontend/work_items/components/work_item_detail_modal_spec.js b/spec/frontend/work_items/components/work_item_detail_modal_spec.js index 9f35ccb853b..bcd91bf583a 100644 --- a/spec/frontend/work_items/components/work_item_detail_modal_spec.js +++ b/spec/frontend/work_items/components/work_item_detail_modal_spec.js @@ -4,7 +4,6 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; import WorkItemDetail from '~/work_items/components/work_item_detail.vue'; import WorkItemDetailModal from '~/work_items/components/work_item_detail_modal.vue'; -import WorkItemActions from '~/work_items/components/work_item_actions.vue'; describe('WorkItemDetailModal component', () => { let wrapper; @@ -12,12 +11,11 @@ describe('WorkItemDetailModal component', () => { Vue.use(VueApollo); const findModal = () => wrapper.findComponent(GlModal); - const findWorkItemActions = () => wrapper.findComponent(WorkItemActions); const findWorkItemDetail = () => wrapper.findComponent(WorkItemDetail); - const createComponent = ({ visible = true, workItemId = '1', canUpdate = false } = {}) => { + const createComponent = ({ visible = true, workItemId = '1' } = {}) => { wrapper = shallowMount(WorkItemDetailModal, { - propsData: { visible, workItemId, canUpdate }, + propsData: { visible, workItemId }, stubs: { GlModal, }, @@ -36,23 +34,9 @@ describe('WorkItemDetailModal component', () => { }); }); - it('renders heading', () => { - createComponent(); - - expect(wrapper.find('h2').text()).toBe('Work Item'); - }); - it('renders WorkItemDetail', () => { createComponent(); expect(findWorkItemDetail().props()).toEqual({ workItemId: '1' }); }); - - it('shows work item actions', () => { - createComponent({ - canUpdate: true, - }); - - expect(findWorkItemActions().exists()).toBe(true); - }); }); diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js index 1b2944b6078..8aea475ba07 100644 --- a/spec/frontend/work_items/mock_data.js +++ b/spec/frontend/work_items/mock_data.js @@ -10,6 +10,10 @@ export const workItemQueryResponse = { id: 'gid://gitlab/WorkItems::Type/5', name: 'Task', }, + userPermissions: { + deleteWorkItem: false, + updateWorkItem: false, + }, }, }, }; @@ -28,6 +32,10 @@ export const updateWorkItemMutationResponse = { id: 'gid://gitlab/WorkItems::Type/5', name: 'Task', }, + userPermissions: { + deleteWorkItem: false, + updateWorkItem: false, + }, }, }, }, @@ -61,6 +69,10 @@ export const createWorkItemMutationResponse = { id: 'gid://gitlab/WorkItems::Type/5', name: 'Task', }, + userPermissions: { + deleteWorkItem: false, + updateWorkItem: false, + }, }, }, }, @@ -75,6 +87,10 @@ export const createWorkItemFromTaskMutationResponse = { descriptionHtml: '<p>New description</p>', id: 'gid://gitlab/WorkItem/13', __typename: 'WorkItem', + userPermissions: { + deleteWorkItem: false, + updateWorkItem: false, + }, }, }, }, diff --git a/spec/frontend/work_items/pages/work_item_root_spec.js b/spec/frontend/work_items/pages/work_item_root_spec.js index 2803724b9af..81d01a0cb45 100644 --- a/spec/frontend/work_items/pages/work_item_root_spec.js +++ b/spec/frontend/work_items/pages/work_item_root_spec.js @@ -26,6 +26,8 @@ describe('Work items root component', () => { it('renders WorkItemDetail', () => { createComponent(); - expect(findWorkItemDetail().props()).toEqual({ workItemId: 'gid://gitlab/WorkItem/1' }); + expect(findWorkItemDetail().props()).toEqual({ + workItemId: 'gid://gitlab/WorkItem/1', + }); }); }); diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb index da2734feb51..dd8238456aa 100644 --- a/spec/serializers/build_details_entity_spec.rb +++ b/spec/serializers/build_details_entity_spec.rb @@ -127,21 +127,48 @@ RSpec.describe BuildDetailsEntity do end context 'when the build has failed due to a missing dependency' do - let!(:test1) { create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test1', stage_idx: 0) } - let!(:test2) { create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test2', stage_idx: 1) } - let!(:build) { create(:ci_build, :pending, pipeline: pipeline, stage_idx: 2, options: { dependencies: %w(test1 test2) }) } let(:message) { subject[:callout_message] } - before do - build.pipeline.unlocked! - build.drop!(:missing_dependency_failure) + context 'when the dependency is in the same pipeline' do + let!(:test1) { create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test1', stage_idx: 0) } + let!(:test2) { create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test2', stage_idx: 1) } + let!(:build) { create(:ci_build, :pending, pipeline: pipeline, stage_idx: 2, options: { dependencies: %w(test1 test2) }) } + + before do + build.pipeline.unlocked! + build.drop!(:missing_dependency_failure) + end + + it { is_expected.to include(failure_reason: 'missing_dependency_failure') } + + it 'includes the failing dependencies in the callout message' do + expect(message).to include('test1') + expect(message).to include('test2') + end + + it 'includes message for list of invalid dependencies' do + expect(message).to include('could not retrieve the needed artifacts:') + end end - it { is_expected.to include(failure_reason: 'missing_dependency_failure') } + context 'when dependency is not found' do + let!(:build) { create(:ci_build, :pending, pipeline: pipeline, stage_idx: 2, options: { dependencies: %w(test1 test2) }) } + + before do + build.pipeline.unlocked! + build.drop!(:missing_dependency_failure) + end - it 'includes the failing dependencies in the callout message' do - expect(message).to include('test1') - expect(message).to include('test2') + it { is_expected.to include(failure_reason: 'missing_dependency_failure') } + + it 'excludes the failing dependencies in the callout message' do + expect(message).not_to include('test1') + expect(message).not_to include('test2') + end + + it 'includes the correct punctuation in the message' do + expect(message).to include('could not retrieve the needed artifacts.') + end end end |