From d1bc31b8d5eba0c27d888245d5c8d3b557ebd5c6 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 2 Nov 2023 00:11:35 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- app/assets/javascripts/graphql_shared/constants.js | 1 + .../components/invite_members_modal.vue | 17 +- .../invite_members/utils/member_utils.js | 4 + .../organizations/profile/preferences/index.js | 41 +++++ .../graphql/queries/organization.query.graphql | 9 ++ .../pages/profiles/preferences/show/index.js | 2 + .../components/entity_select/constants.js | 10 ++ .../components/entity_select/entity_select.vue | 16 +- .../entity_select/organization_select.vue | 150 +++++++++++++++++ app/helpers/organizations/organization_helper.rb | 7 + app/services/spam/spam_action_service.rb | 19 +++ app/views/profiles/preferences/show.html.haml | 3 + app/views/projects/_home_panel.html.haml | 6 +- app/views/shared/_ci_catalog_badge.html.haml | 2 +- app/views/shared/projects/_project.html.haml | 4 +- app/workers/abuse/spam_abuse_events_worker.rb | 60 +++++++ app/workers/all_queues.yml | 9 ++ config/sidekiq_queues.yml | 2 + doc/administration/geo/index.md | 2 - doc/security/email_verification.md | 2 + .../sast/customize_rulesets.md | 4 +- doc/user/profile/comment_templates.md | 4 +- doc/user/profile/img/comment_template_v16_6.png | Bin 0 -> 15154 bytes .../profile/img/saved_replies_dropdown_v16_0.png | Bin 16149 -> 0 bytes doc/user/project/merge_requests/reviews/index.md | 8 +- locale/gitlab.pot | 21 ++- scripts/lint-doc.sh | 2 +- .../user_activates_issue_tracker_spec.rb | 6 +- .../integrations/user_activates_jira_spec.rb | 14 +- .../invite_members/utils/member_utils_spec.js | 16 +- .../components/entity_select/entity_select_spec.js | 27 ++++ .../entity_select/organization_select_spec.js | 179 +++++++++++++++++++++ .../organizations/organization_helper_spec.rb | 10 ++ spec/services/spam/spam_action_service_spec.rb | 59 +++++++ .../project_integrations_shared_context.rb | 2 +- .../workers/abuse/spam_abuse_events_worker_spec.rb | 85 ++++++++++ 36 files changed, 767 insertions(+), 36 deletions(-) create mode 100644 app/assets/javascripts/organizations/profile/preferences/index.js create mode 100644 app/assets/javascripts/organizations/shared/graphql/queries/organization.query.graphql create mode 100644 app/assets/javascripts/vue_shared/components/entity_select/organization_select.vue create mode 100644 app/workers/abuse/spam_abuse_events_worker.rb create mode 100644 doc/user/profile/img/comment_template_v16_6.png delete mode 100644 doc/user/profile/img/saved_replies_dropdown_v16_0.png create mode 100644 spec/frontend/vue_shared/components/entity_select/organization_select_spec.js create mode 100644 spec/workers/abuse/spam_abuse_events_worker_spec.rb diff --git a/app/assets/javascripts/graphql_shared/constants.js b/app/assets/javascripts/graphql_shared/constants.js index 5ba46697496..2863f52bea9 100644 --- a/app/assets/javascripts/graphql_shared/constants.js +++ b/app/assets/javascripts/graphql_shared/constants.js @@ -27,5 +27,6 @@ export const TYPENAME_USER = 'User'; export const TYPENAME_VULNERABILITIES_SCANNER = 'Vulnerabilities::Scanner'; export const TYPENAME_VULNERABILITY = 'Vulnerability'; export const TYPENAME_WORK_ITEM = 'WorkItem'; +export const TYPENAME_ORGANIZATION = 'Organization'; export const TYPE_USERS_SAVED_REPLY = 'Users::SavedReply'; export const TYPE_WORKSPACE = 'RemoteDevelopment::Workspace'; diff --git a/app/assets/javascripts/invite_members/components/invite_members_modal.vue b/app/assets/javascripts/invite_members/components/invite_members_modal.vue index 505612c59da..1a10130e969 100644 --- a/app/assets/javascripts/invite_members/components/invite_members_modal.vue +++ b/app/assets/javascripts/invite_members/components/invite_members_modal.vue @@ -7,7 +7,11 @@ import Api from '~/api'; import Tracking from '~/tracking'; import { BV_SHOW_MODAL, BV_HIDE_MODAL } from '~/lib/utils/constants'; import { n__, s__, sprintf } from '~/locale'; -import { memberName, triggerExternalAlert } from 'ee_else_ce/invite_members/utils/member_utils'; +import { + memberName, + triggerExternalAlert, + inviteMembersTrackingOptions, +} from 'ee_else_ce/invite_members/utils/member_utils'; import { captureException } from '~/ci/runner/sentry_utils'; import { USERS_FILTER_ALL, @@ -135,6 +139,9 @@ export default { isCelebration() { return this.mode === 'celebrate'; }, + baseTrackingDetails() { + return { label: this.source, celebrate: this.isCelebration }; + }, isTextForAdmin() { return this.isCurrentUserAdmin && Boolean(this.newUsersUrl); }, @@ -252,7 +259,7 @@ export default { this.source = source; this.$root.$emit(BV_SHOW_MODAL, this.modalId); - this.track('render', { label: this.source }); + this.track('render', inviteMembersTrackingOptions(this.baseTrackingDetails)); }, closeModal() { this.$root.$emit(BV_HIDE_MODAL, this.modalId); @@ -321,10 +328,10 @@ export default { return this.newUsersToInvite.find((member) => memberName(member) === username)?.name; }, onCancel() { - this.track('click_cancel', { label: this.source }); + this.track('click_cancel', inviteMembersTrackingOptions(this.baseTrackingDetails)); }, onClose() { - this.track('click_x', { label: this.source }); + this.track('click_x', inviteMembersTrackingOptions(this.baseTrackingDetails)); }, resetFields() { this.clearValidation(); @@ -333,7 +340,7 @@ export default { this.newUsersToInvite = []; }, onInviteSuccess() { - this.track('invite_successful', { label: this.source }); + this.track('invite_successful', inviteMembersTrackingOptions(this.baseTrackingDetails)); if (this.reloadPageOnSubmit) { reloadOnInvitationSuccess(); diff --git a/app/assets/javascripts/invite_members/utils/member_utils.js b/app/assets/javascripts/invite_members/utils/member_utils.js index 7998cb69445..52fb5e98f27 100644 --- a/app/assets/javascripts/invite_members/utils/member_utils.js +++ b/app/assets/javascripts/invite_members/utils/member_utils.js @@ -6,3 +6,7 @@ export function memberName(member) { export function triggerExternalAlert() { return false; } + +export function inviteMembersTrackingOptions(options) { + return { label: options.label }; +} diff --git a/app/assets/javascripts/organizations/profile/preferences/index.js b/app/assets/javascripts/organizations/profile/preferences/index.js new file mode 100644 index 00000000000..0b0dd313cd8 --- /dev/null +++ b/app/assets/javascripts/organizations/profile/preferences/index.js @@ -0,0 +1,41 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; +import { s__ } from '~/locale'; +import OrganizationSelect from '~/vue_shared/components/entity_select/organization_select.vue'; +import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import resolvers from '../../shared/graphql/resolvers'; + +export const initHomeOrganizationSetting = () => { + const el = document.getElementById('js-home-organization-setting'); + + if (!el) return false; + + const { + dataset: { appData }, + } = el; + const { initialSelection } = convertObjectPropsToCamelCase(JSON.parse(appData)); + + const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(resolvers), + }); + + return new Vue({ + el, + name: 'HomeOrganizationSetting', + apolloProvider, + render(createElement) { + return createElement(OrganizationSelect, { + props: { + block: true, + label: s__('Organization|Home organization'), + description: s__('Organization|Choose what organization you want to see by default.'), + inputName: 'home_organization', + inputId: 'home_organization', + initialSelection, + toggleClass: 'gl-form-input-xl', + }, + }); + }, + }); +}; diff --git a/app/assets/javascripts/organizations/shared/graphql/queries/organization.query.graphql b/app/assets/javascripts/organizations/shared/graphql/queries/organization.query.graphql new file mode 100644 index 00000000000..1d95786fcb0 --- /dev/null +++ b/app/assets/javascripts/organizations/shared/graphql/queries/organization.query.graphql @@ -0,0 +1,9 @@ +query getOrganization($id: ID!) { + organization(id: $id) @client { + id + name + descriptionHtml + avatarUrl + webUrl + } +} diff --git a/app/assets/javascripts/pages/profiles/preferences/show/index.js b/app/assets/javascripts/pages/profiles/preferences/show/index.js index 76939434680..3668811bec7 100644 --- a/app/assets/javascripts/pages/profiles/preferences/show/index.js +++ b/app/assets/javascripts/pages/profiles/preferences/show/index.js @@ -1,5 +1,7 @@ import initProfilePreferences from '~/profile/preferences/profile_preferences_bundle'; import initProfilePreferencesDiffsColors from '~/profile/preferences/profile_preferences_diffs_colors'; +import { initHomeOrganizationSetting } from '~/organizations/profile/preferences'; initProfilePreferences(); initProfilePreferencesDiffsColors(); +initHomeOrganizationSetting(); diff --git a/app/assets/javascripts/vue_shared/components/entity_select/constants.js b/app/assets/javascripts/vue_shared/components/entity_select/constants.js index 0fb5a2d5534..5bad907c9f9 100644 --- a/app/assets/javascripts/vue_shared/components/entity_select/constants.js +++ b/app/assets/javascripts/vue_shared/components/entity_select/constants.js @@ -14,3 +14,13 @@ export const PROJECT_TOGGLE_TEXT = s__('ProjectSelect|Search for project'); export const PROJECT_HEADER_TEXT = s__('ProjectSelect|Select a project'); export const FETCH_PROJECTS_ERROR = __('Unable to fetch projects. Reload the page to try again.'); export const FETCH_PROJECT_ERROR = __('Unable to fetch project. Reload the page to try again.'); + +// Organizations +export const ORGANIZATION_TOGGLE_TEXT = s__('Organization|Search for an organization'); +export const ORGANIZATION_HEADER_TEXT = s__('Organization|Select an organization'); +export const FETCH_ORGANIZATIONS_ERROR = s__( + 'Organization|Unable to fetch organizations. Reload the page to try again.', +); +export const FETCH_ORGANIZATION_ERROR = s__( + 'Organization|Unable to fetch organizations. Reload the page to try again.', +); diff --git a/app/assets/javascripts/vue_shared/components/entity_select/entity_select.vue b/app/assets/javascripts/vue_shared/components/entity_select/entity_select.vue index 970c24c6e87..1a215454ab6 100644 --- a/app/assets/javascripts/vue_shared/components/entity_select/entity_select.vue +++ b/app/assets/javascripts/vue_shared/components/entity_select/entity_select.vue @@ -22,6 +22,11 @@ export default { type: String, required: true, }, + description: { + type: String, + required: false, + default: '', + }, inputName: { type: String, required: true, @@ -31,7 +36,7 @@ export default { required: true, }, initialSelection: { - type: String, + type: [String, Number], required: false, default: null, }, @@ -57,6 +62,11 @@ export default { required: false, default: null, }, + toggleClass: { + type: [String, Array, Object], + required: false, + default: '', + }, }, data() { return { @@ -152,6 +162,7 @@ export default { this.searching = true; const name = await this.fetchInitialSelectionText(this.initialSelection); + this.selectedValue = this.initialSelection; this.selectedText = name; this.pristine = false; @@ -178,7 +189,7 @@ export default {