Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
1252510698
commit
4965365aeb
|
@ -80,6 +80,8 @@ include:
|
|||
SKIP_IMAGE_VERIFICATION: "true"
|
||||
# set specific arch list
|
||||
ARCH_LIST: amd64
|
||||
# use larger runner for complex rails build jobs
|
||||
HIGH_CAPACITY_RUNNER_TAG: high-cpu
|
||||
trigger:
|
||||
project: '${CI_PROJECT_NAMESPACE}/$[[ inputs.cng_path ]]'
|
||||
branch: $TRIGGER_BRANCH
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
- export GOPATH=$CI_PROJECT_DIR/.go
|
||||
- mkdir -p $GOPATH
|
||||
- source scripts/utils.sh
|
||||
- log_disk_usage before_script # https://gitlab.com/gitlab-org/gitlab/-/issues/478880
|
||||
- log_disk_usage "false" # https://gitlab.com/gitlab-org/gitlab/-/issues/478880
|
||||
|
||||
.default-before_script:
|
||||
before_script:
|
||||
|
|
|
@ -102,7 +102,7 @@ include:
|
|||
- rspec_section rspec_parallelized_job "--fail-fast=${RSPEC_FAIL_FAST_THRESHOLD} --tag ~quarantine --tag ~level:background_migration --tag ~click_house"
|
||||
after_script:
|
||||
- source scripts/utils.sh
|
||||
- log_disk_usage after_script # https://gitlab.com/gitlab-org/gitlab/-/issues/478880
|
||||
- log_disk_usage # https://gitlab.com/gitlab-org/gitlab/-/issues/478880
|
||||
- bundle exec gem list gitlab_quality-test_tooling
|
||||
- |
|
||||
section_start "failed-test-issues" "Report test failures"
|
||||
|
|
|
@ -2558,6 +2558,13 @@
|
|||
- <<: *if-default-refs
|
||||
changes: *code-backstage-qa-patterns
|
||||
|
||||
.static-analysis:rules:ensure-application-settings-have-definition-file:
|
||||
rules:
|
||||
- <<: *if-default-refs
|
||||
changes:
|
||||
- db/structure.sql
|
||||
- config/application_setting_columns/*.yml
|
||||
|
||||
.static-analysis:rules:haml-lint:
|
||||
rules:
|
||||
- <<: *if-default-refs
|
||||
|
|
|
@ -169,6 +169,16 @@ feature-flags-usage:
|
|||
paths:
|
||||
- tmp/feature_flags/
|
||||
|
||||
ensure-application-settings-have-definition-file:
|
||||
image: ruby:${RUBY_VERSION}-alpine
|
||||
extends:
|
||||
- .static-analysis-base
|
||||
- .static-analysis:rules:ensure-application-settings-have-definition-file
|
||||
variables:
|
||||
USE_BUNDLE_INSTALL: "false"
|
||||
script:
|
||||
- run_timed_command "scripts/cells/ci-ensure-application-settings-have-definition-file.rb"
|
||||
|
||||
semgrep-appsec-custom-rules:
|
||||
stage: lint
|
||||
extends:
|
||||
|
|
|
@ -105,11 +105,6 @@ build-cng:
|
|||
variables:
|
||||
# use larger runner for complex rails build jobs
|
||||
HIGH_CAPACITY_RUNNER_TAG: e2e
|
||||
# quality specific fork, see: https://gitlab.com/gitlab-org/quality/quality-engineering/team-tasks/-/issues/2839
|
||||
trigger:
|
||||
project: ${CI_PROJECT_NAMESPACE}/quality/quality-engineering/CNG-mirror
|
||||
branch: $TRIGGER_BRANCH
|
||||
strategy: depend
|
||||
|
||||
download-knapsack-report:
|
||||
extends:
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
MINIMUM_VERSION="v8.20"
|
||||
SCRIPT_NAME=$(basename "$0")
|
||||
HOOK_TYPE="${1:-}"
|
||||
|
||||
if ! command -v gitleaks &>/dev/null; then
|
||||
cat >&2 <<EOF
|
||||
WARNING: gitleaks is not installed. Skipping secrets detection.
|
||||
Please install at least version v$MINIMUM_VERSION using "asdf install" or see:
|
||||
https://gitlab.com/gitlab-com/gl-security/security-research/gitleaks-endpoint-installer.
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$HOOK_TYPE" ]; then
|
||||
cat >&2 <<EOF
|
||||
ERROR: Hook type argument is required.
|
||||
Usage: ./$SCRIPT_NAME [pre-commit|pre-push]
|
||||
Please specify 'pre-commit' or 'pre-push' as the argument.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$HOOK_TYPE" == "pre-commit" ]; then
|
||||
gitleaks git --pre-commit --staged --no-banner --redact --verbose
|
||||
elif [ "$HOOK_TYPE" == "pre-push" ]; then
|
||||
BASE_COMMIT=$(git merge-base origin/master HEAD)
|
||||
gitleaks git --log-opts="$BASE_COMMIT..HEAD" --no-banner --redact --verbose
|
||||
else
|
||||
cat >&2 <<EOF
|
||||
ERROR: Unsupported hook type '$HOOK_TYPE'.
|
||||
Usage: ./$SCRIPT_NAME [pre-commit|pre-push]
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
|
@ -1986,7 +1986,6 @@ Layout/LineLength:
|
|||
- 'ee/spec/services/quick_actions/interpret_service_spec.rb'
|
||||
- 'ee/spec/services/requirements_management/export_csv_service_spec.rb'
|
||||
- 'ee/spec/services/resource_events/change_weight_service_spec.rb'
|
||||
- 'ee/spec/services/search/global_service_spec.rb'
|
||||
- 'ee/spec/services/search/snippet_service_spec.rb'
|
||||
- 'ee/spec/services/security/ingestion/finding_map_collection_spec.rb'
|
||||
- 'ee/spec/services/security/ingestion/ingest_report_service_spec.rb'
|
||||
|
@ -3865,7 +3864,6 @@ Layout/LineLength:
|
|||
- 'spec/requests/api/feature_flags_spec.rb'
|
||||
- 'spec/requests/api/features_spec.rb'
|
||||
- 'spec/requests/api/files_spec.rb'
|
||||
- 'spec/requests/api/generic_packages_spec.rb'
|
||||
- 'spec/requests/api/go_proxy_spec.rb'
|
||||
- 'spec/requests/api/graphql/boards/board_list_issues_query_spec.rb'
|
||||
- 'spec/requests/api/graphql/boards/board_list_query_spec.rb'
|
||||
|
|
|
@ -325,7 +325,6 @@ Rails/StrongParams:
|
|||
- 'ee/app/controllers/security/projects_controller.rb'
|
||||
- 'ee/app/controllers/smartcard_controller.rb'
|
||||
- 'ee/app/controllers/subscriptions/groups_controller.rb'
|
||||
- 'ee/app/controllers/subscriptions/hand_raise_leads_controller.rb'
|
||||
- 'ee/app/controllers/subscriptions_controller.rb'
|
||||
- 'ee/app/controllers/users/base_identity_verification_controller.rb'
|
||||
- 'ee/app/controllers/users/registrations_identity_verification_controller.rb'
|
||||
|
|
|
@ -733,7 +733,6 @@ RSpec/ContextWording:
|
|||
- 'ee/spec/services/requirements_management/export_csv_service_spec.rb'
|
||||
- 'ee/spec/services/resource_access_tokens/create_service_spec.rb'
|
||||
- 'ee/spec/services/resource_access_tokens/revoke_service_spec.rb'
|
||||
- 'ee/spec/services/search/global_service_spec.rb'
|
||||
- 'ee/spec/services/search/snippet_service_spec.rb'
|
||||
- 'ee/spec/services/security/ingestion/tasks/ingest_vulnerabilities/create_spec.rb'
|
||||
- 'ee/spec/services/security/ingestion/tasks/update_vulnerability_uuids_spec.rb'
|
||||
|
|
|
@ -1 +1 @@
|
|||
6175a5f017f01e11959045c0dc24d9ca237865e6
|
||||
39a5e315d1b3e112db13930382d11061bfa95964
|
||||
|
|
|
@ -292,7 +292,7 @@
|
|||
{"name":"graphiql-rails","version":"1.10.0","platform":"ruby","checksum":"b557f989a737c8b9e985142609bec52fb1e9393a701eb50e02a7c14422891040"},
|
||||
{"name":"graphlient","version":"0.8.0","platform":"ruby","checksum":"98c408da1d083454e9f5e274f3b0b6261e2a0c2b5f2ed7b3ef9441d46f8e7cb1"},
|
||||
{"name":"graphlyte","version":"1.0.0","platform":"ruby","checksum":"b5af4ab67dde6e961f00ea1c18f159f73b52ed11395bb4ece297fe628fa1804d"},
|
||||
{"name":"graphql","version":"2.3.16","platform":"ruby","checksum":"6ac9966998914c5b470e527c7105d936db70af2306ec0445f88953404bce49c7"},
|
||||
{"name":"graphql","version":"2.3.17","platform":"ruby","checksum":"5e03655bf8ab07cd9710821f7f991ca6f5e86cf632261350ab185527169554e3"},
|
||||
{"name":"graphql-client","version":"0.23.0","platform":"ruby","checksum":"f238b8e451676baad06bd15f95396e018192243dcf12c4e6d13fb41d9a2babc1"},
|
||||
{"name":"graphql-docs","version":"5.0.0","platform":"ruby","checksum":"76baca6e5a803a4b6a9fbbbfdbf16742b7c4c546c8592b6e1a7aa4e79e562d04"},
|
||||
{"name":"grpc","version":"1.63.0","platform":"aarch64-linux","checksum":"dc75c5fd570b819470781d9512105dddfdd11d984f38b8e60bb946f92d1f79ee"},
|
||||
|
|
|
@ -919,7 +919,7 @@ GEM
|
|||
faraday (~> 2.0)
|
||||
graphql-client
|
||||
graphlyte (1.0.0)
|
||||
graphql (2.3.16)
|
||||
graphql (2.3.17)
|
||||
base64
|
||||
fiber-storage
|
||||
graphql-client (0.23.0)
|
||||
|
|
|
@ -293,7 +293,7 @@
|
|||
{"name":"graphiql-rails","version":"1.10.0","platform":"ruby","checksum":"b557f989a737c8b9e985142609bec52fb1e9393a701eb50e02a7c14422891040"},
|
||||
{"name":"graphlient","version":"0.8.0","platform":"ruby","checksum":"98c408da1d083454e9f5e274f3b0b6261e2a0c2b5f2ed7b3ef9441d46f8e7cb1"},
|
||||
{"name":"graphlyte","version":"1.0.0","platform":"ruby","checksum":"b5af4ab67dde6e961f00ea1c18f159f73b52ed11395bb4ece297fe628fa1804d"},
|
||||
{"name":"graphql","version":"2.3.16","platform":"ruby","checksum":"6ac9966998914c5b470e527c7105d936db70af2306ec0445f88953404bce49c7"},
|
||||
{"name":"graphql","version":"2.3.17","platform":"ruby","checksum":"5e03655bf8ab07cd9710821f7f991ca6f5e86cf632261350ab185527169554e3"},
|
||||
{"name":"graphql-client","version":"0.23.0","platform":"ruby","checksum":"f238b8e451676baad06bd15f95396e018192243dcf12c4e6d13fb41d9a2babc1"},
|
||||
{"name":"graphql-docs","version":"5.0.0","platform":"ruby","checksum":"76baca6e5a803a4b6a9fbbbfdbf16742b7c4c546c8592b6e1a7aa4e79e562d04"},
|
||||
{"name":"grpc","version":"1.63.0","platform":"aarch64-linux","checksum":"dc75c5fd570b819470781d9512105dddfdd11d984f38b8e60bb946f92d1f79ee"},
|
||||
|
|
|
@ -929,7 +929,7 @@ GEM
|
|||
faraday (~> 2.0)
|
||||
graphql-client
|
||||
graphlyte (1.0.0)
|
||||
graphql (2.3.16)
|
||||
graphql (2.3.17)
|
||||
base64
|
||||
fiber-storage
|
||||
graphql-client (0.23.0)
|
||||
|
|
|
@ -6,7 +6,7 @@ require "guard/rspec/dsl"
|
|||
|
||||
cmd = ENV['GUARD_CMD'] || (ENV['SPRING'] ? 'spring rspec' : 'bundle exec rspec')
|
||||
|
||||
directories %w[app ee keeps lib rubocop tooling spec]
|
||||
directories %w[app ee keeps lib rubocop scripts spec tooling]
|
||||
|
||||
rspec_context_for = proc do |context_path|
|
||||
OpenStruct.new(to_s: "spec").tap do |rspec| # rubocop:disable Style/OpenStructUse
|
||||
|
@ -45,6 +45,7 @@ guard_setup = proc do |context_path|
|
|||
watch(%r{^#{context_path}(lib/.+)\.rb$}) { |m| rspec.spec.call(m[1]) }
|
||||
watch(%r{^#{context_path}(rubocop/.+)\.rb$}) { |m| rspec.spec.call(m[1]) }
|
||||
watch(%r{^#{context_path}(tooling/.+)\.rb$}) { |m| rspec.spec.call(m[1]) }
|
||||
watch(%r{^#{context_path}(scripts/.+)\.rb$}) { |m| rspec.spec.call(m[1].tr('-', '_')) }
|
||||
|
||||
# Rails files
|
||||
rails = rails_context_for.call(context_path, %w[erb haml slim])
|
||||
|
|
|
@ -65,7 +65,7 @@ export default {
|
|||
|
||||
<template #header>
|
||||
<div
|
||||
class="gl-flex gl-min-h-8 gl-items-center gl-border-b-1 gl-border-b-gray-200 !gl-p-4 gl-border-b-solid"
|
||||
class="gl-flex gl-min-h-8 gl-items-center gl-border-b-1 gl-border-b-dropdown !gl-p-4 gl-border-b-solid"
|
||||
>
|
||||
<span class="gl-grow gl-pr-2 gl-text-sm gl-font-bold">
|
||||
{{ n__('%d pending comment', '%d pending comments', draftsCount) }}
|
||||
|
|
|
@ -133,6 +133,7 @@ export default {
|
|||
:column-index="columnIndex"
|
||||
@toggleNewForm="toggleNewForm"
|
||||
@setFilters="$emit('setFilters', $event)"
|
||||
@cannot-find-active-item="$emit('cannot-find-active-item')"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
|
|
|
@ -7,6 +7,7 @@ import BoardAddNewColumn from 'ee_else_ce/boards/components/board_add_new_column
|
|||
import BoardAddNewColumnTrigger from '~/boards/components/board_add_new_column_trigger.vue';
|
||||
import WorkItemDrawer from '~/work_items/components/work_item_drawer.vue';
|
||||
import { s__ } from '~/locale';
|
||||
import { removeParams, updateHistory } from '~/lib/utils/url_utility';
|
||||
import { defaultSortableOptions, DRAG_DELAY } from '~/sortable/constants';
|
||||
import { mapWorkItemWidgetsToIssuableFields } from '~/issues/list/utils';
|
||||
import {
|
||||
|
@ -19,6 +20,7 @@ import {
|
|||
DEFAULT_BOARD_LIST_ITEMS_SIZE,
|
||||
BoardType,
|
||||
} from 'ee_else_ce/boards/constants';
|
||||
import { DETAIL_VIEW_QUERY_PARAM_NAME } from '~/work_items/constants';
|
||||
import { calculateNewPosition } from 'ee_else_ce/boards/boards_util';
|
||||
import { setError } from '../graphql/cache_updates';
|
||||
import BoardColumn from './board_column.vue';
|
||||
|
@ -88,6 +90,7 @@ export default {
|
|||
return {
|
||||
boardHeight: null,
|
||||
highlightedLists: [],
|
||||
columnsThatCannotFindActiveItem: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -245,6 +248,14 @@ export default {
|
|||
isLastList(index) {
|
||||
return this.boardListsToUse.length - 1 === index;
|
||||
},
|
||||
handleCannotFindActiveItem() {
|
||||
this.columnsThatCannotFindActiveItem += 1;
|
||||
if (this.columnsThatCannotFindActiveItem === this.boardListsToUse.length) {
|
||||
updateHistory({
|
||||
url: removeParams([DETAIL_VIEW_QUERY_PARAM_NAME]),
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -281,6 +292,7 @@ export default {
|
|||
@setActiveList="$emit('setActiveList', $event)"
|
||||
@setFilters="$emit('setFilters', $event)"
|
||||
@addNewListAfter="$emit('setAddColumnFormVisibility', $event)"
|
||||
@cannot-find-active-item="handleCannotFindActiveItem"
|
||||
/>
|
||||
|
||||
<transition mode="out-in" name="slide" @after-enter="afterFormEnters">
|
||||
|
|
|
@ -7,6 +7,7 @@ import { ESC_KEY_CODE } from '~/lib/utils/keycodes';
|
|||
import { defaultSortableOptions, DRAG_DELAY } from '~/sortable/constants';
|
||||
import { sortableStart, sortableEnd } from '~/sortable/utils';
|
||||
import Tracking from '~/tracking';
|
||||
import { getParameterByName } from '~/lib/utils/url_utility';
|
||||
import listQuery from 'ee_else_ce/boards/graphql/board_lists_deferred.query.graphql';
|
||||
import setActiveBoardItemMutation from 'ee_else_ce/boards/graphql/client/set_active_board_item.mutation.graphql';
|
||||
import BoardNewIssue from 'ee_else_ce/boards/components/board_new_issue.vue';
|
||||
|
@ -18,6 +19,7 @@ import {
|
|||
listIssuablesQueries,
|
||||
ListType,
|
||||
} from 'ee_else_ce/boards/constants';
|
||||
import { DETAIL_VIEW_QUERY_PARAM_NAME } from '~/work_items/constants';
|
||||
import {
|
||||
addItemToList,
|
||||
removeItemFromList,
|
||||
|
@ -90,6 +92,7 @@ export default {
|
|||
addItemToListInProgress: false,
|
||||
updateIssueOrderInProgress: false,
|
||||
dragCancelled: false,
|
||||
hasMadeDrawerAttempt: false,
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
|
@ -128,6 +131,28 @@ export default {
|
|||
message: s__('Boards|An error occurred while fetching a list. Please try again.'),
|
||||
});
|
||||
},
|
||||
result({ data }) {
|
||||
if (this.hasMadeDrawerAttempt) {
|
||||
return;
|
||||
}
|
||||
const queryParam = getParameterByName(DETAIL_VIEW_QUERY_PARAM_NAME);
|
||||
|
||||
if (!data || !queryParam) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { iid, full_path: fullPath } = JSON.parse(atob(queryParam));
|
||||
const boardItem = this.boardListItems.find(
|
||||
(item) => item.iid === iid && item.referencePath.includes(fullPath),
|
||||
);
|
||||
|
||||
if (boardItem) {
|
||||
this.setActiveWorkItem(boardItem);
|
||||
} else {
|
||||
this.$emit('cannot-find-active-item');
|
||||
}
|
||||
this.hasMadeDrawerAttempt = true;
|
||||
},
|
||||
},
|
||||
toList: {
|
||||
query() {
|
||||
|
@ -603,16 +628,19 @@ export default {
|
|||
});
|
||||
} finally {
|
||||
this.addItemToListInProgress = false;
|
||||
this.$apollo.mutate({
|
||||
mutation: setActiveBoardItemMutation,
|
||||
variables: {
|
||||
boardItem: issuable,
|
||||
listId: this.list.id,
|
||||
isIssue: this.isIssueBoard,
|
||||
},
|
||||
});
|
||||
this.setActiveWorkItem(issuable);
|
||||
}
|
||||
},
|
||||
setActiveWorkItem(boardItem) {
|
||||
this.$apollo.mutate({
|
||||
mutation: setActiveBoardItemMutation,
|
||||
variables: {
|
||||
boardItem,
|
||||
listId: this.list.id,
|
||||
isIssue: this.isIssueBoard,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -145,14 +145,18 @@ export default {
|
|||
return Number(this.pageInfo.hasNextPage);
|
||||
},
|
||||
fields() {
|
||||
return [
|
||||
this.canBulkDestroyArtifacts && {
|
||||
key: 'checkbox',
|
||||
label: '',
|
||||
thClass: 'gl-w-1/20',
|
||||
},
|
||||
...this.$options.fields,
|
||||
];
|
||||
if (this.canBulkDestroyArtifacts) {
|
||||
return [
|
||||
{
|
||||
key: 'checkbox',
|
||||
label: '',
|
||||
thClass: 'gl-w-1/20',
|
||||
},
|
||||
...this.$options.fields,
|
||||
];
|
||||
}
|
||||
|
||||
return this.$options.fields;
|
||||
},
|
||||
anyArtifactsSelected() {
|
||||
return Boolean(this.selectedArtifacts.length);
|
||||
|
|
|
@ -180,7 +180,7 @@ export default {
|
|||
:data-testid="testid"
|
||||
>
|
||||
<template #list-item>
|
||||
<div class="-gl-my-1 -gl-ml-2 gl-flex gl-items-center gl-justify-between">
|
||||
<div class="-gl-my-2 -gl-ml-2 gl-flex gl-items-center gl-justify-between">
|
||||
<job-name-component
|
||||
v-gl-tooltip.viewport.left
|
||||
:title="tooltipText"
|
||||
|
|
|
@ -137,7 +137,7 @@ export default {
|
|||
|
||||
<template #header>
|
||||
<div
|
||||
class="gl-flex gl-min-h-8 gl-items-center gl-border-b-1 gl-border-b-gray-200 !gl-p-4 gl-text-sm gl-font-bold gl-leading-1 gl-border-b-solid"
|
||||
class="gl-flex gl-min-h-8 gl-items-center gl-border-b-1 gl-border-b-dropdown !gl-p-4 gl-text-sm gl-font-bold gl-leading-1 gl-border-b-solid"
|
||||
>
|
||||
<template v-if="isLoading">
|
||||
<span>{{ $options.i18n.stage }}</span>
|
||||
|
|
|
@ -133,7 +133,7 @@ export default {
|
|||
<template #header>
|
||||
<div
|
||||
data-testid="pipeline-stage-dropdown-menu-title"
|
||||
class="gl-flex gl-min-h-8 gl-items-center gl-border-b-1 gl-border-b-gray-200 !gl-p-4 gl-text-sm gl-font-bold gl-leading-1 gl-border-b-solid"
|
||||
class="gl-flex gl-min-h-8 gl-items-center gl-border-b-1 gl-border-b-dropdown !gl-p-4 gl-text-sm gl-font-bold gl-leading-1 gl-border-b-solid"
|
||||
>
|
||||
<span>{{ dropdownHeaderText }}</span>
|
||||
</div>
|
||||
|
|
|
@ -144,11 +144,11 @@ export default {
|
|||
<template #header>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="gl-flex gl-min-h-8 gl-items-center gl-border-b-1 gl-border-b-gray-200 !gl-p-4 gl-text-sm gl-font-bold gl-text-gray-900 gl-border-b-solid"
|
||||
class="gl-flex gl-min-h-8 gl-items-center gl-border-b-1 gl-border-b-dropdown !gl-p-4 gl-text-sm gl-font-bold gl-text-gray-900 gl-border-b-solid"
|
||||
>
|
||||
{{ $options.i18n.downloadArtifacts }}
|
||||
</div>
|
||||
<div v-if="hasArtifacts" class="gl-border-b-1 gl-border-b-gray-200 gl-border-b-solid">
|
||||
<div v-if="hasArtifacts" class="gl-border-b-1 gl-border-b-dropdown gl-border-b-solid">
|
||||
<gl-search-box-by-type
|
||||
ref="searchInput"
|
||||
v-model.trim="searchQuery"
|
||||
|
|
|
@ -89,7 +89,7 @@ export default {
|
|||
<template v-if="shouldRenderCreateButton" #footer>
|
||||
<gl-button
|
||||
category="tertiary"
|
||||
class="!gl-justify-start !gl-rounded-tl-none !gl-rounded-tr-none !gl-border-t-1 gl-border-t-gray-200 !gl-pl-7 gl-border-t-solid"
|
||||
class="!gl-justify-start !gl-rounded-tl-none !gl-rounded-tr-none !gl-border-t-1 gl-border-t-dropdown !gl-pl-7 gl-border-t-solid"
|
||||
:class="{ 'gl-mt-3': !filteredResults.length }"
|
||||
@click="selectAgent(searchTerm)"
|
||||
>
|
||||
|
|
|
@ -170,7 +170,7 @@ export default {
|
|||
<gl-search-box-by-type
|
||||
ref="searchValue"
|
||||
v-model="searchValue"
|
||||
class="add-reaction-search gl-border-b-1 gl-border-b-gray-200 gl-border-b-solid"
|
||||
class="add-reaction-search gl-border-b-1 gl-border-b-dropdown gl-border-b-solid"
|
||||
borderless
|
||||
autofocus
|
||||
debounce="500"
|
||||
|
@ -218,7 +218,7 @@ export default {
|
|||
|
||||
<template v-if="newCustomEmojiPath" #footer>
|
||||
<div
|
||||
class="gl-flex gl-flex-col gl-border-t-1 gl-border-t-gray-200 !gl-p-2 !gl-pt-0 gl-border-t-solid"
|
||||
class="gl-flex gl-flex-col gl-border-t-1 gl-border-t-dropdown !gl-p-2 !gl-pt-0 gl-border-t-solid"
|
||||
>
|
||||
<gl-button
|
||||
:href="newCustomEmojiPath"
|
||||
|
|
|
@ -37,7 +37,7 @@ export default {
|
|||
'gl-text-base',
|
||||
'gl-font-normal',
|
||||
'gl-leading-normal',
|
||||
'gl-shadow-inner-1-gray-200',
|
||||
'gl-shadow-inner-1-dropdown',
|
||||
'gl-py-3',
|
||||
'gl-px-4',
|
||||
'gl-mb-0',
|
||||
|
|
|
@ -135,7 +135,7 @@ export default {
|
|||
<template v-if="shouldRenderSelectButton" #footer>
|
||||
<gl-button
|
||||
category="tertiary"
|
||||
class="!gl-justify-start !gl-rounded-tl-none !gl-rounded-tr-none !gl-border-t-1 gl-border-t-gray-200 !gl-pl-7 gl-border-t-solid"
|
||||
class="!gl-justify-start !gl-rounded-tl-none !gl-rounded-tr-none !gl-border-t-1 gl-border-t-dropdown !gl-pl-7 gl-border-t-solid"
|
||||
:class="{ 'gl-mt-3': !filteredNamespacesList.length }"
|
||||
@click="onSelect(searchTerm)"
|
||||
>
|
||||
|
|
|
@ -324,7 +324,7 @@ export default {
|
|||
<gl-dropdown
|
||||
:text="__('Recent searches')"
|
||||
class="filtered-search-history-dropdown-wrapper"
|
||||
toggle-class="filtered-search-history-dropdown-toggle-button !gl-shadow-none !gl-border-r-gray-200 !gl-border-1 !gl-rounded-none"
|
||||
toggle-class="filtered-search-history-dropdown-toggle-button !gl-shadow-none !gl-border-r-dropdown !gl-border-1 !gl-rounded-none"
|
||||
:disabled="loading"
|
||||
>
|
||||
<div v-if="!$options.hasLocalStorage" class="gl-px-5">
|
||||
|
|
|
@ -99,7 +99,7 @@ export default {
|
|||
<template #footer>
|
||||
<div
|
||||
v-if="isCreateEnvironmentShown"
|
||||
class="gl-border-t-1 gl-border-t-gray-200 gl-p-2 gl-border-t-solid"
|
||||
class="gl-border-t-1 gl-border-t-dropdown gl-p-2 gl-border-t-solid"
|
||||
>
|
||||
<gl-button
|
||||
category="tertiary"
|
||||
|
|
|
@ -25,10 +25,11 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<settings-block id="incident-management-settings" data-testid="incidents-settings-content">
|
||||
<template #title>
|
||||
<span ref="sectionHeader">{{ $options.i18n.headerText }}</span>
|
||||
</template>
|
||||
<settings-block
|
||||
id="incident-management-settings"
|
||||
:title="$options.i18n.headerText"
|
||||
data-testid="incidents-settings-content"
|
||||
>
|
||||
<template #description>
|
||||
<span ref="sectionSubHeader">{{ $options.i18n.subHeaderText }}</span>
|
||||
</template>
|
||||
|
|
|
@ -48,7 +48,12 @@ import axios from '~/lib/utils/axios_utils';
|
|||
import { fetchPolicies } from '~/lib/graphql';
|
||||
import { isPositiveInteger } from '~/lib/utils/number_utils';
|
||||
import { scrollUp } from '~/lib/utils/scroll_utils';
|
||||
import { getParameterByName, joinPaths } from '~/lib/utils/url_utility';
|
||||
import {
|
||||
getParameterByName,
|
||||
joinPaths,
|
||||
removeParams,
|
||||
updateHistory,
|
||||
} from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
import {
|
||||
OPERATORS_IS,
|
||||
|
@ -85,8 +90,12 @@ import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_ro
|
|||
import { DEFAULT_PAGE_SIZE, issuableListTabs } from '~/vue_shared/issuable/list/constants';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import NewResourceDropdown from '~/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue';
|
||||
import { WORK_ITEM_TYPE_ENUM_OBJECTIVE } from '~/work_items/constants';
|
||||
import {
|
||||
WORK_ITEM_TYPE_ENUM_OBJECTIVE,
|
||||
DETAIL_VIEW_QUERY_PARAM_NAME,
|
||||
} from '~/work_items/constants';
|
||||
import WorkItemDrawer from '~/work_items/components/work_item_drawer.vue';
|
||||
import { makeDrawerUrlParam } from '~/work_items/utils';
|
||||
import {
|
||||
CREATED_DESC,
|
||||
i18n,
|
||||
|
@ -244,6 +253,7 @@ export default {
|
|||
}
|
||||
this.pageInfo = data[this.namespace]?.issues.pageInfo ?? {};
|
||||
this.exportCsvPathWithQuery = this.getExportCsvPathWithQuery();
|
||||
this.checkDrawerParams();
|
||||
},
|
||||
error(error) {
|
||||
this.issuesError = this.$options.i18n.errorFetchingIssues;
|
||||
|
@ -538,7 +548,10 @@ export default {
|
|||
return this.tabCounts[this.state] ?? 0;
|
||||
},
|
||||
urlParams() {
|
||||
return {
|
||||
const show = this.activeIssuable
|
||||
? makeDrawerUrlParam(this.activeIssuable, this.fullPath)
|
||||
: undefined;
|
||||
const base = {
|
||||
sort: urlSortParams[this.sortKey],
|
||||
state: this.state,
|
||||
...this.urlFilterParams,
|
||||
|
@ -547,6 +560,10 @@ export default {
|
|||
page_after: this.pageParams.afterCursor ?? undefined,
|
||||
page_before: this.pageParams.beforeCursor ?? undefined,
|
||||
};
|
||||
if (show) {
|
||||
return { ...base, show };
|
||||
}
|
||||
return base;
|
||||
},
|
||||
// due to the issues with cache-and-network, we need this hack to check if there is any data for the query in the cache.
|
||||
// if we have cached data, we disregard the loading state
|
||||
|
@ -577,6 +594,11 @@ export default {
|
|||
if (newValue.fullPath !== oldValue.fullPath) {
|
||||
this.updateData(getParameterByName(PARAM_SORT));
|
||||
}
|
||||
if (newValue.query.show) {
|
||||
this.checkDrawerParams();
|
||||
} else {
|
||||
this.activeIssuable = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
|
@ -820,7 +842,6 @@ export default {
|
|||
handleSelectIssuable(issuable) {
|
||||
this.activeIssuable = {
|
||||
...issuable,
|
||||
fullPath: this.fullPath,
|
||||
};
|
||||
},
|
||||
updateIssuablesCache(workItem) {
|
||||
|
@ -831,9 +852,13 @@ export default {
|
|||
});
|
||||
|
||||
const activeIssuable = issuesList[this.namespace].issues.nodes.find(
|
||||
(issue) => issue.iid === workItem.iid,
|
||||
(issue) => getIdFromGraphQLId(issue.id) === getIdFromGraphQLId(workItem.id),
|
||||
);
|
||||
|
||||
if (!activeIssuable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// when we change issuable state, it's moved to a different tab
|
||||
// to ensure that we show 20 items of the first page, we need to refetch issuables
|
||||
if (!activeIssuable.state.includes(workItem.state.toLowerCase())) {
|
||||
|
@ -883,6 +908,29 @@ export default {
|
|||
|
||||
client.writeQuery({ query: getIssuesQuery, variables: this.queryVariables, data });
|
||||
},
|
||||
checkDrawerParams() {
|
||||
const queryParam = getParameterByName(DETAIL_VIEW_QUERY_PARAM_NAME);
|
||||
|
||||
if (this.activeIssuable || !queryParam) {
|
||||
return;
|
||||
}
|
||||
|
||||
const params = JSON.parse(atob(queryParam));
|
||||
if (params.id) {
|
||||
const issue = this.issues.find((i) => getIdFromGraphQLId(i.id) === params.id);
|
||||
if (issue) {
|
||||
this.activeIssuable = {
|
||||
...issue,
|
||||
// we need fullPath here to prevent cache invalidation
|
||||
fullPath: params.full_path,
|
||||
};
|
||||
} else {
|
||||
updateHistory({
|
||||
url: removeParams([DETAIL_VIEW_QUERY_PARAM_NAME]),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -314,7 +314,7 @@ export default {
|
|||
|
||||
<template #footer>
|
||||
<div
|
||||
class="gl-flex gl-flex-col gl-border-t-1 gl-border-t-gray-200 !gl-p-2 !gl-pt-0 gl-border-t-solid"
|
||||
class="gl-flex gl-flex-col gl-border-t-1 gl-border-t-dropdown !gl-p-2 !gl-pt-0 gl-border-t-solid"
|
||||
>
|
||||
<gl-button
|
||||
category="tertiary"
|
||||
|
|
|
@ -44,8 +44,11 @@ export default {
|
|||
},
|
||||
},
|
||||
watch: {
|
||||
count(newVal) {
|
||||
this.open = newVal > 0;
|
||||
count: {
|
||||
handler(newVal) {
|
||||
this.open = newVal > 0;
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -187,7 +187,7 @@ export default {
|
|||
|
||||
<template v-if="directlyInviteMembers" #footer>
|
||||
<div
|
||||
class="gl-flex gl-flex-col gl-border-t-1 gl-border-t-gray-200 !gl-p-2 !gl-pt-0 gl-border-t-solid"
|
||||
class="gl-flex gl-flex-col gl-border-t-1 gl-border-t-dropdown !gl-p-2 !gl-pt-0 gl-border-t-solid"
|
||||
>
|
||||
<invite-members-trigger
|
||||
trigger-element="button"
|
||||
|
|
|
@ -171,7 +171,7 @@ export default {
|
|||
</template>
|
||||
<template #footer>
|
||||
<div
|
||||
class="gl-flex gl-flex-col gl-border-t-1 gl-border-t-gray-200 !gl-p-2 !gl-pt-0 gl-border-t-solid"
|
||||
class="gl-flex gl-flex-col gl-border-t-1 gl-border-t-dropdown !gl-p-2 !gl-pt-0 gl-border-t-solid"
|
||||
>
|
||||
<gl-button
|
||||
v-for="(item, idx) in extraLinks"
|
||||
|
|
|
@ -214,11 +214,11 @@ export default {
|
|||
@action="setPromoteModalVisibility(true)"
|
||||
/>
|
||||
|
||||
<gl-disclosure-dropdown-group v-if="canReadMilestone" bordered class="!gl-border-t-gray-200">
|
||||
<gl-disclosure-dropdown-group v-if="canReadMilestone" bordered class="!gl-border-t-dropdown">
|
||||
<gl-disclosure-dropdown-item :item="copyIdItem" :data-clipboard-text="id" />
|
||||
</gl-disclosure-dropdown-group>
|
||||
|
||||
<gl-disclosure-dropdown-group v-if="showDelete" bordered class="!gl-border-t-gray-200">
|
||||
<gl-disclosure-dropdown-group v-if="showDelete" bordered class="!gl-border-t-dropdown">
|
||||
<gl-disclosure-dropdown-item :item="deleteItem" @action="setDeleteModalVisibility(true)" />
|
||||
</gl-disclosure-dropdown-group>
|
||||
|
||||
|
|
|
@ -16,8 +16,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<settings-block id="organization-settings-advanced">
|
||||
<template #title>{{ $options.i18n.settingsBlock.title }}</template>
|
||||
<settings-block id="organization-settings-advanced" :title="$options.i18n.settingsBlock.title">
|
||||
<template #description>{{ $options.i18n.settingsBlock.description }}</template>
|
||||
<template #default>
|
||||
<change-url />
|
||||
|
|
|
@ -100,8 +100,11 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<settings-block id="organization-settings" default-expanded>
|
||||
<template #title>{{ $options.i18n.settingsBlock.title }}</template>
|
||||
<settings-block
|
||||
id="organization-settings"
|
||||
:title="$options.i18n.settingsBlock.title"
|
||||
default-expanded
|
||||
>
|
||||
<template #description>{{ $options.i18n.settingsBlock.description }}</template>
|
||||
<template #default>
|
||||
<form-errors-alert v-model="errors" :scroll-on-error="true" />
|
||||
|
|
|
@ -48,8 +48,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<settings-block id="organization-settings-visibility">
|
||||
<template #title>{{ $options.i18n.settingsBlock.title }}</template>
|
||||
<settings-block id="organization-settings-visibility" :title="$options.i18n.settingsBlock.title">
|
||||
<template #description>{{ $options.i18n.settingsBlock.description }}</template>
|
||||
<template #default>
|
||||
<gl-form :id="$options.formId">
|
||||
|
|
|
@ -70,7 +70,7 @@ export default {
|
|||
<div data-testid="tag-name-search">
|
||||
<gl-search-box-by-type
|
||||
:value="query"
|
||||
class="gl-border-b-1 gl-border-gray-200 gl-border-b-solid"
|
||||
class="gl-border-b-1 gl-border-dropdown gl-border-b-solid"
|
||||
borderless
|
||||
autofocus
|
||||
@input="onSearchBoxInput"
|
||||
|
@ -95,7 +95,7 @@ export default {
|
|||
{{ $options.i18n.noResults }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="gl-border-t-1 gl-border-gray-200 gl-py-3 gl-border-t-solid">
|
||||
<div class="gl-border-t-1 gl-border-dropdown gl-py-3 gl-border-t-solid">
|
||||
<gl-button
|
||||
category="tertiary"
|
||||
class="!gl-justify-start !gl-rounded-none"
|
||||
|
|
|
@ -240,7 +240,7 @@ export default {
|
|||
v-if="isFocused"
|
||||
v-outside.click.focusin="closeDropdown"
|
||||
data-testid="header-search-dropdown-menu"
|
||||
class="header-search-dropdown-menu gl-absolute gl-z-2 gl-mt-3 !gl-w-full !gl-min-w-full !gl-max-w-none gl-overflow-y-auto gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-200 gl-bg-white gl-shadow-x0-y2-b4-s0"
|
||||
class="header-search-dropdown-menu gl-absolute gl-z-2 gl-mt-3 !gl-w-full !gl-min-w-full !gl-max-w-none gl-overflow-y-auto gl-rounded-base gl-border-1 gl-border-solid gl-border-dropdown gl-bg-white gl-shadow-x0-y2-b4-s0"
|
||||
>
|
||||
<div class="header-search-dropdown-content gl-py-2">
|
||||
<dropdown-keyboard-navigation
|
||||
|
|
|
@ -18,8 +18,14 @@ export function isExpanded(sectionArg) {
|
|||
|
||||
export function expandSection(sectionArg) {
|
||||
const $section = $(sectionArg);
|
||||
const title = $section.find('.js-settings-toggle-trigger-only').text();
|
||||
|
||||
$section.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only)').text(__('Collapse'));
|
||||
$section
|
||||
.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only) .gl-button-text')
|
||||
.text(__('Collapse'));
|
||||
$section
|
||||
.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only)')
|
||||
.attr('aria-label', `${__('Collapse')} ${title}`);
|
||||
$section.addClass('expanded');
|
||||
if (!$section.hasClass('no-animate')) {
|
||||
$section
|
||||
|
@ -34,8 +40,15 @@ export function expandSection(sectionArg) {
|
|||
|
||||
export function closeSection(sectionArg) {
|
||||
const $section = $(sectionArg);
|
||||
const title = $section.find('.js-settings-toggle-trigger-only').text();
|
||||
|
||||
$section
|
||||
.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only) .gl-button-text')
|
||||
.text(__('Expand'));
|
||||
$section
|
||||
.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only)')
|
||||
.attr('aria-label', `${__('Expand')} ${title}`);
|
||||
|
||||
$section.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only)').text(__('Expand'));
|
||||
$section.removeClass('expanded');
|
||||
if (!$section.hasClass('no-animate')) {
|
||||
$section
|
||||
|
|
|
@ -68,7 +68,7 @@ export default {
|
|||
</button>
|
||||
</template>
|
||||
<template #header>
|
||||
<span class="gl-border-b-1 gl-border-gray-200 gl-p-4 gl-border-b-solid">
|
||||
<span class="gl-border-b-1 gl-border-dropdown gl-p-4 gl-border-b-solid">
|
||||
{{ $options.i18n.header }}
|
||||
</span>
|
||||
</template>
|
||||
|
|
|
@ -163,7 +163,7 @@ export default {
|
|||
</template>
|
||||
|
||||
<template v-if="!organizationSwitchingEnabled" #footer>
|
||||
<div class="gl-border-t gl-mt-2 gl-border-t-gray-200 gl-px-4 gl-pt-3">
|
||||
<div class="gl-border-t gl-mt-2 gl-border-t-dropdown gl-px-4 gl-pt-3">
|
||||
<div class="gl-text-sm gl-font-bold">
|
||||
{{ $options.i18n.switchOrganizations }}
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
<script>
|
||||
import { GlLoadingIcon, GlKeysetPagination, GlButton, GlBadge, GlTab, GlTabs } from '@gitlab/ui';
|
||||
import {
|
||||
GlLoadingIcon,
|
||||
GlKeysetPagination,
|
||||
GlLink,
|
||||
GlButton,
|
||||
GlBadge,
|
||||
GlTab,
|
||||
GlTabs,
|
||||
} from '@gitlab/ui';
|
||||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import { createAlert } from '~/alert';
|
||||
import { s__ } from '~/locale';
|
||||
|
@ -14,6 +22,7 @@ const STATUS_BY_TAB = [['pending'], ['done'], ['pending', 'done']];
|
|||
|
||||
export default {
|
||||
components: {
|
||||
GlLink,
|
||||
GlLoadingIcon,
|
||||
GlKeysetPagination,
|
||||
GlButton,
|
||||
|
@ -209,6 +218,12 @@ export default {
|
|||
@prev="prevPage"
|
||||
@next="nextPage"
|
||||
/>
|
||||
|
||||
<div class="gl-mt-5 gl-text-center">
|
||||
<gl-link href="https://gitlab.com/gitlab-org/gitlab/-/issues/498315" target="_blank">{{
|
||||
s__('Todos|Leave feedback')
|
||||
}}</gl-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -79,9 +79,9 @@ export default {
|
|||
type: String,
|
||||
required: false,
|
||||
},
|
||||
pipelineIid: {
|
||||
type: Number,
|
||||
required: false,
|
||||
pipelineMiniGraphVariables: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
buildsWithCoverage: {
|
||||
type: Array,
|
||||
|
@ -128,10 +128,6 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
sourceProjectFullPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
targetProjectFullPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
@ -155,13 +151,14 @@ export default {
|
|||
return this.hasPipeline && !this.ciStatus;
|
||||
},
|
||||
status() {
|
||||
return this.pipeline.details && this.pipeline.details.status
|
||||
? this.pipeline.details.status
|
||||
: {};
|
||||
return this.pipeline?.details?.status || {};
|
||||
},
|
||||
artifacts() {
|
||||
return this.pipeline?.details?.artifacts;
|
||||
},
|
||||
hasArtifacts() {
|
||||
return Boolean(this.pipeline?.details?.artifacts?.length);
|
||||
},
|
||||
hasStages() {
|
||||
return this.pipeline?.details?.stages?.length > 0;
|
||||
},
|
||||
|
@ -210,9 +207,6 @@ export default {
|
|||
this.buildsWithCoverage.length,
|
||||
);
|
||||
},
|
||||
pipelineMiniGraphQueryId() {
|
||||
return this.pipelineIid?.toString() || null;
|
||||
},
|
||||
isMergeTrain() {
|
||||
return Boolean(this.pipeline.flags?.merge_train_pipeline);
|
||||
},
|
||||
|
@ -307,9 +301,9 @@ export default {
|
|||
<div class="gl-inline-flex gl-grow gl-items-center gl-justify-between">
|
||||
<div>
|
||||
<pipeline-mini-graph
|
||||
v-if="isGraphQLPipelineMiniGraph && pipelineMiniGraphQueryId"
|
||||
:iid="pipelineMiniGraphQueryId"
|
||||
:full-path="sourceProjectFullPath"
|
||||
v-if="isGraphQLPipelineMiniGraph && pipelineMiniGraphVariables.iid"
|
||||
:iid="pipelineMiniGraphVariables.iid"
|
||||
:full-path="pipelineMiniGraphVariables.fullPath"
|
||||
:is-merge-train="isMergeTrain"
|
||||
:pipeline-etag="pipelineEtag"
|
||||
/>
|
||||
|
@ -323,6 +317,7 @@ export default {
|
|||
/>
|
||||
</div>
|
||||
<pipeline-artifacts
|
||||
v-if="hasArtifacts"
|
||||
:pipeline-id="pipeline.id"
|
||||
:artifacts="artifacts"
|
||||
class="gl-ml-3"
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
<script>
|
||||
import { sanitize } from '~/lib/dompurify';
|
||||
import { n__ } from '~/locale';
|
||||
import { n__, __ } from '~/locale';
|
||||
import { createAlert } from '~/alert';
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import { TYPENAME_CI_PIPELINE } from '~/graphql_shared/constants';
|
||||
import { getQueryHeaders, toggleQueryPollingByVisibility } from '~/ci/pipeline_details/graph/utils';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { PIPELINE_MINI_GRAPH_POLL_INTERVAL } from '~/ci/pipeline_details/constants';
|
||||
import MergeRequestStore from '../stores/mr_widget_store';
|
||||
import getMergePipeline from '../queries/get_merge_pipeline.query.graphql';
|
||||
import ArtifactsApp from './artifacts_list_app.vue';
|
||||
import DeploymentList from './deployment/deployment_list.vue';
|
||||
import MrWidgetContainer from './mr_widget_container.vue';
|
||||
|
@ -38,7 +44,39 @@ export default {
|
|||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mergePipeline: {},
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
mergePipeline: {
|
||||
context() {
|
||||
return getQueryHeaders(this.mr.pipelineEtag);
|
||||
},
|
||||
query: getMergePipeline,
|
||||
skip() {
|
||||
return !this.useMergePipelineQuery;
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
fullPath: this.mr.targetProjectFullPath,
|
||||
id: convertToGraphQLId(TYPENAME_CI_PIPELINE, this.mr.mergePipeline.id),
|
||||
};
|
||||
},
|
||||
pollInterval: PIPELINE_MINI_GRAPH_POLL_INTERVAL,
|
||||
update({ project }) {
|
||||
return project?.pipeline || {};
|
||||
},
|
||||
error() {
|
||||
createAlert({ message: __('There was a problem fetching the merge pipeline.') });
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
useMergePipelineQuery() {
|
||||
return this.isPostMerge && this.glFeatures?.ciGraphqlPipelineMiniGraph;
|
||||
},
|
||||
branch() {
|
||||
return this.isPostMerge ? this.mr.targetBranch : this.mr.sourceBranch;
|
||||
},
|
||||
|
@ -57,6 +95,17 @@ export default {
|
|||
pipeline() {
|
||||
return this.isPostMerge ? this.mr.mergePipeline : this.mr.pipeline;
|
||||
},
|
||||
pipelineMiniGraphVariables() {
|
||||
return this.isPostMerge
|
||||
? {
|
||||
fullPath: this.mergePipeline?.project?.fullPath,
|
||||
iid: this.mergePipeline?.iid,
|
||||
}
|
||||
: {
|
||||
fullPath: this.mr.pipelineProjectPath || '',
|
||||
iid: this.mr.pipelineIid || '',
|
||||
};
|
||||
},
|
||||
showCollapsedDeployments() {
|
||||
return this.deployments.length > 3;
|
||||
},
|
||||
|
@ -74,6 +123,11 @@ export default {
|
|||
return this.isPostMerge ? this.mr?.mergePipeline?.details?.status?.text : this.mr.ciStatus;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.useMergePipelineQuery) {
|
||||
toggleQueryPollingByVisibility(this.$apollo.queries.mergePipeline);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
|
@ -82,7 +136,7 @@ export default {
|
|||
:pipeline="pipeline"
|
||||
:pipeline-coverage-delta="mr.pipelineCoverageDelta"
|
||||
:pipeline-etag="mr.pipelineEtag"
|
||||
:pipeline-iid="mr.pipelineIid"
|
||||
:pipeline-mini-graph-variables="pipelineMiniGraphVariables"
|
||||
:builds-with-coverage="mr.buildsWithCoverage"
|
||||
:ci-status="ciStatus"
|
||||
:has-ci="mr.hasCI"
|
||||
|
@ -95,7 +149,6 @@ export default {
|
|||
:retargeted="mr.retargeted"
|
||||
:target-project-id="mr.targetProjectId"
|
||||
:iid="mr.iid"
|
||||
:source-project-full-path="mr.sourceProjectFullPath"
|
||||
:target-project-full-path="mr.targetProjectFullPath"
|
||||
/>
|
||||
<template #footer>
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
query getMergePipeline($fullPath: ID!, $id: CiPipelineID!) {
|
||||
project(fullPath: $fullPath) {
|
||||
id
|
||||
pipeline(id: $id) {
|
||||
id
|
||||
iid
|
||||
project {
|
||||
id
|
||||
fullPath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ import { STATUS_CLOSED, STATUS_MERGED, STATUS_OPEN } from '~/issues/constants';
|
|||
import { formatDate, getTimeago, newDate, timeagoLanguageCode } from '~/lib/utils/datetime_utility';
|
||||
import { machine } from '~/lib/utils/finite_state_machine';
|
||||
import { badgeState } from '~/merge_requests/components/merge_request_header.vue';
|
||||
import { cleanLeadingSeparator } from '~/lib/utils/url_utility';
|
||||
import {
|
||||
MTWPS_MERGE_STRATEGY,
|
||||
MT_MERGE_STRATEGY,
|
||||
|
@ -141,7 +142,10 @@ export default class MergeRequestStore {
|
|||
this.isPipelineSkipped = this.ciStatus === 'skipped';
|
||||
this.pipelineDetailedStatus = pipelineStatus;
|
||||
this.isPipelineActive = data.pipeline ? data.pipeline.active : false;
|
||||
this.pipelineIid = data.pipeline?.iid;
|
||||
this.pipelineIid = data.pipeline?.iid?.toString() || '';
|
||||
this.pipelineProjectPath = data.pipeline?.project_path
|
||||
? cleanLeadingSeparator(data.pipeline?.project_path)
|
||||
: '';
|
||||
this.isPipelineBlocked =
|
||||
data.only_allow_merge_if_pipeline_succeeds && pipelineStatus?.group === 'manual';
|
||||
this.faviconOverlayPath = data.favicon_overlay_path;
|
||||
|
|
|
@ -47,9 +47,11 @@ export default {
|
|||
>
|
||||
<gl-sprintf :message="$options.i18n.message">
|
||||
<template #link="{ content }">
|
||||
<help-page-link href="subscriptions/gitlab_com/index" anchor="change-the-linked-group">{{
|
||||
content
|
||||
}}</help-page-link>
|
||||
<help-page-link
|
||||
href="subscriptions/gitlab_com/index"
|
||||
anchor="link-subscription-to-a-group"
|
||||
>{{ content }}</help-page-link
|
||||
>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</gl-modal>
|
||||
|
|
|
@ -173,7 +173,7 @@ export default {
|
|||
>
|
||||
<template #header>
|
||||
<div
|
||||
class="gl-min-h-8 gl-border-b-1 gl-border-b-gray-200 !gl-p-4 gl-text-sm gl-font-bold gl-border-b-solid"
|
||||
class="gl-min-h-8 gl-border-b-1 gl-border-b-dropdown !gl-p-4 gl-text-sm gl-font-bold gl-border-b-solid"
|
||||
>
|
||||
{{ __('Manage') }}
|
||||
</div>
|
||||
|
|
|
@ -35,6 +35,12 @@ export default {
|
|||
toggleButtonText() {
|
||||
return this.expanded ? this.$options.i18n.collapseText : this.$options.i18n.expandText;
|
||||
},
|
||||
toggleButtonAriaLabel() {
|
||||
return `${this.toggleButtonText} ${this.$scopedSlots.title || this.title}`;
|
||||
},
|
||||
expandedClass() {
|
||||
return this.expanded ? 'expanded' : '';
|
||||
},
|
||||
collapseId() {
|
||||
return this.id || uniqueId('settings-block-');
|
||||
},
|
||||
|
@ -54,8 +60,24 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<section :id="id" class="vue-settings-block settings no-animate">
|
||||
<div class="gl-flex gl-items-start gl-justify-between">
|
||||
<section :id="id" class="vue-settings-block settings no-animate" :class="expandedClass">
|
||||
<div class="gl-flex gl-items-start gl-justify-between gl-gap-x-3">
|
||||
<div class="-gl-mr-3 gl-shrink-0 gl-px-2 gl-py-0 sm:gl-mr-0 sm:gl-p-2">
|
||||
<gl-button
|
||||
category="tertiary"
|
||||
size="small"
|
||||
class="settings-toggle gl-shrink-0 !gl-pl-2 !gl-pr-0"
|
||||
icon="chevron-lg-right"
|
||||
button-text-classes="gl-sr-only"
|
||||
:aria-label="toggleButtonAriaLabel"
|
||||
:aria-expanded="ariaExpanded"
|
||||
:aria-controls="collapseId"
|
||||
data-testid="settings-block-toggle"
|
||||
@click="toggleExpanded"
|
||||
>
|
||||
{{ toggleButtonText }}
|
||||
</gl-button>
|
||||
</div>
|
||||
<div class="gl-grow">
|
||||
<h2
|
||||
role="button"
|
||||
|
@ -63,34 +85,16 @@ export default {
|
|||
class="gl-heading-2 !gl-mb-2 gl-cursor-pointer"
|
||||
:aria-expanded="ariaExpanded"
|
||||
:aria-controls="collapseId"
|
||||
data-testid="settings-block-title"
|
||||
@click="toggleExpanded"
|
||||
>
|
||||
<slot v-if="$scopedSlots.title" name="title"></slot>
|
||||
<template v-else>{{ title }}</template>
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p class="gl-m-0 gl-text-subtle"><slot name="description"></slot></p>
|
||||
</div>
|
||||
<div class="gl-shrink-0 gl-px-2">
|
||||
<gl-button
|
||||
class="gl-min-w-12 gl-shrink-0"
|
||||
:aria-expanded="ariaExpanded"
|
||||
:aria-controls="collapseId"
|
||||
data-testid="settings-block-toggle"
|
||||
@click="toggleExpanded"
|
||||
>
|
||||
<span aria-hidden="true">
|
||||
{{ toggleButtonText }}
|
||||
</span>
|
||||
<span class="gl-sr-only">
|
||||
{{ toggleButtonText }}
|
||||
<slot v-if="$scopedSlots.title" name="title"></slot>
|
||||
<template v-else>{{ title }}</template>
|
||||
</span>
|
||||
</gl-button>
|
||||
</div>
|
||||
</div>
|
||||
<gl-collapse :id="collapseId" v-model="expanded" data-testid="settings-block-content">
|
||||
<div class="gl-pt-5">
|
||||
<div class="gl-pl-7 gl-pt-5 sm:gl-pl-8">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</gl-collapse>
|
||||
|
|
|
@ -100,7 +100,9 @@ export default {
|
|||
return this.issuable.iid;
|
||||
},
|
||||
workItemFullPath() {
|
||||
return this.issuable.namespace?.fullPath;
|
||||
return (
|
||||
this.issuable.namespace?.fullPath || this.issuable.reference?.split(this.issuableSymbol)[0]
|
||||
);
|
||||
},
|
||||
author() {
|
||||
return this.issuable.author || {};
|
||||
|
@ -267,6 +269,7 @@ export default {
|
|||
return;
|
||||
}
|
||||
this.$emit('select-issuable', {
|
||||
id: this.issuable.id,
|
||||
iid: this.issuableIid,
|
||||
webUrl: this.issuable.webUrl,
|
||||
fullPath: this.workItemFullPath,
|
||||
|
|
|
@ -6,6 +6,7 @@ import PageSizeSelector from '~/vue_shared/components/page_size_selector.vue';
|
|||
import { updateHistory, setUrlParams } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
import { DRAG_DELAY } from '~/sortable/constants';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
||||
|
@ -307,7 +308,9 @@ export default {
|
|||
this.$emit('page-size-change', newPageSize);
|
||||
},
|
||||
isIssuableActive(issuable) {
|
||||
return Boolean(issuable.iid === this.activeIssuable?.iid);
|
||||
return Boolean(
|
||||
getIdFromGraphQLId(issuable.id) === getIdFromGraphQLId(this.activeIssuable?.id),
|
||||
);
|
||||
},
|
||||
},
|
||||
PAGE_SIZE_STORAGE_KEY,
|
||||
|
|
|
@ -244,7 +244,7 @@ export default {
|
|||
<slot name="list-item" :item="item">{{ item.text }}</slot>
|
||||
</template>
|
||||
<template v-if="showFooter" #footer>
|
||||
<div class="gl-border-t-1 gl-border-t-gray-200 !gl-p-2 gl-border-t-solid">
|
||||
<div class="gl-border-t-1 gl-border-t-dropdown !gl-p-2 gl-border-t-solid">
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -482,7 +482,7 @@ export default {
|
|||
});
|
||||
},
|
||||
openInModal({ event, modalWorkItem, context }) {
|
||||
if (!this.workItemsAlphaEnabled || context === LINKED_ITEMS_ANCHOR) {
|
||||
if (!this.workItemsAlphaEnabled || context === LINKED_ITEMS_ANCHOR || this.isDrawer) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -896,7 +896,7 @@ export default {
|
|||
</section>
|
||||
</section>
|
||||
<work-item-detail-modal
|
||||
v-if="!isModal"
|
||||
v-if="!isModal && !isDrawer"
|
||||
ref="modal"
|
||||
:parent-id="workItem.id"
|
||||
:work-item-id="modalWorkItemId"
|
||||
|
|
|
@ -5,8 +5,10 @@ import { __ } from '~/locale';
|
|||
import deleteWorkItemMutation from '~/work_items/graphql/delete_work_item.mutation.graphql';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
|
||||
import { DETAIL_VIEW_QUERY_PARAM_NAME } from '~/work_items/constants';
|
||||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { visitUrl, setUrlParams, updateHistory, removeParams } from '~/lib/utils/url_utility';
|
||||
import { makeDrawerItemFullPath, makeDrawerUrlParam } from '../utils';
|
||||
|
||||
export default {
|
||||
name: 'WorkItemDrawer',
|
||||
|
@ -51,14 +53,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
activeItemFullPath() {
|
||||
if (this.activeItem?.fullPath) {
|
||||
return this.activeItem.fullPath;
|
||||
}
|
||||
const delimiter = this.issuableType === TYPE_EPIC ? '&' : '#';
|
||||
if (!this.activeItem.referencePath) {
|
||||
return undefined;
|
||||
}
|
||||
return this.activeItem.referencePath.split(delimiter)[0];
|
||||
return makeDrawerItemFullPath(this.activeItem, this.fullPath, this.issuableType);
|
||||
},
|
||||
modalIsGroup() {
|
||||
return this.issuableType.toLowerCase() === TYPE_EPIC;
|
||||
|
@ -75,6 +70,17 @@ export default {
|
|||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
activeItem: {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
handler(newValue) {
|
||||
if (newValue?.iid) {
|
||||
this.setDrawerParams();
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async deleteWorkItem({ workItemId }) {
|
||||
try {
|
||||
|
@ -119,6 +125,17 @@ export default {
|
|||
this.copyTooltipText = this.$options.i18n.copyTooltipText;
|
||||
}, 2000);
|
||||
},
|
||||
setDrawerParams() {
|
||||
const params = makeDrawerUrlParam(this.activeItem, this.fullPath, this.issuableType);
|
||||
updateHistory({
|
||||
// we're using `show` to match the modal view parameter
|
||||
url: setUrlParams({ [DETAIL_VIEW_QUERY_PARAM_NAME]: params }),
|
||||
});
|
||||
},
|
||||
handleClose() {
|
||||
updateHistory({ url: removeParams([DETAIL_VIEW_QUERY_PARAM_NAME]) });
|
||||
this.$emit('close');
|
||||
},
|
||||
handleClickOutside(event) {
|
||||
for (const selector of this.$options.defaultExcludedSelectors) {
|
||||
const excludedElements = document.querySelectorAll(selector);
|
||||
|
@ -136,7 +153,7 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
this.$emit('close');
|
||||
this.handleClose();
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
|
@ -164,7 +181,7 @@ export default {
|
|||
header-sticky
|
||||
header-height="calc(var(--top-bar-height) + var(--performance-bar-height))"
|
||||
class="gl-w-full gl-leading-reset lg:gl-w-[480px] xl:gl-w-[768px] min-[1440px]:gl-w-[912px]"
|
||||
@close="$emit('close')"
|
||||
@close="handleClose"
|
||||
>
|
||||
<template #title>
|
||||
<div class="gl-text gl-flex gl-w-full gl-items-center gl-gap-x-2 xl:gl-px-4">
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
convertToUrlParams,
|
||||
} from 'ee_else_ce/issues/list/utils';
|
||||
import { TYPENAME_USER } from '~/graphql_shared/constants';
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import {
|
||||
STATUS_ALL,
|
||||
STATUS_CLOSED,
|
||||
|
@ -65,8 +65,13 @@ import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_ro
|
|||
import WorkItemDrawer from '~/work_items/components/work_item_drawer.vue';
|
||||
import { DEFAULT_PAGE_SIZE, issuableListTabs } from '~/vue_shared/issuable/list/constants';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { getParameterByName } from '~/lib/utils/url_utility';
|
||||
import { STATE_CLOSED, STATE_OPEN, WORK_ITEM_TYPE_ENUM_EPIC } from '../constants';
|
||||
import { getParameterByName, removeParams, updateHistory } from '~/lib/utils/url_utility';
|
||||
import {
|
||||
STATE_CLOSED,
|
||||
STATE_OPEN,
|
||||
WORK_ITEM_TYPE_ENUM_EPIC,
|
||||
DETAIL_VIEW_QUERY_PARAM_NAME,
|
||||
} from '../constants';
|
||||
import getWorkItemsQuery from '../graphql/list/get_work_items.query.graphql';
|
||||
import getWorkItemStateCountsQuery from '../graphql/list/get_work_item_state_counts.query.graphql';
|
||||
import { sortOptions, urlSortParams } from './list/constants';
|
||||
|
@ -163,6 +168,7 @@ export default {
|
|||
document.title = `Issues · ${data.project.name} · GitLab`;
|
||||
}
|
||||
}
|
||||
this.checkDrawerParams();
|
||||
},
|
||||
error(error) {
|
||||
this.error = s__(
|
||||
|
@ -416,6 +422,11 @@ export default {
|
|||
if (newValue.fullPath !== oldValue.fullPath) {
|
||||
this.updateData(getParameterByName(PARAM_SORT));
|
||||
}
|
||||
if (newValue.query[DETAIL_VIEW_QUERY_PARAM_NAME] && !this.$apollo.queries.workItems.loading) {
|
||||
this.checkDrawerParams();
|
||||
} else {
|
||||
this.activeItem = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
|
@ -564,6 +575,29 @@ export default {
|
|||
this.sortKey = deriveSortKey({ sort, sortMap: urlSortParams });
|
||||
this.state = state || STATUS_OPEN;
|
||||
},
|
||||
checkDrawerParams() {
|
||||
const queryParam = getParameterByName(DETAIL_VIEW_QUERY_PARAM_NAME);
|
||||
|
||||
if (!queryParam) {
|
||||
return;
|
||||
}
|
||||
|
||||
const params = JSON.parse(atob(queryParam));
|
||||
if (params.id) {
|
||||
const issue = this.workItems.find((i) => getIdFromGraphQLId(i.id) === params.id);
|
||||
if (issue) {
|
||||
this.activeItem = {
|
||||
...issue,
|
||||
// we need fullPath here to prevent cache invalidation
|
||||
fullPath: params.full_path,
|
||||
};
|
||||
} else {
|
||||
updateHistory({
|
||||
url: removeParams([DETAIL_VIEW_QUERY_PARAM_NAME]),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -2,6 +2,7 @@ import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
|||
import { queryToObject } from '~/lib/utils/url_utility';
|
||||
import AccessorUtilities from '~/lib/utils/accessor';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import { TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
|
||||
|
||||
import {
|
||||
NEW_WORK_ITEM_IID,
|
||||
|
@ -248,6 +249,40 @@ export const getShowLabelsFromLocalStorage = (showLabelsLocalStorageKey, default
|
|||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {{fullPath?: string, referencePath?: string}} activeItem
|
||||
* @param {string} fullPath
|
||||
* @param {string} issuableType
|
||||
* @returns {string}
|
||||
*/
|
||||
export const makeDrawerItemFullPath = (activeItem, fullPath, issuableType = TYPE_ISSUE) => {
|
||||
if (activeItem?.fullPath) {
|
||||
return activeItem.fullPath;
|
||||
}
|
||||
const delimiter = issuableType === TYPE_EPIC ? '&' : '#';
|
||||
if (!activeItem?.referencePath) {
|
||||
return fullPath;
|
||||
}
|
||||
return activeItem.referencePath.split(delimiter)[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* since legacy epics don't have GID matching the work item ID, we need additional parameters
|
||||
* @param {{iid: string, id: string}} activeItem
|
||||
* @param {string} fullPath
|
||||
* @param {string} issuableType
|
||||
* @returns {{iid: string, full_path: string, id: number}}
|
||||
*/
|
||||
export const makeDrawerUrlParam = (activeItem, fullPath, issuableType = TYPE_ISSUE) => {
|
||||
return btoa(
|
||||
JSON.stringify({
|
||||
iid: activeItem.iid,
|
||||
full_path: makeDrawerItemFullPath(activeItem, fullPath, issuableType),
|
||||
id: getIdFromGraphQLId(activeItem.id),
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
export const getNewWorkItemAutoSaveKey = (fullPath, workItemType) => {
|
||||
if (!workItemType || !fullPath) return '';
|
||||
return `new-${fullPath}-${workItemType.toLowerCase()}-draft`;
|
||||
|
|
|
@ -42,6 +42,14 @@
|
|||
&.animating {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.settings-toggle svg {
|
||||
@apply gl-transition;
|
||||
}
|
||||
|
||||
&.expanded .settings-toggle svg {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
.vue-settings-block {
|
||||
|
@ -163,4 +171,4 @@
|
|||
background-color: var(--orange-50, $orange-50);
|
||||
border: 1px solid var(--orange-200, $orange-200);
|
||||
border-radius: $gl-border-radius-base;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
- if callout?
|
||||
= callout
|
||||
.gl-flex.gl-justify-between.gl-items-start.gl-gap-x-3.gl-pt-5
|
||||
.gl-shrink-0.gl-px-2.gl-py-0.-gl-mr-3.sm:gl-p-2.sm:gl-mr-0
|
||||
= render Pajamas::ButtonComponent.new(category: :tertiary, size: :small, icon: 'chevron-lg-right', icon_classes: '!-gl-mx-2', button_text_classes: 'gl-sr-only', button_options: @button_options.merge(class: 'settings-toggle js-settings-toggle', 'aria-label': aria_label)) do
|
||||
= button_text
|
||||
.gl-grow
|
||||
%h2{ class: title_classes }
|
||||
= heading || @heading
|
||||
- if description || @description
|
||||
%p.gl-text-subtle.gl-m-0
|
||||
= description || @description
|
||||
.gl-shrink-0.gl-px-2
|
||||
= render Pajamas::ButtonComponent.new(button_options: @button_options.merge(class: 'gl-min-w-12 js-settings-toggle')) do
|
||||
= button_text
|
||||
.settings-content
|
||||
.gl-mt-5
|
||||
.gl-pl-7.sm:gl-pl-8.gl-mt-5
|
||||
= body
|
||||
|
|
|
@ -41,5 +41,9 @@ module Layouts
|
|||
def button_text
|
||||
@expanded ? _('Collapse') : _('Expand')
|
||||
end
|
||||
|
||||
def aria_label
|
||||
@expanded ? "#{_('Collapse')} #{@heading}" : "#{_('Expand')} #{@heading}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
module StreamDiffs
|
||||
extend ActiveSupport::Concern
|
||||
include ActionController::Live
|
||||
include DiffHelper
|
||||
|
||||
def diffs
|
||||
return render_404 unless rapid_diffs_enabled?
|
||||
|
@ -11,7 +12,7 @@ module StreamDiffs
|
|||
|
||||
offset = { offset_index: params.permit(:offset)[:offset].to_i }
|
||||
|
||||
stream_diff_files(options.merge(offset))
|
||||
stream_diff_files(streaming_diff_options.merge(offset))
|
||||
rescue StandardError => e
|
||||
Gitlab::AppLogger.error("Error streaming diffs: #{e.message}")
|
||||
response.stream.write e.message
|
||||
|
@ -29,8 +30,8 @@ module StreamDiffs
|
|||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def options
|
||||
{}
|
||||
def streaming_diff_options
|
||||
diff_options
|
||||
end
|
||||
|
||||
def view
|
||||
|
|
|
@ -41,6 +41,7 @@ class GroupsController < Groups::ApplicationController
|
|||
push_force_frontend_feature_flag(:work_items_beta, group.work_items_beta_feature_flag_enabled?)
|
||||
push_force_frontend_feature_flag(:work_items_alpha, group.work_items_alpha_feature_flag_enabled?)
|
||||
push_frontend_feature_flag(:issues_grid_view)
|
||||
push_frontend_feature_flag(:issues_list_drawer, group)
|
||||
push_force_frontend_feature_flag(:namespace_level_work_items, group.namespace_work_items_enabled?)
|
||||
end
|
||||
|
||||
|
|
|
@ -10,11 +10,12 @@ module Projects
|
|||
commit
|
||||
end
|
||||
|
||||
def options
|
||||
opts = diff_options
|
||||
opts[:offset_index] = params.permit(:offset)[:offset].to_i
|
||||
def streaming_diff_options
|
||||
opts = super
|
||||
|
||||
opts[:ignore_whitespace_change] = true if params.permit(:format)[:format] == 'diff'
|
||||
opts[:use_extra_viewer_as_main] = false
|
||||
|
||||
opts
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,10 +11,6 @@ module Projects
|
|||
@merge_request
|
||||
end
|
||||
|
||||
def options
|
||||
{}
|
||||
end
|
||||
|
||||
def stream_diff_files(options)
|
||||
if !!ActiveModel::Type::Boolean.new.cast(params[:diff_blobs])
|
||||
stream_diff_blobs(options)
|
||||
|
|
|
@ -11,6 +11,7 @@ class ProjectSetting < ApplicationRecord
|
|||
belongs_to :project, inverse_of: :project_setting
|
||||
|
||||
scope :for_projects, ->(projects) { where(project_id: projects) }
|
||||
scope :with_namespace, -> { joins(project: :namespace) }
|
||||
|
||||
attr_encrypted :cube_api_key,
|
||||
mode: :per_attribute_iv,
|
||||
|
|
|
@ -12,6 +12,10 @@ class MergeRequests::PipelineEntity < Grape::Entity
|
|||
project_pipeline_path(pipeline.project, pipeline)
|
||||
end
|
||||
|
||||
expose :project_path do |pipeline|
|
||||
project_path(pipeline.project)
|
||||
end
|
||||
|
||||
expose :flags do
|
||||
expose :merged_result_pipeline?, as: :merge_request_pipeline # deprecated, use merged_result_pipeline going forward
|
||||
expose :merged_result_pipeline?, as: :merged_result_pipeline
|
||||
|
|
|
@ -6,6 +6,7 @@ module Import
|
|||
MEMBER_DELETE_BATCH_SIZE = 1_000
|
||||
GROUP_FINDER_MEMBER_RELATIONS = %i[direct inherited shared_from_groups].freeze
|
||||
PROJECT_FINDER_MEMBER_RELATIONS = %i[direct inherited invited_groups shared_into_ancestors].freeze
|
||||
RELATION_BATCH_SLEEP = 5
|
||||
|
||||
def initialize(import_source_user)
|
||||
@import_source_user = import_source_user
|
||||
|
@ -73,6 +74,9 @@ module Import
|
|||
user_reference_column: user_reference_column
|
||||
) do |model_relation, placeholder_references|
|
||||
reassign_placeholder_records_batch(model_relation, placeholder_references, user_reference_column)
|
||||
|
||||
# TODO: Remove with https://gitlab.com/gitlab-org/gitlab/-/issues/493977
|
||||
Kernel.sleep RELATION_BATCH_SLEEP
|
||||
end
|
||||
rescue NameError => e
|
||||
::Import::Framework::Logger.error(
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
id: 'js-gitpod-settings',
|
||||
expanded: expanded) do |c|
|
||||
- c.with_description do
|
||||
#js-gitpod-settings-help-text{ data: {"message" => gitpod_enable_description, "message-url" => "https://gitpod.io/" } }
|
||||
%span#js-gitpod-settings-help-text{ data: {"message" => gitpod_enable_description, "message-url" => "https://gitpod.io/" } }
|
||||
= link_to sprite_icon('question-o'), help_page_path('integration/gitpod.md'), target: '_blank', class: 'has-tooltip', title: _('More information')
|
||||
- c.with_body do
|
||||
= gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-gitpod-settings'), html: { class: 'fieldset-form', id: 'gitpod-settings' } do |f|
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
- if group.linked_to_subscription?
|
||||
= render Pajamas::AlertComponent.new(variant: :tip, dismissible: false, alert_options: { class: 'gl-mb-5', data: { testid: 'group-has-linked-subscription-alert' }}) do |c|
|
||||
- c.with_body do
|
||||
= html_escape(_("This group can't be removed because it is linked to a subscription. To remove this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "<a href=\"#{help_page_path('subscriptions/gitlab_com/index.md', anchor: 'change-the-linked-group')}\">".html_safe, linkEnd: '</a>'.html_safe }
|
||||
= html_escape(_("This group can't be removed because it is linked to a subscription. To remove this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "<a href=\"#{help_page_path('subscriptions/gitlab_com/index.md', anchor: 'link-subscription-to-a-group')}\">".html_safe, linkEnd: '</a>'.html_safe }
|
||||
|
||||
.js-confirm-danger{ data: group_confirm_modal_data(group: group, remove_form_id: remove_form_id) }
|
||||
|
|
|
@ -21,5 +21,5 @@
|
|||
- if group.paid?
|
||||
= render Pajamas::AlertComponent.new(variant: :tip, dismissible: false, alert_options: { class: 'gl-mb-5' }) do |c|
|
||||
- c.with_body do
|
||||
= html_escape(_("This group can't be transferred because it is linked to a subscription. To transfer this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "<a href=\"#{help_page_path('subscriptions/gitlab_com/index.md', anchor: 'change-the-linked-group')}\">".html_safe, linkEnd: '</a>'.html_safe }
|
||||
= html_escape(_("This group can't be transferred because it is linked to a subscription. To transfer this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "<a href=\"#{help_page_path('subscriptions/gitlab_com/index.md', anchor: 'link-subscription-to-a-group')}\">".html_safe, linkEnd: '</a>'.html_safe }
|
||||
.js-transfer-group-form{ data: initial_data }
|
||||
|
|
|
@ -12,6 +12,9 @@ module Import
|
|||
sidekiq_options retry: 5, dead: false
|
||||
sidekiq_options max_retries_after_interruption: 20
|
||||
|
||||
# TODO: Remove with https://gitlab.com/gitlab-org/gitlab/-/issues/493977
|
||||
concurrency_limit -> { 4 }
|
||||
|
||||
sidekiq_retries_exhausted do |msg, exception|
|
||||
new.perform_failure(exception, msg['args'])
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ class PostReceive
|
|||
|
||||
idempotent!
|
||||
deduplicate :none
|
||||
data_consistency :sticky, feature_flag: :load_balanacing_for_sticky_post_receive_worker
|
||||
data_consistency :sticky
|
||||
|
||||
sidekiq_options retry: 3
|
||||
include Gitlab::Experiment::Dsl
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
api_type:
|
||||
attr: allow_top_level_group_owners_to_create_service_accounts
|
||||
clusterwide: false
|
||||
column: allow_top_level_group_owners_to_create_service_accounts
|
||||
db_type: boolean
|
||||
default: 'false'
|
||||
description:
|
||||
encrypted: false
|
||||
gitlab_com_different_than_default: false
|
||||
jihu: false
|
||||
not_null: true
|
|
@ -8,6 +8,6 @@ default: "'{}'::jsonb"
|
|||
description: "[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/408314) in
|
||||
GitLab 17.0. For available options, see [Options for `default_branch_protection_defaults`](groups.md#options-for-default_branch_protection_defaults)."
|
||||
encrypted: false
|
||||
gitlab_com_different_than_default: false
|
||||
gitlab_com_different_than_default: true
|
||||
jihu: false
|
||||
not_null: true
|
||||
|
|
|
@ -10,6 +10,6 @@ description: Specifies whether users who have not confirmed their email should b
|
|||
`unconfirmed_users_delete_after_days` days. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352514)
|
||||
in GitLab 16.1. Self-managed, Premium and Ultimate only.
|
||||
encrypted: false
|
||||
gitlab_com_different_than_default: false
|
||||
gitlab_com_different_than_default: true
|
||||
jihu: false
|
||||
not_null: true
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
---
|
||||
api_type:
|
||||
api_type: boolean
|
||||
attr: pre_receive_secret_detection_enabled
|
||||
clusterwide: true
|
||||
column: pre_receive_secret_detection_enabled
|
||||
db_type: boolean
|
||||
default: 'false'
|
||||
description:
|
||||
description: Allow projects to enable secret push protection. This does not enable
|
||||
secret push protection. When you enable this feature, you accept the [GitLab Testing
|
||||
Agreement](https://handbook.gitlab.com/handbook/legal/testing-agreement/). Ultimate
|
||||
only.
|
||||
encrypted: false
|
||||
gitlab_com_different_than_default: true
|
||||
jihu: false
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
name: load_balanacing_for_sticky_post_receive_worker
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/402254
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/167317
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/495040
|
||||
milestone: '17.5'
|
||||
group: group::source code
|
||||
type: worker
|
||||
default_enabled: false
|
|
@ -0,0 +1,37 @@
|
|||
- title: "GitLab Runner Docker Machine executor is deprecated"
|
||||
# The milestones for the deprecation announcement, and the removal.
|
||||
removal_milestone: "20.0"
|
||||
announcement_milestone: "17.5"
|
||||
# Change breaking_change to false if needed.
|
||||
breaking_change: true
|
||||
# The stage and GitLab username of the person reporting the change,
|
||||
# and a link to the deprecation issue
|
||||
reporter: DarrenEastman
|
||||
stage: verify
|
||||
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/498268
|
||||
# Use the impact calculator https://gitlab-com.gitlab.io/gl-infra/breaking-change-impact-calculator/?
|
||||
impact: medium
|
||||
scope: [instance, group, project]
|
||||
resolution_role: [Admin, Owner, Maintainer]
|
||||
manual_task: true
|
||||
body: | # (required) Don't change this line.
|
||||
The [GitLab Runner Docker Machine executor](https://docs.gitlab.com/runner/executors/docker_machine.html) is deprecated and will be fully removed from the product as a supported feature in GitLab 20.0 (May 2027). The replacement for Docker Machine, [GitLab Runner Autoscaler](https://docs.gitlab.com/runner/runner_autoscale/) with GitLab developed plugins for Amazon Web Services (AWS) EC2, Google Compute Engine (GCE) and Microsoft Azure virtual machines (VMs) is generally available. With this announcement, the GitLab Runner team will no longer accept community contributions for the GitLab maintained Docker Machine fork, or resolve newly identified bugs.
|
||||
|
||||
# ==============================
|
||||
# OPTIONAL END-OF-SUPPORT FIELDS
|
||||
# ==============================
|
||||
#
|
||||
# If an End of Support period applies:
|
||||
# 1) Share this announcement in the `#spt_managers` Support channel in Slack
|
||||
# 2) Mention `@gitlab-com/support` in this merge request.
|
||||
#
|
||||
# When support for this feature ends, in XX.YY milestone format.
|
||||
end_of_support_milestone:
|
||||
# Array of tiers the feature is currently available to,
|
||||
# like [Free, Silver, Gold, Core, Premium, Ultimate]
|
||||
tiers:
|
||||
# Links to documentation and thumbnail image
|
||||
documentation_url:
|
||||
image_url:
|
||||
# Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
|
||||
video_url:
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
migration_job_name: RequeueBackfillPCiPipelineVariablesProjectId
|
||||
description: Requeue backfill sharding key `p_ci_pipeline_variables.project_id` from `p_ci_pipelines` for gitlab.com
|
||||
feature_category: continuous_integration
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/168493
|
||||
milestone: '17.5'
|
||||
queued_migration_version: 20241008064311
|
||||
finalized_by: # version of the migration that finalized this BBM
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddTempMigratingColumnToNamespaceHistoricalStatistics < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.5'
|
||||
|
||||
def up
|
||||
add_column :vulnerability_namespace_historical_statistics, :migrating, :boolean, default: false, null: false
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :vulnerability_namespace_historical_statistics, :migrating
|
||||
end
|
||||
end
|
|
@ -0,0 +1,36 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RequeueBackfillPCiPipelineVariablesProjectId < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.5'
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_ci
|
||||
|
||||
MIGRATION = "BackfillPCiPipelineVariablesProjectId"
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
BATCH_SIZE = 75_000
|
||||
SUB_BATCH_SIZE = 250
|
||||
TABLE_NAME = :p_ci_pipeline_variables
|
||||
BATCH_COLUMN = :id
|
||||
JOB_ARGS = %i[project_id p_ci_pipelines project_id pipeline_id partition_id]
|
||||
|
||||
def up
|
||||
return unless Gitlab.com_except_jh?
|
||||
|
||||
delete_batched_background_migration(MIGRATION, TABLE_NAME, BATCH_COLUMN, JOB_ARGS)
|
||||
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
TABLE_NAME,
|
||||
BATCH_COLUMN,
|
||||
*JOB_ARGS,
|
||||
job_interval: DELAY_INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
return unless Gitlab.com_except_jh?
|
||||
|
||||
delete_batched_background_migration(MIGRATION, TABLE_NAME, BATCH_COLUMN, JOB_ARGS)
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
5485b5a71ea889318831649bbdbc829b0565e7c01126cf9907544f6e39450bae
|
|
@ -0,0 +1 @@
|
|||
201b3763cefe1ada643eb517712f354aa4c10a7c872d99357e6e2b48848bf2d8
|
|
@ -20658,7 +20658,8 @@ CREATE TABLE vulnerability_namespace_historical_statistics (
|
|||
unknown integer DEFAULT 0 NOT NULL,
|
||||
info integer DEFAULT 0 NOT NULL,
|
||||
date date NOT NULL,
|
||||
letter_grade smallint NOT NULL
|
||||
letter_grade smallint NOT NULL,
|
||||
migrating boolean DEFAULT false NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE vulnerability_namespace_historical_statistics_id_seq
|
||||
|
|
|
@ -182,6 +182,8 @@ Backups do not include:
|
|||
- [Mattermost data](../../integration/mattermost/index.md#back-up-gitlab-mattermost)
|
||||
- Redis (and thus Sidekiq jobs)
|
||||
- [Object storage](#object-storage) on Linux package (Omnibus) / Docker / Self-compiled installations
|
||||
- [Global server hooks](../server_hooks.md#create-global-server-hooks-for-all-repositories)
|
||||
- [File hooks](../file_hooks.md)
|
||||
|
||||
WARNING:
|
||||
GitLab does not back up any configuration files (`/etc/gitlab`), TLS keys and certificates, or system
|
||||
|
|
|
@ -454,8 +454,12 @@ You can use the [AWS CLI](https://aws.amazon.com/cli/) to verify that access to
|
|||
|
||||
The S3 bucket contains a combination of **infrastructure logs** and **application logs** from the GitLab [log system](../../administration/logs/index.md). The logs in the bucket are encrypted using an AWS KMS key that is managed by GitLab. If you choose to enable [BYOK](../../administration/dedicated/create_instance.md#encrypted-data-at-rest-byok), the application logs are not encrypted with the key you provide.
|
||||
|
||||
<!-- vale gitlab_base.Spelling = NO -->
|
||||
|
||||
The logs in the S3 bucket are organized by date in `YYYY/MM/DD/HH` format. For example, there would be a directory like `2023/10/12/13`. That directory would contain the logs from October 12, 2023 at 1300 UTC. The logs are streamed into the bucket with [Amazon Kinesis Data Firehose](https://aws.amazon.com/firehose/).
|
||||
|
||||
<!-- vale gitlab_base.Spelling = YES -->
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Outbound Private Link
|
||||
|
|
|
@ -596,7 +596,7 @@ If one or more of these values is significantly high, this could indicate a prob
|
|||
If you get a **secondary** site in a broken state and want to reset the replication state,
|
||||
to start again from scratch, there are a few steps that can help you:
|
||||
|
||||
1. Stop Sidekiq and the Geo LogCursor.
|
||||
1. Stop Sidekiq and the Geo Log Cursor.
|
||||
|
||||
It's possible to make Sidekiq stop gracefully, but making it stop getting new jobs and
|
||||
wait until the current jobs to finish processing.
|
||||
|
|
|
@ -59,7 +59,7 @@ When running Gitaly in Kubernetes, you must:
|
|||
|
||||
A pod can rotate for many reasons. Understanding and planing the service lifecycle helps minimize disruption.
|
||||
|
||||
For example, in Gitaly's case, a Kubernetes `StatefulSet` rotates on `spec.template` object changes, which can happen during Helm Chart upgrades (labels, or image tag) or pod resource requests or limits updates.
|
||||
For example, with Gitaly, a Kubernetes `StatefulSet` rotates on `spec.template` object changes, which can happen during Helm Chart upgrades (labels, or image tag) or pod resource requests or limits updates.
|
||||
|
||||
This section focuses on common pod disruption cases and how to address them.
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ staggered across Gitaly nodes so the scheduled housekeeping is not running
|
|||
simultaneously on multiple nodes.
|
||||
|
||||
If a scheduled housekeeping run reaches the `duration` specified, the running tasks are
|
||||
gracefully cancelled. On subsequent scheduled housekeeping runs, Gitaly randomly shuffles
|
||||
gracefully canceled. On subsequent scheduled housekeeping runs, Gitaly randomly shuffles
|
||||
the repository list to process.
|
||||
|
||||
The following snippet enables daily background repository maintenance starting at
|
||||
|
|
|
@ -178,7 +178,7 @@ For more information, see [user deactivation emails](../administration/settings/
|
|||
To deactivate users with the GitLab API, see [deactivate user](../api/user_moderation.md#deactivate-a-user). For information about permanent user restrictions, see [block and unblock users](#block-and-unblock-users).
|
||||
|
||||
To remove a user from a GitLab.com subscription, see
|
||||
[Remove users from your subscription](../subscriptions/gitlab_com/index.md#remove-users-from-your-subscription).
|
||||
[Remove users from your subscription](../subscriptions/gitlab_com/index.md#remove-users-from-subscription).
|
||||
|
||||
### Automatically deactivate dormant users
|
||||
|
||||
|
|
|
@ -30,9 +30,13 @@ to the UI. This is properly balanced and scheduled, and therefore is
|
|||
a better indicator of effective uptime. You can also monitor the sign-in
|
||||
page `/users/sign_in` endpoint.
|
||||
|
||||
<!-- vale gitlab_base.Spelling = NO -->
|
||||
|
||||
On GitLab.com, tools such as [Pingdom](https://www.pingdom.com/) and
|
||||
Apdex measurements are used to determine uptime.
|
||||
|
||||
<!-- vale gitlab_base.Spelling = YES -->
|
||||
|
||||
## IP allowlist
|
||||
|
||||
To access monitoring resources, the requesting client IP needs to be included in the allowlist.
|
||||
|
|
|
@ -561,7 +561,7 @@ To enable it:
|
|||
1. On the left sidebar, at the bottom, select **Admin**.
|
||||
1. Select **Settings > Preferences**.
|
||||
1. Expand **Pages**.
|
||||
1. Enter the email address for receiving notifications and accept Let's Encrypt's Terms of Service.
|
||||
1. Enter the email address for receiving notifications and accept the Terms of Service for Let's Encrypt.
|
||||
1. Select **Save changes**.
|
||||
|
||||
### Access control
|
||||
|
|
|
@ -1526,8 +1526,8 @@ input/output operations per second (IOPS) for read operations and 2,000 IOPS for
|
|||
write operations. If you're running the environment on a Cloud provider,
|
||||
refer to their documentation about how to configure IOPS correctly.
|
||||
|
||||
Gitaly servers must not be exposed to the public internet, as Gitaly's network
|
||||
traffic is unencrypted by default. The use of a firewall is highly recommended
|
||||
Gitaly servers must not be exposed to the public internet, as network traffic
|
||||
on Gitaly is unencrypted by default. The use of a firewall is highly recommended
|
||||
to restrict access to the Gitaly server. Another option is to
|
||||
[use TLS](#gitaly-cluster-tls-support).
|
||||
|
||||
|
|
|
@ -1532,8 +1532,8 @@ input/output operations per second (IOPS) for read operations and 2,000 IOPS for
|
|||
write operations. If you're running the environment on a Cloud provider,
|
||||
refer to their documentation about how to configure IOPS correctly.
|
||||
|
||||
Gitaly servers must not be exposed to the public internet, as Gitaly's network
|
||||
traffic is unencrypted by default. The use of a firewall is highly recommended
|
||||
Gitaly servers must not be exposed to the public internet, as network traffic
|
||||
on Gitaly is unencrypted by default. The use of a firewall is highly recommended
|
||||
to restrict access to the Gitaly server. Another option is to
|
||||
[use TLS](#gitaly-cluster-tls-support).
|
||||
|
||||
|
|
|
@ -444,8 +444,8 @@ Be sure to note the following items:
|
|||
- A GitLab server can use one or more Gitaly server nodes.
|
||||
- Gitaly addresses must be specified to be correctly resolvable for *all*
|
||||
Gitaly clients.
|
||||
- Gitaly servers must not be exposed to the public internet, as Gitaly's network
|
||||
traffic is unencrypted by default. The use of a firewall is highly recommended
|
||||
- Gitaly servers must not be exposed to the public internet, as network traffic
|
||||
on Gitaly is unencrypted by default. The use of a firewall is highly recommended
|
||||
to restrict access to the Gitaly server. Another option is to
|
||||
[use TLS](#gitaly-tls-support).
|
||||
|
||||
|
|
|
@ -1362,8 +1362,8 @@ input/output operations per second (IOPS) for read operations and 2,000 IOPS for
|
|||
write operations. If you're running the environment on a Cloud provider,
|
||||
refer to their documentation about how to configure IOPS correctly.
|
||||
|
||||
Gitaly servers must not be exposed to the public internet, as Gitaly's network
|
||||
traffic is unencrypted by default. The use of a firewall is highly recommended
|
||||
Gitaly servers must not be exposed to the public internet, as network traffic
|
||||
on Gitaly is unencrypted by default. The use of a firewall is highly recommended
|
||||
to restrict access to the Gitaly server. Another option is to
|
||||
[use TLS](#gitaly-cluster-tls-support).
|
||||
|
||||
|
@ -2127,13 +2127,13 @@ If not stated below, no other modifications are supported for lower use counts.
|
|||
- Combining select nodes: The following specific components are supported to be combined onto the same nodes to reduce complexity at the cost of some performance:
|
||||
- GitLab Rails and Sidekiq: Sidekiq nodes can be removed, and the component instead enabled on the GitLab Rails nodes.
|
||||
- PostgreSQL and PgBouncer: PgBouncer nodes could be removed and instead be enabled on PostgreSQL nodes with the Internal Load Balancer pointing to them. However, to enable [Database Load Balancing](../postgresql/database_load_balancing.md), a separate PgBouncer array is still required.
|
||||
- Reducing the node counts: Some node types do not need consensus and can run with fewer nodes (but more than one for redundancy). This will also lead to reduced performance.
|
||||
- Reducing the node counts: Some node types do not need consensus and can run with fewer nodes (but more than one for redundancy):
|
||||
- GitLab Rails and Sidekiq: Stateless services don't have a minimum node count. Two are enough for redundancy.
|
||||
- PostgreSQL and PgBouncer: A quorum is not strictly necessary. Two PostgreSQL nodes and two PgBouncer nodes are enough for redundancy.
|
||||
- Consul, Redis Sentinel, and Praefect: Require an odd number, and a minimum of three nodes, for a voting quorum.
|
||||
- Running select components in reputable Cloud PaaS solutions: The following specific components are supported to be run on reputable Cloud Provider PaaS solutions. By doing this, additional dependent components can also be removed:
|
||||
- PostgreSQL: Can be run on reputable Cloud PaaS solutions such as Google Cloud SQL or Amazon RDS. In this setup, the PgBouncer and Consul nodes are no longer required:
|
||||
- Consul may still be desired if [Prometheus](../monitoring/prometheus/index.md) auto discovery is a requirement, otherwise you would need to [manually add scrape configurations](../monitoring/prometheus/index.md#adding-custom-scrape-configurations) for all nodes.
|
||||
- As Redis Sentinel runs on the same box as Consul in this architecture, it may need to be run on a separate box if Redis is still being run using the Linux package.
|
||||
- Redis: Can be run on reputable Cloud PaaS solutions such as Google Memorystore and AWS ElastiCache. In this setup, the Redis Sentinel is no longer required.
|
||||
|
||||
## Cloud Native Hybrid reference architecture with Helm Charts (alternative)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue