diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-03 03:10:55 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-03 03:10:55 +0300 |
commit | 198460d5879a516844f81f667c6bc4fe84ed1719 (patch) | |
tree | cd6e50aec1232500dc4486adf2cb8dd28c8ac378 | |
parent | 9579eee8954e0405c2dadb19c2a73c9597ce37ea (diff) |
Add latest changes from gitlab-org/gitlab@master
47 files changed, 404 insertions, 181 deletions
diff --git a/app/assets/javascripts/frequent_items/components/app.vue b/app/assets/javascripts/frequent_items/components/app.vue index a4e883c96b5..947d3053094 100644 --- a/app/assets/javascripts/frequent_items/components/app.vue +++ b/app/assets/javascripts/frequent_items/components/app.vue @@ -6,6 +6,7 @@ import { mapVuexModuleActions, mapVuexModuleGetters, } from '~/lib/utils/vuex_module_mappers'; +import Tracking from '~/tracking'; import { FREQUENT_ITEMS, STORAGE_KEY } from '../constants'; import eventHub from '../event_hub'; import { isMobile, updateExistingFrequentItem, sanitizeItem } from '../utils'; @@ -13,6 +14,8 @@ import FrequentItemsList from './frequent_items_list.vue'; import frequentItemsMixin from './frequent_items_mixin'; import FrequentItemsSearchInput from './frequent_items_search_input.vue'; +const trackingMixin = Tracking.mixin(); + export default { components: { FrequentItemsSearchInput, @@ -24,7 +27,7 @@ export default { directives: { GlTooltip: GlTooltipDirective, }, - mixins: [frequentItemsMixin], + mixins: [frequentItemsMixin, trackingMixin], inject: ['vuexModule'], props: { currentUserName: { @@ -84,6 +87,13 @@ export default { 'toggleItemsListEditablity', 'fetchFrequentItems', ]), + toggleItemsListEditablityTracked() { + this.track('click_button', { + label: 'toggle_edit_frequent_items', + property: 'navigation_top', + }); + this.toggleItemsListEditablity(); + }, dropdownOpenHandler() { if (this.searchQuery === '' || isMobile()) { this.fetchFrequentItems(); @@ -155,7 +165,7 @@ export default { :title="translations.headerEditToggle" :class="{ 'gl-bg-gray-100!': isItemsListEditable }" class="gl-p-2!" - @click="toggleItemsListEditablity" + @click="toggleItemsListEditablityTracked" > <gl-icon name="pencil" :class="{ 'gl-text-gray-900!': isItemsListEditable }" /> </gl-button> diff --git a/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue b/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue index 430498e7194..056dedf8757 100644 --- a/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue +++ b/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue @@ -64,6 +64,13 @@ export default { }, }, methods: { + removeFrequentItemTracked(item) { + this.track('click_button', { + label: `${this.dropdownType}_dropdown_remove_frequent_item`, + property: 'navigation_top', + }); + this.removeFrequentItem(item); + }, ...mapVuexModuleActions((vm) => vm.vuexModule, ['removeFrequentItem']), }, }; @@ -77,7 +84,7 @@ export default { class="gl-text-left gl-w-full" button-text-classes="gl-display-flex gl-w-full" data-testid="frequent-item-link" - @click="track('click_link', { label: itemTrackingLabel })" + @click="track('click_link', { label: itemTrackingLabel, property: 'navigation_top' })" > <div class="gl-flex-grow-1"> <project-avatar @@ -117,7 +124,7 @@ export default { :title="__('Remove')" class="gl-align-self-center gl-p-1! gl-absolute! gl-w-auto! gl-right-4 gl-top-half gl-translate-y-n50" data-testid="item-remove" - @click.stop.prevent="removeFrequentItem(itemId)" + @click.stop.prevent="removeFrequentItemTracked(itemId)" > <gl-icon name="close" /> </gl-button> diff --git a/app/assets/javascripts/frequent_items/components/frequent_items_search_input.vue b/app/assets/javascripts/frequent_items/components/frequent_items_search_input.vue index 4a1b7e57749..023245f050b 100644 --- a/app/assets/javascripts/frequent_items/components/frequent_items_search_input.vue +++ b/app/assets/javascripts/frequent_items/components/frequent_items_search_input.vue @@ -28,12 +28,25 @@ export default { searchQuery: debounce(function debounceSearchQuery() { this.track('type_search_query', { label: `${this.dropdownType}_dropdown_frequent_items_search_input`, + property: 'navigation_top', }); this.setSearchQuery(this.searchQuery); }, 500), }, methods: { ...mapVuexModuleActions((vm) => vm.vuexModule, ['setSearchQuery']), + trackFocus() { + this.track('focus_input', { + label: `${this.dropdownType}_dropdown_frequent_items_search_input`, + property: 'navigation_top', + }); + }, + trackBlur() { + this.track('blur_input', { + label: `${this.dropdownType}_dropdown_frequent_items_search_input`, + property: 'navigation_top', + }); + }, }, }; </script> @@ -43,6 +56,8 @@ export default { <gl-search-box-by-type v-model="searchQuery" :placeholder="translations.searchInputPlaceholder" + @focus="trackFocus" + @blur="trackBlur" /> </div> </template> diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js index f58781fa9ec..6c9354b663f 100644 --- a/app/assets/javascripts/header.js +++ b/app/assets/javascripts/header.js @@ -33,6 +33,13 @@ function initStatusTriggers() { if (setStatusModalTriggerEl) { setStatusModalTriggerEl.addEventListener('click', () => { + const topNavbar = document.querySelector('.navbar-gitlab'); + const buttonWithinTopNav = topNavbar && topNavbar.contains(setStatusModalTriggerEl); + Tracking.event(undefined, 'click_button', { + label: 'user_edit_status', + property: buttonWithinTopNav ? 'navigation_top' : undefined, + }); + import( /* webpackChunkName: 'statusModalBundle' */ './set_status_modal/set_status_modal_wrapper.vue' ) diff --git a/app/assets/javascripts/header_search/components/app.vue b/app/assets/javascripts/header_search/components/app.vue index bf5daf29b21..ace0d77c431 100644 --- a/app/assets/javascripts/header_search/components/app.vue +++ b/app/assets/javascripts/header_search/components/app.vue @@ -171,7 +171,7 @@ export default { Tracking.event(undefined, 'focus_input', { label: 'global_search', - property: 'top_navigation', + property: 'navigation_top', }); } }, @@ -190,7 +190,7 @@ export default { Tracking.event(undefined, 'blur_input', { label: 'global_search', - property: 'top_navigation', + property: 'navigation_top', }); }, 200); }, diff --git a/app/assets/javascripts/nav/components/new_nav_toggle.vue b/app/assets/javascripts/nav/components/new_nav_toggle.vue index 7b0076cc5d4..da22a8d2fb7 100644 --- a/app/assets/javascripts/nav/components/new_nav_toggle.vue +++ b/app/assets/javascripts/nav/components/new_nav_toggle.vue @@ -45,7 +45,7 @@ export default { Tracking.event(undefined, 'click_toggle', { label: this.enabled ? 'disable_new_nav_beta' : 'enable_new_nav_beta', - property: 'navigation', + property: this.enabled ? 'navigation' : 'navigation_top', }); window.location.reload(); diff --git a/app/assets/javascripts/nav/components/top_nav_app.vue b/app/assets/javascripts/nav/components/top_nav_app.vue index e55bf25a60c..ab9313f7041 100644 --- a/app/assets/javascripts/nav/components/top_nav_app.vue +++ b/app/assets/javascripts/nav/components/top_nav_app.vue @@ -24,7 +24,7 @@ export default { trackToggleEvent() { Tracking.event(undefined, 'click_nav', { label: 'hamburger_menu', - property: 'top_navigation', + property: 'navigation_top', }); }, }, diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue index a04b082fa87..4b65d6fd9ac 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue @@ -62,6 +62,7 @@ export default { fetchingApprovals: true, hasApprovalAuthError: false, isApproving: false, + updatedCount: 0, }; }, computed: { @@ -197,6 +198,7 @@ export default { return serviceFn() .then((data) => { this.mr.setApprovals(data); + this.updatedCount += 1; if (!window.gon?.features?.realtimeMrStatusChange) { eventHub.$emit('MRWidgetUpdateRequested'); @@ -250,10 +252,10 @@ export default { /> <approvals-summary v-else - :approved="isApproved" - :approvals-left="approvals.approvals_left || 0" - :rules-left="approvals.approvalRuleNamesLeft" - :approvers="approvedBy" + :project-path="mr.targetProjectFullPath" + :iid="`${mr.iid}`" + :updated-count="updatedCount" + :multiple-approval-rules-available="mr.multipleApprovalRulesAvailable" /> </div> <div v-if="hasInvalidRules" class="gl-text-gray-400 gl-mt-2" data-testid="invalid-rules"> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue index d7255eb6ad2..7c283c42a03 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue @@ -1,4 +1,5 @@ <script> +import { GlSkeletonLoader } from '@gitlab/ui'; import { toNounSeriesText } from '~/lib/utils/grammar'; import { n__, sprintf } from '~/locale'; import { @@ -7,32 +8,68 @@ import { APPROVED_BY_OTHERS, } from '~/vue_merge_request_widget/components/approvals/messages'; import UserAvatarList from '~/vue_shared/components/user_avatar/user_avatar_list.vue'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import { getApprovalRuleNamesLeft } from 'ee_else_ce/vue_merge_request_widget/mappers'; +import approvedByQuery from 'ee_else_ce/vue_merge_request_widget/components/approvals/queries/approved_by.query.graphql'; export default { + apollo: { + approvalState: { + query: approvedByQuery, + variables() { + return { + projectPath: this.projectPath, + iid: this.iid, + }; + }, + update: (data) => data.project.mergeRequest, + }, + }, components: { + GlSkeletonLoader, UserAvatarList, }, props: { - approved: { - type: Boolean, + projectPath: { + type: String, required: true, }, - approvalsLeft: { - type: Number, + iid: { + type: String, required: true, }, - rulesLeft: { - type: Array, + updatedCount: { + type: Number, required: false, - default: () => [], + default: 0, }, - approvers: { - type: Array, + multipleApprovalRulesAvailable: { + type: Boolean, required: false, - default: () => [], + default: false, }, }, + data() { + return { + approvalState: {}, + }; + }, computed: { + approvers() { + return this.approvalState.approvedBy?.nodes || []; + }, + approved() { + return this.approvalState.approved || this.approvalState.approvedBy?.nodes.length > 0; + }, + approvalsLeft() { + return this.approvalState.approvalsLeft || 0; + }, + rulesLeft() { + return getApprovalRuleNamesLeft( + this.multipleApprovalRulesAvailable, + (this.approvalState.approvalState?.rules || []).filter((r) => r.approvalsRequired !== 0), + ); + }, approvalLeftMessage() { if (this.rulesLeft.length) { return sprintf( @@ -81,32 +118,53 @@ export default { if (!this.currentUserId) { return false; } - return this.approvers.some((approver) => approver.id === this.currentUserId); + return this.approvers.some( + (approver) => getIdFromGraphQLId(approver.id) === this.currentUserId, + ); }, approvedByOthers() { if (!this.currentUserId) { return false; } - return this.approvers.some((approver) => approver.id !== this.currentUserId); + return this.approvers.some( + (approver) => getIdFromGraphQLId(approver.id) !== this.currentUserId, + ); }, currentUserId() { return gon.current_user_id; }, }, + watch: { + updatedCount() { + this.$apollo.queries.approvalState.refetch(); + }, + }, }; </script> <template> <div data-qa-selector="approvals_summary_content"> - <span class="gl-font-weight-bold">{{ approvalLeftMessage }}</span> - <template v-if="hasApprovers"> - <span v-if="approvalLeftMessage">{{ message }}</span> - <span v-else class="gl-font-weight-bold">{{ message }}</span> - <user-avatar-list - class="gl-display-inline-block gl-vertical-align-middle gl-pt-1" - :img-size="24" - :items="approvers" - /> + <div + v-if="$apollo.queries.approvalState.loading" + class="gl-display-inline-block gl-vertical-align-middle" + style="width: 132px; height: 24px" + > + <gl-skeleton-loader :width="132" :height="24"> + <rect width="100" height="24" x="0" y="0" rx="4" /> + <circle cx="120" cy="12" r="12" /> + </gl-skeleton-loader> + </div> + <template v-else> + <span class="gl-font-weight-bold">{{ approvalLeftMessage }}</span> + <template v-if="hasApprovers"> + <span v-if="approvalLeftMessage">{{ message }}</span> + <span v-else class="gl-font-weight-bold">{{ message }}</span> + <user-avatar-list + class="gl-display-inline-block gl-vertical-align-middle gl-pt-1" + :img-size="24" + :items="approvers" + /> + </template> </template> </div> </template> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/queries/approved_by.query.graphql b/app/assets/javascripts/vue_merge_request_widget/components/approvals/queries/approved_by.query.graphql new file mode 100644 index 00000000000..c8cae6a8885 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/approvals/queries/approved_by.query.graphql @@ -0,0 +1,16 @@ +query approvedBy($projectPath: ID!, $iid: String!) { + project(fullPath: $projectPath) { + id + mergeRequest(iid: $iid) { + id + approvedBy { + nodes { + id + name + avatarUrl + webUrl + } + } + } + } +} diff --git a/app/assets/javascripts/vue_merge_request_widget/mappers.js b/app/assets/javascripts/vue_merge_request_widget/mappers.js new file mode 100644 index 00000000000..63c4c3dc871 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/mappers.js @@ -0,0 +1,3 @@ +export function getApprovalRuleNamesLeft(_, rules) { + return rules; +} diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js index 85df2ea63c8..f6a7ef58c10 100644 --- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js +++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js @@ -30,6 +30,7 @@ export default class MergeRequestStore { this.machineValue = this.stateMachine.value; this.mergeDetailsCollapsed = window.innerWidth < 768; this.mergeError = data.mergeError; + this.multipleApprovalRulesAvailable = data.multiple_approval_rules_available || false; this.id = data.id; this.setPaths(data); diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_list.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_list.vue index 231f5ff3d1f..4f3b482d7f8 100644 --- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_list.vue +++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_list.vue @@ -75,7 +75,7 @@ export default { v-for="item in visibleItems" :key="item.id" :link-href="item.web_url" - :img-src="item.avatar_url" + :img-src="item.avatar_url || item.avatarUrl" :img-alt="item.name" :tooltip-text="item.name" :img-size="imgSize" diff --git a/app/assets/javascripts/whats_new/components/app.vue b/app/assets/javascripts/whats_new/components/app.vue index 9e5361e8302..472bc1dfacc 100644 --- a/app/assets/javascripts/whats_new/components/app.vue +++ b/app/assets/javascripts/whats_new/components/app.vue @@ -35,7 +35,11 @@ export default { const body = document.querySelector('body'); const { namespaceId } = body.dataset; - this.track('click_whats_new_drawer', { label: 'namespace_id', value: namespaceId }); + this.track('click_whats_new_drawer', { + label: 'namespace_id', + value: namespaceId, + property: 'navigation_top', + }); }, methods: { ...mapActions(['openDrawer', 'closeDrawer', 'fetchItems', 'setDrawerBodyHeight']), diff --git a/app/helpers/nav/new_dropdown_helper.rb b/app/helpers/nav/new_dropdown_helper.rb index 4972d359bd6..ddd6469a9e4 100644 --- a/app/helpers/nav/new_dropdown_helper.rb +++ b/app/helpers/nav/new_dropdown_helper.rb @@ -32,7 +32,7 @@ module Nav id: 'new_project', title: _('New project/repository'), href: new_project_path(namespace_id: group.id), - data: { track_action: 'click_link_new_project_group', track_label: 'plus_menu_dropdown' } + data: { track_action: 'click_link_new_project_group', track_label: 'plus_menu_dropdown', track_property: 'navigation_top' } ) ) end @@ -43,7 +43,7 @@ module Nav id: 'new_subgroup', title: _('New subgroup'), href: new_group_path(parent_id: group.id, anchor: 'create-group-pane'), - data: { track_action: 'click_link_new_subgroup', track_label: 'plus_menu_dropdown' } + data: { track_action: 'click_link_new_subgroup', track_label: 'plus_menu_dropdown', track_property: 'navigation_top' } ) ) end @@ -74,7 +74,7 @@ module Nav id: 'new_issue', title: _('New issue'), href: new_project_issue_path(project), - data: { track_action: 'click_link_new_issue', track_label: 'plus_menu_dropdown', qa_selector: 'new_issue_link' } + data: { track_action: 'click_link_new_issue', track_label: 'plus_menu_dropdown', track_property: 'navigation_top', qa_selector: 'new_issue_link' } ) ) end @@ -85,7 +85,7 @@ module Nav id: 'new_mr', title: _('New merge request'), href: project_new_merge_request_path(merge_project), - data: { track_action: 'click_link_new_mr', track_label: 'plus_menu_dropdown' } + data: { track_action: 'click_link_new_mr', track_label: 'plus_menu_dropdown', track_property: 'navigation_top' } ) ) end @@ -96,7 +96,7 @@ module Nav id: 'new_snippet', title: _('New snippet'), href: new_project_snippet_path(project), - data: { track_action: 'click_link_new_snippet_project', track_label: 'plus_menu_dropdown' } + data: { track_action: 'click_link_new_snippet_project', track_label: 'plus_menu_dropdown', track_property: 'navigation_top' } ) ) end @@ -124,7 +124,7 @@ module Nav id: 'general_new_project', title: _('New project/repository'), href: new_project_path, - data: { track_action: 'click_link_new_project', track_label: 'plus_menu_dropdown', qa_selector: 'global_new_project_link' } + data: { track_action: 'click_link_new_project', track_label: 'plus_menu_dropdown', track_property: 'navigation_top', qa_selector: 'global_new_project_link' } ) ) end @@ -135,7 +135,7 @@ module Nav id: 'general_new_group', title: _('New group'), href: new_group_path, - data: { track_action: 'click_link_new_group', track_label: 'plus_menu_dropdown', qa_selector: 'global_new_group_link' } + data: { track_action: 'click_link_new_group', track_label: 'plus_menu_dropdown', track_property: 'navigation_top', qa_selector: 'global_new_group_link' } ) ) end @@ -146,7 +146,7 @@ module Nav id: 'general_new_snippet', title: _('New snippet'), href: new_snippet_path, - data: { track_action: 'click_link_new_snippet_parent', track_label: 'plus_menu_dropdown', qa_selector: 'global_new_snippet_link' } + data: { track_action: 'click_link_new_snippet_parent', track_label: 'plus_menu_dropdown', track_property: 'navigation_top', qa_selector: 'global_new_snippet_link' } ) ) end @@ -165,7 +165,8 @@ module Nav href: href, data: { track_action: 'click_link_invite_members', - track_label: 'plus_menu_dropdown' + track_label: 'plus_menu_dropdown', + track_property: 'navigation_top' } ) end diff --git a/app/helpers/nav/top_nav_helper.rb b/app/helpers/nav/top_nav_helper.rb index bd4d661ab49..fb11c183aeb 100644 --- a/app/helpers/nav/top_nav_helper.rb +++ b/app/helpers/nav/top_nav_helper.rb @@ -101,7 +101,7 @@ module Nav builder.add_primary_menu_item_with_shortcut( header: top_nav_localized_headers[:switch_to], active: nav == 'project' || active_nav_link?(path: %w[root#index projects#trending projects#starred dashboard/projects#index]), - data: { track_label: "projects_dropdown", track_action: "click_dropdown", qa_selector: "projects_dropdown" }, + data: { track_label: "projects_dropdown", track_action: "click_dropdown", track_property: "navigation_top", qa_selector: "projects_dropdown" }, view: PROJECTS_VIEW, shortcut_href: dashboard_projects_path, **projects_menu_item_attrs @@ -115,7 +115,7 @@ module Nav builder.add_primary_menu_item_with_shortcut( header: top_nav_localized_headers[:switch_to], active: nav == 'group' || active_nav_link?(path: %w[dashboard/groups explore/groups]), - data: { track_label: "groups_dropdown", track_action: "click_dropdown", qa_selector: "groups_dropdown" }, + data: { track_label: "groups_dropdown", track_action: "click_dropdown", track_property: "navigation_top", qa_selector: "groups_dropdown" }, view: GROUPS_VIEW, shortcut_href: dashboard_groups_path, **groups_menu_item_attrs @@ -233,7 +233,7 @@ module Nav tracking_attrs( "menu_#{label.underscore.parameterize(separator: '_')}", 'click_dropdown', - 'navigation' + 'navigation_top' )[:data] || {} end diff --git a/app/models/concerns/vulnerability_finding_helpers.rb b/app/models/concerns/vulnerability_finding_helpers.rb index b5d48260072..1e8a290c050 100644 --- a/app/models/concerns/vulnerability_finding_helpers.rb +++ b/app/models/concerns/vulnerability_finding_helpers.rb @@ -49,7 +49,7 @@ module VulnerabilityFindingHelpers finding_data = report_finding.to_hash.except(:compare_key, :identifiers, :location, :scanner, :links, :signatures, :flags, :evidence) - identifiers = report_finding.identifiers.map do |identifier| + identifiers = report_finding.identifiers.uniq(&:fingerprint).map do |identifier| Vulnerabilities::Identifier.new(identifier.to_hash.merge({ project: project })) end signatures = report_finding.signatures.map do |signature| diff --git a/app/models/packages/package.rb b/app/models/packages/package.rb index c6e8ff6c3fa..c5da647eea5 100644 --- a/app/models/packages/package.rb +++ b/app/models/packages/package.rb @@ -279,6 +279,7 @@ class Packages::Package < ApplicationRecord project.packages .preload_pipelines .including_tags + .displayable .with_name(name) .where.not(version: version) .with_package_type(package_type) diff --git a/app/views/layouts/header/_current_user_dropdown.html.haml b/app/views/layouts/header/_current_user_dropdown.html.haml index 8363d424c1b..af27026845e 100644 --- a/app/views/layouts/header/_current_user_dropdown.html.haml +++ b/app/views/layouts/header/_current_user_dropdown.html.haml @@ -3,7 +3,7 @@ %ul %li.current-user - if current_user_menu?(:profile) - = link_to current_user, class: 'gl-line-height-20!', data: { user: current_user.username, testid: 'user-profile-link', qa_selector: 'user_profile_link' } do + = link_to current_user, class: 'gl-line-height-20!', data: { user: current_user.username, testid: 'user-profile-link', track_action: "click_link", track_label: "user_profile", track_property: "navigation_top", qa_selector: 'user_profile_link' } do = render 'layouts/header/current_user_dropdown_item' - else .gl-py-3.gl-px-4 @@ -23,28 +23,28 @@ = emoji_icon('rocket') - if current_user_menu?(:settings) %li - = link_to s_("CurrentUser|Edit profile"), profile_path, data: { qa_selector: 'edit_profile_link' } + = link_to s_("CurrentUser|Edit profile"), profile_path, data: { qa_selector: 'edit_profile_link', track_action: "click_link", track_label: "user_edit_profile", track_property: "navigation_top" } %li - = link_to s_("CurrentUser|Preferences"), profile_preferences_path + = link_to s_("CurrentUser|Preferences"), profile_preferences_path, data: { track_action: "click_link", track_label: "user_preferences", track_property: "navigation_top" } = render_if_exists 'layouts/header/buy_pipeline_minutes', project: @project, namespace: @group - if current_user_menu?(:help) %li.divider.d-md-none %li.d-md-none - = link_to _("Help"), help_path + = link_to _("Help"), help_path, data: {track_action: 'click_link', track_label: 'help', track_property: 'navigation_top'} %li.d-md-none - = link_to _("Support"), support_url + = link_to _("Support"), support_url, data: {track_action: 'click_link', track_label: 'support', track_property: 'navigation_top'} %li.d-md-none = render 'shared/help_dropdown_forum_link' %li.d-md-none - = link_to _("Submit feedback"), Gitlab::Utils.append_path(promo_url, "submit-feedback") + = link_to _("Submit feedback"), Gitlab::Utils.append_path(promo_url, "submit-feedback"), data: {track_action: 'click_link', track_label: 'submit_feedback', track_property: 'navigation_top'} - if current_user_menu?(:help) || current_user_menu?(:settings) || current_user_menu?(:profile) %li.d-md-none = render 'shared/user_dropdown_contributing_link' = render 'shared/user_dropdown_instance_review' - if Gitlab.com_but_not_canary? %li.d-md-none - = link_to _("Switch to GitLab Next"), Gitlab::Saas.canary_toggle_com_url + = link_to _("Switch to GitLab Next"), Gitlab::Saas.canary_toggle_com_url, data: { track_action: "click_link", track_label: "switch_to_canary", track_property: "navigation_top" } - if Feature.enabled?(:super_sidebar_nav, current_user) %li.divider @@ -53,4 +53,4 @@ - if current_user_menu?(:sign_out) %li.divider %li - = link_to _("Sign out"), destroy_user_session_path, method: :post, class: "sign-out-link", data: { qa_selector: 'sign_out_link' } + = link_to _("Sign out"), destroy_user_session_path, method: :post, class: "sign-out-link", data: { qa_selector: 'sign_out_link', track_action: "click_link", track_label: "user_sign_out", track_property: "navigation_top" } diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 4cd876e4fc0..3b2cd4c30dd 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -8,7 +8,7 @@ .title-container.hide-when-top-nav-responsive-open.gl-transition-medium.gl-display-flex.gl-align-items-stretch.gl-pt-0.gl-mr-3 .title %span.gl-sr-only GitLab - = link_to root_path, title: _('Dashboard'), id: 'logo', class: 'has-tooltip', **tracking_attrs('main_navigation', 'click_gitlab_logo_link', 'navigation') do + = link_to root_path, title: _('Dashboard'), id: 'logo', class: 'has-tooltip', **tracking_attrs('main_navigation', 'click_gitlab_logo_link', 'navigation_top') do = brand_header_logo .gl-display-flex.gl-align-items-center - if Gitlab.com_and_canary? @@ -36,7 +36,11 @@ - else = render 'layouts/search' %li.nav-item{ class: 'd-none d-sm-inline-block d-lg-none' } - = link_to search_menu_item.fetch(:href), title: search_menu_item.fetch(:title), aria: { label: search_menu_item.fetch(:title) }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do + = link_to search_menu_item.fetch(:href), title: search_menu_item.fetch(:title), aria: { label: search_menu_item.fetch(:title) }, + data: { toggle: 'tooltip', placement: 'bottom', container: 'body', + track_action: 'click_link', + track_label: 'global_search', + track_property: 'navigation_top' } do = sprite_icon(search_menu_item.fetch(:icon)) .navbar-collapse.gl-transition-medium.collapse @@ -49,7 +53,7 @@ data: { qa_selector: 'issues_shortcut_button', toggle: 'tooltip', placement: 'bottom', track_label: 'main_navigation', track_action: 'click_issues_link', - track_property: 'navigation', + track_property: 'navigation_top', container: 'body' } do = sprite_icon('issues') - issues_count = assigned_issuables_count(:issues) @@ -62,9 +66,9 @@ data: { qa_selector: 'merge_requests_shortcut_button', toggle: "dropdown", placement: 'bottom', - track_label: 'main_navigation', - track_action: 'click_merge_link', - track_property: 'navigation', + track_label: 'merge_requests_menu', + track_action: 'click_dropdown', + track_property: 'navigation_top', container: 'body' } do = sprite_icon('git-merge') = gl_badge_tag({ size: :sm, variant: :warning }, { class: "js-merge-requests-count gl-ml-n2 #{'gl-display-none' if user_merge_requests_counts[:total] == 0}", "aria-label": n_("%d merge request", "%d merge requests", user_merge_requests_counts[:total]) % user_merge_requests_counts[:total] }) do @@ -75,12 +79,16 @@ %li.dropdown-header = _('Merge requests') %li - = link_to assigned_mrs_dashboard_path, class: 'gl-display-flex! gl-align-items-center js-prefetch-document' do + = link_to assigned_mrs_dashboard_path, + class: 'gl-display-flex! gl-align-items-center js-prefetch-document', + data: {track_action: 'click_link', track_label: 'merge_requests_assigned', track_property: 'navigation_top'} do = _('Assigned') = gl_badge_tag({ variant: :neutral, size: :sm }, { class: "js-assigned-mr-count gl-ml-auto" }) do = user_merge_requests_counts[:assigned] %li - = link_to reviewer_mrs_dashboard_path, class: 'dashboard-shortcuts-review_requests gl-display-flex! gl-align-items-center js-prefetch-document' do + = link_to reviewer_mrs_dashboard_path, + class: 'dashboard-shortcuts-review_requests gl-display-flex! gl-align-items-center js-prefetch-document', + data: {track_action: 'click_link', track_label: 'merge_requests_to_review', track_property: 'navigation_top'} do = _('Review requests') = gl_badge_tag({ variant: :neutral, size: :sm }, { class: "js-reviewer-mr-count gl-ml-auto" }) do = user_merge_requests_counts[:review_requested] @@ -90,15 +98,15 @@ data: { qa_selector: 'todos_shortcut_button', toggle: 'tooltip', placement: 'bottom', track_label: 'main_navigation', track_action: 'click_to_do_link', - track_property: 'navigation', + track_property: 'navigation_top', container: 'body' } do = sprite_icon('todo-done') -# The todos' counter badge's visibility is being toggled by adding or removing the .hidden class in Js. -# We'll eventually migrate to .gl-display-none: https://gitlab.com/gitlab-org/gitlab/-/issues/351792. = gl_badge_tag({ size: :sm, variant: :info }, { class: "js-todos-count gl-ml-n2 #{'hidden' if todos_pending_count == 0}", "aria-label": _("Todos count") }) do = todos_count_format(todos_pending_count) - %li.nav-item.header-help.dropdown.d-none.d-md-block{ data: { track_action: 'click_question_mark_link', track_label: 'main_navigation', track_property: 'navigation', track_experiment: 'cross_stage_fdm' } } - = link_to help_path, class: 'header-help-dropdown-toggle gl-relative', data: { toggle: "dropdown" } do + %li.nav-item.header-help.dropdown.d-none.d-md-block + = link_to help_path, class: 'header-help-dropdown-toggle gl-relative', data: { toggle: "dropdown", track_action: 'click_question_mark_link', track_label: 'main_navigation', track_property: 'navigation_top', track_experiment: 'cross_stage_fdm' } do %span.gl-sr-only = s_('Nav|Help') = sprite_icon('question-o') @@ -110,8 +118,8 @@ %li.nav-item.gl-display-none.gl-sm-display-block = render "layouts/nav/top_nav" - if header_link?(:user_dropdown) - %li.nav-item.header-user.js-nav-user-dropdown.dropdown{ data: { track_label: "profile_dropdown", track_action: "click_dropdown", track_value: "", qa_selector: 'user_menu', testid: 'user-menu' }, class: ('mr-0' if has_impersonation_link) } - = link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do + %li.nav-item.header-user.js-nav-user-dropdown.dropdown{ data: { qa_selector: 'user_menu', testid: 'user-menu' }, class: ('mr-0' if has_impersonation_link) } + = link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown", track_label: "profile_dropdown", track_action: "click_dropdown", track_property: "navigation_top" } do = render Pajamas::AvatarComponent.new(current_user, size: 24, class: 'header-user-avatar', avatar_options: { data: { qa_selector: 'user_avatar_content' } }) = render_if_exists 'layouts/header/user_notification_dot', project: project, namespace: group = sprite_icon('chevron-down', css_class: 'caret-down') diff --git a/app/views/layouts/header/_gitlab_version.html.haml b/app/views/layouts/header/_gitlab_version.html.haml index 581d4d498e1..22771ac09c9 100644 --- a/app/views/layouts/header/_gitlab_version.html.haml +++ b/app/views/layouts/header/_gitlab_version.html.haml @@ -7,7 +7,7 @@ testid: 'gitlab-version-container', track_action: 'click_link', track_label: 'version_help_dropdown', - track_property: "#{Gitlab.version_info.major}.#{Gitlab.version_info.minor}" + track_property: 'navigation_top' } } %span diff --git a/app/views/layouts/header/_help_dropdown.html.haml b/app/views/layouts/header/_help_dropdown.html.haml index bdd1ae291fd..f50df72afbc 100644 --- a/app/views/layouts/header/_help_dropdown.html.haml +++ b/app/views/layouts/header/_help_dropdown.html.haml @@ -5,22 +5,22 @@ = render_if_exists 'layouts/header/help_dropdown/cross_stage_fdm' = render 'layouts/header/whats_new_dropdown_item' %li - = link_to _("Help"), help_path + = link_to _("Help"), help_path, data: {track_action: 'click_link', track_label: 'help', track_property: 'navigation_top'} %li - = link_to _("Support"), support_url + = link_to _("Support"), support_url, data: {track_action: 'click_link', track_label: 'support', track_property: 'navigation_top'} %li = render 'shared/help_dropdown_forum_link' %li - %button.js-shortcuts-modal-trigger{ type: "button" } + %button.js-shortcuts-modal-trigger{ type: "button", data: {track_action: 'click_button', track_label: 'keyboard_shortcuts_help', track_property: 'navigation_top'} } = _("Keyboard shortcuts") %kbd.flat.float-right{ "aria-hidden": "true" }= '?'.html_safe %li.divider %li - = link_to _("Submit feedback"), "https://about.gitlab.com/submit-feedback" + = link_to _("Submit feedback"), "https://about.gitlab.com/submit-feedback", data: {track_action: 'click_link', track_label: 'submit_feedback', track_property: 'navigation_top'} - if current_user_menu?(:help) || current_user_menu?(:settings) || current_user_menu?(:profile) %li = render 'shared/user_dropdown_contributing_link' = render 'shared/user_dropdown_instance_review' - if Gitlab.com_but_not_canary? %li - = link_to _("Switch to GitLab Next"), Gitlab::Saas.canary_toggle_com_url + = link_to _("Switch to GitLab Next"), Gitlab::Saas.canary_toggle_com_url, data: {track_action: 'click_link', track_label: 'gitlab_next', track_property: 'navigation_top'} diff --git a/app/views/layouts/header/_new_dropdown.html.haml b/app/views/layouts/header/_new_dropdown.html.haml index f39fb53032d..a135ee8fed8 100644 --- a/app/views/layouts/header/_new_dropdown.html.haml +++ b/app/views/layouts/header/_new_dropdown.html.haml @@ -6,7 +6,7 @@ - return if menu_sections.empty? -%li.header-new.gl-flex-grow-1.gl-flex-shrink-1.dropdown{ class: top_class, data: { track_label: "new_dropdown", track_action: "click_dropdown" } } +%li.header-new.gl-flex-grow-1.gl-flex-shrink-1.dropdown{ class: top_class, data: { track_label: "new_dropdown", track_action: "click_dropdown", track_property: "navigation_top" } } = link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip gl-display-flex", id: "js-onboarding-new-project-link", title: title, ref: 'tooltip', aria: { label: title }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body', display: 'static', qa_selector: 'new_menu_toggle' } do = sprite_icon('plus-square') = sprite_icon('chevron-down', css_class: 'caret-down') diff --git a/app/views/shared/_help_dropdown_forum_link.html.haml b/app/views/shared/_help_dropdown_forum_link.html.haml index 06889428e82..6d65f2e61bd 100644 --- a/app/views/shared/_help_dropdown_forum_link.html.haml +++ b/app/views/shared/_help_dropdown_forum_link.html.haml @@ -1,2 +1,2 @@ = link_to _("Community forum"), ApplicationHelper.community_forum, target: '_blank', class: 'text-nowrap', - rel: 'noopener noreferrer', data: { 'track_action': 'click_forum', 'track_property': 'question_menu' } + rel: 'noopener noreferrer', data: { 'track_action': 'click_link', 'track_label': 'community_forum', 'track_property': 'navigation_top' } diff --git a/app/views/shared/_user_dropdown_contributing_link.html.haml b/app/views/shared/_user_dropdown_contributing_link.html.haml index d4c3e11d051..70d9db998fc 100644 --- a/app/views/shared/_user_dropdown_contributing_link.html.haml +++ b/app/views/shared/_user_dropdown_contributing_link.html.haml @@ -1,2 +1,2 @@ -= link_to "https://about.gitlab.com/contributing", target: '_blank', class: 'text-nowrap' do += link_to "https://about.gitlab.com/contributing", target: '_blank', class: 'text-nowrap', data: {track_action: 'click_link', track_label: 'contribute_to_gitlab', track_property: 'navigation_top'} do = _("Contribute to GitLab") diff --git a/app/views/shared/_user_dropdown_instance_review.html.haml b/app/views/shared/_user_dropdown_instance_review.html.haml index 18bfb5d7e3e..1a02f9958b0 100644 --- a/app/views/shared/_user_dropdown_instance_review.html.haml +++ b/app/views/shared/_user_dropdown_instance_review.html.haml @@ -2,5 +2,5 @@ %li.divider %li - = link_to admin_instance_review_path, target: '_blank', class: 'text-nowrap' do + = link_to admin_instance_review_path, target: '_blank', class: 'text-nowrap', data: {track_action: 'click_link', track_label: 'instance_review', track_property: 'navigation_top'} do = _("Get a free instance review") diff --git a/db/migrate/20230123095022_create_scan_result_policies.rb b/db/migrate/20230123095022_create_scan_result_policies.rb index d5cd8a017a1..6f9eb7d0511 100644 --- a/db/migrate/20230123095022_create_scan_result_policies.rb +++ b/db/migrate/20230123095022_create_scan_result_policies.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class CreateScanResultPolicies < Gitlab::Database::Migration[2.1] - INDEX_NAME = "index_scan_result_policies_on_policy_configuration_id".freeze + INDEX_NAME = "index_scan_result_policies_on_policy_configuration_id" def change create_table :scan_result_policies do |t| diff --git a/db/post_migrate/20230123095023_add_scan_result_policy_id_to_software_license_policies.rb b/db/post_migrate/20230123095023_add_scan_result_policy_id_to_software_license_policies.rb index c3f1bcda441..7f61b3bfe85 100644 --- a/db/post_migrate/20230123095023_add_scan_result_policy_id_to_software_license_policies.rb +++ b/db/post_migrate/20230123095023_add_scan_result_policy_id_to_software_license_policies.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class AddScanResultPolicyIdToSoftwareLicensePolicies < Gitlab::Database::Migration[2.1] - INDEX_NAME = "index_software_license_policies_on_scan_result_policy_id".freeze + INDEX_NAME = "index_software_license_policies_on_scan_result_policy_id" def change # rubocop:disable Migration/AddReference diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md index aee37de9774..20127304bbe 100644 --- a/doc/development/contributing/merge_request_workflow.md +++ b/doc/development/contributing/merge_request_workflow.md @@ -224,7 +224,7 @@ requirements. 1. Working and clean code that is commented where needed. 1. The change is evaluated to [limit the impact of far-reaching work](https://about.gitlab.com/handbook/engineering/development/#reducing-the-impact-of-far-reaching-work). 1. [Performance guidelines](../merge_request_concepts/performance.md) have been followed. -1. [Secure coding guidelines](https://gitlab.com/gitlab-com/gl-security/security-guidelines) have been followed. +1. [Secure coding guidelines](../secure_coding_guidelines.md) have been followed. 1. [Application and rate limit guidelines](../merge_request_concepts/rate_limits.md) have been followed. 1. [Documented](../documentation/index.md) in the `/doc` directory. 1. If your MR touches code that executes shell commands, reads or opens files, or diff --git a/doc/user/clusters/agent/ci_cd_workflow.md b/doc/user/clusters/agent/ci_cd_workflow.md index 304bbaee256..982411d35f9 100644 --- a/doc/user/clusters/agent/ci_cd_workflow.md +++ b/doc/user/clusters/agent/ci_cd_workflow.md @@ -66,7 +66,7 @@ To authorize the agent to access the GitLab project where you keep Kubernetes ma 1. On the top bar, select **Main menu > Projects** and find the project that contains the [agent configuration file](install/index.md#create-an-agent-configuration-file) (`config.yaml`). 1. Edit the `config.yaml` file. Under the `ci_access` keyword, add the `projects` attribute. -1. For the `id`, add the path: +1. For the `id`, add the path to the project. Do not wrap the path in quotation marks. ```yaml ci_access: diff --git a/qa/Gemfile b/qa/Gemfile index 06bb6f6e6a1..efece7a7dfb 100644 --- a/qa/Gemfile +++ b/qa/Gemfile @@ -2,7 +2,7 @@ source 'https://rubygems.org' -gem 'gitlab-qa', '~> 8', '>= 8.15.2', require: 'gitlab/qa' +gem 'gitlab-qa', '~> 8', '>= 8.15.3', require: 'gitlab/qa' gem 'activesupport', '~> 6.1.7.2' # This should stay in sync with the root's Gemfile gem 'allure-rspec', '~> 2.20.0' gem 'capybara', '~> 3.38.0' diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock index ae98caecee6..56fb838a7df 100644 --- a/qa/Gemfile.lock +++ b/qa/Gemfile.lock @@ -102,7 +102,7 @@ GEM gitlab (4.18.0) httparty (~> 0.18) terminal-table (>= 1.5.1) - gitlab-qa (8.15.2) + gitlab-qa (8.15.3) activesupport (~> 6.1) gitlab (~> 4.18.0) http (~> 5.0) @@ -317,7 +317,7 @@ DEPENDENCIES faraday-retry (~> 2.0) fog-core (= 2.1.0) fog-google (~> 1.19) - gitlab-qa (~> 8, >= 8.15.2) + gitlab-qa (~> 8, >= 8.15.3) influxdb-client (~> 2.9) knapsack (~> 4.0) nokogiri (~> 1.14, >= 1.14.1) diff --git a/spec/frontend/fixtures/merge_requests.rb b/spec/frontend/fixtures/merge_requests.rb index 18f89fbc5e5..7ee89ca3694 100644 --- a/spec/frontend/fixtures/merge_requests.rb +++ b/spec/frontend/fixtures/merge_requests.rb @@ -148,6 +148,53 @@ RSpec.describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: end end + context 'merge request with no approvals' do + base_input_path = 'vue_merge_request_widget/components/approvals/queries/' + base_output_path = 'graphql/merge_requests/approvals/' + query_name = 'approved_by.query.graphql' + + it "#{base_output_path}#{query_name}_no_approvals.json" do + query = get_graphql_query_as_string("#{base_input_path}#{query_name}", ee: Gitlab.ee?) + + post_graphql(query, current_user: user, variables: { projectPath: project.full_path, iid: merge_request.iid.to_s }) + + expect_graphql_errors_to_be_empty + end + end + + context 'merge request approved by current user' do + base_input_path = 'vue_merge_request_widget/components/approvals/queries/' + base_output_path = 'graphql/merge_requests/approvals/' + query_name = 'approved_by.query.graphql' + + it "#{base_output_path}#{query_name}.json" do + merge_request.approved_by_users << user + + query = get_graphql_query_as_string("#{base_input_path}#{query_name}", ee: Gitlab.ee?) + + post_graphql(query, current_user: user, variables: { projectPath: project.full_path, iid: merge_request.iid.to_s }) + + expect_graphql_errors_to_be_empty + end + end + + context 'merge request approved by multiple users' do + base_input_path = 'vue_merge_request_widget/components/approvals/queries/' + base_output_path = 'graphql/merge_requests/approvals/' + query_name = 'approved_by.query.graphql' + + it "#{base_output_path}#{query_name}_multiple_users.json" do + merge_request.approved_by_users << user + merge_request.approved_by_users << create(:user) + + query = get_graphql_query_as_string("#{base_input_path}#{query_name}", ee: Gitlab.ee?) + + post_graphql(query, current_user: user, variables: { projectPath: project.full_path, iid: merge_request.iid.to_s }) + + expect_graphql_errors_to_be_empty + end + end + context 'merge request in state getState query' do base_input_path = 'vue_merge_request_widget/queries/' base_output_path = 'graphql/merge_requests/' diff --git a/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js b/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js index bbc27a621ea..c54a2a1d039 100644 --- a/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js +++ b/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js @@ -155,6 +155,7 @@ describe('FrequentItemsListItemComponent', () => { expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_link', { label: 'projects_dropdown_frequent_items_list_item', + property: 'navigation_top', }); }); }); diff --git a/spec/frontend/frequent_items/components/frequent_items_search_input_spec.js b/spec/frontend/frequent_items/components/frequent_items_search_input_spec.js index 94fc97b82c2..dfce88ca0a8 100644 --- a/spec/frontend/frequent_items/components/frequent_items_search_input_spec.js +++ b/spec/frontend/frequent_items/components/frequent_items_search_input_spec.js @@ -65,6 +65,7 @@ describe('FrequentItemsSearchInputComponent', () => { expect(trackingSpy).toHaveBeenCalledWith(undefined, 'type_search_query', { label: 'projects_dropdown_frequent_items_search_input', + property: 'navigation_top', }); expect(store.dispatch).toHaveBeenCalledWith('frequentProjects/setSearchQuery', value); }); diff --git a/spec/frontend/header_search/components/app_spec.js b/spec/frontend/header_search/components/app_spec.js index c714c269ca0..d6263c663d2 100644 --- a/spec/frontend/header_search/components/app_spec.js +++ b/spec/frontend/header_search/components/app_spec.js @@ -375,7 +375,7 @@ describe('HeaderSearchApp', () => { expect(findHeaderSearchDropdown().exists()).toBe(true); expect(trackingSpy).toHaveBeenCalledWith(undefined, 'focus_input', { label: 'global_search', - property: 'top_navigation', + property: 'navigation_top', }); }); @@ -388,7 +388,7 @@ describe('HeaderSearchApp', () => { expect(findHeaderSearchDropdown().exists()).toBe(true); expect(trackingSpy).toHaveBeenCalledWith(undefined, 'focus_input', { label: 'global_search', - property: 'top_navigation', + property: 'navigation_top', }); }); diff --git a/spec/frontend/nav/components/top_nav_app_spec.js b/spec/frontend/nav/components/top_nav_app_spec.js index b32ab5ebe09..e70f70afc97 100644 --- a/spec/frontend/nav/components/top_nav_app_spec.js +++ b/spec/frontend/nav/components/top_nav_app_spec.js @@ -65,7 +65,7 @@ describe('~/nav/components/top_nav_app.vue', () => { expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_nav', { label: 'hamburger_menu', - property: 'top_navigation', + property: 'navigation_top', }); }); }); diff --git a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js index 3d212ee03af..3fa0780a3c4 100644 --- a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_spec.js @@ -92,6 +92,8 @@ describe('MRWidget approvals', () => { approvalRules: [], isOpen: true, state: 'open', + targetProjectFullPath: 'gitlab-org/gitlab', + iid: '1', }; jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); @@ -389,15 +391,14 @@ describe('MRWidget approvals', () => { }); it('is rendered with props', () => { - const expected = testApprovals(); const summary = findSummary(); expect(findOptionalSummary().exists()).toBe(false); expect(summary.exists()).toBe(true); expect(summary.props()).toMatchObject({ - approvalsLeft: expected.approvals_left, - rulesLeft: expected.approval_rules_left, - approvers: testApprovedBy(), + projectPath: 'gitlab-org/gitlab', + iid: '1', + updatedCount: 0, }); }); }); diff --git a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js index f4234083346..e75ce7c60c9 100644 --- a/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/approvals/approvals_summary_spec.js @@ -1,5 +1,12 @@ -import { shallowMount } from '@vue/test-utils'; -import { toNounSeriesText } from '~/lib/utils/grammar'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import { mount } from '@vue/test-utils'; +import approvedByMultipleUsers from 'test_fixtures/graphql/merge_requests/approvals/approved_by.query.graphql_multiple_users.json'; +import noApprovalsResponse from 'test_fixtures/graphql/merge_requests/approvals/approved_by.query.graphql_no_approvals.json'; +import approvedByCurrentUser from 'test_fixtures/graphql/merge_requests/approvals/approved_by.query.graphql.json'; +import waitForPromises from 'helpers/wait_for_promises'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import ApprovalsSummary from '~/vue_merge_request_widget/components/approvals/approvals_summary.vue'; import { APPROVED_BY_OTHERS, @@ -7,25 +14,21 @@ import { APPROVED_BY_YOU_AND_OTHERS, } from '~/vue_merge_request_widget/components/approvals/messages'; import UserAvatarList from '~/vue_shared/components/user_avatar/user_avatar_list.vue'; +import approvedByQuery from 'ee_else_ce/vue_merge_request_widget/components/approvals/queries/approved_by.query.graphql'; -const exampleUserId = 1; -const testApprovers = () => Array.from({ length: 5 }, (_, i) => i).map((id) => ({ id })); -const testRulesLeft = () => ['Lorem', 'Ipsum', 'dolar & sit']; -const TEST_APPROVALS_LEFT = 3; +Vue.use(VueApollo); describe('MRWidget approvals summary', () => { const originalUserId = gon.current_user_id; let wrapper; - const createComponent = (props = {}) => { - wrapper = shallowMount(ApprovalsSummary, { + const createComponent = (response = approvedByCurrentUser) => { + wrapper = mount(ApprovalsSummary, { propsData: { - approved: false, - approvers: testApprovers(), - approvalsLeft: TEST_APPROVALS_LEFT, - rulesLeft: testRulesLeft(), - ...props, + projectPath: 'gitlab-org/gitlab', + iid: '1', }, + apolloProvider: createMockApollo([[approvedByQuery, jest.fn().mockResolvedValue(response)]]), }); }; @@ -38,10 +41,10 @@ describe('MRWidget approvals summary', () => { }); describe('when approved', () => { - beforeEach(() => { - createComponent({ - approved: true, - }); + beforeEach(async () => { + createComponent(); + + await waitForPromises(); }); it('shows approved message', () => { @@ -54,18 +57,19 @@ describe('MRWidget approvals summary', () => { expect(avatars.exists()).toBe(true); expect(avatars.props()).toEqual( expect.objectContaining({ - items: testApprovers(), + items: approvedByCurrentUser.data.project.mergeRequest.approvedBy.nodes, }), ); }); describe('by the current user', () => { - beforeEach(() => { - gon.current_user_id = exampleUserId; - createComponent({ - approvers: [{ id: exampleUserId }], - approved: true, - }); + beforeEach(async () => { + gon.current_user_id = getIdFromGraphQLId( + approvedByCurrentUser.data.project.mergeRequest.approvedBy.nodes[0].id, + ); + createComponent(); + + await waitForPromises(); }); it('shows "Approved by you" message', () => { @@ -74,12 +78,13 @@ describe('MRWidget approvals summary', () => { }); describe('by the current user and others', () => { - beforeEach(() => { - gon.current_user_id = exampleUserId; - createComponent({ - approvers: [{ id: exampleUserId }, { id: exampleUserId + 1 }], - approved: true, - }); + beforeEach(async () => { + gon.current_user_id = getIdFromGraphQLId( + approvedByMultipleUsers.data.project.mergeRequest.approvedBy.nodes[0].id, + ); + createComponent(approvedByMultipleUsers); + + await waitForPromises(); }); it('shows "Approved by you and others" message', () => { @@ -88,12 +93,10 @@ describe('MRWidget approvals summary', () => { }); describe('by other users than the current user', () => { - beforeEach(() => { - gon.current_user_id = exampleUserId; - createComponent({ - approvers: [{ id: exampleUserId + 1 }], - approved: true, - }); + beforeEach(async () => { + createComponent(approvedByMultipleUsers); + + await waitForPromises(); }); it('shows "Approved by others" message', () => { @@ -102,37 +105,11 @@ describe('MRWidget approvals summary', () => { }); }); - describe('when not approved', () => { - beforeEach(() => { - createComponent(); - }); - - it('render message', () => { - const names = toNounSeriesText(testRulesLeft()); - - expect(wrapper.text()).toContain(`Requires ${TEST_APPROVALS_LEFT} approvals from ${names}.`); - }); - }); - - describe('when no rulesLeft', () => { - beforeEach(() => { - createComponent({ - rulesLeft: [], - }); - }); - - it('renders message', () => { - expect(wrapper.text()).toContain( - `Requires ${TEST_APPROVALS_LEFT} approvals from eligible users`, - ); - }); - }); - describe('when no approvers', () => { - beforeEach(() => { - createComponent({ - approvers: [], - }); + beforeEach(async () => { + createComponent(noApprovalsResponse); + + await waitForPromises(); }); it('does not render avatar list', () => { diff --git a/spec/frontend/whats_new/components/app_spec.js b/spec/frontend/whats_new/components/app_spec.js index da95b51c0b1..ee15034daff 100644 --- a/spec/frontend/whats_new/components/app_spec.js +++ b/spec/frontend/whats_new/components/app_spec.js @@ -91,6 +91,7 @@ describe('App', () => { expect(actions.openDrawer).toHaveBeenCalledWith(expect.any(Object), 'version-digest'); expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_whats_new_drawer', { label: 'namespace_id', + property: 'navigation_top', value: 'namespace-840', }); }); diff --git a/spec/helpers/nav/new_dropdown_helper_spec.rb b/spec/helpers/nav/new_dropdown_helper_spec.rb index b325a0ba228..2a69f8a56b3 100644 --- a/spec/helpers/nav/new_dropdown_helper_spec.rb +++ b/spec/helpers/nav/new_dropdown_helper_spec.rb @@ -46,7 +46,8 @@ RSpec.describe Nav::NewDropdownHelper do href: expected_href, data: { track_action: 'click_link_invite_members', - track_label: 'plus_menu_dropdown' + track_label: 'plus_menu_dropdown', + track_property: 'navigation_top' } ) ) @@ -82,7 +83,12 @@ RSpec.describe Nav::NewDropdownHelper do id: 'general_new_project', title: 'New project/repository', href: '/projects/new', - data: { track_action: 'click_link_new_project', track_label: 'plus_menu_dropdown', qa_selector: 'global_new_project_link' } + data: { + track_action: 'click_link_new_project', + track_label: 'plus_menu_dropdown', + track_property: 'navigation_top', + qa_selector: 'global_new_project_link' + } ) ) ) @@ -100,7 +106,12 @@ RSpec.describe Nav::NewDropdownHelper do id: 'general_new_group', title: 'New group', href: '/groups/new', - data: { qa_selector: 'global_new_group_link', track_action: 'click_link_new_group', track_label: 'plus_menu_dropdown' } + data: { + track_action: 'click_link_new_group', + track_label: 'plus_menu_dropdown', + track_property: 'navigation_top', + qa_selector: 'global_new_group_link' + } ) ) ) @@ -118,7 +129,12 @@ RSpec.describe Nav::NewDropdownHelper do id: 'general_new_snippet', title: 'New snippet', href: '/-/snippets/new', - data: { track_action: 'click_link_new_snippet_parent', track_label: 'plus_menu_dropdown', qa_selector: 'global_new_snippet_link' } + data: { + track_action: 'click_link_new_snippet_parent', + track_label: 'plus_menu_dropdown', + track_property: 'navigation_top', + qa_selector: 'global_new_snippet_link' + } ) ) ) @@ -156,7 +172,11 @@ RSpec.describe Nav::NewDropdownHelper do id: 'new_project', title: 'New project/repository', href: "/projects/new?namespace_id=#{group.id}", - data: { track_action: 'click_link_new_project_group', track_label: 'plus_menu_dropdown' } + data: { + track_action: 'click_link_new_project_group', + track_label: 'plus_menu_dropdown', + track_property: 'navigation_top' + } ) ) ) @@ -174,7 +194,11 @@ RSpec.describe Nav::NewDropdownHelper do id: 'new_subgroup', title: 'New subgroup', href: "/groups/new?parent_id=#{group.id}#create-group-pane", - data: { track_action: 'click_link_new_subgroup', track_label: 'plus_menu_dropdown' } + data: { + track_action: 'click_link_new_subgroup', + track_label: 'plus_menu_dropdown', + track_property: 'navigation_top' + } ) ) ) @@ -223,7 +247,12 @@ RSpec.describe Nav::NewDropdownHelper do id: 'new_issue', title: 'New issue', href: "/#{project.path_with_namespace}/-/issues/new", - data: { track_action: 'click_link_new_issue', track_label: 'plus_menu_dropdown', qa_selector: 'new_issue_link' } + data: { + track_action: 'click_link_new_issue', + track_label: 'plus_menu_dropdown', + track_property: 'navigation_top', + qa_selector: 'new_issue_link' + } ) ) ) @@ -241,7 +270,11 @@ RSpec.describe Nav::NewDropdownHelper do id: 'new_mr', title: 'New merge request', href: "/#{merge_project.path_with_namespace}/-/merge_requests/new", - data: { track_action: 'click_link_new_mr', track_label: 'plus_menu_dropdown' } + data: { + track_action: 'click_link_new_mr', + track_label: 'plus_menu_dropdown', + track_property: 'navigation_top' + } ) ) ) @@ -259,7 +292,11 @@ RSpec.describe Nav::NewDropdownHelper do id: 'new_snippet', title: 'New snippet', href: "/#{project.path_with_namespace}/-/snippets/new", - data: { track_action: 'click_link_new_snippet_project', track_label: 'plus_menu_dropdown' } + data: { + track_action: 'click_link_new_snippet_project', + track_label: 'plus_menu_dropdown', + track_property: 'navigation_top' + } ) ) ) diff --git a/spec/helpers/nav/top_nav_helper_spec.rb b/spec/helpers/nav/top_nav_helper_spec.rb index c4a8536032e..ce5ac2e5404 100644 --- a/spec/helpers/nav/top_nav_helper_spec.rb +++ b/spec/helpers/nav/top_nav_helper_spec.rb @@ -125,6 +125,7 @@ RSpec.describe Nav::TopNavHelper do data: { track_action: 'click_dropdown', track_label: 'projects_dropdown', + track_property: 'navigation_top', qa_selector: 'projects_dropdown' }, icon: 'project', @@ -222,6 +223,7 @@ RSpec.describe Nav::TopNavHelper do data: { track_action: 'click_dropdown', track_label: 'groups_dropdown', + track_property: 'navigation_top', qa_selector: 'groups_dropdown' }, icon: 'group', @@ -517,7 +519,7 @@ RSpec.describe Nav::TopNavHelper do { track_label: "menu_#{label}", track_action: 'click_dropdown', - track_property: 'navigation' + track_property: 'navigation_top' } end end diff --git a/spec/lib/gitlab/ci/build/auto_retry_spec.rb b/spec/lib/gitlab/ci/build/auto_retry_spec.rb index 9ff9200322e..d69b6679e30 100644 --- a/spec/lib/gitlab/ci/build/auto_retry_spec.rb +++ b/spec/lib/gitlab/ci/build/auto_retry_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Build::AutoRetry do +RSpec.describe Gitlab::Ci::Build::AutoRetry, feature_category: :pipeline_authoring do let(:auto_retry) { described_class.new(build) } describe '#allowed?' do diff --git a/spec/models/packages/package_spec.rb b/spec/models/packages/package_spec.rb index 751482aeb89..992cc5c4354 100644 --- a/spec/models/packages/package_spec.rb +++ b/spec/models/packages/package_spec.rb @@ -1068,14 +1068,16 @@ RSpec.describe Packages::Package, type: :model, feature_category: :package_regis let_it_be(:project) { create(:project) } let_it_be(:package) { create(:maven_package, project: project) } let_it_be(:package2) { create(:maven_package, project: project) } - let_it_be(:package3) { create(:maven_package, project: project, name: 'foo') } + let_it_be(:package3) { create(:maven_package, :error, project: project) } + let_it_be(:package4) { create(:maven_package, project: project, name: 'foo') } + let_it_be(:pending_destruction_package) { create(:maven_package, :pending_destruction, project: project) } it 'returns other package versions of the same package name belonging to the project' do - expect(package.versions).to contain_exactly(package2) + expect(package.versions).to contain_exactly(package2, package3) end it 'does not return different packages' do - expect(package.versions).not_to include(package3) + expect(package.versions).not_to include(package4) end end diff --git a/spec/requests/api/graphql/packages/package_spec.rb b/spec/requests/api/graphql/packages/package_spec.rb index 42927634119..da5478cf409 100644 --- a/spec/requests/api/graphql/packages/package_spec.rb +++ b/spec/requests/api/graphql/packages/package_spec.rb @@ -113,6 +113,29 @@ RSpec.describe 'package details', feature_category: :package_registry do end end + context 'versions field', :aggregate_failures do + let_it_be(:composer_package2) { create(:composer_package, project: project, name: composer_package.name) } + let_it_be(:composer_package3) { create(:composer_package, :error, project: project, name: composer_package.name) } + let_it_be(:pending_destruction) { create(:composer_package, :pending_destruction, project: project, name: composer_package.name) } + + def run_query + versions_nodes = <<~QUERY + nodes { id } + QUERY + + query = graphql_query_for(:package, { id: package_global_id }, query_graphql_field("versions", {}, versions_nodes)) + post_graphql(query, current_user: user) + end + + it 'returns other versions' do + run_query + versions_ids = graphql_data.dig('package', 'versions', 'nodes').pluck('id') + expected_ids = [composer_package2, composer_package3].map(&:to_gid).map(&:to_s) + + expect(versions_ids).to contain_exactly(*expected_ids) + end + end + context 'pipelines field', :aggregate_failures do let(:pipelines) { create_list(:ci_pipeline, 6, project: project) } let(:pipeline_gids) { pipelines.sort_by(&:id).map(&:to_gid).map(&:to_s).reverse } diff --git a/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb b/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb index 5382641742e..a3042ac2e26 100644 --- a/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb +++ b/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb @@ -56,8 +56,7 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do end end - it 'generates Debian distribution and component files', :aggregate_failures, - quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/389950' do + it 'generates Debian distribution and component files', :aggregate_failures do current_time = Time.utc(2020, 01, 25, 15, 17, 18, 123456) travel_to(current_time) do @@ -193,7 +192,7 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do Architectures: all amd64 arm64 Components: contrib main SHA256: - #{contrib_all_sha256} #{contrib_all_size} contrib/binary-all/Packages + #{contrib_all_sha256} #{contrib_all_size.to_s.rjust(8)} contrib/binary-all/Packages e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-all/Packages e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/binary-amd64/Packages e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-amd64/Packages @@ -202,11 +201,11 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/source/Sources e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/binary-all/Packages e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/debian-installer/binary-all/Packages - #{main_amd64_sha256} #{main_amd64_size} main/binary-amd64/Packages - #{main_amd64_di_sha256} #{main_amd64_di_size} main/debian-installer/binary-amd64/Packages + #{main_amd64_sha256} #{main_amd64_size.to_s.rjust(8)} main/binary-amd64/Packages + #{main_amd64_di_sha256} #{main_amd64_di_size.to_s.rjust(8)} main/debian-installer/binary-amd64/Packages e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/binary-arm64/Packages e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/debian-installer/binary-arm64/Packages - #{main_sources_sha256} #{main_sources_size} main/source/Sources + #{main_sources_sha256} #{main_sources_size.to_s.rjust(8)} main/source/Sources EOF expected_release_content = "Suite: #{distribution.suite}\n#{expected_release_content}" if distribution.suite diff --git a/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb b/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb index 4f1dcf54216..a027bdd6357 100644 --- a/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb +++ b/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb @@ -29,8 +29,7 @@ RSpec.describe 'layouts/header/_gitlab_version' do ) expect(rendered).to have_selector( - 'a[data-testid="gitlab-version-container"]' \ - "[data-track-property=\"#{Gitlab.version_info.major}.#{Gitlab.version_info.minor}\"]" + 'a[data-testid="gitlab-version-container"][data-track-property="navigation_top"]' ) end end |