From d58a3afef8facbdcdd326c50823ac5116bdf8833 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 4 Jun 2025 12:07:18 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../potential_methods_to_remove.yml | 2 - .../ci_environments_dropdown.vue | 23 +- .../environment_breadcrumbs.vue | 7 +- .../javascripts/environments/mount_show.js | 2 +- .../javascripts/lib/utils/breadcrumbs.js | 28 +-- .../container_registry/explorer/index.js | 9 +- .../components/harbor_registry_breadcrumb.vue | 12 +- .../harbor_registry/index.js | 12 +- .../package_registry/index.js | 9 +- .../shared/components/registry_breadcrumb.vue | 7 +- .../components/inbound_token_access.vue | 8 +- .../components/token_access_table.vue | 10 +- .../customizable_dashboard.stories.js | 2 +- .../dashboard_layout.stories.js | 2 +- .../dashboard_layout.vue | 6 + .../panels_base.stories.js | 2 +- .../customizable_dashboard/panels_base.vue | 8 + .../components/work_item_breadcrumb.vue | 9 +- app/assets/javascripts/work_items/index.js | 5 +- .../groups/work_items_controller.rb | 2 +- app/finders/concerns/time_frame_filter.rb | 8 +- app/finders/issuable_finder.rb | 18 +- app/finders/work_items/work_items_finder.rb | 104 ++------ .../namespaces/work_items_resolver.rb | 2 +- app/graphql/types/ci/runner_type.rb | 9 +- app/helpers/projects_helper.rb | 10 - app/models/ci/job_token/authorization.rb | 6 +- app/models/ci/job_token/project_scope_link.rb | 9 - app/models/ci/job_token/scope.rb | 12 +- app/models/group.rb | 5 + app/models/work_item.rb | 12 +- .../update_policies_service.rb | 19 +- .../protection/concerns/tag_rule.rb | 8 +- app/workers/all_queues.yml | 3 +- .../parallel_project_export_worker.rb | 1 + db/docs/merge_request_assignment_events.yml | 12 +- ...t_assignment_events_project_id_not_null.rb | 14 ++ db/schema_migrations/20250603194823 | 1 + db/structure.sql | 3 +- doc/api/graphql/reference/_index.md | 2 +- doc/subscriptions/customers_portal.md | 4 + keeps/quarantine_flaky_tests.rb | 6 + lib/gitlab/auth/identity.rb | 3 +- locale/gitlab.pot | 36 +-- qa/gdk/Dockerfile.gdk | 3 + .../features/dashboard/merge_requests_spec.rb | 8 +- .../work_items/work_items_finder_spec.rb | 229 ++++++++--------- .../__helpers__/mock_apollo_helper.js | 12 + .../ci_environments_dropdown_spec.js | 26 +- .../environment_breadcrumbs_spec.js | 6 +- spec/frontend/lib/utils/breadcrumbs_spec.js | 63 ++--- .../harbor_registry_breadcrumb.spec.js | 42 ++-- .../components/registry_breadcrumb_spec.js | 10 +- .../token_access/inbound_token_access_spec.js | 16 ++ spec/frontend/token_access/mock_data.js | 64 +++++ .../token_access/token_access_table_spec.js | 23 +- .../components/work_item_breadcrumb_spec.js | 4 +- spec/helpers/projects_helper_spec.rb | 26 -- spec/lib/gitlab/auth/auth_finders_spec.rb | 3 +- spec/lib/gitlab/auth/identity_spec.rb | 16 ++ spec/models/ability_spec.rb | 10 + .../models/ci/job_token/authorization_spec.rb | 6 +- .../ci/job_token/project_scope_link_spec.rb | 5 +- spec/models/ci/job_token/scope_spec.rb | 2 +- spec/models/group_spec.rb | 8 + .../group/work_item_state_counts_spec.rb | 237 ------------------ .../api/project_job_token_scope_spec.rb | 8 +- .../groups/work_items_controller_spec.rb | 72 +----- .../add_project_service_spec.rb | 2 +- .../update_policies_service_spec.rb | 32 +++ .../protection/concerns/tag_rule_spec.rb | 90 +------ .../groups/autocomplete_service_spec.rb | 23 +- .../services/projects/destroy_service_spec.rb | 16 +- ..._registry_protection_tag_rules_examples.rb | 55 ++++ ...variable_list_env_scope_shared_examples.rb | 2 +- .../finders/issues_finder_shared_examples.rb | 8 +- ..._finder_group_parameter_shared_examples.rb | 130 +++++----- ...job_token_authorization_shared_examples.rb | 3 +- 78 files changed, 717 insertions(+), 1015 deletions(-) create mode 100644 db/post_migrate/20250603194823_add_merge_request_assignment_events_project_id_not_null.rb create mode 100644 db/schema_migrations/20250603194823 delete mode 100644 spec/requests/api/graphql/group/work_item_state_counts_spec.rb create mode 100644 spec/support/shared_examples/container_registry_protection_tag_rules_examples.rb diff --git a/.gitlab/lint/unused_helper_methods/potential_methods_to_remove.yml b/.gitlab/lint/unused_helper_methods/potential_methods_to_remove.yml index 5ce9a44108f..01eb364bbd9 100644 --- a/.gitlab/lint/unused_helper_methods/potential_methods_to_remove.yml +++ b/.gitlab/lint/unused_helper_methods/potential_methods_to_remove.yml @@ -51,8 +51,6 @@ text_color_for_bg: file: app/helpers/labels_helper.rb manage_labels_title: file: app/helpers/labels_helper.rb -show_projects?: - file: app/helpers/projects_helper.rb request_access_group_members_path: file: app/helpers/routing/groups/members_helper.rb approve_access_request_group_member_path: diff --git a/app/assets/javascripts/ci/ci_environments_dropdown/ci_environments_dropdown.vue b/app/assets/javascripts/ci/ci_environments_dropdown/ci_environments_dropdown.vue index dc6cefb537f..11fa8793ad2 100644 --- a/app/assets/javascripts/ci/ci_environments_dropdown/ci_environments_dropdown.vue +++ b/app/assets/javascripts/ci/ci_environments_dropdown/ci_environments_dropdown.vue @@ -73,8 +73,12 @@ export default { }; }, computed: { - composedCreateButtonLabel() { - return sprintf(__('Create wildcard: %{searchTerm}'), { searchTerm: this.searchTerm }); + composedCreateScopeButtonLabel() { + const label = this.searchTerm?.includes('*') + ? __('Create wildcard: %{searchTerm}') + : s__('CiVariable|Create environment scope: %{searchTerm}'); + + return sprintf(label, { searchTerm: this.searchTerm }); }, environmentScopeLabel() { return convertEnvironmentScope(this.selectedEnvironmentScope); @@ -108,15 +112,12 @@ export default { text: environment, })); }, - shouldRenderCreateButton() { - if (!this.canCreateWildcard) { + shouldRenderCreateScopeButton() { + if (!this.canCreateWildcard || !this.searchTerm) { return false; } - return ( - this.searchTerm?.includes('*') && - ![...this.environments, this.customEnvScope].includes(this.searchTerm) - ); + return ![...this.environments, this.customEnvScope].includes(this.searchTerm); }, shouldRenderDivider() { return !this.areEnvironmentsLoading; @@ -174,14 +175,14 @@ export default { {{ $options.i18n.searchQueryNote }} -
+
- {{ composedCreateButtonLabel }} + {{ composedCreateScopeButtonLabel }}
diff --git a/app/assets/javascripts/environments/environment_details/environment_breadcrumbs.vue b/app/assets/javascripts/environments/environment_details/environment_breadcrumbs.vue index 766cce3be05..f817f7faac3 100644 --- a/app/assets/javascripts/environments/environment_details/environment_breadcrumbs.vue +++ b/app/assets/javascripts/environments/environment_details/environment_breadcrumbs.vue @@ -7,9 +7,8 @@ export default { }, props: { staticBreadcrumbs: { - type: Object, - required: false, - default: () => ({ items: [] }), + type: Array, + required: true, }, }, computed: { @@ -37,7 +36,7 @@ export default { if (!this.isLoaded) { return []; } - const breadCrumbs = [...this.staticBreadcrumbs.items, this.rootRoute]; + const breadCrumbs = [...this.staticBreadcrumbs, this.rootRoute]; if (!this.isRootRoute) { breadCrumbs.push(this.logsRoute); diff --git a/app/assets/javascripts/environments/mount_show.js b/app/assets/javascripts/environments/mount_show.js index d08f4c1771f..6be199bce13 100644 --- a/app/assets/javascripts/environments/mount_show.js +++ b/app/assets/javascripts/environments/mount_show.js @@ -109,7 +109,7 @@ export const initPage = async () => { }, }); - injectVueAppBreadcrumbs(router, EnvironmentBreadcrumbs, null, {}, { singleNavOptIn: true }); + injectVueAppBreadcrumbs(router, EnvironmentBreadcrumbs); return new Vue({ el, diff --git a/app/assets/javascripts/lib/utils/breadcrumbs.js b/app/assets/javascripts/lib/utils/breadcrumbs.js index 70a03b27b91..fd01582280e 100644 --- a/app/assets/javascripts/lib/utils/breadcrumbs.js +++ b/app/assets/javascripts/lib/utils/breadcrumbs.js @@ -7,11 +7,6 @@ export const injectVueAppBreadcrumbs = ( BreadcrumbsComponent, apolloProvider = null, provide = {}, - // this is intended to be a temporary option. Once all uses of - // injectVueAppBreadcrumbs use it, the option should be removed and its - // behavior should be the default. - // Cf. https://gitlab.com/gitlab-org/gitlab/-/merge_requests/186906 - { singleNavOptIn = false } = {}, // eslint-disable-next-line max-params ) => { const injectBreadcrumbEl = document.querySelector('#js-injected-page-breadcrumbs'); @@ -20,22 +15,9 @@ export const injectVueAppBreadcrumbs = ( return false; } - if (singleNavOptIn) { - destroySuperSidebarBreadcrumbs(); - // After singleNavOptIn is turned on for all Vue apps, we can stop - // changing the content of staticBreadcrumbs and instead pass a mutated - // copy of it to the CustomBreadcrumbsRoot component. For now, we need - // to conditionally mutate the staticBreadcrumbs object so that the last - // breadcrumb is hidden for Vue apps that have not opted in to the - // singleNavOptIn. - // Cf. https://gitlab.com/gitlab-org/gitlab/-/merge_requests/186906 - staticBreadcrumbs.items = staticBreadcrumbs.items.slice(0, -1); - } else { - // Hide the last of the static breadcrumbs by nulling its values. - // This way, the separator "/" stays visible and also the new "last" static item isn't displayed in bold font. - staticBreadcrumbs.items[staticBreadcrumbs.items.length - 1].text = ''; - staticBreadcrumbs.items[staticBreadcrumbs.items.length - 1].href = ''; - } + destroySuperSidebarBreadcrumbs(); + + const { items } = staticBreadcrumbs; return new Vue({ el: injectBreadcrumbEl, @@ -47,7 +29,9 @@ export const injectVueAppBreadcrumbs = ( return createElement(BreadcrumbsComponent, { class: injectBreadcrumbEl.className, props: { - staticBreadcrumbs, + // The last item from the static breadcrumb set is replaced by the + // root of the vue app, so the last item should be removed + staticBreadcrumbs: items.slice(0, -1), }, }); }, diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js index 2edef1c6a94..ca5327c864b 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js @@ -92,14 +92,7 @@ export default () => { }); return { - attachBreadcrumb: () => - injectVueAppBreadcrumbs( - router, - RegistryBreadcrumb, - apolloProvider, - {}, - { singleNavOptIn: true }, - ), + attachBreadcrumb: () => injectVueAppBreadcrumbs(router, RegistryBreadcrumb, apolloProvider), attachMainComponent, }; }; diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/components/harbor_registry_breadcrumb.vue b/app/assets/javascripts/packages_and_registries/harbor_registry/components/harbor_registry_breadcrumb.vue index fae705a16e9..df11054a67b 100644 --- a/app/assets/javascripts/packages_and_registries/harbor_registry/components/harbor_registry_breadcrumb.vue +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/components/harbor_registry_breadcrumb.vue @@ -11,9 +11,8 @@ export default { }, props: { staticBreadcrumbs: { - type: Object, - default: () => ({ items: [] }), - required: false, + type: Array, + required: true, }, }, computed: { @@ -42,9 +41,7 @@ export default { }); } - const staticCrumbs = this.staticBreadcrumbs.items; - - return [...staticCrumbs, ...routeInfoList]; + return [...this.staticBreadcrumbs, ...routeInfoList]; }, isLoaded() { return this.isRootRoute || last(this.currentRoute).text; @@ -59,9 +56,8 @@ export default { if (!this.isRootRoute) { crumbs = crumbs.concat(this.currentRoute); } - const staticCrumbs = this.staticBreadcrumbs.items; - return [...staticCrumbs, ...crumbs]; + return [...this.staticBreadcrumbs, ...crumbs]; }, }, }; diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/index.js b/app/assets/javascripts/packages_and_registries/harbor_registry/index.js index d3815da2e00..18187a5c5ff 100644 --- a/app/assets/javascripts/packages_and_registries/harbor_registry/index.js +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/index.js @@ -77,17 +77,7 @@ export default (id) => { }; return { - attachBreadcrumb: () => - injectVueAppBreadcrumbs( - router, - RegistryBreadcrumb, - null, - {}, - { - // cf. https://gitlab.com/gitlab-org/gitlab/-/merge_requests/186906 - singleNavOptIn: true, - }, - ), + attachBreadcrumb: () => injectVueAppBreadcrumbs(router, RegistryBreadcrumb), attachMainComponent, }; }; diff --git a/app/assets/javascripts/packages_and_registries/package_registry/index.js b/app/assets/javascripts/packages_and_registries/package_registry/index.js index 2c8e93924b7..cbd781532f8 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/index.js +++ b/app/assets/javascripts/packages_and_registries/package_registry/index.js @@ -51,14 +51,7 @@ export default () => { }); return { - attachBreadcrumb: () => - injectVueAppBreadcrumbs( - router, - RegistryBreadcrumb, - apolloProvider, - {}, - { singleNavOptIn: true }, - ), + attachBreadcrumb: () => injectVueAppBreadcrumbs(router, RegistryBreadcrumb, apolloProvider), attachMainComponent, }; }; diff --git a/app/assets/javascripts/packages_and_registries/shared/components/registry_breadcrumb.vue b/app/assets/javascripts/packages_and_registries/shared/components/registry_breadcrumb.vue index b2955ba515e..56c626f5a81 100644 --- a/app/assets/javascripts/packages_and_registries/shared/components/registry_breadcrumb.vue +++ b/app/assets/javascripts/packages_and_registries/shared/components/registry_breadcrumb.vue @@ -11,9 +11,8 @@ export default { }, props: { staticBreadcrumbs: { - type: Object, - required: false, - default: () => ({ items: [] }), + type: Array, + required: true, }, }, computed: { @@ -34,7 +33,7 @@ export default { }, allCrumbs() { const crumbs = [ - ...this.staticBreadcrumbs.items, + ...this.staticBreadcrumbs, { text: this.rootRoute.meta.nameGenerator(), to: this.rootRoute.path, diff --git a/app/assets/javascripts/token_access/components/inbound_token_access.vue b/app/assets/javascripts/token_access/components/inbound_token_access.vue index c0cf55e93b8..12426c063d7 100644 --- a/app/assets/javascripts/token_access/components/inbound_token_access.vue +++ b/app/assets/javascripts/token_access/components/inbound_token_access.vue @@ -142,8 +142,10 @@ export default { groups = this.mapAllowlistNodes(allowlist?.groupsAllowlist); projects = this.mapAllowlistNodes(allowlist?.projectsAllowlist); // Add a dummy entry for the current project. The new ciJobTokenScopeAllowlist endpoint doesn't have an entry - // for the current project like the old ciJobTokenScope endpoint did, so we have to add it in manually. - projects.push({ ...project, defaultPermissions: true, jobTokenPolicies: [] }); + // for the current project like the old ciJobTokenScope endpoint did, so we have to add it in manually, if it + // doesn't exist yet. + if (!projects.some(({ id }) => id === project.id)) + projects.push({ ...project, defaultPermissions: true, jobTokenPolicies: [] }); } else { projects = project?.ciJobTokenScope?.inboundAllowlist?.nodes ?? []; groups = project?.ciJobTokenScope?.groupsAllowlist?.nodes ?? []; @@ -211,7 +213,7 @@ export default { }, allowlist() { const { groups, projects } = this.groupsAndProjectsWithAccess; - return [...groups, ...projects]; + return [...groups, ...projects].sort((a, b) => a.fullPath.localeCompare(b.fullPath)); }, disclosureDropdownOptions() { return [ diff --git a/app/assets/javascripts/token_access/components/token_access_table.vue b/app/assets/javascripts/token_access/components/token_access_table.vue index c29da091aa5..5e761a408dc 100644 --- a/app/assets/javascripts/token_access/components/token_access_table.vue +++ b/app/assets/javascripts/token_access/components/token_access_table.vue @@ -1,5 +1,6 @@ @@ -136,6 +135,9 @@ export default { class="gl-ml-3 gl-shrink-0" data-testid="autopopulated-icon" /> + {{ + __('Current project') + }}
@@ -159,7 +161,7 @@ export default {