Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
f1ce233e6a
commit
bb0d99269b
|
|
@ -1103,3 +1103,10 @@ RSpec/UselessDynamicDefinition:
|
|||
Exclude:
|
||||
- 'spec/factories/**/*'
|
||||
- 'ee/spec/factories/**/*'
|
||||
|
||||
Database/AvoidUsingPluckWithoutLimit:
|
||||
Enabled: true
|
||||
Exclude:
|
||||
- 'spec/**/*.rb'
|
||||
- 'ee/spec/**/*.rb'
|
||||
- 'qa/qa/specs/**/*.rb'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,167 @@
|
|||
---
|
||||
Database/AvoidUsingPluckWithoutLimit:
|
||||
Details: grace period
|
||||
Exclude:
|
||||
- app/finders/groups/projects_requiring_authorizations_refresh/base.rb
|
||||
- app/finders/issuables/label_filter.rb
|
||||
- app/finders/projects/members/effective_access_level_finder.rb
|
||||
- app/models/application_record.rb
|
||||
- app/models/ci/build.rb
|
||||
- app/models/ci/build_trace_chunks/fog.rb
|
||||
- app/models/ci/build_trace_chunks/redis_base.rb
|
||||
- app/models/ci/group_variable.rb
|
||||
- app/models/ci/job_artifact.rb
|
||||
- app/models/ci/job_token/allowlist.rb
|
||||
- app/models/ci/pipeline.rb
|
||||
- app/models/ci/runner.rb
|
||||
- app/models/ci/runner_manager_build.rb
|
||||
- app/models/commit_collection.rb
|
||||
- app/models/commit_signatures/gpg_signature.rb
|
||||
- app/models/commit_status.rb
|
||||
- app/models/concerns/cascading_namespace_setting_attribute.rb
|
||||
- app/models/concerns/commit_signature.rb
|
||||
- app/models/concerns/integrations/reset_secret_fields.rb
|
||||
- app/models/concerns/issuable.rb
|
||||
- app/models/concerns/packages/debian/distribution.rb
|
||||
- app/models/concerns/subquery.rb
|
||||
- app/models/concerns/taggable_queries.rb
|
||||
- app/models/customer_relations/contact.rb
|
||||
- app/models/customer_relations/issue_contact.rb
|
||||
- app/models/environment.rb
|
||||
- app/models/event_collection.rb
|
||||
- app/models/group.rb
|
||||
- app/models/incident_management/timeline_event_tag.rb
|
||||
- app/models/integration.rb
|
||||
- app/models/integrations/base_chat_notification.rb
|
||||
- app/models/integrations/slack_workspace/api_scope.rb
|
||||
- app/models/integrations/slack_workspace/integration_api_scope.rb
|
||||
- app/models/issue.rb
|
||||
- app/models/label.rb
|
||||
- app/models/loose_foreign_keys/deleted_record.rb
|
||||
- app/models/member.rb
|
||||
- app/models/members/last_group_owner_assigner.rb
|
||||
- app/models/merge_request.rb
|
||||
- app/models/merge_request_diff.rb
|
||||
- app/models/merge_requests_closing_issues.rb
|
||||
- app/models/namespace.rb
|
||||
- app/models/namespaces/traversal/linear.rb
|
||||
- app/models/namespaces/traversal/recursive.rb
|
||||
- app/models/note.rb
|
||||
- app/models/packages/build_info.rb
|
||||
- app/models/packages/dependency.rb
|
||||
- app/models/packages/maven/metadatum.rb
|
||||
- app/models/packages/package.rb
|
||||
- app/models/pages_deployment.rb
|
||||
- app/models/postgresql/replication_slot.rb
|
||||
- app/models/project.rb
|
||||
- app/models/project_authorizations/changes.rb
|
||||
- app/models/project_team.rb
|
||||
- app/models/prometheus_alert.rb
|
||||
- app/models/protected_branch.rb
|
||||
- app/models/remote_mirror.rb
|
||||
- app/models/shard.rb
|
||||
- app/models/slack_integration.rb
|
||||
- app/models/todo.rb
|
||||
- app/models/uploads/fog.rb
|
||||
- app/models/user.rb
|
||||
- app/models/users/group_visit.rb
|
||||
- app/models/users/project_visit.rb
|
||||
- app/models/x509_certificate.rb
|
||||
- app/services/authorized_project_update/project_recalculate_service.rb
|
||||
- app/services/boards/base_items_list_service.rb
|
||||
- app/services/branches/delete_merged_service.rb
|
||||
- app/services/bulk_imports/batched_relation_export_service.rb
|
||||
- app/services/ci/job_artifacts/bulk_delete_by_project_service.rb
|
||||
- app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb
|
||||
- app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb
|
||||
- app/services/ci/queue/pending_builds_strategy.rb
|
||||
- app/services/ci/refs/enqueue_pipelines_to_unlock_service.rb
|
||||
- app/services/ci/runners/reconcile_existing_runner_versions_service.rb
|
||||
- app/services/ci/unlock_pipeline_service.rb
|
||||
- app/services/groups/autocomplete_service.rb
|
||||
- app/services/groups/destroy_service.rb
|
||||
- app/services/groups/transfer_service.rb
|
||||
- app/services/issues/referenced_merge_requests_service.rb
|
||||
- app/services/labels/available_labels_service.rb
|
||||
- app/services/labels/promote_service.rb
|
||||
- app/services/labels/transfer_service.rb
|
||||
- app/services/merge_requests/push_options_handler_service.rb
|
||||
- app/services/merge_requests/pushed_branches_service.rb
|
||||
- app/services/packages/cleanup/execute_policy_service.rb
|
||||
- app/services/projects/slack_application_install_service.rb
|
||||
- app/services/projects/unlink_fork_service.rb
|
||||
- ee/app/finders/ee/issuables/label_filter.rb
|
||||
- ee/app/finders/ee/merge_requests_finder.rb
|
||||
- ee/app/finders/groups_with_templates_finder.rb
|
||||
- ee/app/finders/namespaces/billed_users_finder.rb
|
||||
- ee/app/finders/namespaces/free_user_cap/users_finder.rb
|
||||
- ee/app/finders/namespaces/free_user_cap/users_without_added_members_finder.rb
|
||||
- ee/app/models/ai/ai_resource/concerns/noteable.rb
|
||||
- ee/app/models/allowed_email_domain.rb
|
||||
- ee/app/models/analytics/issues_analytics.rb
|
||||
- ee/app/models/approval_wrapped_rule.rb
|
||||
- ee/app/models/concerns/audit_events/streaming/streamable_event_type_filter.rb
|
||||
- ee/app/models/concerns/ee/ci/artifactable.rb
|
||||
- ee/app/models/concerns/ee/issuable_link.rb
|
||||
- ee/app/models/concerns/elasticsearch_indexed_container.rb
|
||||
- ee/app/models/concerns/geo/verifiable_model.rb
|
||||
- ee/app/models/dast_scanner_profile.rb
|
||||
- ee/app/models/dast_site_profile.rb
|
||||
- ee/app/models/ee/ci/daily_build_group_report_result.rb
|
||||
- ee/app/models/ee/ci/pipeline.rb
|
||||
- ee/app/models/ee/design_management/repository.rb
|
||||
- ee/app/models/ee/epic.rb
|
||||
- ee/app/models/ee/group.rb
|
||||
- ee/app/models/ee/group_group_link.rb
|
||||
- ee/app/models/ee/group_member.rb
|
||||
- ee/app/models/ee/label.rb
|
||||
- ee/app/models/ee/merge_request.rb
|
||||
- ee/app/models/ee/personal_access_token.rb
|
||||
- ee/app/models/ee/project.rb
|
||||
- ee/app/models/ee/project_authorization.rb
|
||||
- ee/app/models/ee/project_group_link.rb
|
||||
- ee/app/models/ee/projects/wiki_repository.rb
|
||||
- ee/app/models/ee/uploads/local.rb
|
||||
- ee/app/models/ee/user.rb
|
||||
- ee/app/models/embedding/application_record.rb
|
||||
- ee/app/models/geo/base_registry.rb
|
||||
- ee/app/models/geo/container_repository_registry.rb
|
||||
- ee/app/models/geo/lfs_object_registry.rb
|
||||
- ee/app/models/geo/tracking_base.rb
|
||||
- ee/app/models/geo/upload_registry.rb
|
||||
- ee/app/models/gitlab_subscriptions/user_add_on_assignment.rb
|
||||
- ee/app/models/incident_management/oncall_rotation.rb
|
||||
- ee/app/models/instance_security_dashboard.rb
|
||||
- ee/app/models/issuables_analytics.rb
|
||||
- ee/app/models/iteration.rb
|
||||
- ee/app/models/merge_requests/external_status_check.rb
|
||||
- ee/app/models/protected_environment.rb
|
||||
- ee/app/models/security/finding.rb
|
||||
- ee/app/models/security/scan.rb
|
||||
- ee/app/models/security/scan_result_policy_violation.rb
|
||||
- ee/app/models/software_license.rb
|
||||
- ee/app/models/vulnerabilities/finding.rb
|
||||
- ee/app/models/vulnerabilities/read.rb
|
||||
- ee/app/services/analytics/cycle_analytics/consistency_check_service.rb
|
||||
- ee/app/services/analytics/cycle_analytics/data_loader_service.rb
|
||||
- ee/app/services/approval_rules/params_filtering_service.rb
|
||||
- ee/app/services/click_house/data_ingestion/ci_finished_builds_sync_service.rb
|
||||
- ee/app/services/ee/groups/destroy_service.rb
|
||||
- ee/app/services/ee/search/global_service.rb
|
||||
- ee/app/services/epics/update_dates_service.rb
|
||||
- ee/app/services/gitlab_subscriptions/preview_billable_user_change_service.rb
|
||||
- ee/app/services/security/merge_request_security_report_generation_service.rb
|
||||
- ee/app/services/security/scan_result_policies/sync_any_merge_request_rules_service.rb
|
||||
- ee/app/services/security/scan_result_policies/update_approvals_service.rb
|
||||
- ee/app/services/security/security_orchestration_policies/default_branch_updation_check_service.rb
|
||||
- ee/app/services/security/security_orchestration_policies/fetch_policy_approvers_service.rb
|
||||
- ee/app/services/security/security_orchestration_policies/policy_branches_service.rb
|
||||
- ee/app/services/security/security_orchestration_policies/process_scan_result_policy_service.rb
|
||||
- ee/app/services/security/security_orchestration_policies/protected_branches_deletion_check_service.rb
|
||||
- ee/app/services/security/security_orchestration_policies/protected_branches_push_service.rb
|
||||
- ee/app/services/security/security_orchestration_policies/rule_schedule_service.rb
|
||||
- ee/app/services/security/security_orchestration_policies/validate_policy_service.rb
|
||||
- ee/app/services/security/sync_license_scanning_rules_service.rb
|
||||
- ee/app/services/vulnerabilities/bulk_dismiss_service.rb
|
||||
- ee/app/services/vulnerability_exports/export_service.rb
|
||||
- ee/lib/ee/gitlab/background_migration/migrate_approver_to_approval_rules.rb
|
||||
|
|
@ -2281,7 +2281,6 @@ Layout/LineLength:
|
|||
- 'ee/spec/views/admin/dashboard/index.html.haml_spec.rb'
|
||||
- 'ee/spec/views/compliance_management/compliance_framework/_project_settings.html.haml_spec.rb'
|
||||
- 'ee/spec/views/groups/security/discover/show.html.haml_spec.rb'
|
||||
- 'ee/spec/views/layouts/header/_current_user_dropdown.html.haml_spec.rb'
|
||||
- 'ee/spec/views/operations/environments.html.haml_spec.rb'
|
||||
- 'ee/spec/views/projects/security/discover/show.html.haml_spec.rb'
|
||||
- 'ee/spec/views/shared/_mirror_status.html.haml_spec.rb'
|
||||
|
|
|
|||
|
|
@ -205,7 +205,6 @@ RSpec/FactoryBot/AvoidCreate:
|
|||
- 'ee/spec/views/groups/settings/reporting/show.html.haml_spec.rb'
|
||||
- 'ee/spec/views/layouts/application.html.haml_spec.rb'
|
||||
- 'ee/spec/views/layouts/group.html.haml_spec.rb'
|
||||
- 'ee/spec/views/layouts/header/_current_user_dropdown.html.haml_spec.rb'
|
||||
- 'ee/spec/views/layouts/header/_read_only_banner.html.haml_spec.rb'
|
||||
- 'ee/spec/views/layouts/project.html.haml_spec.rb'
|
||||
- 'ee/spec/views/projects/edit.html.haml_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1445,7 +1445,6 @@ RSpec/FeatureCategory:
|
|||
- 'ee/spec/views/groups/settings/reporting/show.html.haml_spec.rb'
|
||||
- 'ee/spec/views/layouts/application.html.haml_spec.rb'
|
||||
- 'ee/spec/views/layouts/checkout.html.haml_spec.rb'
|
||||
- 'ee/spec/views/layouts/header/_current_user_dropdown.html.haml_spec.rb'
|
||||
- 'ee/spec/views/layouts/header/_ee_subscribable_banner.html.haml_spec.rb'
|
||||
- 'ee/spec/views/layouts/header/_read_only_banner.html.haml_spec.rb'
|
||||
- 'ee/spec/views/operations/environments.html.haml_spec.rb'
|
||||
|
|
@ -4061,8 +4060,6 @@ RSpec/FeatureCategory:
|
|||
- 'spec/lib/gitlab/usage/metrics/instrumentations/gitlab_for_jira_app_direct_installations_count_metric_spec.rb'
|
||||
- 'spec/lib/gitlab/usage/metrics/instrumentations/gitlab_for_jira_app_proxy_installations_count_metric_spec.rb'
|
||||
- 'spec/lib/gitlab/usage/metrics/instrumentations/hostname_metric_spec.rb'
|
||||
- 'spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_cta_clicked_metric_spec.rb'
|
||||
- 'spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_sent_metric_spec.rb'
|
||||
- 'spec/lib/gitlab/usage/metrics/instrumentations/jira_imports_total_imported_issues_count_metric_spec.rb'
|
||||
- 'spec/lib/gitlab/usage/metrics/instrumentations/merge_request_widget_extension_metric_spec.rb'
|
||||
- 'spec/lib/gitlab/usage/metrics/instrumentations/numbers_metric_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1188,7 +1188,6 @@ RSpec/NamedSubject:
|
|||
- 'ee/spec/validators/user_existence_validator_spec.rb'
|
||||
- 'ee/spec/validators/user_id_existence_validator_spec.rb'
|
||||
- 'ee/spec/views/devise/registrations/new.html.haml_spec.rb'
|
||||
- 'ee/spec/views/layouts/header/_current_user_dropdown.html.haml_spec.rb'
|
||||
- 'ee/spec/workers/active_user_count_threshold_worker_spec.rb'
|
||||
- 'ee/spec/workers/admin_emails_worker_spec.rb'
|
||||
- 'ee/spec/workers/app_sec/dast/profile_schedule_worker_spec.rb'
|
||||
|
|
@ -3528,7 +3527,6 @@ RSpec/NamedSubject:
|
|||
- 'spec/services/users/activity_service_spec.rb'
|
||||
- 'spec/services/users/approve_service_spec.rb'
|
||||
- 'spec/services/users/assigned_issues_count_service_spec.rb'
|
||||
- 'spec/services/users/in_product_marketing_email_records_spec.rb'
|
||||
- 'spec/services/users/keys_count_service_spec.rb'
|
||||
- 'spec/services/users/reject_service_spec.rb'
|
||||
- 'spec/services/users/saved_replies/create_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ export const initHomeOrganizationSetting = () => {
|
|||
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',
|
||||
inputName: 'user[home_organization_id]',
|
||||
inputId: 'user_home_organization_id',
|
||||
initialSelection,
|
||||
toggleClass: 'gl-form-input-xl',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -22,12 +22,17 @@ export default class PersistentUserCallout {
|
|||
|
||||
init() {
|
||||
const followLink = this.container.querySelector('.js-follow-link');
|
||||
const closeAndFollowLink = this.container.querySelector('.js-close-and-follow-link');
|
||||
|
||||
if (this.closeButtons.length) {
|
||||
this.handleCloseButtonCallout();
|
||||
} else if (followLink) {
|
||||
this.handleFollowLinkCallout(followLink);
|
||||
}
|
||||
|
||||
if (closeAndFollowLink) {
|
||||
this.handleFollowLinkCallout(closeAndFollowLink);
|
||||
}
|
||||
}
|
||||
|
||||
handleCloseButtonCallout() {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ const PERSISTENT_USER_CALLOUTS = [
|
|||
'.js-recovery-settings-callout',
|
||||
'.js-users-over-license-callout',
|
||||
'.js-admin-licensed-user-count-threshold',
|
||||
'.js-buy-pipeline-minutes-notification-callout',
|
||||
'.js-token-expiry-callout',
|
||||
'.js-registration-enabled-callout',
|
||||
'.js-new-user-signups-cap-reached',
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ export default {
|
|||
projectKey: {
|
||||
default: '',
|
||||
},
|
||||
reopenIssueOnExternalParticipantNote: {
|
||||
default: false,
|
||||
},
|
||||
addExternalParticipantsFromCc: {
|
||||
default: false,
|
||||
},
|
||||
|
|
@ -115,6 +118,7 @@ export default {
|
|||
fileTemplateProjectId,
|
||||
outgoingName,
|
||||
projectKey,
|
||||
reopenIssueOnExternalParticipantNote,
|
||||
addExternalParticipantsFromCc,
|
||||
}) {
|
||||
this.isTemplateSaving = true;
|
||||
|
|
@ -123,6 +127,7 @@ export default {
|
|||
issue_template_key: selectedTemplate,
|
||||
outgoing_name: outgoingName,
|
||||
project_key: projectKey,
|
||||
reopen_issue_on_external_participant_note: reopenIssueOnExternalParticipantNote,
|
||||
add_external_participants_from_cc: addExternalParticipantsFromCc,
|
||||
service_desk_enabled: this.isEnabled,
|
||||
file_template_project_id: fileTemplateProjectId,
|
||||
|
|
@ -195,6 +200,7 @@ export default {
|
|||
:initial-selected-file-template-project-id="selectedFileTemplateProjectId"
|
||||
:initial-outgoing-name="outgoingName"
|
||||
:initial-project-key="projectKey"
|
||||
:initial-reopen-issue-on-external-participant-note="reopenIssueOnExternalParticipantNote"
|
||||
:initial-add-external-participants-from-cc="addExternalParticipantsFromCc"
|
||||
:templates="templates"
|
||||
:is-template-saving="isTemplateSaving"
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@ export default {
|
|||
issueTrackerEnableMessage: __(
|
||||
'To use Service Desk in this project, you must %{linkStart}activate the issue tracker%{linkEnd}.',
|
||||
),
|
||||
reopenIssueOnExternalParticipantNote: {
|
||||
label: s__('ServiceDesk|Reopen issues when an external participant comments'),
|
||||
help: s__(
|
||||
'ServiceDesk|This also adds an internal comment that mentions the assignees of the issue.',
|
||||
),
|
||||
},
|
||||
addExternalParticipantsFromCc: {
|
||||
label: s__('ServiceDesk|Add external participants from the %{codeStart}Cc%{codeEnd} header'),
|
||||
help: s__(
|
||||
|
|
@ -91,6 +97,11 @@ export default {
|
|||
required: false,
|
||||
default: '',
|
||||
},
|
||||
initialReopenIssueOnExternalParticipantNote: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
initialAddExternalParticipantsFromCc: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
|
|
@ -113,6 +124,7 @@ export default {
|
|||
selectedFileTemplateProjectId: this.initialSelectedFileTemplateProjectId,
|
||||
outgoingName: this.initialOutgoingName || __('GitLab Support Bot'),
|
||||
projectKey: this.initialProjectKey,
|
||||
reopenIssueOnExternalParticipantNote: this.initialReopenIssueOnExternalParticipantNote,
|
||||
addExternalParticipantsFromCc: this.initialAddExternalParticipantsFromCc,
|
||||
searchTerm: '',
|
||||
projectKeyError: null,
|
||||
|
|
@ -156,6 +168,7 @@ export default {
|
|||
selectedTemplate: this.selectedTemplate,
|
||||
outgoingName: this.outgoingName,
|
||||
projectKey: this.projectKey,
|
||||
reopenIssueOnExternalParticipantNote: this.reopenIssueOnExternalParticipantNote,
|
||||
addExternalParticipantsFromCc: this.addExternalParticipantsFromCc,
|
||||
fileTemplateProjectId: this.selectedFileTemplateProjectId,
|
||||
});
|
||||
|
|
@ -322,10 +335,23 @@ export default {
|
|||
</template>
|
||||
</gl-form-group>
|
||||
|
||||
<gl-form-checkbox
|
||||
v-model="reopenIssueOnExternalParticipantNote"
|
||||
:disabled="!isIssueTrackerEnabled"
|
||||
data-testid="reopen-issue-on-external-participant-note"
|
||||
>
|
||||
{{ $options.i18n.reopenIssueOnExternalParticipantNote.label }}
|
||||
|
||||
<template #help>
|
||||
{{ $options.i18n.reopenIssueOnExternalParticipantNote.help }}
|
||||
</template>
|
||||
</gl-form-checkbox>
|
||||
|
||||
<gl-form-checkbox
|
||||
v-if="showAddExternalParticipantsFromCC"
|
||||
v-model="addExternalParticipantsFromCc"
|
||||
:disabled="!isIssueTrackerEnabled"
|
||||
data-testid="add-external-participants-from-cc"
|
||||
>
|
||||
<gl-sprintf :message="$options.i18n.addExternalParticipantsFromCc.label">
|
||||
<template #code="{ content }">
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ export default () => {
|
|||
incomingEmail,
|
||||
outgoingName,
|
||||
projectKey,
|
||||
reopenIssueOnExternalParticipantNote,
|
||||
addExternalParticipantsFromCc,
|
||||
selectedTemplate,
|
||||
selectedFileTemplateProjectId,
|
||||
|
|
@ -40,6 +41,7 @@ export default () => {
|
|||
isIssueTrackerEnabled: parseBoolean(issueTrackerEnabled),
|
||||
outgoingName,
|
||||
projectKey,
|
||||
reopenIssueOnExternalParticipantNote: parseBoolean(reopenIssueOnExternalParticipantNote),
|
||||
addExternalParticipantsFromCc: parseBoolean(addExternalParticipantsFromCc),
|
||||
selectedTemplate,
|
||||
selectedFileTemplateProjectId: parseInt(selectedFileTemplateProjectId, 10) || null,
|
||||
|
|
|
|||
|
|
@ -31,13 +31,14 @@ const fetchData = (projectPath, path, ref, offset, refType) => {
|
|||
|
||||
fetchedBatches.push(offset);
|
||||
|
||||
const encodePathFunc = gon.features.encodingLogsTree ? encodeURI : encodeURIComponent;
|
||||
const url = joinPaths(
|
||||
gon.relative_url_root || '/',
|
||||
projectPath,
|
||||
'/-/refs/',
|
||||
encodeURIComponent(ref),
|
||||
encodePathFunc(ref),
|
||||
'/logs_tree/',
|
||||
encodeURIComponent(removeLeadingSlash(path)),
|
||||
encodePathFunc(removeLeadingSlash(path)),
|
||||
);
|
||||
|
||||
return axios
|
||||
|
|
|
|||
|
|
@ -1,30 +1,41 @@
|
|||
import setHighlightClass from 'ee_else_ce/search/highlight_blob_search_result';
|
||||
import { queryToObject } from '~/lib/utils/url_utility';
|
||||
import syntaxHighlight from '~/syntax_highlight';
|
||||
import { initSidebar, sidebarInitState } from './sidebar';
|
||||
import { initSidebar } from './sidebar';
|
||||
import { initSearchSort } from './sort';
|
||||
import createStore from './store';
|
||||
import { initTopbar } from './topbar';
|
||||
import { initBlobRefSwitcher } from './under_topbar';
|
||||
|
||||
const topbarInitState = () => {
|
||||
const el = document.getElementById('js-search-topbar');
|
||||
const sidebarInitState = () => {
|
||||
const el = document.getElementById('js-search-sidebar');
|
||||
if (!el) return {};
|
||||
const { defaultBranchName } = el.dataset;
|
||||
return { defaultBranchName };
|
||||
|
||||
const { navigationJson, searchType, groupInitialJson, projectInitialJson } = el.dataset;
|
||||
|
||||
const navigationJsonParsed = JSON.parse(navigationJson);
|
||||
const groupInitialJsonParsed = JSON.parse(groupInitialJson);
|
||||
const projectInitialJsonParsed = JSON.parse(projectInitialJson);
|
||||
|
||||
return { navigationJsonParsed, searchType, groupInitialJsonParsed, projectInitialJsonParsed };
|
||||
};
|
||||
|
||||
export const initSearchApp = () => {
|
||||
syntaxHighlight(document.querySelectorAll('.js-search-results'));
|
||||
const query = queryToObject(window.location.search, { gatherArrays: true });
|
||||
const { navigationJsonParsed: navigation, searchType } = sidebarInitState() || {};
|
||||
const { defaultBranchName } = topbarInitState() || {};
|
||||
const {
|
||||
navigationJsonParsed: navigation,
|
||||
searchType,
|
||||
groupInitialJsonParsed: groupInitialJson,
|
||||
projectInitialJsonParsed: projectInitialJson,
|
||||
} = sidebarInitState() || {};
|
||||
|
||||
const store = createStore({
|
||||
query,
|
||||
navigation,
|
||||
searchType,
|
||||
defaultBranchName,
|
||||
groupInitialJson,
|
||||
projectInitialJson,
|
||||
});
|
||||
|
||||
initTopbar(store);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<script>
|
||||
import GroupFilter from './group_filter.vue';
|
||||
import ProjectFilter from './project_filter.vue';
|
||||
|
||||
export default {
|
||||
name: 'AllScopesStartFilters',
|
||||
components: {
|
||||
GroupFilter,
|
||||
ProjectFilter,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gl-px-5 gl-pt-6">
|
||||
<group-filter class="gl-mb-5" />
|
||||
<project-filter class="gl-mb-5" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -25,6 +25,7 @@ import NotesFilters from './notes_filters.vue';
|
|||
import CommitsFilters from './commits_filters.vue';
|
||||
import MilestonesFilters from './milestones_filters.vue';
|
||||
import WikiBlobsFilters from './wiki_blobs_filters.vue';
|
||||
import AllScopesStartFilters from './all_scopes_start_filters.vue';
|
||||
|
||||
export default {
|
||||
name: 'GlobalSearchSidebar',
|
||||
|
|
@ -40,8 +41,16 @@ export default {
|
|||
DomElementListener,
|
||||
CommitsFilters,
|
||||
MilestonesFilters,
|
||||
AllScopesStartFilters,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
headerText: {
|
||||
required: false,
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState(['searchType']),
|
||||
...mapGetters(['currentScope']),
|
||||
|
|
@ -82,6 +91,13 @@ export default {
|
|||
<section>
|
||||
<dom-element-listener selector="#js-open-mobile-filters" @click="toggleFiltersFromSidebar" />
|
||||
<sidebar-portal>
|
||||
<all-scopes-start-filters />
|
||||
<div
|
||||
v-if="headerText"
|
||||
class="gl-px-5 gl-pt-3 gl-pb-2 gl-m-0 gl-reset-line-height gl-font-weight-bold gl-font-sm super-sidebar-context-header"
|
||||
>
|
||||
{{ headerText }}
|
||||
</div>
|
||||
<scope-sidebar-navigation />
|
||||
<issues-filters v-if="showIssuesFilters" />
|
||||
<merge-requests-filters v-if="showMergeRequestFilters" />
|
||||
|
|
|
|||
|
|
@ -2,34 +2,27 @@
|
|||
import { isEmpty } from 'lodash';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { mapState, mapActions, mapGetters } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
|
||||
import { ANY_OPTION, GROUP_DATA, PROJECT_DATA } from '../constants';
|
||||
import SearchableDropdown from './searchable_dropdown.vue';
|
||||
|
||||
export default {
|
||||
name: 'GroupFilter',
|
||||
i18n: {
|
||||
groupFieldLabel: s__('GlobalSearch|Group'),
|
||||
},
|
||||
components: {
|
||||
SearchableDropdown,
|
||||
},
|
||||
props: {
|
||||
groupInitialJson: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
labelId: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'labelId',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: '',
|
||||
labelId: 'group-filter-dropdown-id',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['query', 'groups', 'fetchingGroups']),
|
||||
...mapState(['query', 'groups', 'fetchingGroups', 'groupInitialJson', 'useSidebarNavigation']),
|
||||
...mapGetters(['frequentGroups', 'currentScope']),
|
||||
selectedGroup() {
|
||||
return isEmpty(this.groupInitialJson) ? ANY_OPTION : this.groupInitialJson;
|
||||
|
|
@ -73,17 +66,22 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<searchable-dropdown
|
||||
data-testid="group-filter"
|
||||
:header-text="$options.GROUP_DATA.headerText"
|
||||
:name="$options.GROUP_DATA.name"
|
||||
:loading="fetchingGroups"
|
||||
:selected-item="selectedGroup"
|
||||
:items="groups"
|
||||
:frequent-items="frequentGroups"
|
||||
:search-handler="fetchGroups"
|
||||
:label-id="labelId"
|
||||
@first-open="firstLoad"
|
||||
@change="handleGroupChange"
|
||||
/>
|
||||
<div>
|
||||
<h5 :id="labelId" class="gl-mt-0 gl-mb-5 gl-font-sm">
|
||||
{{ $options.i18n.groupFieldLabel }}
|
||||
</h5>
|
||||
<searchable-dropdown
|
||||
data-testid="group-filter"
|
||||
:header-text="$options.GROUP_DATA.headerText"
|
||||
:name="$options.GROUP_DATA.name"
|
||||
:loading="fetchingGroups"
|
||||
:selected-item="selectedGroup"
|
||||
:items="groups"
|
||||
:frequent-items="frequentGroups"
|
||||
:search-handler="fetchGroups"
|
||||
:label-id="labelId"
|
||||
@first-open="firstLoad"
|
||||
@change="handleGroupChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -2,34 +2,33 @@
|
|||
import { isEmpty } from 'lodash';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { mapState, mapActions, mapGetters } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
|
||||
import { ANY_OPTION, GROUP_DATA, PROJECT_DATA } from '../constants';
|
||||
import { ANY_OPTION, GROUP_DATA, PROJECT_DATA } from '~/search/sidebar/constants';
|
||||
import SearchableDropdown from './searchable_dropdown.vue';
|
||||
|
||||
export default {
|
||||
name: 'ProjectFilter',
|
||||
i18n: {
|
||||
projectFieldLabel: s__('GlobalSearch|Project'),
|
||||
},
|
||||
components: {
|
||||
SearchableDropdown,
|
||||
},
|
||||
props: {
|
||||
projectInitialJson: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => null,
|
||||
},
|
||||
labelId: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: '',
|
||||
labelId: 'projects-filter-dropdown-id',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['query', 'projects', 'fetchingProjects']),
|
||||
...mapState([
|
||||
'query',
|
||||
'projects',
|
||||
'fetchingProjects',
|
||||
'projectInitialJson',
|
||||
'useSidebarNavigation',
|
||||
]),
|
||||
...mapGetters(['frequentProjects', 'currentScope']),
|
||||
selectedProject() {
|
||||
return isEmpty(this.projectInitialJson) ? ANY_OPTION : this.projectInitialJson;
|
||||
|
|
@ -74,17 +73,22 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<searchable-dropdown
|
||||
data-testid="project-filter"
|
||||
:header-text="$options.PROJECT_DATA.headerText"
|
||||
:name="$options.PROJECT_DATA.name"
|
||||
:loading="fetchingProjects"
|
||||
:selected-item="selectedProject"
|
||||
:items="projects"
|
||||
:frequent-items="frequentProjects"
|
||||
:search-handler="fetchProjects"
|
||||
:label-id="labelId"
|
||||
@first-open="firstLoad"
|
||||
@change="handleProjectChange"
|
||||
/>
|
||||
<div>
|
||||
<h5 :id="labelId" class="gl-mt-0 gl-mb-5 gl-font-sm">
|
||||
{{ $options.i18n.projectFieldLabel }}
|
||||
</h5>
|
||||
<searchable-dropdown
|
||||
data-testid="project-filter"
|
||||
:header-text="$options.PROJECT_DATA.headerText"
|
||||
:name="$options.PROJECT_DATA.name"
|
||||
:loading="fetchingProjects"
|
||||
:selected-item="selectedProject"
|
||||
:items="projects"
|
||||
:frequent-items="frequentProjects"
|
||||
:search-handler="fetchProjects"
|
||||
:label-id="labelId"
|
||||
@first-open="firstLoad"
|
||||
@change="handleProjectChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// eslint-disable-next-line no-restricted-imports
|
||||
import { mapActions, mapState, mapGetters } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import eventHub from '~/super_sidebar/event_hub';
|
||||
import NavItem from '~/super_sidebar/components/nav_item.vue';
|
||||
import { NAV_LINK_DEFAULT_CLASSES, NAV_LINK_COUNT_DEFAULT_CLASSES } from '../constants';
|
||||
|
||||
|
|
@ -18,6 +19,8 @@ export default {
|
|||
...mapGetters(['navigationItems']),
|
||||
},
|
||||
created() {
|
||||
eventHub.$emit('toggle-menu-header', false);
|
||||
|
||||
if (this.urlQuery?.search) {
|
||||
this.fetchSidebarCount();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { __ } from '~/locale';
|
||||
|
||||
export const SCOPE_ISSUES = 'issues';
|
||||
export const SCOPE_MERGE_REQUESTS = 'merge_requests';
|
||||
export const SCOPE_BLOB = 'blobs';
|
||||
|
|
@ -26,3 +28,23 @@ export const TRACKING_LABEL_RESET = 'Reset Filters';
|
|||
export const SEARCH_TYPE_BASIC = 'basic';
|
||||
export const SEARCH_TYPE_ADVANCED = 'advanced';
|
||||
export const SEARCH_TYPE_ZOEKT = 'zoekt';
|
||||
|
||||
export const ANY_OPTION = {
|
||||
id: null,
|
||||
name: __('Any'),
|
||||
name_with_namespace: __('Any'),
|
||||
};
|
||||
|
||||
export const GROUP_DATA = {
|
||||
headerText: __('Filter results by group'),
|
||||
queryParam: 'group_id',
|
||||
name: 'name',
|
||||
fullName: 'full_name',
|
||||
};
|
||||
|
||||
export const PROJECT_DATA = {
|
||||
headerText: __('Filter results by project'),
|
||||
queryParam: 'project_id',
|
||||
name: 'name',
|
||||
fullName: 'name_with_namespace',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,27 +4,23 @@ import GlobalSearchSidebar from './components/app.vue';
|
|||
|
||||
Vue.use(Translate);
|
||||
|
||||
export const sidebarInitState = () => {
|
||||
const el = document.getElementById('js-search-sidebar');
|
||||
if (!el) return {};
|
||||
|
||||
const { navigationJson, searchType } = el.dataset;
|
||||
|
||||
const navigationJsonParsed = JSON.parse(navigationJson);
|
||||
|
||||
return { navigationJsonParsed, searchType };
|
||||
};
|
||||
|
||||
export const initSidebar = (store) => {
|
||||
const el = document.getElementById('js-search-sidebar');
|
||||
const hederEl = document.getElementById('super-sidebar-context-header');
|
||||
const headerText = hederEl.innerText;
|
||||
|
||||
if (!el) return false;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
name: 'GlobalSearchSidebar',
|
||||
store,
|
||||
render(createElement) {
|
||||
return createElement(GlobalSearchSidebar);
|
||||
return createElement(GlobalSearchSidebar, {
|
||||
props: {
|
||||
headerText,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { cloneDeep } from 'lodash';
|
||||
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants';
|
||||
|
||||
const createState = ({ query, navigation, defaultBranchName, searchType }) => ({
|
||||
const createState = ({ query, navigation, searchType, groupInitialJson, projectInitialJson }) => ({
|
||||
urlQuery: cloneDeep(query),
|
||||
query,
|
||||
groups: [],
|
||||
|
|
@ -21,7 +21,8 @@ const createState = ({ query, navigation, defaultBranchName, searchType }) => ({
|
|||
},
|
||||
searchLabelString: '',
|
||||
searchType,
|
||||
defaultBranchName,
|
||||
groupInitialJson,
|
||||
projectInitialJson,
|
||||
});
|
||||
|
||||
export default createState;
|
||||
|
|
|
|||
|
|
@ -3,13 +3,10 @@ import { GlSearchBoxByType, GlButton } from '@gitlab/ui';
|
|||
// eslint-disable-next-line no-restricted-imports
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import MarkdownDrawer from '~/vue_shared/components/markdown_drawer/markdown_drawer.vue';
|
||||
import { ZOEKT_SEARCH_TYPE, ADVANCED_SEARCH_TYPE } from '~/search/store/constants';
|
||||
import { SYNTAX_OPTIONS_ADVANCED_DOCUMENT, SYNTAX_OPTIONS_ZOEKT_DOCUMENT } from '../constants';
|
||||
import SearchTypeIndicator from './search_type_indicator.vue';
|
||||
import GroupFilter from './group_filter.vue';
|
||||
import ProjectFilter from './project_filter.vue';
|
||||
|
||||
export default {
|
||||
name: 'GlobalSearchTopbar',
|
||||
|
|
@ -23,22 +20,10 @@ export default {
|
|||
components: {
|
||||
GlButton,
|
||||
GlSearchBoxByType,
|
||||
GroupFilter,
|
||||
ProjectFilter,
|
||||
MarkdownDrawer,
|
||||
SearchTypeIndicator,
|
||||
},
|
||||
props: {
|
||||
groupInitialJson: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
projectInitialJson: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
defaultBranchName: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
|
@ -55,9 +40,6 @@ export default {
|
|||
this.setQuery({ key: 'search', value });
|
||||
},
|
||||
},
|
||||
showFilters() {
|
||||
return !parseBoolean(this.query.snippets);
|
||||
},
|
||||
showSyntaxOptions() {
|
||||
return (
|
||||
(this.searchType === ZOEKT_SEARCH_TYPE || this.searchType === ADVANCED_SEARCH_TYPE) &&
|
||||
|
|
@ -103,31 +85,17 @@ export default {
|
|||
</template>
|
||||
<search-type-indicator />
|
||||
</div>
|
||||
<div class="search-page-form gl-lg-display-flex gl-flex-direction-row gl-align-items-flex-end">
|
||||
<div class="gl-flex-grow-1 gl-lg-mb-0 gl-lg-mr-2">
|
||||
<gl-search-box-by-type
|
||||
id="dashboard_search"
|
||||
v-model="search"
|
||||
name="search"
|
||||
:placeholder="$options.i18n.searchPlaceholder"
|
||||
@submit="applyQuery"
|
||||
@keydown.enter.stop.prevent="applyQuery"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="showFilters" class="gl-mb-4 gl-lg-mb-0 gl-lg-mx-3 gl-min-w-20">
|
||||
<label id="groupfilterDropdown" class="gl-display-block gl-mb-1 gl-md-pb-2">{{
|
||||
$options.i18n.groupFieldLabel
|
||||
}}</label>
|
||||
<group-filter label-id="groupfilterDropdown" :group-initial-json="groupInitialJson" />
|
||||
</div>
|
||||
<div v-if="showFilters" class="gl-mb-4 gl-lg-mb-0 gl-lg-ml-3 gl-min-w-20">
|
||||
<label id="projectfilterDropdown" class="gl-display-block gl-mb-1 gl-md-pb-2">{{
|
||||
$options.i18n.projectFieldLabel
|
||||
}}</label>
|
||||
<project-filter
|
||||
label-id="projectfilterDropdown"
|
||||
:project-initial-json="projectInitialJson"
|
||||
/>
|
||||
<div class="search-page-form gl-lg-display-flex gl-flex-direction-column">
|
||||
<div class="gl-lg-display-flex gl-flex-direction-row gl-align-items-flex-start">
|
||||
<div class="gl-flex-grow-1 gl-pb-8 gl-lg-mb-0 gl-lg-mr-2">
|
||||
<gl-search-box-by-type
|
||||
id="dashboard_search"
|
||||
v-model="search"
|
||||
name="search"
|
||||
:placeholder="$options.i18n.searchPlaceholder"
|
||||
@keydown.enter.stop.prevent="applyQuery"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -1,25 +1,3 @@
|
|||
import { __ } from '~/locale';
|
||||
|
||||
export const ANY_OPTION = Object.freeze({
|
||||
id: null,
|
||||
name: __('Any'),
|
||||
name_with_namespace: __('Any'),
|
||||
});
|
||||
|
||||
export const GROUP_DATA = {
|
||||
headerText: __('Filter results by group'),
|
||||
queryParam: 'group_id',
|
||||
name: 'name',
|
||||
fullName: 'full_name',
|
||||
};
|
||||
|
||||
export const PROJECT_DATA = {
|
||||
headerText: __('Filter results by project'),
|
||||
queryParam: 'project_id',
|
||||
name: 'name',
|
||||
fullName: 'name_with_namespace',
|
||||
};
|
||||
|
||||
export const SYNTAX_OPTIONS_ADVANCED_DOCUMENT = 'drawers/drawers/advanced_search_syntax.md';
|
||||
export const SYNTAX_OPTIONS_ZOEKT_DOCUMENT = 'drawers/drawers/exact_code_search_syntax.md';
|
||||
|
||||
|
|
|
|||
|
|
@ -11,19 +11,16 @@ export const initTopbar = (store) => {
|
|||
return false;
|
||||
}
|
||||
|
||||
const { groupInitialJson, projectInitialJson } = el.dataset;
|
||||
|
||||
const groupInitialJsonParsed = JSON.parse(groupInitialJson);
|
||||
const projectInitialJsonParsed = JSON.parse(projectInitialJson);
|
||||
const { defaultBranchName } = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
name: 'GlobalSearchTopbar',
|
||||
store,
|
||||
render(createElement) {
|
||||
return createElement(GlobalSearchTopbar, {
|
||||
props: {
|
||||
groupInitialJson: groupInitialJsonParsed,
|
||||
projectInitialJson: projectInitialJsonParsed,
|
||||
defaultBranchName,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export const initBlobRefSwitcher = () => {
|
|||
|
||||
return new Vue({
|
||||
el,
|
||||
name: 'GlobalSearchUnderTopbar',
|
||||
render(createElement) {
|
||||
return createElement(RefSelector, {
|
||||
props: {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { TAB_KEY_CODE } from '~/lib/utils/keycodes';
|
|||
import { keysFor, TOGGLE_SUPER_SIDEBAR } from '~/behaviors/shortcuts/keybindings';
|
||||
import { __, s__ } from '~/locale';
|
||||
import Tracking from '~/tracking';
|
||||
import eventHub from '../event_hub';
|
||||
import {
|
||||
sidebarState,
|
||||
SUPER_SIDEBAR_PEEK_STATE_CLOSED as STATE_CLOSED,
|
||||
|
|
@ -58,6 +59,7 @@ export default {
|
|||
showPeekHint: false,
|
||||
isMouseover: false,
|
||||
breakpoint: null,
|
||||
showSuperSidebarContextHeader: true,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -96,6 +98,7 @@ export default {
|
|||
mounted() {
|
||||
this.setupFocusTrapListener();
|
||||
Mousetrap.bind(keysFor(TOGGLE_SUPER_SIDEBAR), this.toggleSidebar);
|
||||
eventHub.$on('toggle-menu-header', this.onToggleMenuHeader);
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('keydown', this.focusTrap);
|
||||
|
|
@ -166,6 +169,9 @@ export default {
|
|||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
onToggleMenuHeader(forceState) {
|
||||
this.showSuperSidebarContextHeader = forceState;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -207,6 +213,7 @@ export default {
|
|||
>
|
||||
<scroll-scrim class="gl-flex-grow-1" data-testid="nav-container">
|
||||
<div
|
||||
v-if="showSuperSidebarContextHeader"
|
||||
id="super-sidebar-context-header"
|
||||
class="gl-px-5 gl-pt-3 gl-pb-2 gl-m-0 gl-reset-line-height gl-font-weight-bold gl-font-sm super-sidebar-context-header"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -92,8 +92,7 @@
|
|||
@include transition(background-color, border-color, color, box-shadow);
|
||||
}
|
||||
|
||||
.dropdown-menu-toggle,
|
||||
.header-user-avatar {
|
||||
.dropdown-menu-toggle {
|
||||
@include transition(border-color);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -810,14 +810,6 @@
|
|||
.navbar-gitlab {
|
||||
li.dropdown {
|
||||
position: static;
|
||||
|
||||
&.user-counter {
|
||||
margin-left: 8px !important;
|
||||
|
||||
> a {
|
||||
padding: 0 4px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,12 +98,6 @@
|
|||
.container-fluid {
|
||||
padding: 0;
|
||||
|
||||
.user-counter {
|
||||
svg {
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
@include media-breakpoint-down(xs) {
|
||||
display: flex;
|
||||
|
|
@ -120,12 +114,6 @@
|
|||
}
|
||||
|
||||
.nav > li {
|
||||
&.header-user {
|
||||
@include media-breakpoint-down(xs) {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
> a {
|
||||
will-change: color;
|
||||
margin: 4px 0;
|
||||
|
|
@ -137,38 +125,11 @@
|
|||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.header-user-dropdown-toggle {
|
||||
margin-left: 2px;
|
||||
|
||||
.header-user-avatar {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-new-dropdown-toggle {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.impersonated-user,
|
||||
.impersonated-user:hover {
|
||||
margin-right: 1px;
|
||||
background-color: $white;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.impersonation-btn,
|
||||
.impersonation-btn:hover {
|
||||
background-color: $white;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
|
||||
svg {
|
||||
color: $orange-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -223,10 +184,6 @@
|
|||
top: -1px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.impersonation i {
|
||||
color: $red-500;
|
||||
}
|
||||
}
|
||||
|
||||
.caret-down,
|
||||
|
|
@ -238,7 +195,6 @@
|
|||
fill: currentColor;
|
||||
}
|
||||
|
||||
.header-user .dropdown-menu,
|
||||
.header-new .dropdown-menu {
|
||||
margin-top: $dropdown-vertical-offset;
|
||||
}
|
||||
|
|
@ -304,44 +260,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-user-dropdown-toggle {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header-user-avatar {
|
||||
float: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header-user {
|
||||
&.show .dropdown-menu {
|
||||
margin-top: 4px;
|
||||
color: var(--gl-text-color, $gl-text-color);
|
||||
left: auto;
|
||||
max-height: $dropdown-max-height-lg;
|
||||
|
||||
.user-status {
|
||||
max-width: 240px;
|
||||
}
|
||||
|
||||
svg {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
a.ci-minutes-emoji gl-emoji,
|
||||
a.trial-link gl-emoji {
|
||||
font-size: $gl-font-size;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-user-avatar {
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid $gray-normal;
|
||||
}
|
||||
|
||||
.notification-dot {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
module Explore
|
||||
class CatalogController < Explore::ApplicationController
|
||||
feature_category :pipeline_composition
|
||||
before_action :check_feature_flag
|
||||
before_action :check_resource_access, only: :show
|
||||
|
||||
def show; end
|
||||
|
|
@ -14,10 +13,6 @@ module Explore
|
|||
|
||||
private
|
||||
|
||||
def check_feature_flag
|
||||
render_404 unless Feature.enabled?(:global_ci_catalog, current_user)
|
||||
end
|
||||
|
||||
def check_resource_access
|
||||
render_404 unless catalog_resource.present?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController
|
|||
:color_scheme_id,
|
||||
:diffs_deletion_color,
|
||||
:diffs_addition_color,
|
||||
:home_organization_id,
|
||||
:layout,
|
||||
:dashboard,
|
||||
:project_view,
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
push_frontend_feature_flag(:blob_blame_info, @project)
|
||||
push_frontend_feature_flag(:highlight_js_worker, @project)
|
||||
push_frontend_feature_flag(:explain_code_chat, current_user)
|
||||
push_frontend_feature_flag(:encoding_logs_tree)
|
||||
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,13 @@ class Projects::ServiceDeskController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def allowed_update_attributes
|
||||
%i[issue_template_key outgoing_name project_key add_external_participants_from_cc]
|
||||
%i[
|
||||
issue_template_key
|
||||
outgoing_name
|
||||
project_key
|
||||
reopen_issue_on_external_participant_note
|
||||
add_external_participants_from_cc
|
||||
]
|
||||
end
|
||||
|
||||
def service_desk_attributes
|
||||
|
|
@ -42,6 +48,7 @@ class Projects::ServiceDeskController < Projects::ApplicationController
|
|||
template_file_missing: service_desk_settings&.issue_template_missing?,
|
||||
outgoing_name: service_desk_settings&.outgoing_name,
|
||||
project_key: service_desk_settings&.project_key,
|
||||
reopen_issue_on_external_participant_note: service_desk_settings&.reopen_issue_on_external_participant_note,
|
||||
add_external_participants_from_cc: service_desk_settings&.add_external_participants_from_cc
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class Projects::TreeController < Projects::ApplicationController
|
|||
push_frontend_feature_flag(:blob_blame_info, @project)
|
||||
push_frontend_feature_flag(:highlight_js_worker, @project)
|
||||
push_frontend_feature_flag(:explain_code_chat, current_user)
|
||||
push_frontend_feature_flag(:encoding_logs_tree)
|
||||
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ class ProjectsController < Projects::ApplicationController
|
|||
push_frontend_feature_flag(:remove_monitor_metrics, @project)
|
||||
push_frontend_feature_flag(:explain_code_chat, current_user)
|
||||
push_frontend_feature_flag(:issue_email_participants, @project)
|
||||
push_frontend_feature_flag(:encoding_logs_tree)
|
||||
# TODO: We need to remove the FF eventually when we rollout page_specific_styles
|
||||
push_frontend_feature_flag(:page_specific_styles, current_user)
|
||||
push_licensed_feature(:file_locks) if @project.present? && @project.licensed_feature_available?(:file_locks)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Resolvers
|
||||
module Namespaces
|
||||
class WorkItemStateCountsResolver < WorkItemsResolver
|
||||
type Types::WorkItemStateCountsType, null: true
|
||||
|
||||
def ready?(**args)
|
||||
# The search filter is not supported for work times at the namespace level.
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/work_items/393126
|
||||
if args[:search]
|
||||
raise Gitlab::Graphql::Errors::ArgumentError,
|
||||
'Searching is not available for work items at the namespace level yet'
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def resolve(**args)
|
||||
return if resource_parent.nil?
|
||||
|
||||
Gitlab::IssuablesCountForState.new(
|
||||
finder(args),
|
||||
resource_parent,
|
||||
store_in_redis_cache: true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Resolvers
|
||||
class WorkItemStateCountsResolver < WorkItemsResolver
|
||||
type Types::WorkItemStateCountsType, null: true
|
||||
|
||||
def resolve(**args)
|
||||
return if resource_parent.nil?
|
||||
|
||||
work_item_finder = finder(prepare_finder_params(args))
|
||||
work_item_finder.parent_param = resource_parent
|
||||
|
||||
Gitlab::IssuablesCountForState.new(work_item_finder, resource_parent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -275,6 +275,14 @@ module Types
|
|||
description: 'Find a work item by IID directly associated with the group. Returns `null` if the ' \
|
||||
'`namespace_level_work_items` feature flag is disabled.'
|
||||
|
||||
field :work_item_state_counts,
|
||||
Types::WorkItemStateCountsType,
|
||||
null: true,
|
||||
alpha: { milestone: '16.7' },
|
||||
description: 'Counts of work items by state for the namespace. Returns `null` if the ' \
|
||||
'`namespace_level_work_items` feature flag is disabled.',
|
||||
resolver: Resolvers::Namespaces::WorkItemStateCountsResolver
|
||||
|
||||
field :autocomplete_users,
|
||||
null: true,
|
||||
resolver: Resolvers::AutocompleteUsersResolver,
|
||||
|
|
|
|||
|
|
@ -254,6 +254,13 @@ module Types
|
|||
extras: [:lookahead],
|
||||
resolver: Resolvers::WorkItemsResolver
|
||||
|
||||
field :work_item_state_counts,
|
||||
Types::WorkItemStateCountsType,
|
||||
null: true,
|
||||
alpha: { milestone: '16.7' },
|
||||
description: 'Counts of work items by state for the project.',
|
||||
resolver: Resolvers::WorkItemStateCountsResolver
|
||||
|
||||
field :issue_status_counts,
|
||||
Types::IssueStatusCountsType,
|
||||
null: true,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
# rubocop: disable Graphql/AuthorizeTypes -- Parent node applies authorization
|
||||
class WorkItemStateCountsType < BaseObject
|
||||
graphql_name 'WorkItemStateCountsType'
|
||||
description 'Represents total number of work items for the represented states'
|
||||
|
||||
field :all,
|
||||
GraphQL::Types::Int,
|
||||
null: true,
|
||||
description: 'Number of work items for the project or group.'
|
||||
|
||||
field :closed,
|
||||
GraphQL::Types::Int,
|
||||
null: true,
|
||||
description: 'Number of work items with state CLOSED for the project or group.'
|
||||
|
||||
field :opened,
|
||||
GraphQL::Types::Int,
|
||||
null: true,
|
||||
description: 'Number of work items with state OPENED for the project or group.'
|
||||
end
|
||||
# rubocop: enable Graphql/AuthorizeTypes
|
||||
end
|
||||
|
|
@ -315,8 +315,8 @@ module ApplicationHelper
|
|||
class_names << 'issue-boards-page gl-overflow-auto' if current_controller?(:boards)
|
||||
class_names << 'epic-boards-page gl-overflow-auto' if current_controller?(:epic_boards)
|
||||
class_names << 'with-performance-bar' if performance_bar_enabled?
|
||||
class_names << 'with-header' if !show_super_sidebar? || !current_user
|
||||
class_names << 'with-top-bar' if show_super_sidebar? && !@hide_top_bar_padding
|
||||
class_names << 'with-header' unless current_user
|
||||
class_names << 'with-top-bar' unless @hide_top_bar_padding
|
||||
class_names << system_message_class
|
||||
|
||||
class_names
|
||||
|
|
|
|||
|
|
@ -3,18 +3,6 @@
|
|||
module DashboardHelper
|
||||
include IconsHelper
|
||||
|
||||
def assigned_issues_dashboard_path
|
||||
issues_dashboard_path(assignee_username: current_user.username)
|
||||
end
|
||||
|
||||
def assigned_mrs_dashboard_path
|
||||
merge_requests_dashboard_path(assignee_username: current_user.username)
|
||||
end
|
||||
|
||||
def reviewer_mrs_dashboard_path
|
||||
merge_requests_dashboard_path(reviewer_username: current_user.username)
|
||||
end
|
||||
|
||||
def has_start_trial?
|
||||
false
|
||||
end
|
||||
|
|
|
|||
|
|
@ -149,16 +149,6 @@ module IssuablesHelper
|
|||
end
|
||||
end
|
||||
|
||||
def assigned_open_issues_count_text
|
||||
count = assigned_issuables_count(:issues)
|
||||
|
||||
if count > User::MAX_LIMIT_FOR_ASSIGNEED_ISSUES_COUNT - 1
|
||||
"#{count - 1}+"
|
||||
else
|
||||
count.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def issuable_reference(issuable)
|
||||
@show_full_reference ? issuable.to_reference(full: true) : issuable.to_reference(@group || @project)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -40,14 +40,6 @@ module NavHelper
|
|||
end
|
||||
end
|
||||
|
||||
def user_dropdown_class
|
||||
class_names = []
|
||||
class_names << 'header-user-dropdown-toggle'
|
||||
class_names << 'impersonated-user' if session[:impersonator_id]
|
||||
|
||||
class_names
|
||||
end
|
||||
|
||||
def page_has_markdown?
|
||||
current_path?('projects/merge_requests#show') ||
|
||||
current_path?('projects/merge_requests/conflicts#show') ||
|
||||
|
|
|
|||
|
|
@ -51,8 +51,7 @@ module Organizations
|
|||
|
||||
def home_organization_setting_app_data
|
||||
{
|
||||
# TODO: use real setting - https://gitlab.com/gitlab-org/gitlab/-/issues/428668
|
||||
initial_selection: 1
|
||||
initial_selection: current_user.home_organization_id
|
||||
}.to_json
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -5,10 +5,6 @@ module TodosHelper
|
|||
@todos_pending_count ||= current_user.todos_pending_count
|
||||
end
|
||||
|
||||
def todos_count_format(count)
|
||||
count > 99 ? '99+' : count.to_s
|
||||
end
|
||||
|
||||
def todos_done_count
|
||||
@todos_done_count ||= current_user.todos_done_count
|
||||
end
|
||||
|
|
|
|||
|
|
@ -758,6 +758,11 @@ class Issue < ApplicationRecord
|
|||
Gitlab::HookData::IssueBuilder.new(self).build
|
||||
end
|
||||
|
||||
override :gfm_reference
|
||||
def gfm_reference(from = nil)
|
||||
"#{work_item_type_with_default.name.underscore} #{to_reference(from)}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project_level_readable_by?(user)
|
||||
|
|
|
|||
|
|
@ -400,6 +400,7 @@ class User < MainClusterwide::ApplicationRecord
|
|||
:pinned_nav_items, :pinned_nav_items=,
|
||||
:achievements_enabled, :achievements_enabled=,
|
||||
:enabled_following, :enabled_following=,
|
||||
:home_organization, :home_organization_id, :home_organization_id=,
|
||||
to: :user_preference
|
||||
|
||||
delegate :path, to: :namespace, allow_nil: true, prefix: true
|
||||
|
|
@ -613,6 +614,10 @@ class User < MainClusterwide::ApplicationRecord
|
|||
|
||||
strip_attributes! :name
|
||||
|
||||
def user_belongs_to_organization?(organization)
|
||||
organization_users.exists?(organization: organization)
|
||||
end
|
||||
|
||||
def preferred_language
|
||||
read_attribute('preferred_language').presence || Gitlab::CurrentSettings.default_preferred_language
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ class UserPreference < MainClusterwide::ApplicationRecord
|
|||
TIME_DISPLAY_FORMATS = { system: 0, non_iso_format: 1, iso_format: 2 }.freeze
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :home_organization, class_name: "Organizations::Organization", optional: true
|
||||
|
||||
scope :with_user, -> { joins(:user) }
|
||||
scope :gitpod_enabled, -> { where(gitpod_enabled: true) }
|
||||
|
|
@ -30,6 +31,8 @@ class UserPreference < MainClusterwide::ApplicationRecord
|
|||
|
||||
validates :time_display_format, inclusion: { in: TIME_DISPLAY_FORMATS.values }, presence: true
|
||||
|
||||
validate :user_belongs_to_home_organization, if: :home_organization_changed?
|
||||
|
||||
# 2023-06-22 is after 16.1 release and during 16.2 release https://docs.gitlab.com/ee/development/database/avoiding_downtime_in_migrations.html#ignoring-the-column-release-m
|
||||
ignore_columns :use_legacy_web_ide, remove_with: '16.2', remove_after: '2023-06-22'
|
||||
|
||||
|
|
@ -52,6 +55,16 @@ class UserPreference < MainClusterwide::ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def user_belongs_to_home_organization
|
||||
# If we don't ignore the default organization id below then all users need to have their corresponding entry
|
||||
# with default organization id as organization id in the `organization_users` table.
|
||||
# Otherwise, the user won't be able to the default organization as the home organization.
|
||||
return if home_organization_id == Organizations::Organization::DEFAULT_ORGANIZATION_ID
|
||||
return if user.user_belongs_to_organization?(home_organization_id)
|
||||
|
||||
errors.add(:user, _("is not part of the given organization"))
|
||||
end
|
||||
|
||||
def set_notes_filter(filter_id, issuable)
|
||||
# No need to update the column if the value is already set.
|
||||
if filter_id && NOTES_FILTERS.value?(filter_id)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ module Groups
|
|||
noteable_owner +
|
||||
participants_in_noteable +
|
||||
all_members +
|
||||
groups +
|
||||
group_hierarchy_users
|
||||
group_hierarchy_users +
|
||||
groups
|
||||
|
||||
render_participants_as_hash(participants.uniq)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -35,8 +35,6 @@ module MergeRequests
|
|||
result = maybe_rebase!(**result)
|
||||
result = maybe_merge!(**result)
|
||||
|
||||
update_merge_request!(merge_request, result)
|
||||
|
||||
ServiceResponse.success(payload: result)
|
||||
rescue CreateRefError => error
|
||||
ServiceResponse.error(message: error.message)
|
||||
|
|
@ -118,10 +116,6 @@ module MergeRequests
|
|||
).compact
|
||||
end
|
||||
|
||||
def update_merge_request!(merge_request, result)
|
||||
# overridden in EE
|
||||
end
|
||||
|
||||
def safe_gitaly_operation
|
||||
yield
|
||||
rescue Gitlab::Git::PreReceiveError, Gitlab::Git::CommandError, ArgumentError => error
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Namespaces
|
||||
class InProductMarketingEmailsService
|
||||
TRACKS = {
|
||||
create: {
|
||||
interval_days: [1, 5, 10],
|
||||
completed_actions: [:created],
|
||||
incomplete_actions: [:git_write]
|
||||
},
|
||||
team_short: {
|
||||
interval_days: [1],
|
||||
completed_actions: [:git_write],
|
||||
incomplete_actions: [:user_added]
|
||||
},
|
||||
trial_short: {
|
||||
interval_days: [2],
|
||||
completed_actions: [:git_write],
|
||||
incomplete_actions: [:trial_started]
|
||||
},
|
||||
admin_verify: {
|
||||
interval_days: [3],
|
||||
completed_actions: [:git_write],
|
||||
incomplete_actions: [:pipeline_created]
|
||||
},
|
||||
verify: {
|
||||
interval_days: [4, 8, 13],
|
||||
completed_actions: [:git_write],
|
||||
incomplete_actions: [:pipeline_created]
|
||||
},
|
||||
trial: {
|
||||
interval_days: [1, 5, 10],
|
||||
completed_actions: [:git_write, :pipeline_created],
|
||||
incomplete_actions: [:trial_started]
|
||||
},
|
||||
team: {
|
||||
interval_days: [1, 5, 10],
|
||||
completed_actions: [:git_write, :pipeline_created, :trial_started],
|
||||
incomplete_actions: [:user_added]
|
||||
}
|
||||
}.freeze
|
||||
|
||||
def self.email_count_for_track(track)
|
||||
interval_days = TRACKS.dig(track.to_sym, :interval_days)
|
||||
interval_days&.count || 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Namespaces::InProductMarketingEmailsService.prepend_mod
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Users
|
||||
class InProductMarketingEmailRecords
|
||||
attr_reader :records
|
||||
|
||||
def initialize
|
||||
@records = []
|
||||
end
|
||||
|
||||
def save!
|
||||
Users::InProductMarketingEmail.bulk_insert!(@records)
|
||||
@records = []
|
||||
end
|
||||
|
||||
def add(user, track: nil, series: nil)
|
||||
@records << Users::InProductMarketingEmail.new(
|
||||
user: user,
|
||||
track: track,
|
||||
series: series,
|
||||
created_at: Time.zone.now,
|
||||
updated_at: Time.zone.now
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
|
||||
= yield :page_specific_javascripts
|
||||
|
||||
= webpack_bundle_tag 'super_sidebar' if show_super_sidebar?
|
||||
= webpack_bundle_tag 'super_sidebar'
|
||||
|
||||
= webpack_controller_bundle_tags
|
||||
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
- return unless current_user
|
||||
|
||||
%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', track_action: "click_link", track_label: "user_profile", track_property: "navigation_top" } do
|
||||
= render 'layouts/header/current_user_dropdown_item'
|
||||
- else
|
||||
.gl-py-3.gl-px-4
|
||||
= render 'layouts/header/current_user_dropdown_item'
|
||||
%li.divider
|
||||
- if can?(current_user, :update_user_status, current_user)
|
||||
%li
|
||||
= render Pajamas::ButtonComponent.new(button_options: { class: 'menu-item js-set-status-modal-trigger' }) do
|
||||
- if current_user.status&.busy? || current_user.status&.customized?
|
||||
= s_('SetStatusModal|Edit status')
|
||||
- else
|
||||
= s_('SetStatusModal|Set status')
|
||||
= dispensable_render_if_exists 'layouts/header/start_trial'
|
||||
- if current_user_menu?(:settings)
|
||||
%li
|
||||
= link_to s_("CurrentUser|Edit profile"), profile_path, data: { testid: '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, 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, data: {track_action: 'click_link', track_label: 'help', track_property: 'navigation_top'}
|
||||
%li.d-md-none
|
||||
= 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"), 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, data: { track_action: "click_link", track_label: "switch_to_canary", track_property: "navigation_top" }
|
||||
|
||||
%li.divider
|
||||
.js-new-nav-toggle{ data: { enabled: show_super_sidebar?.to_s, endpoint: profile_preferences_path} }
|
||||
|
||||
- if current_user_menu?(:sign_out)
|
||||
%li.divider
|
||||
%li
|
||||
= link_to _("Sign out"), destroy_user_session_path, method: :post, class: "sign-out-link", data: { testid: 'sign_out_link', track_action: "click_link", track_label: "user_sign_out", track_property: "navigation_top" }
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
.gl-font-weight-bold
|
||||
= current_user.name
|
||||
- if current_user.status&.busy?
|
||||
= render Pajamas::BadgeComponent.new(s_('UserProfile|Busy'), size: 'sm', variant: 'warning')
|
||||
= current_user.to_reference
|
||||
- if current_user.status
|
||||
.user-status.d-flex.align-items-center.gl-mt-2.gl-mr-0.gl-font-sm.has-tooltip{ title: current_user.status.message_html, data: { html: 'true', placement: 'bottom' } }
|
||||
- if current_user.status.customized?
|
||||
.user-status-emoji.d-flex.align-items-center
|
||||
= emoji_icon current_user.status.emoji
|
||||
%span.user-status-message.str-truncated
|
||||
= current_user.status.message_html.html_safe
|
||||
|
|
@ -1,6 +1,3 @@
|
|||
- has_impersonation_link = header_link?(:admin_impersonation)
|
||||
- user_status_data = user_status_properties(current_user)
|
||||
|
||||
%header.navbar.navbar-gitlab.navbar-expand-sm.js-navbar.legacy-top-bar{ data: { testid: 'navbar' } }
|
||||
%a.gl-sr-only.gl-accessibility{ href: "#content-body" } Skip to content
|
||||
.container-fluid
|
||||
|
|
@ -12,64 +9,6 @@
|
|||
%ul.nav.navbar-nav.gl-w-full.gl-align-items-center.gl-justify-content-end
|
||||
- if current_user
|
||||
= render 'layouts/header/new_dropdown', class: 'gl-display-none gl-sm-display-block gl-white-space-nowrap gl-text-right'
|
||||
- if header_link?(:issues)
|
||||
= nav_link(path: 'dashboard#issues', html_options: { class: "user-counter" }) do
|
||||
= link_to assigned_issues_dashboard_path, title: _('Issues'), class: 'dashboard-shortcuts-issues js-prefetch-document', aria: { label: _('Issues') },
|
||||
data: { testid: 'issues_shortcut_button', toggle: 'tooltip', placement: 'bottom',
|
||||
track_label: 'main_navigation',
|
||||
track_action: 'click_issues_link',
|
||||
track_property: 'navigation_top',
|
||||
container: 'body' } do
|
||||
= sprite_icon('issues')
|
||||
- issues_count = assigned_issuables_count(:issues)
|
||||
= gl_badge_tag({ size: :sm, variant: :success }, { class: "gl-ml-n2 #{'gl-display-none' if issues_count == 0}", "aria-label": n_("%d assigned issue", "%d assigned issues", issues_count) % issues_count }) do
|
||||
= assigned_open_issues_count_text
|
||||
- if header_link?(:merge_requests)
|
||||
= nav_link(path: 'dashboard#merge_requests', html_options: { class: "user-counter dropdown" }) do
|
||||
- top_level_link = assigned_mrs_dashboard_path
|
||||
= link_to top_level_link, class: 'dashboard-shortcuts-merge_requests has-tooltip', title: _('Merge requests'), aria: { label: _('Merge requests') },
|
||||
data: { testid: 'merge_requests_shortcut_button',
|
||||
toggle: "dropdown",
|
||||
placement: 'bottom',
|
||||
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
|
||||
= number_with_delimiter(user_merge_requests_counts[:total])
|
||||
= sprite_icon('chevron-down', css_class: 'caret-down gl-mx-0!')
|
||||
.dropdown-menu.dropdown-menu-right
|
||||
%ul
|
||||
%li.dropdown-header
|
||||
= _('Merge requests')
|
||||
%li
|
||||
= 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',
|
||||
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]
|
||||
- if header_link?(:todos)
|
||||
= nav_link(controller: 'dashboard/todos', html_options: { class: "user-counter" }) do
|
||||
= link_to dashboard_todos_path, title: _('To-Do List'), aria: { label: _('To-Do List') }, class: 'shortcuts-todos js-prefetch-document',
|
||||
data: { testid: 'todos-shortcut-button', toggle: 'tooltip', placement: 'bottom',
|
||||
track_label: 'main_navigation',
|
||||
track_action: 'click_to_do_link',
|
||||
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
|
||||
= 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' } do
|
||||
%span.gl-sr-only
|
||||
|
|
@ -79,27 +18,6 @@
|
|||
= sprite_icon('chevron-down', css_class: 'caret-down')
|
||||
.dropdown-menu.dropdown-menu-right
|
||||
= render 'layouts/header/help_dropdown'
|
||||
- if header_link?(:user_dropdown)
|
||||
%li.nav-item.header-user.js-nav-user-dropdown.dropdown{ data: { testid: 'user-dropdown' }, 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: { testid: 'user-avatar-content' } })
|
||||
= render_if_exists 'layouts/header/user_notification_dot', project: project, namespace: group
|
||||
= sprite_icon('chevron-down', css_class: 'caret-down')
|
||||
.dropdown-menu.dropdown-menu-right
|
||||
= render 'layouts/header/current_user_dropdown'
|
||||
- if has_impersonation_link
|
||||
%li.nav-item.impersonation.ml-0
|
||||
= render Pajamas::ButtonComponent.new(href: admin_impersonation_path, icon: 'incognito', button_options: { title: _('Stop impersonation'), class: 'impersonation-btn', aria: { label: _('Stop impersonation') }, data: { method: :delete, toggle: 'tooltip', placement: 'bottom', container: 'body', testid: 'stop_impersonation_btn' } })
|
||||
- if header_link?(:sign_in)
|
||||
- if allow_signup?
|
||||
%li.nav-item
|
||||
= render Pajamas::ButtonComponent.new(href: new_user_registration_path) do
|
||||
= _('Register')
|
||||
%li.nav-item{ class: 'gl-flex-grow-0! gl-flex-basis-half!' }
|
||||
= link_to _('Sign in'), new_session_path(:user, redirect_to_referer: 'yes')
|
||||
|
||||
- if display_whats_new?
|
||||
#whats-new-app{ data: { version_digest: whats_new_version_digest } }
|
||||
|
||||
- if can?(current_user, :update_user_status, current_user)
|
||||
.js-set-status-modal-wrapper{ data: user_status_data }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
- @breadcrumb_title = _("Help")
|
||||
- page_title _("Help")
|
||||
- header_title _("Help"), help_path
|
||||
- if show_super_sidebar?
|
||||
- @force_desktop_expanded_sidebar = true
|
||||
- @force_desktop_expanded_sidebar = true
|
||||
|
||||
= render template: "layouts/application"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
- page_title _("Search")
|
||||
- header_title _("Search"), search_path
|
||||
- add_page_specific_style 'page_bundles/search'
|
||||
- if show_super_sidebar?
|
||||
- @force_desktop_expanded_sidebar = true
|
||||
- @force_desktop_expanded_sidebar = true
|
||||
|
||||
= render template: "layouts/application"
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
selected_file_template_project_id: "#{@project.service_desk_setting&.file_template_project_id}",
|
||||
outgoing_name: "#{@project.service_desk_setting&.outgoing_name}",
|
||||
project_key: "#{@project.service_desk_setting&.project_key}",
|
||||
reopen_issue_on_external_participant_note: "#{@project.service_desk_setting&.reopen_issue_on_external_participant_note}",
|
||||
add_external_participants_from_cc: "#{@project.service_desk_setting&.add_external_participants_from_cc}",
|
||||
templates: available_service_desk_templates_for(@project),
|
||||
public_project: "#{@project.public?}",
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@
|
|||
- elsif @search_objects.blank?
|
||||
= render partial: "search/results/empty"
|
||||
- else
|
||||
- statusBarClass = !show_super_sidebar? ? 'gl-lg-pl-5' : ''
|
||||
|
||||
.section{ class: statusBarClass }
|
||||
.section
|
||||
- if @scope == 'commits'
|
||||
%ul.content-list.commit-list
|
||||
= render partial: "search/results/commit", collection: @search_objects
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
- statusBarClass = !show_super_sidebar? ? 'gl-lg-pl-5' : ''
|
||||
- statusBarClass = statusBarClass + ' gl-lg-display-none' if @search_objects.to_a.empty?
|
||||
|
||||
.section{ class: statusBarClass }
|
||||
.section{ class: ('gl-lg-display-none' if @search_objects.to_a.empty?) }
|
||||
.search-results-status
|
||||
.gl-display-flex.gl-flex-direction-column
|
||||
.gl-p-5.gl-display-flex.gl-flex-wrap
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
- page_description(_("%{count} %{scope} for term '%{term}'") % { count: @search_results.formatted_count(@scope), scope: @scope, term: @search_term })
|
||||
- page_card_attributes("Namespace" => @group&.full_path, "Project" => @project&.full_path)
|
||||
|
||||
#js-search-topbar{ data: { "group-initial-json": group_attributes.to_json, "project-initial-json": project_attributes.to_json, "default-branch-name": @project&.default_branch } }
|
||||
#js-search-topbar{ data: { "default-branch-name": @project&.default_branch } }
|
||||
.results.gl-lg-display-flex.gl-mt-0
|
||||
#js-search-sidebar{ data: { navigation_json: search_navigation_json, search_type: search_service.search_type } }
|
||||
#js-search-sidebar{ data: { navigation_json: search_navigation_json, search_type: search_service.search_type, group_initial_json: group_attributes.to_json, project_initial_json: project_attributes.to_json, } }
|
||||
- if @search_term
|
||||
= render 'search/results'
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
- current_href = Feature.enabled?(:global_ci_catalog, @user) ? href : nil
|
||||
= render Pajamas::BadgeComponent.new(s_('CiCatalog|CI/CD catalog resource'), variant: 'info', icon: 'catalog-checkmark', class: css_class, href: current_href)
|
||||
= render Pajamas::BadgeComponent.new(s_('CiCatalog|CI/CD catalog resource'), variant: 'info', icon: 'catalog-checkmark', class: css_class, href: href)
|
||||
|
|
|
|||
|
|
@ -19,4 +19,4 @@
|
|||
|
||||
%p
|
||||
= s_("Runners|Tags control which type of jobs a runner can handle. By tagging a runner, you make sure shared runners only handle the jobs they are equipped to run.")
|
||||
= link_to _("Learn more."), help_page_path("ci/runners/configure_runners", anchor: "use-tags-to-control-which-jobs-a-runner-can-run"), target: '_blank'
|
||||
= link_to _("Learn more."), help_page_path("ci/runners/configure_runners", anchor: "how-the-runner-uses-tags"), target: '_blank'
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: global_ci_catalog
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/133885
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/427940
|
||||
milestone: '16.6'
|
||||
name: encoding_logs_tree
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/136323
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/432559
|
||||
milestone: '16.7'
|
||||
type: development
|
||||
group: group::pipeline authoring
|
||||
group: group::source code
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: product_analytics_beta_optin
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138469
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/433344
|
||||
milestone: '16.7'
|
||||
type: development
|
||||
group: group::product analytics
|
||||
default_enabled: false
|
||||
|
|
@ -187,6 +187,8 @@
|
|||
- 1
|
||||
- - compliance_management_pending_status_check
|
||||
- 1
|
||||
- - compliance_management_standards_adherence_export_mailer
|
||||
- 1
|
||||
- - compliance_management_standards_gitlab_at_least_two_approvals
|
||||
- 1
|
||||
- - compliance_management_standards_gitlab_base
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@ description: Backfill missing vulnerability dimissal information as a result of
|
|||
feature_category: vulnerability_management
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126253
|
||||
milestone: '16.2'
|
||||
finalized_by: '20231207220935'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
---
|
||||
migration_job_name: BackfillRootStorageStatisticsForkStorageSizes
|
||||
description: Backfill the public_forks_storage_size, internal_forks_storage_size, and private_forks_storage_size columns on the namespace_root_storage_statistics table
|
||||
description: Backfill the public_forks_storage_size, internal_forks_storage_size,
|
||||
and private_forks_storage_size columns on the namespace_root_storage_statistics
|
||||
table
|
||||
feature_category: consumables_cost_management
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/120916
|
||||
milestone: '16.1'
|
||||
finalized_by: '20231207221036'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddHomeOrganizationIdToUserPreferences < Gitlab::Database::Migration[2.2]
|
||||
enable_lock_retries!
|
||||
milestone '16.7'
|
||||
|
||||
def change
|
||||
add_column(:user_preferences, :home_organization_id, :bigint, null: true)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddHomeOrganizationIdIndexToUserPreferences < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
milestone '16.7'
|
||||
|
||||
INDEX = 'index_user_preferences_on_home_organization_id'
|
||||
|
||||
def up
|
||||
add_concurrent_index(:user_preferences, :home_organization_id, name: INDEX)
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name(:user_preferences, name: INDEX)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddHomeOrganizationIdFkToUserPreferences < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
milestone '16.7'
|
||||
|
||||
def up
|
||||
add_concurrent_foreign_key(:user_preferences, :organizations, column: :home_organization_id, on_delete: :nullify)
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_foreign_key_if_exists :user_preferences, column: :home_organization_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeBackfillMissingVulnerabilityDismissalDetails < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.7'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: 'BackfillMissingVulnerabilityDismissalDetails',
|
||||
table_name: :vulnerabilities,
|
||||
column_name: :id,
|
||||
job_arguments: [],
|
||||
finalize: true
|
||||
)
|
||||
end
|
||||
|
||||
def down; end
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeBackfillRootStorageStatisticsForkStorageSizes < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.7'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: 'BackfillRootStorageStatisticsForkStorageSizes',
|
||||
table_name: :namespace_root_storage_statistics,
|
||||
column_name: :namespace_id,
|
||||
job_arguments: [],
|
||||
finalize: true
|
||||
)
|
||||
end
|
||||
|
||||
def down; end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
624bef2f1f8ebd81bdc49c0007a72d77bad34db215dfee01101d976000964e28
|
||||
|
|
@ -0,0 +1 @@
|
|||
4d4539b21d0f9ea2ade7a1223953f2aea36c4432e5f3b042266e98d71f6a9a48
|
||||
|
|
@ -0,0 +1 @@
|
|||
7078ee3b40cd12e32c0d8f2cc1e55e19b4352dac8d2c708b617a2ff03e979c3a
|
||||
|
|
@ -0,0 +1 @@
|
|||
644dfd3c7371feff5431900510e25fc2dc0c661c7ee9142bd26431c10d929416
|
||||
|
|
@ -0,0 +1 @@
|
|||
5afbc4c287ce349c58ab70e2c8b44c833f075fe114cf2af2a29aaf4247053d82
|
||||
|
|
@ -24663,6 +24663,7 @@ CREATE TABLE user_preferences (
|
|||
enabled_zoekt boolean DEFAULT true NOT NULL,
|
||||
keyboard_shortcuts_enabled boolean DEFAULT true NOT NULL,
|
||||
time_display_format smallint DEFAULT 0 NOT NULL,
|
||||
home_organization_id bigint,
|
||||
CONSTRAINT check_89bf269f41 CHECK ((char_length(diffs_deletion_color) <= 7)),
|
||||
CONSTRAINT check_d07ccd35f7 CHECK ((char_length(diffs_addition_color) <= 7))
|
||||
);
|
||||
|
|
@ -34896,6 +34897,8 @@ CREATE INDEX index_user_phone_validations_on_dial_code_phone_number ON user_phon
|
|||
|
||||
CREATE INDEX index_user_preferences_on_gitpod_enabled ON user_preferences USING btree (gitpod_enabled);
|
||||
|
||||
CREATE INDEX index_user_preferences_on_home_organization_id ON user_preferences USING btree (home_organization_id);
|
||||
|
||||
CREATE UNIQUE INDEX index_user_preferences_on_user_id ON user_preferences USING btree (user_id);
|
||||
|
||||
CREATE INDEX index_user_project_callouts_on_project_id ON user_project_callouts USING btree (project_id);
|
||||
|
|
@ -38158,6 +38161,9 @@ ALTER TABLE ONLY gitlab_subscriptions
|
|||
ALTER TABLE ONLY abuse_events
|
||||
ADD CONSTRAINT fk_e5ce49c215 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE ONLY user_preferences
|
||||
ADD CONSTRAINT fk_e5e029c10b FOREIGN KEY (home_organization_id) REFERENCES organizations(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE ONLY merge_requests
|
||||
ADD CONSTRAINT fk_e719a85f8a FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE SET NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -1249,8 +1249,15 @@ By default, Gitaly doesn't sign commits made using GitLab UI. For example, commi
|
|||
- Web IDE.
|
||||
- Merge requests.
|
||||
|
||||
You can configure Gitaly to sign commits made with the GitLab UI. The commits show as unverified and signed by an unknown
|
||||
user. Support for improvements is proposed in [issue 19185](https://gitlab.com/gitlab-org/gitlab/-/issues/19185).
|
||||
You can configure Gitaly to sign commits made with the GitLab UI.
|
||||
|
||||
By default, Gitaly sets the author of a commit as the committer. In this case,
|
||||
it is harder to [Verify commits locally](../../user/project/repository/signed_commits/ssh.md#verify-commits-locally)
|
||||
because the signature belongs to neither the author nor the committer of the commit.
|
||||
|
||||
You can configure Gitaly to reflect that a commit has been committed by your instance by
|
||||
setting `committer_email` and `committer_name`. For example, on GitLab.com these configuration options are
|
||||
set to `noreply@gitlab.com` and `GitLab`.
|
||||
|
||||
Configure Gitaly to sign commits made with the GitLab UI in one of two ways:
|
||||
|
||||
|
|
@ -1281,7 +1288,10 @@ Configure Gitaly to sign commits made with the GitLab UI in one of two ways:
|
|||
# ...
|
||||
git: {
|
||||
# ...
|
||||
committer_name: 'Your Instance',
|
||||
committer_email: 'noreply@yourinstance.com',
|
||||
signing_key: '/etc/gitlab/gitaly/signing_key.gpg',
|
||||
# ...
|
||||
},
|
||||
}
|
||||
```
|
||||
|
|
@ -1310,6 +1320,8 @@ Configure Gitaly to sign commits made with the GitLab UI in one of two ways:
|
|||
|
||||
```toml
|
||||
[git]
|
||||
committer_name = "Your Instance"
|
||||
committer_email = "noreply@yourinstance.com"
|
||||
signing_key = "/etc/gitlab/gitaly/signing_key.gpg"
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -435,7 +435,7 @@ You can change the maximum time a job can run before it times out:
|
|||
|
||||
- At the project-level in the [project's CI/CD settings](../ci/pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run)
|
||||
for a given project. This limit must be between 10 minutes and 1 month.
|
||||
- At the [runner level](../ci/runners/configure_runners.md#set-maximum-job-timeout-for-a-runner).
|
||||
- At the [runner level](../ci/runners/configure_runners.md#set-the-maximum-job-timeout).
|
||||
This limit must be 10 minutes or longer.
|
||||
|
||||
### Maximum number of deployment jobs in a pipeline
|
||||
|
|
|
|||
|
|
@ -108,13 +108,24 @@ Notify.test_email(u.email, "Test email for #{u.name}", 'Test email').deliver_now
|
|||
## Disable database statement timeout
|
||||
|
||||
You can disable the PostgreSQL statement timeout for the current Rails console
|
||||
session by running:
|
||||
session.
|
||||
|
||||
In GitLab 15.11 and earlier, to disable the database statement timeout, run:
|
||||
|
||||
```ruby
|
||||
ActiveRecord::Base.connection.execute('SET statement_timeout TO 0')
|
||||
```
|
||||
|
||||
This change only affects the current Rails console session and is
|
||||
In GitLab 16.0 and later, [GitLab uses two database connections by default](../../update/versions/gitlab_16_changes.md#1600). To disable the database statement timeout, run:
|
||||
|
||||
```ruby
|
||||
ActiveRecord::Base.connection.execute('SET statement_timeout TO 0')
|
||||
Ci::ApplicationRecord.connection.execute('SET statement_timeout TO 0')
|
||||
```
|
||||
|
||||
Instances running GitLab 16.0 and later reconfigured to use a single database connection should disable the database statement timeout using the code for GitLab 15.11 and earlier.
|
||||
|
||||
Disabling the database statement timeout affects only the current Rails console session and is
|
||||
not persisted in the GitLab production environment or in the next Rails
|
||||
console session.
|
||||
|
||||
|
|
|
|||
|
|
@ -109,8 +109,7 @@ Prerequisites:
|
|||
If you need support for namespace in the URL path to remove the requirement for wildcard DNS:
|
||||
|
||||
1. Enable the GitLab Pages flag for this feature by adding
|
||||
`gitlab_pages["namespace_in_path"] = true` to `gitlab.rb`. For more information,
|
||||
see [Use environment variables](#use-environment-variables).
|
||||
`gitlab_pages["namespace_in_path"] = true` to `/etc/gitlab/gitlab.rb`.
|
||||
1. In your DNS provider, add entries for `example.com` and `projects.example.com`.
|
||||
In both lines, replace `example.com` with your domain name, and `192.0.0.0` with
|
||||
the IPv4 version of your IP address. The entries look like this:
|
||||
|
|
@ -214,8 +213,7 @@ Prerequisites:
|
|||
|
||||
pages_nginx['enable'] = true
|
||||
|
||||
# Set this feature flag to enable this feature
|
||||
# For more information, see https://docs.gitlab.com/ee/administration/pages/index.html#use-environment-variables
|
||||
# Set this flag to enable this feature
|
||||
gitlab_pages["namespace_in_path"] = true
|
||||
```
|
||||
|
||||
|
|
@ -304,8 +302,7 @@ daemon doesn't listen to the outside world:
|
|||
pages_nginx['enable'] = true
|
||||
pages_nginx['redirect_http_to_https'] = true
|
||||
|
||||
# Set this feature flag to enable this feature
|
||||
# For more information, see https://docs.gitlab.com/ee/administration/pages/index.html#use-environment-variables
|
||||
# Set this flag to enable this feature
|
||||
gitlab_pages["namespace_in_path"] = true
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -20281,6 +20281,31 @@ Returns [`WorkItem`](#workitem).
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="groupworkitemiid"></a>`iid` | [`String!`](#string) | IID of the work item. |
|
||||
|
||||
##### `Group.workItemStateCounts`
|
||||
|
||||
Counts of work items by state for the namespace. Returns `null` if the `namespace_level_work_items` feature flag is disabled.
|
||||
|
||||
WARNING:
|
||||
**Introduced** in 16.7.
|
||||
This feature is an Experiment. It can be changed or removed at any time.
|
||||
|
||||
Returns [`WorkItemStateCountsType`](#workitemstatecountstype).
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="groupworkitemstatecountsauthorusername"></a>`authorUsername` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.9. This feature is an Experiment. It can be changed or removed at any time. Filter work items by author username. |
|
||||
| <a id="groupworkitemstatecountsiid"></a>`iid` | [`String`](#string) | IID of the work item. For example, "1". |
|
||||
| <a id="groupworkitemstatecountsiids"></a>`iids` | [`[String!]`](#string) | List of IIDs of work items. For example, `["1", "2"]`. |
|
||||
| <a id="groupworkitemstatecountsin"></a>`in` | [`[IssuableSearchableField!]`](#issuablesearchablefield) | Specify the fields to perform the search in. Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.'. |
|
||||
| <a id="groupworkitemstatecountsrequirementlegacywidget"></a>`requirementLegacyWidget` **{warning-solid}** | [`RequirementLegacyFilterInput`](#requirementlegacyfilterinput) | **Deprecated** in 15.9. Use work item IID filter instead. |
|
||||
| <a id="groupworkitemstatecountssearch"></a>`search` | [`String`](#string) | Search query for title or description. |
|
||||
| <a id="groupworkitemstatecountssort"></a>`sort` | [`WorkItemSort`](#workitemsort) | Sort work items by criteria. |
|
||||
| <a id="groupworkitemstatecountsstate"></a>`state` | [`IssuableState`](#issuablestate) | Current state of the work item. |
|
||||
| <a id="groupworkitemstatecountsstatuswidget"></a>`statusWidget` | [`StatusFilterInput`](#statusfilterinput) | Input for status widget filter. Ignored if `work_items_mvc_2` is disabled. |
|
||||
| <a id="groupworkitemstatecountstypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter work items by the given work item types. |
|
||||
|
||||
##### `Group.workItemTypes`
|
||||
|
||||
Work item types available to the group.
|
||||
|
|
@ -25587,6 +25612,31 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
|
|||
| <a id="projectvulnerabilityseveritiescountseverity"></a>`severity` | [`[VulnerabilitySeverity!]`](#vulnerabilityseverity) | Filter vulnerabilities by severity. |
|
||||
| <a id="projectvulnerabilityseveritiescountstate"></a>`state` | [`[VulnerabilityState!]`](#vulnerabilitystate) | Filter vulnerabilities by state. |
|
||||
|
||||
##### `Project.workItemStateCounts`
|
||||
|
||||
Counts of work items by state for the project.
|
||||
|
||||
WARNING:
|
||||
**Introduced** in 16.7.
|
||||
This feature is an Experiment. It can be changed or removed at any time.
|
||||
|
||||
Returns [`WorkItemStateCountsType`](#workitemstatecountstype).
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="projectworkitemstatecountsauthorusername"></a>`authorUsername` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.9. This feature is an Experiment. It can be changed or removed at any time. Filter work items by author username. |
|
||||
| <a id="projectworkitemstatecountsiid"></a>`iid` | [`String`](#string) | IID of the work item. For example, "1". |
|
||||
| <a id="projectworkitemstatecountsiids"></a>`iids` | [`[String!]`](#string) | List of IIDs of work items. For example, `["1", "2"]`. |
|
||||
| <a id="projectworkitemstatecountsin"></a>`in` | [`[IssuableSearchableField!]`](#issuablesearchablefield) | Specify the fields to perform the search in. Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.'. |
|
||||
| <a id="projectworkitemstatecountsrequirementlegacywidget"></a>`requirementLegacyWidget` **{warning-solid}** | [`RequirementLegacyFilterInput`](#requirementlegacyfilterinput) | **Deprecated** in 15.9. Use work item IID filter instead. |
|
||||
| <a id="projectworkitemstatecountssearch"></a>`search` | [`String`](#string) | Search query for title or description. |
|
||||
| <a id="projectworkitemstatecountssort"></a>`sort` | [`WorkItemSort`](#workitemsort) | Sort work items by criteria. |
|
||||
| <a id="projectworkitemstatecountsstate"></a>`state` | [`IssuableState`](#issuablestate) | Current state of the work item. |
|
||||
| <a id="projectworkitemstatecountsstatuswidget"></a>`statusWidget` | [`StatusFilterInput`](#statusfilterinput) | Input for status widget filter. Ignored if `work_items_mvc_2` is disabled. |
|
||||
| <a id="projectworkitemstatecountstypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter work items by the given work item types. |
|
||||
|
||||
##### `Project.workItemTypes`
|
||||
|
||||
Work item types available to the project.
|
||||
|
|
@ -28684,6 +28734,18 @@ Check permissions for the current user on a work item.
|
|||
| <a id="workitempermissionssetworkitemmetadata"></a>`setWorkItemMetadata` | [`Boolean!`](#boolean) | If `true`, the user can perform `set_work_item_metadata` on this resource. |
|
||||
| <a id="workitempermissionsupdateworkitem"></a>`updateWorkItem` | [`Boolean!`](#boolean) | If `true`, the user can perform `update_work_item` on this resource. |
|
||||
|
||||
### `WorkItemStateCountsType`
|
||||
|
||||
Represents total number of work items for the represented states.
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="workitemstatecountstypeall"></a>`all` | [`Int`](#int) | Number of work items for the project or group. |
|
||||
| <a id="workitemstatecountstypeclosed"></a>`closed` | [`Int`](#int) | Number of work items with state CLOSED for the project or group. |
|
||||
| <a id="workitemstatecountstypeopened"></a>`opened` | [`Int`](#int) | Number of work items with state OPENED for the project or group. |
|
||||
|
||||
### `WorkItemType`
|
||||
|
||||
#### Fields
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -45,7 +45,7 @@ can't link to files outside it.
|
|||
|
||||
To ensure maximum availability of the cache, do one or more of the following:
|
||||
|
||||
- [Tag your runners](../runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run) and use the tag on jobs
|
||||
- [Tag your runners](../runners/configure_runners.md#control-jobs-that-a-runner-can-run) and use the tag on jobs
|
||||
that share the cache.
|
||||
- [Use runners that are only available to a particular project](../runners/runners_scope.md#prevent-a-project-runner-from-being-enabled-for-other-projects).
|
||||
- [Use a `key`](../yaml/index.md#cachekey) that fits your workflow. For example,
|
||||
|
|
|
|||
|
|
@ -216,6 +216,17 @@ If you disable [catalog resource setting](#set-a-component-project-as-a-catalog-
|
|||
the component project and all versions are removed from the catalog. To publish it again,
|
||||
you must re-enable the setting and release a new version.
|
||||
|
||||
### Unpublish a component project
|
||||
|
||||
To remove a component project from the catalog, turn off the [**CI/CD Catalog resource**](#set-a-component-project-as-a-catalog-resource) toggle.
|
||||
in the project settings.
|
||||
|
||||
WARNING:
|
||||
This action destroys the metadata about the component project and its versions published
|
||||
in the catalog. The project and its repository still exist, but are not visible in the catalog.
|
||||
|
||||
To publish the component project in the catalog again, you need to [publish a new release](#publish-a-new-release).
|
||||
|
||||
## Best practices
|
||||
|
||||
This section describes some best practices for creating high quality component projects.
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ Some key details about runners:
|
|||
|
||||
- Runners can be [configured](../runners/runners_scope.md) to be shared across an instance,
|
||||
a group, or dedicated to a single project.
|
||||
- You can use the [`tags` keyword](../runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run)
|
||||
- You can use the [`tags` keyword](../runners/configure_runners.md#control-jobs-that-a-runner-can-run)
|
||||
for finer control, and associate runners with specific jobs. For example, you can use a tag for jobs that
|
||||
require dedicated, more powerful, or specific hardware.
|
||||
- GitLab has [autoscaling for runners](https://docs.gitlab.com/runner/configuration/autoscale.html).
|
||||
|
|
|
|||
|
|
@ -482,7 +482,7 @@ Some key details about runners:
|
|||
|
||||
- Runners can be [configured](../runners/runners_scope.md) to be shared across an instance,
|
||||
a group, or dedicated to a single project.
|
||||
- You can use the [`tags` keyword](../runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run)
|
||||
- You can use the [`tags` keyword](../runners/configure_runners.md#control-jobs-that-a-runner-can-run)
|
||||
for finer control, and associate runners with specific jobs. For example, you can use a tag for jobs that
|
||||
require dedicated, more powerful, or specific hardware.
|
||||
- GitLab has [autoscaling for runners](https://docs.gitlab.com/runner/configuration/autoscale.html).
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ You can define how long a job can run before it times out.
|
|||
|
||||
Jobs that exceed the timeout are marked as failed.
|
||||
|
||||
You can override this value [for individual runners](../runners/configure_runners.md#set-maximum-job-timeout-for-a-runner).
|
||||
You can override this value [for individual runners](../runners/configure_runners.md#set-the-maximum-job-timeout).
|
||||
|
||||
## Pipeline badges
|
||||
|
||||
|
|
|
|||
|
|
@ -11,53 +11,79 @@ If you have installed your own runners, you can configure and secure them in Git
|
|||
If you need to configure runners on the machine where you installed GitLab Runner, see
|
||||
[the GitLab Runner documentation](https://docs.gitlab.com/runner/configuration/).
|
||||
|
||||
## Manually clear the runner cache
|
||||
## Set the maximum job timeout
|
||||
|
||||
Read [clearing the cache](../caching/index.md#clearing-the-cache).
|
||||
You can specify a maximum job timeout for each runner to prevent projects
|
||||
with longer job timeouts from using the runner. The maximum job timeout is
|
||||
used of it is shorter than the job timeout defined in the project.
|
||||
|
||||
## Set maximum job timeout for a runner
|
||||
### For a shared runner
|
||||
|
||||
For each runner, you can specify a *maximum job timeout*. This timeout,
|
||||
if smaller than the [project defined timeout](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run), takes precedence.
|
||||
Prerequisites:
|
||||
|
||||
This feature can be used to prevent your shared runner from being overwhelmed
|
||||
by a project that has jobs with a long timeout (for example, one week).
|
||||
- You must be an administrator.
|
||||
|
||||
On GitLab.com, you cannot override the job timeout for shared runners and must use the [project defined timeout](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run).
|
||||
On GitLab.com, you cannot override the job timeout for shared runners and must use the [project defined timeout](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run) instead.
|
||||
|
||||
To set the maximum job timeout:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
1. Select **CI/CD > Runners**.
|
||||
1. To the right of the runner, you want to edit, select **Edit** (**{pencil}**).
|
||||
1. In the **Maximum job timeout** field, enter a value in seconds. The minimum amount is 600 seconds (10 minutes).
|
||||
1. Select **Save changes**.
|
||||
|
||||
### For a group runner
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role for the group.
|
||||
|
||||
To set the maximum job timeout:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your group.
|
||||
1. Select **Build > Runners**.
|
||||
1. To the right of the runner you want to edit, select **Edit** (**{pencil}**).
|
||||
1. In the **Maximum job timeout** field, enter a value in seconds. The minimum amount is 600 seconds (10 minutes).
|
||||
1. Select **Save changes**.
|
||||
|
||||
### For a project runner
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role for the project.
|
||||
|
||||
To set the maximum job timeout:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Settings > CI/CD**.
|
||||
1. Expand **Runners**.
|
||||
1. Select your project runner to edit the settings.
|
||||
1. Enter a value under **Maximum job timeout**. Must be 10 minutes or more. If not
|
||||
defined, the [project's job timeout setting](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run)
|
||||
is used.
|
||||
1. To the right of the runner you want to edit, select **Edit** (**{pencil}**).
|
||||
1. In the **Maximum job timeout** field, enter a value in seconds. The minimum amount is 600 seconds (10 minutes). If not defined, the [job timeout for the project](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run) is used instead.
|
||||
1. Select **Save changes**.
|
||||
|
||||
How this feature works:
|
||||
## How maximum job timeout works
|
||||
|
||||
**Example 1 - Runner timeout bigger than project timeout**
|
||||
|
||||
1. You set the _maximum job timeout_ for a runner to 24 hours
|
||||
1. You set the _CI/CD Timeout_ for a project to **2 hours**
|
||||
1. You start a job
|
||||
1. The job, if running longer, times out after **2 hours**
|
||||
1. You set the _maximum job timeout_ for a runner to 24 hours.
|
||||
1. You set the _CI/CD Timeout_ for a project to **2 hours**.
|
||||
1. You start a job.
|
||||
1. The job, if running longer, times out after **2 hours**.
|
||||
|
||||
**Example 2 - Runner timeout not configured**
|
||||
|
||||
1. You remove the _maximum job timeout_ configuration from a runner
|
||||
1. You set the _CI/CD Timeout_ for a project to **2 hours**
|
||||
1. You start a job
|
||||
1. The job, if running longer, times out after **2 hours**
|
||||
1. You remove the _maximum job timeout_ configuration from a runner.
|
||||
1. You set the _CI/CD Timeout_ for a project to **2 hours**.
|
||||
1. You start a job.
|
||||
1. The job, if running longer, times out after **2 hours**.
|
||||
|
||||
**Example 3 - Runner timeout smaller than project timeout**
|
||||
|
||||
1. You set the _maximum job timeout_ for a runner to **30 minutes**
|
||||
1. You set the _CI/CD Timeout_ for a project to 2 hours
|
||||
1. You start a job
|
||||
1. The job, if running longer, times out after **30 minutes**
|
||||
1. You set the _maximum job timeout_ for a runner to **30 minutes**.
|
||||
1. You set the _CI/CD Timeout_ for a project to 2 hours.
|
||||
1. You start a job.
|
||||
1. The job, if running longer, times out after **30 minutes**.
|
||||
|
||||
## Set `script` and `after_script` timeouts
|
||||
|
||||
|
|
@ -66,7 +92,7 @@ How this feature works:
|
|||
To control the amount of time `script` and `after_script` runs before it terminates, you can set specify a timeout.
|
||||
|
||||
For example, you can specify a timeout to terminate a long-running `script` early, so that artifacts and caches can still be uploaded
|
||||
before the [job timeout](#set-maximum-job-timeout-for-a-runner) is exceeded.
|
||||
before the job timeout is exceeded.
|
||||
|
||||
- To set a timeout for `script`, use the job variable `RUNNER_SCRIPT_TIMEOUT`.
|
||||
- To set a timeout for `after_script`, and override the default of 5 minutes, use the job variable `RUNNER_AFTER_SCRIPT_TIMEOUT`.
|
||||
|
|
@ -105,26 +131,11 @@ of shared runners on large GitLab instances. This ensures that you
|
|||
control access to your GitLab instances and secure [runner executors](https://docs.gitlab.com/runner/executors/).
|
||||
|
||||
If certain executors run a job, the file system, the code the runner executes,
|
||||
and the runner authentication token may be exposed. This means that anyone that runs jobs
|
||||
and the runner authentication token may be exposed. This means that anyone who runs jobs
|
||||
on a _shared runner_ can access another user's code that runs on the runner.
|
||||
Users with access to the runner authentication token can use it to create a clone of
|
||||
a runner and submit false jobs in a vector attack. For more information, see [Security Considerations](https://docs.gitlab.com/runner/security/).
|
||||
|
||||
### Prevent runners from revealing sensitive information
|
||||
|
||||
To ensure runners don't reveal sensitive information, you can configure them to only run jobs
|
||||
on [protected branches](../../user/project/protected_branches.md), or jobs that have [protected tags](../../user/project/protected_tags.md).
|
||||
|
||||
To prevent runners from revealing sensitive information:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Settings > CI/CD**.
|
||||
1. Expand **Runners**.
|
||||
1. Find the runner you want to protect or unprotect. Make sure the runner is enabled.
|
||||
1. Select **Edit** (**{pencil}**).
|
||||
1. Select the **Protected** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
### Using shared runners in forked projects
|
||||
|
||||
When a project is forked, the job settings related to jobs are copied. If you have shared runners
|
||||
|
|
@ -179,37 +190,129 @@ To reset the runner authentication token:
|
|||
- [Create a project runner](runners_scope.md#create-a-project-runner-with-a-runner-authentication-token).
|
||||
1. Optional. To verify that the previous runner authentication token has been revoked, use the [Runners API](../../api/runners.md#verify-authentication-for-a-registered-runner).
|
||||
|
||||
## Use tags to control which jobs a runner can run
|
||||
### Automatically rotate runner authentication tokens
|
||||
|
||||
You can use [tags](../yaml/index.md#tags) to ensure that runners only run the jobs they are equipped
|
||||
to run. For example, you can specify the `rails` tag for runners that have the dependencies to run
|
||||
You can specify an interval for runner authentication tokens to rotate.
|
||||
This rotation helps ensure the security of the tokens assigned to your runners.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Runners must use [GitLab Runner 15.3 or later](https://docs.gitlab.com/runner/#gitlab-runner-versions).
|
||||
- You must be an administrator.
|
||||
|
||||
To automatically rotate runner authentication tokens:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand **Continuous Integration and Deployment**
|
||||
1. Set a **Runners expiration** time for runners, leave empty for no expiration.
|
||||
1. Select **Save changes**.
|
||||
|
||||
Before the interval expires, runners automatically request a new runner authentication token.
|
||||
|
||||
## Prevent runners from revealing sensitive information
|
||||
|
||||
To ensure runners don't reveal sensitive information, you can configure them to only run jobs
|
||||
on [protected branches](../../user/project/protected_branches.md), or jobs that have [protected tags](../../user/project/protected_tags.md).
|
||||
|
||||
### For a shared runner
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must be an administrator.
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
1. Select **CI/CD > Runners**.
|
||||
1. To the right of the runner you want to protect, select **Edit** (**{pencil}**).
|
||||
1. Select the **Protected** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
### For a group runner
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role for the group.
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your group.
|
||||
1. Select **Build > Runners**.
|
||||
1. To the right of the runner you want to protect, select **Edit** (**{pencil}**).
|
||||
1. Select the **Protected** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
### For a project runner
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role for the project.
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Settings > CI/CD**.
|
||||
1. Expand **Runners**.
|
||||
1. To the right of the runner you want to protect, select **Edit** (**{pencil}**).
|
||||
1. Select the **Protected** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Control jobs that a runner can run
|
||||
|
||||
You can use [tags](../yaml/index.md#tags) to control the jobs a runner can run.
|
||||
For example, you can specify the `rails` tag for runners that have the dependencies to run
|
||||
Rails test suites.
|
||||
|
||||
GitLab CI/CD tags are different to Git tags. GitLab CI/CD tags are associated with runners.
|
||||
Git tags are associated with commits.
|
||||
|
||||
### Set a runner to run untagged jobs
|
||||
### For a shared runner
|
||||
|
||||
When you [register a runner](https://docs.gitlab.com/runner/register/), its default behavior is to **only pick**
|
||||
[tagged jobs](../yaml/index.md#tags).
|
||||
To change this, you must have the Owner role for the project.
|
||||
Prerequisites:
|
||||
|
||||
To make a runner pick untagged jobs:
|
||||
- You must be an administrator.
|
||||
|
||||
To set the maximum job timeout:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
1. Select **CI/CD > Runners**.
|
||||
1. To the right of the runner you want to edit, select **Edit** (**{pencil}**).
|
||||
1. Set the runner to run tagged or untagged jobs:
|
||||
- To run tagged jobs, in the **Tags** field, enter the job tags separated with a comma. For example, `macos`, `rails`.
|
||||
- To run untagged jobs, select the **Run untagged jobs** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
### For a group runner
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role for the group.
|
||||
|
||||
To set the maximum job timeout:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your group.
|
||||
1. Select **Build > Runners**.
|
||||
1. To the right of the runner you want to edit, select **Edit** (**{pencil}**).
|
||||
1. Set the runner to run tagged or untagged jobs:
|
||||
- To run tagged jobs, in the **Tags** field, enter the job tags separated with a comma. For example, `macos`, `ruby`.
|
||||
- To run untagged jobs, select the **Run untagged jobs** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
### For a project runner
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role for the project.
|
||||
|
||||
To set a runner to run tagged jobs:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Settings > CI/CD**.
|
||||
1. Expand **Runners**.
|
||||
1. Find the runner you want to pick untagged jobs and make sure it's enabled.
|
||||
1. Select **Edit** (**{pencil}**).
|
||||
1. Select the **Run untagged jobs** checkbox.
|
||||
1. To the right of the runner you want to edit, select **Edit** (**{pencil}**).
|
||||
1. Set the runner to run tagged or untagged jobs:
|
||||
- To run tagged jobs, in the **Tags** field, enter the job tags separated with a comma. For example, `macos`, `ruby`.
|
||||
- To run untagged jobs, select the **Run untagged jobs** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
NOTE:
|
||||
The runner tags list cannot be empty when it's not allowed to pick untagged jobs.
|
||||
### How the runner uses tags
|
||||
|
||||
Below are some example scenarios of different variations.
|
||||
|
||||
### Runner runs only tagged jobs
|
||||
#### Runner runs only tagged jobs
|
||||
|
||||
The following examples illustrate the potential impact of the runner being set
|
||||
to run only tagged jobs.
|
||||
|
|
@ -229,7 +332,7 @@ Example 3:
|
|||
1. The runner is configured to run only tagged jobs and has the `docker` tag.
|
||||
1. A job that has no tags defined is executed and stuck.
|
||||
|
||||
### Runner is allowed to run untagged jobs
|
||||
#### Runner is allowed to run untagged jobs
|
||||
|
||||
The following examples illustrate the potential impact of the runner being set
|
||||
to run tagged and untagged jobs.
|
||||
|
|
@ -246,7 +349,7 @@ Example 2:
|
|||
1. A job that has no tags defined is executed and run.
|
||||
1. A second job that has a `docker` tag defined is stuck.
|
||||
|
||||
### A runner and a job have multiple tags
|
||||
#### A runner and a job have multiple tags
|
||||
|
||||
The selection logic that matches the job and runner is based on the list of `tags`
|
||||
defined in the job.
|
||||
|
|
@ -273,7 +376,9 @@ Example 3:
|
|||
|
||||
You can use tags to run different jobs on different platforms. For
|
||||
example, if you have an OS X runner with tag `osx` and a Windows runner with tag
|
||||
`windows`, you can run a job on each platform:
|
||||
`windows`, you can run a job on each platform.
|
||||
|
||||
Update the `tags` field in the `config.toml`:
|
||||
|
||||
```yaml
|
||||
windows job:
|
||||
|
|
@ -295,7 +400,7 @@ osx job:
|
|||
|
||||
> Introduced in [GitLab 14.1](https://gitlab.com/gitlab-org/gitlab/-/issues/35742).
|
||||
|
||||
You can use [CI/CD variables](../variables/index.md) with `tags` for dynamic runner selection:
|
||||
In the `.gitlab-ci.yml` file, use [CI/CD variables](../variables/index.md) with `tags` for dynamic runner selection:
|
||||
|
||||
```yaml
|
||||
variables:
|
||||
|
|
@ -928,22 +1033,3 @@ No manual intervention should be required, and no running jobs should be affecte
|
|||
|
||||
If you need to manually update the runner authentication token, you can run a
|
||||
command to [reset the token](https://docs.gitlab.com/runner/commands/#gitlab-runner-reset-token).
|
||||
|
||||
### Automatically rotate runner authentication tokens
|
||||
|
||||
You can specify an interval for runner authentication tokens to rotate.
|
||||
This rotation helps ensure the security of the tokens assigned to your runners.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Ensure your runners are using [GitLab Runner 15.3 or later](https://docs.gitlab.com/runner/#gitlab-runner-versions).
|
||||
|
||||
To automatically rotate runner authentication tokens:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand **Continuous Integration and Deployment**
|
||||
1. Set a **Runners expiration** time for runners, leave empty for no expiration.
|
||||
1. Select **Save**.
|
||||
|
||||
Before the interval expires, runners automatically request a new runner authentication token.
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ For more information about the cost factor applied to the machine type based on
|
|||
The number of minutes you can use on these runners depends on the [maximum number of units of compute](../pipelines/cicd_minutes.md)
|
||||
in your [subscription plan](https://about.gitlab.com/pricing/).
|
||||
|
||||
[Untagged](../../ci/runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run) jobs automatically run in containers
|
||||
[Untagged](../../ci/runners/configure_runners.md#control-jobs-that-a-runner-can-run) jobs automatically run in containers
|
||||
on the `small` Linux runners.
|
||||
|
||||
The objective is to make 90% of CI/CD jobs start executing in 120 seconds or less. The error rate should be less than 0.5%.
|
||||
|
|
|
|||
|
|
@ -4568,7 +4568,7 @@ In this example, only runners with *both* the `ruby` and `postgres` tags can run
|
|||
|
||||
**Related topics**:
|
||||
|
||||
- [Use tags to control which jobs a runner can run](../runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run).
|
||||
- [Use tags to control which jobs a runner can run](../runners/configure_runners.md#control-jobs-that-a-runner-can-run).
|
||||
- [Select different runner tags for each parallel matrix job](../jobs/job_control.md#select-different-runner-tags-for-each-parallel-matrix-job).
|
||||
|
||||
### `timeout`
|
||||
|
|
@ -4579,7 +4579,7 @@ Use `timeout` to configure a timeout for a specific job. If the job runs for lon
|
|||
than the timeout, the job fails.
|
||||
|
||||
The job-level timeout can be longer than the [project-level timeout](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run),
|
||||
but can't be longer than the [runner's timeout](../runners/configure_runners.md#set-maximum-job-timeout-for-a-runner).
|
||||
but can't be longer than the [runner's timeout](../runners/configure_runners.md#set-the-maximum-job-timeout).
|
||||
|
||||
**Keyword type**: Job keyword. You can use it only as part of a job or in the
|
||||
[`default` section](#default).
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ For more information on:
|
|||
gitlab_rails['omniauth_block_auto_created_users'] = false
|
||||
```
|
||||
|
||||
1. Optional. You can automatically link SAML users with existing GitLab users if their
|
||||
email addresses match by adding the following setting in `/etc/gitlab/gitlab.rb`:
|
||||
1. Optional. You should automatically link a first-time SAML sign-in with existing GitLab users if their
|
||||
email addresses match. To do this, add the following setting in `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_auto_link_saml_user'] = true
|
||||
|
|
@ -728,6 +728,9 @@ On GitLab.com, Microsoft Azure/Entra ID attributes are introduced
|
|||
[with a flag](../administration/feature_flags.md) named `saml_microsoft_attribute_names`.
|
||||
On GitLab.com, this feature is unavailable but can be configured by GitLab.com administrators only.
|
||||
|
||||
NOTE:
|
||||
The attributes are case-sensitive.
|
||||
|
||||
| Field | Supported default keys |
|
||||
|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Email (required)| `email`, `mail`, `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`, `http://schemas.microsoft.com/ws/2008/06/identity/claims/emailaddress` |
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ To create a project runner:
|
|||
1. Expand the **Runners** section.
|
||||
1. Select **New project runner**.
|
||||
1. Select your operating system.
|
||||
1. In the **Tags** section, select the **Run untagged** checkbox. [Tags](../../ci/runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run) specify which jobs
|
||||
1. In the **Tags** section, select the **Run untagged** checkbox. [Tags](../../ci/runners/configure_runners.md#control-jobs-that-a-runner-can-run) specify which jobs
|
||||
the runner can run and are optional.
|
||||
1. Select **Create runner**.
|
||||
1. Follow the on-screen instructions to register the runner from the command line. When prompted:
|
||||
|
|
|
|||
|
|
@ -541,6 +541,10 @@ by this issue.
|
|||
[throw errors on startup](../../install/docker.md#threaderror-cant-create-thread-operation-not-permitted).
|
||||
- Starting with 16.0, GitLab self-managed installations now have two database connections by default, instead of one. This change doubles the number of PostgreSQL connections. It makes self-managed versions of GitLab behave similarly to GitLab.com, and is a step toward enabling a separate database for CI features for self-managed versions of GitLab. Before upgrading to 16.0, determine if you need to [increase max connections for PostgreSQL](https://docs.gitlab.com/omnibus/settings/database.html#configuring-multiple-database-connections).
|
||||
- This change applies to installation methods with Linux packages (Omnibus), GitLab Helm chart, GitLab Operator, GitLab Docker images, and self-compiled installations.
|
||||
- The second database connection can be disabled:
|
||||
- [Linux package and Docker installations](https://docs.gitlab.com/omnibus/settings/database.html#configuring-multiple-database-connections).
|
||||
- [Helm chart and GitLab Operator installations](https://docs.gitlab.com/charts/charts/globals.html#configure-multiple-database-connections).
|
||||
- [Self-compiled installations](../../install/installation.md#configure-gitlab-db-settings).
|
||||
- Container registry using Azure storage might be empty with zero tags. You can fix this by following the [breaking change instructions](../deprecations.md#azure-storage-driver-defaults-to-the-correct-root-prefix).
|
||||
|
||||
### Linux package installations
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue