Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-04-14 15:09:04 +00:00
parent 7f408a3831
commit a3dfd311f4
223 changed files with 3024 additions and 1628 deletions

View File

@ -555,6 +555,7 @@
when: never
- <<: *if-merge-request
changes: *db-patterns
when: manual
.rails:rules:ee-and-foss-unit:
rules:

View File

@ -1,6 +1,6 @@
workhorse:verify:
extends: .workhorse:rules:workhorse
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.15
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.16
stage: test
needs: []
script:
@ -23,14 +23,10 @@ workhorse:verify:
- apt-get update && apt-get -y install libimage-exiftool-perl
- make -C workhorse test
workhorse:test using go 1.13:
extends: .workhorse:test
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.13
workhorse:test using go 1.14:
extends: .workhorse:test
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.14
workhorse:test using go 1.15:
extends: .workhorse:test
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.15
workhorse:test using go 1.16:
extends: .workhorse:test
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.16

View File

@ -73,9 +73,6 @@ Rails/SaveBang:
- 'ee/spec/models/elasticsearch_indexed_namespace_spec.rb'
- 'ee/spec/models/environment_spec.rb'
- 'ee/spec/models/epic_spec.rb'
- 'ee/spec/models/geo/project_registry_spec.rb'
- 'ee/spec/models/geo_node_spec.rb'
- 'ee/spec/models/geo_node_status_spec.rb'
- 'ee/spec/models/gitlab_subscription_spec.rb'
- 'ee/spec/models/issue_spec.rb'
- 'ee/spec/models/label_note_spec.rb'
@ -431,8 +428,6 @@ RSpec/EmptyLineAfterFinalLetItBe:
- ee/spec/controllers/projects/merge_requests_controller_spec.rb
- ee/spec/controllers/projects/mirrors_controller_spec.rb
- ee/spec/controllers/projects/threat_monitoring_controller_spec.rb
- ee/spec/controllers/registrations/groups_controller_spec.rb
- ee/spec/controllers/registrations/projects_controller_spec.rb
- ee/spec/controllers/subscriptions_controller_spec.rb
- ee/spec/features/boards/group_boards/multiple_boards_spec.rb
- ee/spec/features/ci_shared_runner_warnings_spec.rb
@ -597,9 +592,6 @@ RSpec/EmptyLineAfterFinalLetItBe:
- ee/spec/services/requirements_management/update_requirement_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/security/auto_fix_label_service_spec.rb
- ee/spec/services/security/store_grouped_scans_service_spec.rb
- ee/spec/services/security/store_report_service_spec.rb
- ee/spec/services/status_page/publish_attachments_service_spec.rb
- ee/spec/services/status_page/publish_details_service_spec.rb
- ee/spec/services/status_page/publish_list_service_spec.rb
@ -905,36 +897,11 @@ RSpec/EmptyLineAfterFinalLetItBe:
- spec/requests/lfs_http_spec.rb
- spec/requests/product_analytics/collector_app_spec.rb
- spec/requests/rack_attack_global_spec.rb
- spec/serializers/admin/user_entity_spec.rb
- spec/serializers/ci/lint/result_serializer_spec.rb
- spec/serializers/ci/pipeline_entity_spec.rb
- spec/serializers/container_repository_entity_spec.rb
- spec/serializers/container_tag_entity_spec.rb
- spec/serializers/deployment_serializer_spec.rb
- spec/serializers/diff_file_entity_spec.rb
- spec/serializers/evidences/evidence_entity_spec.rb
- spec/serializers/fork_namespace_entity_spec.rb
- spec/serializers/group_link/group_group_link_entity_spec.rb
- spec/serializers/group_link/project_group_link_entity_spec.rb
- spec/serializers/issue_board_entity_spec.rb
- spec/serializers/member_entity_spec.rb
- spec/serializers/member_user_entity_spec.rb
- spec/serializers/merge_request_diff_entity_spec.rb
- spec/serializers/merge_request_poll_cached_widget_entity_spec.rb
- spec/serializers/merge_request_user_entity_spec.rb
- spec/serializers/namespace_basic_entity_spec.rb
- spec/serializers/pipeline_details_entity_spec.rb
- spec/serializers/project_import_entity_spec.rb
- spec/serializers/project_serializer_spec.rb
- spec/serializers/review_app_setup_entity_spec.rb
- spec/services/admin/propagate_service_template_spec.rb
- spec/services/alert_management/create_alert_issue_service_spec.rb
- spec/services/audit_event_service_spec.rb
- spec/services/auth/dependency_proxy_authentication_service_spec.rb
- spec/services/auto_merge_service_spec.rb
- spec/services/award_emojis/add_service_spec.rb
- spec/services/award_emojis/destroy_service_spec.rb
- spec/services/award_emojis/toggle_service_spec.rb
- spec/services/boards/destroy_service_spec.rb
- spec/services/boards/issues/move_service_spec.rb
- spec/services/bulk_create_integration_service_spec.rb
@ -968,9 +935,6 @@ RSpec/EmptyLineAfterFinalLetItBe:
- spec/services/design_management/save_designs_service_spec.rb
- spec/services/discussions/resolve_service_spec.rb
- spec/services/discussions/unresolve_service_spec.rb
- spec/services/environments/auto_stop_service_spec.rb
- spec/services/environments/canary_ingress/update_service_spec.rb
- spec/services/environments/reset_auto_stop_service_spec.rb
- spec/services/feature_flags/create_service_spec.rb
- spec/services/feature_flags/destroy_service_spec.rb
- spec/services/feature_flags/disable_service_spec.rb

View File

@ -2,6 +2,15 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 13.10.3 (2021-04-13)
### Security (3 changes)
- Check image content type before running exiftool in workhorse.
- Clean only legitimate JPG and TIFF files.
- Update ruby-saml and rexml gems.
## 13.10.2 (2021-04-01)
### Fixed (1 change)
@ -562,6 +571,14 @@ entry.
- Convert mattermost alert to pajamas. !56556
## 13.9.6 (2021-04-13)
### Security (2 changes)
- Clean only legitimate JPG and TIFF files.
- Update ruby-saml and rexml gems.
## 13.9.5 (2021-03-31)
### Security (6 changes)
@ -1199,6 +1216,14 @@ entry.
- Apply new GitLab UI for buttons in pipeline schedules.
## 13.8.8 (2021-04-13)
### Security (2 changes)
- Clean only legitimate JPG and TIFF files.
- Update ruby-saml and rexml gems.
## 13.8.7 (2021-03-31)
### Security (5 changes)

View File

@ -28,6 +28,8 @@ gem 'devise', '~> 4.7.2'
gem 'bcrypt', '~> 3.1', '>= 3.1.14'
gem 'doorkeeper', '~> 5.5.0.rc2'
gem 'doorkeeper-openid_connect', '~> 1.7.5'
gem 'rexml', '~> 3.2.5'
gem 'ruby-saml', '~> 1.12.1'
gem 'omniauth', '~> 1.8'
gem 'omniauth-auth0', '~> 2.0.0'
gem 'omniauth-azure-activedirectory-v2', '~> 0.1'
@ -298,7 +300,7 @@ gem 'gon', '~> 6.4.0'
gem 'request_store', '~> 1.5'
gem 'base32', '~> 0.3.0'
gem "gitlab-license", "~> 1.3"
gem "gitlab-license", "~> 1.4"
# Protect against bruteforcing
gem 'rack-attack', '~> 6.3.0'

View File

@ -475,7 +475,7 @@ GEM
opentracing (~> 0.4)
pg_query (~> 1.3)
redis (> 3.0.0, < 5.0.0)
gitlab-license (1.3.1)
gitlab-license (1.4.0)
gitlab-mail_room (0.0.9)
gitlab-markup (1.7.1)
gitlab-net-dns (0.9.1)
@ -1050,7 +1050,7 @@ GEM
retriable (3.1.2)
reverse_markdown (1.4.0)
nokogiri
rexml (3.2.4)
rexml (3.2.5)
rinku (2.0.0)
rotp (6.2.0)
rouge (3.26.0)
@ -1125,8 +1125,9 @@ GEM
mini_portile2 (~> 2.5.0)
ruby-prof (1.3.1)
ruby-progressbar (1.11.0)
ruby-saml (1.7.2)
nokogiri (>= 1.5.10)
ruby-saml (1.12.1)
nokogiri (>= 1.10.5)
rexml
ruby-statistics (2.1.2)
ruby2_keywords (0.0.2)
ruby_parser (3.15.0)
@ -1436,7 +1437,7 @@ DEPENDENCIES
gitlab-fog-azure-rm (~> 1.0.1)
gitlab-fog-google (~> 1.13)
gitlab-labkit (~> 0.16.2)
gitlab-license (~> 1.3)
gitlab-license (~> 1.4)
gitlab-mail_room (~> 0.0.9)
gitlab-markup (~> 1.7.1)
gitlab-net-dns (~> 0.9.1)
@ -1561,6 +1562,7 @@ DEPENDENCIES
request_store (~> 1.5)
responders (~> 3.0)
retriable (~> 3.1.2)
rexml (~> 3.2.5)
rouge (~> 3.26.0)
rqrcode-rails3 (~> 0.1.7)
rspec-parameterized
@ -1572,6 +1574,7 @@ DEPENDENCIES
ruby-magic (~> 0.4)
ruby-prof (~> 1.3.0)
ruby-progressbar (~> 1.10)
ruby-saml (~> 1.12.1)
ruby_parser (~> 3.15)
rubyzip (~> 2.0.0)
rugged (~> 1.1)

View File

@ -0,0 +1,15 @@
import $ from 'jquery';
export default function initDeprecatedRemoveRowBehavior() {
$('.js-remove-row').on('ajax:success', function removeRowAjaxSuccessCallback() {
$(this).closest('li').addClass('gl-display-none!');
});
$('.js-remove-tr').on('ajax:before', function removeTRAjaxBeforeCallback() {
$(this).parent().find('.btn').addClass('disabled');
});
$('.js-remove-tr').on('ajax:success', function removeTRAjaxSuccessCallback() {
$(this).closest('tr').addClass('gl-display-none!');
});
}

View File

@ -21,26 +21,30 @@ export default {
components: {
GlToggle,
},
inject: ['emailsDisabled'],
data() {
return {
loading: false,
};
},
computed: {
...mapGetters(['activeBoardItem', 'projectPathForActiveIssue']),
...mapGetters(['activeBoardItem', 'projectPathForActiveIssue', 'isEpicBoard']),
isEmailsDisabled() {
return this.isEpicBoard ? this.emailsDisabled : this.activeBoardItem.emailsDisabled;
},
notificationText() {
return this.activeBoardItem.emailsDisabled
return this.isEmailsDisabled
? this.$options.i18n.header.subscribeDisabledDescription
: this.$options.i18n.header.title;
},
},
methods: {
...mapActions(['setActiveIssueSubscribed']),
...mapActions(['setActiveItemSubscribed']),
async handleToggleSubscription() {
this.loading = true;
try {
await this.setActiveIssueSubscribed({
await this.setActiveItemSubscribed({
subscribed: !this.activeBoardItem.subscribed,
projectPath: this.projectPathForActiveIssue,
});
@ -61,7 +65,7 @@ export default {
>
<span data-testid="notification-header-text"> {{ notificationText }} </span>
<gl-toggle
v-if="!activeBoardItem.emailsDisabled"
v-if="!isEmailsDisabled"
:value="activeBoardItem.subscribed"
:is-loading="loading"
:label="$options.i18n.header.title"

View File

@ -1,6 +1,8 @@
import { __ } from '~/locale';
import updateEpicSubscriptionMutation from '~/sidebar/queries/update_epic_subscription.mutation.graphql';
import updateEpicTitleMutation from '~/sidebar/queries/update_epic_title.mutation.graphql';
import boardBlockingIssuesQuery from './graphql/board_blocking_issues.query.graphql';
import issueSetSubscriptionMutation from './graphql/issue_set_subscription.mutation.graphql';
import issueSetTitleMutation from './graphql/issue_set_title.mutation.graphql';
export const issuableTypes = {
@ -63,3 +65,12 @@ export const titleQueries = {
mutation: updateEpicTitleMutation,
},
};
export const subscriptionQueries = {
[issuableTypes.issue]: {
mutation: issueSetSubscriptionMutation,
},
[issuableTypes.epic]: {
mutation: updateEpicSubscriptionMutation,
},
};

View File

@ -1,5 +1,5 @@
mutation issueSetSubscription($input: IssueSetSubscriptionInput!) {
issueSetSubscription(input: $input) {
updateIssuableSubscription: issueSetSubscription(input: $input) {
issue {
subscribed
}

View File

@ -95,6 +95,7 @@ export default () => {
assigneeListsAvailable: parseBoolean($boardApp.dataset.assigneeListsAvailable),
iterationListsAvailable: parseBoolean($boardApp.dataset.iterationListsAvailable),
issuableType: issuableTypes.issue,
emailsDisabled: parseBoolean($boardApp.dataset.emailsDisabled),
},
store,
apolloProvider,

View File

@ -10,6 +10,7 @@ import {
flashAnimationDuration,
ISSUABLE,
titleQueries,
subscriptionQueries,
} from '~/boards/constants';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import createGqClient, { fetchPolicies } from '~/lib/graphql';
@ -35,7 +36,6 @@ import issueCreateMutation from '../graphql/issue_create.mutation.graphql';
import issueSetDueDateMutation from '../graphql/issue_set_due_date.mutation.graphql';
import issueSetLabelsMutation from '../graphql/issue_set_labels.mutation.graphql';
import issueSetMilestoneMutation from '../graphql/issue_set_milestone.mutation.graphql';
import issueSetSubscriptionMutation from '../graphql/issue_set_subscription.mutation.graphql';
import listsIssuesQuery from '../graphql/lists_issues.query.graphql';
import * as types from './mutation_types';
@ -597,26 +597,31 @@ export default {
});
},
setActiveIssueSubscribed: async ({ commit, getters }, input) => {
setActiveItemSubscribed: async ({ commit, getters, state }, input) => {
const { activeBoardItem, isEpicBoard } = getters;
const { fullPath, issuableType } = state;
const workspacePath = isEpicBoard
? { groupPath: fullPath }
: { projectPath: input.projectPath };
const { data } = await gqlClient.mutate({
mutation: issueSetSubscriptionMutation,
mutation: subscriptionQueries[issuableType].mutation,
variables: {
input: {
iid: String(getters.activeBoardItem.iid),
projectPath: input.projectPath,
...workspacePath,
iid: String(activeBoardItem.iid),
subscribedState: input.subscribed,
},
},
});
if (data.issueSetSubscription?.errors?.length > 0) {
throw new Error(data.issueSetSubscription.errors);
if (data.updateIssuableSubscription?.errors?.length > 0) {
throw new Error(data.updateIssuableSubscription[issuableType].errors);
}
commit(types.UPDATE_BOARD_ITEM_BY_ID, {
itemId: getters.activeBoardItem.id,
itemId: activeBoardItem.id,
prop: 'subscribed',
value: data.issueSetSubscription.issue.subscribed,
value: data.updateIssuableSubscription[issuableType].subscribed,
});
},

View File

@ -185,6 +185,7 @@ export default {
'mrReviews',
]),
...mapGetters('diffs', ['whichCollapsedTypes', 'isParallelView', 'currentDiffIndex']),
...mapGetters('batchComments', ['draftsCount']),
...mapGetters(['isNotesFetched', 'getNoteableData']),
diffs() {
if (!this.viewDiffsFileByFile) {
@ -500,6 +501,7 @@ export default {
<div
v-if="renderFileTree"
:style="{ width: `${treeWidth}px` }"
:class="{ 'review-bar-visible': draftsCount > 0 }"
class="diff-tree-list js-diff-tree-list px-3 pr-md-0"
>
<panel-resizer

View File

@ -1,24 +1,5 @@
import axios from 'axios';
export const getJwt = () => {
return new Promise((resolve) => {
AP.context.getToken((token) => {
resolve(token);
});
});
};
export const getLocation = () => {
return new Promise((resolve) => {
if (typeof AP.getLocation !== 'function') {
resolve();
}
AP.getLocation((location) => {
resolve(location);
});
});
};
import { getJwt } from '~/jira_connect/utils';
export const addSubscription = async (addPath, namespace) => {
const jwt = await getJwt();

View File

@ -1,22 +1,23 @@
<script>
import { GlAlert, GlButton, GlModal, GlModalDirective, GlLink, GlSprintf } from '@gitlab/ui';
import { GlAlert, GlButton, GlLink, GlModal, GlModalDirective, GlSprintf } from '@gitlab/ui';
import { mapState, mapMutations } from 'vuex';
import { getLocation } from '~/jira_connect/api';
import { retrieveAlert, getLocation } from '~/jira_connect/utils';
import { __ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { SET_ALERT } from '../store/mutation_types';
import { retrieveAlert } from '../utils';
import GroupsList from './groups_list.vue';
import SubscriptionsList from './subscriptions_list.vue';
export default {
name: 'JiraConnectApp',
components: {
GlAlert,
GlButton,
GlModal,
GroupsList,
GlLink,
GlModal,
GlSprintf,
GroupsList,
SubscriptionsList,
},
directives: {
GlModalDirective,
@ -91,37 +92,36 @@ export default {
<h2 class="gl-text-center">{{ s__('JiraService|GitLab for Jira Configuration') }}</h2>
<div
class="jira-connect-app-body gl-display-flex gl-justify-content-space-between gl-my-7 gl-pb-4 gl-border-b-solid gl-border-b-1 gl-border-b-gray-200"
>
<h5 class="gl-align-self-center gl-mb-0" data-testid="new-jira-connect-ui-heading">
{{ s__('Integrations|Linked namespaces') }}
</h5>
<gl-button
v-if="usersPath"
category="primary"
variant="info"
class="gl-align-self-center"
:href="usersPathWithReturnTo"
target="_blank"
>{{ s__('Integrations|Sign in to add namespaces') }}</gl-button
>
<template v-else>
<div class="jira-connect-app-body gl-my-7 gl-px-5 gl-pb-4">
<div class="gl-display-flex gl-justify-content-end">
<gl-button
v-gl-modal-directive="'add-namespace-modal'"
v-if="usersPath"
category="primary"
variant="info"
class="gl-align-self-center"
>{{ s__('Integrations|Add namespace') }}</gl-button
:href="usersPathWithReturnTo"
target="_blank"
>{{ s__('Integrations|Sign in to add namespaces') }}</gl-button
>
<gl-modal
modal-id="add-namespace-modal"
:title="s__('Integrations|Link namespaces')"
:action-cancel="$options.modal.cancelProps"
>
<groups-list />
</gl-modal>
</template>
<template v-else>
<gl-button
v-gl-modal-directive="'add-namespace-modal'"
category="primary"
variant="info"
class="gl-align-self-center"
>{{ s__('Integrations|Add namespace') }}</gl-button
>
<gl-modal
modal-id="add-namespace-modal"
:title="s__('Integrations|Link namespaces')"
:action-cancel="$options.modal.cancelProps"
>
<groups-list />
</gl-modal>
</template>
</div>
<subscriptions-list />
</div>
</div>
</template>

View File

@ -0,0 +1,37 @@
<script>
import { GlAvatar, GlIcon } from '@gitlab/ui';
export default {
components: {
GlAvatar,
GlIcon,
},
props: {
group: {
type: Object,
required: true,
},
},
};
</script>
<template>
<div class="gl-display-flex gl-align-items-center">
<gl-icon name="folder-o" class="gl-mr-3" />
<div class="gl-display-none gl-flex-shrink-0 gl-sm-display-flex gl-mr-3">
<gl-avatar :size="32" shape="rect" :entity-name="group.name" :src="group.avatar_url" />
</div>
<div>
<span
class="gl-mr-3 gl-text-gray-900! gl-font-weight-bold"
data-testid="group-list-item-name"
>
{{ group.full_name }}
</span>
<div v-if="group.description" data-testid="group-list-item-description">
<p class="gl-mt-2! gl-mb-0 gl-text-gray-600" v-text="group.description"></p>
</div>
</div>
</div>
</template>

View File

@ -1,15 +1,15 @@
<script>
import { GlAvatar, GlButton, GlIcon } from '@gitlab/ui';
import { GlButton } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { addSubscription } from '~/jira_connect/api';
import { persistAlert, reloadPage } from '~/jira_connect/utils';
import { s__ } from '~/locale';
import { persistAlert } from '../utils';
import GroupItemName from './group_item_name.vue';
export default {
components: {
GlAvatar,
GlButton,
GlIcon,
GroupItemName,
},
inject: {
subscriptionsPath: {
@ -47,7 +47,7 @@ export default {
variant: 'success',
});
AP.navigator.reload();
reloadPage();
})
.catch((error) => {
this.$emit(
@ -55,8 +55,6 @@ export default {
error?.response?.data?.error ||
s__('Integrations|Failed to link namespace. Please try again.'),
);
})
.finally(() => {
this.isLoading = false;
});
},
@ -67,23 +65,9 @@ export default {
<template>
<li class="gl-border-b-1 gl-border-b-solid gl-border-b-gray-100">
<div class="gl-display-flex gl-align-items-center gl-py-3">
<gl-icon name="folder-o" class="gl-mr-3" />
<div class="gl-display-none gl-flex-shrink-0 gl-sm-display-flex gl-mr-3">
<gl-avatar :size="32" shape="rect" :entity-name="group.name" :src="group.avatar_url" />
</div>
<div class="gl-min-w-0 gl-display-flex gl-flex-grow-1 gl-flex-shrink-1 gl-align-items-center">
<div class="gl-min-w-0 gl-flex-grow-1 flex-shrink-1">
<div class="gl-display-flex gl-align-items-center gl-flex-wrap">
<span
class="gl-mr-3 gl-text-gray-900! gl-font-weight-bold"
data-testid="group-list-item-name"
>
{{ group.full_name }}
</span>
</div>
<div v-if="group.description" data-testid="group-list-item-description">
<p class="gl-mt-2! gl-mb-0 gl-text-gray-600" v-text="group.description"></p>
</div>
<group-item-name :group="group" />
</div>
<gl-button

View File

@ -0,0 +1,98 @@
<script>
import { GlButton, GlEmptyState, GlTable } from '@gitlab/ui';
import { isEmpty } from 'lodash';
import { removeSubscription } from '~/jira_connect/api';
import { reloadPage } from '~/jira_connect/utils';
import { __, s__ } from '~/locale';
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import GroupItemName from './group_item_name.vue';
export default {
components: {
GlButton,
GlEmptyState,
GlTable,
GroupItemName,
TimeagoTooltip,
},
inject: {
subscriptions: {
default: [],
},
},
data() {
return {
loadingItem: null,
};
},
fields: [
{
key: 'name',
label: s__('Integrations|Linked namespaces'),
},
{
key: 'created_at',
label: __('Added'),
tdClass: 'gl-vertical-align-middle! gl-w-20p',
},
{
key: 'actions',
label: '',
tdClass: 'gl-text-right gl-vertical-align-middle! gl-pl-0!',
},
],
i18n: {
emptyTitle: s__('Integrations|No linked namespaces'),
emptyDescription: s__(
'Integrations|Namespaces are the GitLab groups and subgroups you link to this Jira instance.',
),
},
methods: {
isEmpty,
isLoadingItem(item) {
return this.loadingItem === item;
},
unlinkBtnClass(item) {
return this.isLoadingItem(item) ? '' : 'gl-ml-6';
},
onClick(item) {
this.loadingItem = item;
removeSubscription(item.unlink_path)
.then(() => {
reloadPage();
})
.catch(() => {
this.loadingItem = null;
});
},
},
};
</script>
<template>
<div>
<gl-empty-state
v-if="isEmpty(subscriptions)"
:title="$options.i18n.emptyTitle"
:description="$options.i18n.emptyDescription"
/>
<gl-table v-else :items="subscriptions" :fields="$options.fields">
<template #cell(name)="{ item }">
<group-item-name :group="item.group" />
</template>
<template #cell(created_at)="{ item }">
<timeago-tooltip :time="item.created_at" />
</template>
<template #cell(actions)="{ item }">
<gl-button
:class="unlinkBtnClass(item)"
category="secondary"
:loading="isLoadingItem(item)"
@click.prevent="onClick(item)"
>{{ __('Unlink') }}</gl-button
>
</template>
</gl-table>
</div>
</template>

View File

@ -1,6 +1,7 @@
import setConfigs from '@gitlab/ui/dist/config';
import Vue from 'vue';
import { addSubscription, removeSubscription, getLocation } from '~/jira_connect/api';
import { addSubscription, removeSubscription } from '~/jira_connect/api';
import { getLocation, reloadPage, sizeToParent } from '~/jira_connect/utils';
import GlFeatureFlagsPlugin from '~/vue_shared/gl_feature_flags_plugin';
import Translate from '~/vue_shared/translate';
@ -10,10 +11,6 @@ import { SET_ALERT } from './store/mutation_types';
const store = createStore();
const reqComplete = () => {
AP.navigator.reload();
};
const reqFailed = (res, fallbackErrorMessage) => {
const { error = fallbackErrorMessage } = res || {};
@ -35,7 +32,7 @@ const initRemoveSubscriptionButtonHandlers = () => {
const removePath = e.target.getAttribute('href');
removeSubscription(removePath)
.then(reqComplete)
.then(reloadPage)
.catch((err) =>
reqFailed(err.response.data, 'Failed to remove namespace. Please try again.'),
);
@ -56,7 +53,7 @@ const initAddSubscriptionFormHandler = () => {
const namespace = (e.target.querySelector('#namespace-input') || {}).value;
addSubscription(addPath, namespace)
.then(reqComplete)
.then(reloadPage)
.catch((err) => reqFailed(err.response.data, 'Failed to add namespace. Please try again.'));
});
};
@ -76,14 +73,15 @@ export async function initJiraConnect() {
Vue.use(Translate);
Vue.use(GlFeatureFlagsPlugin);
const { groupsPath, subscriptionsPath, usersPath } = el.dataset;
AP.sizeToParent();
const { groupsPath, subscriptions, subscriptionsPath, usersPath } = el.dataset;
sizeToParent();
return new Vue({
el,
store,
provide: {
groupsPath,
subscriptions: JSON.parse(subscriptions),
subscriptionsPath,
usersPath,
},

View File

@ -1,6 +1,8 @@
import AccessorUtilities from '~/lib/utils/accessor';
import { ALERT_LOCALSTORAGE_KEY } from './constants';
const isFunction = (fn) => typeof fn === 'function';
/**
* Persist alert data to localStorage.
*/
@ -31,3 +33,41 @@ export const retrieveAlert = () => {
return JSON.parse(initialAlertJSON);
};
export const getJwt = () => {
return new Promise((resolve) => {
if (isFunction(AP?.context?.getToken)) {
AP.context.getToken((token) => {
resolve(token);
});
} else {
resolve();
}
});
};
export const getLocation = () => {
return new Promise((resolve) => {
if (isFunction(AP?.getLocation)) {
AP.getLocation((location) => {
resolve(location);
});
} else {
resolve();
}
});
};
export const reloadPage = () => {
if (isFunction(AP?.navigator?.reload)) {
AP.navigator.reload();
} else {
window.location.reload();
}
};
export const sizeToParent = () => {
if (isFunction(AP?.sizeToParent)) {
AP.sizeToParent();
}
};

View File

@ -109,20 +109,6 @@ function deferredInitialisation() {
addSelectOnFocusBehaviour('.js-select-on-focus');
$('.remove-row').on('ajax:success', function removeRowAjaxSuccessCallback() {
tooltips.dispose(this);
$(this).closest('li').addClass('gl-display-none!');
});
$('.js-remove-tr').on('ajax:before', function removeTRAjaxBeforeCallback() {
$(this).hide();
});
$('.js-remove-tr').on('ajax:success', function removeTRAjaxSuccessCallback() {
$(this).closest('tr').addClass('gl-display-none!');
});
const glTooltipDelay = localStorage.getItem('gl-tooltip-delay');
const delay = glTooltipDelay ? JSON.parse(glTooltipDelay) : 0;

View File

@ -3,7 +3,7 @@ import { mapState, mapActions } from 'vuex';
import { __, s__ } from '~/locale';
import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
import UrlSync from '~/vue_shared/components/url_sync.vue';
import getTableHeaders from '../utils';
import { sortableFields } from '../utils';
import PackageTypeToken from './tokens/package_type_token.vue';
export default {
@ -25,7 +25,7 @@ export default {
filter: (state) => state.filter,
}),
sortableFields() {
return getTableHeaders(this.isGroupPage);
return sortableFields(this.isGroupPage);
},
},
methods: {

View File

@ -1,7 +1,7 @@
import { LIST_KEY_PROJECT, SORT_FIELDS } from './constants';
export default (isGroupPage) =>
SORT_FIELDS.filter((f) => f.key !== LIST_KEY_PROJECT || isGroupPage);
export const sortableFields = (isGroupPage) =>
SORT_FIELDS.filter((f) => f.orderBy !== LIST_KEY_PROJECT || isGroupPage);
/**
* A small util function that works out if the delete action has deleted the

View File

@ -1,7 +1,7 @@
<script>
import { mapState, mapActions } from 'vuex';
import { LIST_KEY_PACKAGE_TYPE } from '~/packages/list/constants';
import getTableHeaders from '~/packages/list/utils';
import { sortableFields } from '~/packages/list/utils';
import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
import UrlSync from '~/vue_shared/components/url_sync.vue';
@ -14,7 +14,7 @@ export default {
filter: (state) => state.filter,
}),
sortableFields() {
return getTableHeaders(this.isGroupPage).filter((h) => h.orderBy !== LIST_KEY_PACKAGE_TYPE);
return sortableFields(this.isGroupPage).filter((h) => h.orderBy !== LIST_KEY_PACKAGE_TYPE);
},
},
methods: {

View File

@ -1,5 +1,8 @@
import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
import UsersSelect from '~/users_select';
import AbuseReports from './abuse_reports';
new AbuseReports(); /* eslint-disable-line no-new */
new UsersSelect(); /* eslint-disable-line no-new */
document.addEventListener('DOMContentLoaded', initDeprecatedRemoveRowBehavior);

View File

@ -1,3 +1,7 @@
import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
import initBroadcastMessagesForm from './broadcast_message';
document.addEventListener('DOMContentLoaded', initBroadcastMessagesForm);
document.addEventListener('DOMContentLoaded', () => {
initBroadcastMessagesForm();
initDeprecatedRemoveRowBehavior();
});

View File

@ -0,0 +1,3 @@
import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
document.addEventListener('DOMContentLoaded', initDeprecatedRemoveRowBehavior);

View File

@ -0,0 +1,3 @@
import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
document.addEventListener('DOMContentLoaded', initDeprecatedRemoveRowBehavior);

View File

@ -1,3 +1,4 @@
import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
import AjaxLoadingSpinner from '~/branches/ajax_loading_spinner';
import BranchSortDropdown from '~/branches/branch_sort_dropdown';
import DeleteModal from '~/branches/branches_delete_modal';
@ -12,3 +13,4 @@ const { divergingCountsEndpoint, defaultBranch } = document.querySelector(
initDiverganceGraph(divergingCountsEndpoint, defaultBranch);
BranchSortDropdown();
initDeprecatedRemoveRowBehavior();

View File

@ -0,0 +1,3 @@
import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
document.addEventListener('DOMContentLoaded', initDeprecatedRemoveRowBehavior);

View File

@ -7,6 +7,7 @@ const PERSISTENT_USER_CALLOUTS = [
'.js-buy-pipeline-minutes-notification-callout',
'.js-token-expiry-callout',
'.js-registration-enabled-callout',
'.js-service-templates-deprecated-callout',
'.js-new-user-signups-cap-reached',
'.js-eoa-bronze-plan-banner',
];

View File

@ -0,0 +1,8 @@
mutation epicSetSubscription($input: EpicSetSubscriptionInput!) {
updateIssuableSubscription: epicSetSubscription(input: $input) {
epic {
subscribed
}
errors
}
}

View File

@ -257,7 +257,11 @@ function UsersSelect(currentUser, els, options = {}) {
deprecatedJQueryDropdown.options.processData(term, users, callback);
});
},
processData(term, data, callback) {
processData(term, dataArg, callback) {
// Sometimes the `dataArg` can contain special dropdown items like
// dividers which we don't want to consider here.
const data = dataArg.filter((x) => !x.type);
let users = data;
// Only show assigned user list when there is no search term

View File

@ -929,6 +929,7 @@ Merge requests
$mr-tabs-height: 48px;
$mr-version-controls-height: 56px;
$mr-widget-margin-left: 40px;
$mr-review-bar-height: calc(2rem + 13px);
/*
Compare Branches

View File

@ -15,6 +15,7 @@
@import '@gitlab/ui/src/components/base/loading_icon/loading_icon';
@import '@gitlab/ui/src/components/base/modal/modal';
@import '@gitlab/ui/src/components/base/pagination/pagination';
@import '@gitlab/ui/src/components/base/table/table';
@import '@gitlab/ui/src/components/base/tooltip/tooltip';
@import '@gitlab/ui/src/components/base/search_box_by_type/search_box_by_type';
@ -55,7 +56,7 @@ $header-height: 40px;
}
.jira-connect-app-body {
max-width: 600px;
max-width: 768px;
margin-left: auto;
margin-right: auto;
}

View File

@ -9,6 +9,18 @@
min-width: 0;
}
.with-system-header {
--system-header-height: #{$system-header-height};
}
.with-performance-bar {
--performance-bar-height: #{$performance-bar-height};
}
.review-bar-visible {
--review-bar-height: #{$mr-review-bar-height};
}
.diff-tree-list {
// This 11px value should match the additional value found in
// /assets/stylesheets/framework/diffs.scss
@ -23,24 +35,13 @@
position: -webkit-sticky;
position: sticky;
top: $top-pos;
max-height: calc(100vh - #{$top-pos});
// Unitless zero values are not allowed in calculations https://stackoverflow.com/a/55391061
// stylelint-disable-next-line length-zero-no-unit
top: calc(#{$top-pos} + var(--system-header-height, 0px) + var(--performance-bar-height, 0px));
// stylelint-disable-next-line length-zero-no-unit
max-height: calc(100vh - #{$top-pos} - var(--system-header-height, 0px) - var(--performance-bar-height, 0px) - var(--review-bar-height, 0px));
z-index: 202;
.with-system-header & {
top: $top-pos + $system-header-height;
}
.with-system-header.with-performance-bar & {
top: $top-pos + $system-header-height + $performance-bar-height;
}
.with-performance-bar & {
$performance-bar-top-pos: $performance-bar-height + $top-pos;
top: $performance-bar-top-pos;
max-height: calc(100vh - #{$performance-bar-top-pos});
}
.drag-handle {
bottom: 16px;
transform: translateX(10px);

View File

@ -159,7 +159,7 @@
color: $blue-600;
}
&.remove-row:hover {
&.hover-red:hover {
color: $red-500;
}
}

View File

@ -395,8 +395,6 @@ class IssuableFinder
# We want CE users to be able to say "Issues not assigned to either PersonA nor PersonB"
if not_params.assignees.present?
items.not_assigned_to(not_params.assignees)
elsif not_params.assignee_id? || not_params.assignee_username? # assignee not found
items.none
else
items
end

View File

@ -12,10 +12,10 @@ module IssueResolverArguments
argument :iids, [GraphQL::STRING_TYPE],
required: false,
description: 'List of IIDs of issues. For example, [1, 2].'
argument :label_name, GraphQL::STRING_TYPE.to_list_type,
argument :label_name, [GraphQL::STRING_TYPE, null: true],
required: false,
description: 'Labels applied to this issue.'
argument :milestone_title, GraphQL::STRING_TYPE.to_list_type,
argument :milestone_title, [GraphQL::STRING_TYPE, null: true],
required: false,
description: 'Milestone applied to this issue.'
argument :author_username, GraphQL::STRING_TYPE,
@ -55,6 +55,10 @@ module IssueResolverArguments
as: :issue_types,
description: 'Filter issues by the given issue types.',
required: false
argument :not, Types::Issues::NegatedIssueFilterInputType,
description: 'List of negated params.',
prepare: ->(negated_args, ctx) { negated_args.to_h },
required: false
end
def resolve_with_lookahead(**args)
@ -69,11 +73,22 @@ module IssueResolverArguments
args[:iids] ||= [args.delete(:iid)].compact if args[:iid]
args[:attempt_project_search_optimizations] = true if args[:search].present?
prepare_assignee_username_params(args)
finder = IssuesFinder.new(current_user, args)
continue_issue_resolve(parent, finder, **args)
end
def ready?(**args)
if args.slice(*mutually_exclusive_assignee_username_args).compact.size > 1
arg_str = mutually_exclusive_assignee_username_args.map { |x| x.to_s.camelize(:lower) }.join(', ')
raise Gitlab::Graphql::Errors::ArgumentError, "only one of [#{arg_str}] arguments is allowed at the same time."
end
super
end
class_methods do
def resolver_complexity(args, child_complexity:)
complexity = super
@ -82,4 +97,15 @@ module IssueResolverArguments
complexity
end
end
private
def prepare_assignee_username_params(args)
args[:assignee_username] = args.delete(:assignee_usernames) if args[:assignee_usernames].present?
args[:not][:assignee_username] = args[:not].delete(:assignee_usernames) if args.dig(:not, :assignee_usernames).present?
end
def mutually_exclusive_assignee_username_args
[:assignee_usernames, :assignee_username]
end
end

View File

@ -4,7 +4,7 @@ module Types
module Boards
# Common arguments that we can be used to filter boards epics and issues
class BoardIssuableInputBaseType < BaseInputObject
argument :label_name, GraphQL::STRING_TYPE.to_list_type,
argument :label_name, [GraphQL::STRING_TYPE, null: true],
required: false,
description: 'Filter by label name.'

View File

@ -8,7 +8,7 @@ module Types
required: false,
description: 'Filter by milestone title.'
argument :assignee_username, GraphQL::STRING_TYPE.to_list_type,
argument :assignee_username, [GraphQL::STRING_TYPE, null: true],
required: false,
description: 'Filter by assignee username.'

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
module Types
module Issues
class NegatedIssueFilterInputType < BaseInputObject
graphql_name 'NegatedIssueFilterInput'
argument :iids, [GraphQL::STRING_TYPE],
required: false,
description: 'List of IIDs of issues to exclude. For example, [1, 2].'
argument :label_name, [GraphQL::STRING_TYPE],
required: false,
description: 'Labels not applied to this issue.'
argument :milestone_title, [GraphQL::STRING_TYPE],
required: false,
description: 'Milestone not applied to this issue.'
argument :assignee_usernames, [GraphQL::STRING_TYPE],
required: false,
description: 'Usernames of users not assigned to the issue.'
argument :assignee_id, GraphQL::STRING_TYPE,
required: false,
description: 'ID of a user not assigned to the issues.'
end
end
end
Types::Issues::NegatedIssueFilterInputType.prepend_if_ee('::EE::Types::Issues::NegatedIssueFilterInputType')

View File

@ -190,12 +190,8 @@ module DiffHelper
def render_overflow_warning?(diffs_collection)
diff_files = diffs_collection.raw_diff_files
if diff_files.any?(&:too_large?)
Gitlab::Metrics.add_event(:diffs_overflow_single_file_limits)
end
diff_files.overflow?.tap do |overflown|
Gitlab::Metrics.add_event(:diffs_overflow_collection_limits) if overflown
log_overflow_limits(diff_files)
end
end
@ -286,4 +282,18 @@ module DiffHelper
conflicts_service.conflicts.files.index_by(&:our_path)
end
def log_overflow_limits(diff_files)
if diff_files.any?(&:too_large?)
Gitlab::Metrics.add_event(:diffs_overflow_single_file_limits)
end
Gitlab::Metrics.add_event(:diffs_overflow_collection_limits) if diff_files.overflow?
Gitlab::Metrics.add_event(:diffs_overflow_max_bytes_limits) if diff_files.overflow_max_bytes?
Gitlab::Metrics.add_event(:diffs_overflow_max_files_limits) if diff_files.overflow_max_files?
Gitlab::Metrics.add_event(:diffs_overflow_max_lines_limits) if diff_files.overflow_max_lines?
Gitlab::Metrics.add_event(:diffs_overflow_collapsed_bytes_limits) if diff_files.collapsed_safe_bytes?
Gitlab::Metrics.add_event(:diffs_overflow_collapsed_files_limits) if diff_files.collapsed_safe_files?
Gitlab::Metrics.add_event(:diffs_overflow_collapsed_lines_limits) if diff_files.collapsed_safe_lines?
end
end

View File

@ -6,8 +6,24 @@ module JiraConnectHelper
{
groups_path: api_v4_groups_path(params: { min_access_level: Gitlab::Access::MAINTAINER, skip_groups: skip_groups }),
subscriptions: subscriptions.map { |s| serialize_subscription(s) }.to_json,
subscriptions_path: jira_connect_subscriptions_path,
users_path: current_user ? nil : jira_connect_users_path
}
end
private
def serialize_subscription(subscription)
{
group: {
name: subscription.namespace.name,
avatar_url: subscription.namespace.avatar_url,
full_name: subscription.namespace.full_name,
description: subscription.namespace.description
},
created_at: subscription.created_at,
unlink_path: jira_connect_subscription_path(subscription)
}
end
end

View File

@ -15,7 +15,7 @@ module SidebarsHelper
end
def project_sidebar_context(project, user)
Sidebars::Context.new(**project_sidebar_context_data(project, user))
Sidebars::Projects::Context.new(**project_sidebar_context_data(project, user))
end
private
@ -35,8 +35,7 @@ module SidebarsHelper
def project_sidebar_context_data(project, user)
{
current_user: user,
container: project,
project: project
container: project
}
end
end

View File

@ -5,7 +5,7 @@ module UserCalloutsHelper
GKE_CLUSTER_INTEGRATION = 'gke_cluster_integration'
GCP_SIGNUP_OFFER = 'gcp_signup_offer'
SUGGEST_POPOVER_DISMISSED = 'suggest_popover_dismissed'
SERVICE_TEMPLATES_DEPRECATED = 'service_templates_deprecated'
SERVICE_TEMPLATES_DEPRECATED_CALLOUT = 'service_templates_deprecated_callout'
TABS_POSITION_HIGHLIGHT = 'tabs_position_highlight'
WEBHOOKS_MOVED = 'webhooks_moved'
CUSTOMIZE_HOMEPAGE = 'customize_homepage'
@ -41,8 +41,11 @@ module UserCalloutsHelper
!user_dismissed?(SUGGEST_POPOVER_DISMISSED)
end
def show_service_templates_deprecated?
!user_dismissed?(SERVICE_TEMPLATES_DEPRECATED)
def show_service_templates_deprecated_callout?
!Gitlab.com? &&
current_user&.admin? &&
Service.for_template.active.exists? &&
!user_dismissed?(SERVICE_TEMPLATES_DEPRECATED_CALLOUT)
end
def show_webhooks_moved_alert?

View File

@ -179,18 +179,6 @@ class CommitStatus < ApplicationRecord
ExpireJobCacheWorker.perform_async(id)
end
end
after_transition any => :failed do |commit_status|
next if Feature.enabled?(:async_add_build_failure_todo, commit_status.project, default_enabled: :yaml)
next unless commit_status.project
# rubocop: disable CodeReuse/ServiceClass
commit_status.run_after_commit do
MergeRequests::AddTodoWhenBuildFailsService
.new(project, nil).execute(self)
end
# rubocop: enable CodeReuse/ServiceClass
end
end
def self.names

View File

@ -6,12 +6,12 @@ module Integration
class_methods do
def with_custom_integration_for(integration, page = nil, per = nil)
custom_integration_project_ids = Service
.select(:project_id)
.where(type: integration.type)
.where(inherit_from_id: nil)
.distinct # Required until https://gitlab.com/gitlab-org/gitlab/-/issues/207385
.where.not(project_id: nil)
.page(page)
.per(per)
.pluck(:project_id)
Project.where(id: custom_integration_project_ids)
end

View File

@ -52,8 +52,6 @@ module Pages
return if deployment.file.file_storage? && !Feature.enabled?(:pages_serve_with_zip_file_protocol, project, default_enabled: :yaml)
return if deployment.migrated? && !Feature.enabled?(:pages_serve_from_migrated_zip, project, default_enabled: true)
global_id = ::Gitlab::GlobalId.build(deployment, id: deployment.id).to_s
{

View File

@ -3,6 +3,8 @@
require "discordrb/webhooks"
class DiscordService < ChatNotificationService
include ActionView::Helpers::UrlHelper
ATTACHMENT_REGEX = /: (?<entry>.*?)\n - (?<name>.*)\n*/.freeze
def title
@ -10,7 +12,7 @@ class DiscordService < ChatNotificationService
end
def description
s_("DiscordService|Receive event notifications in Discord")
s_("DiscordService|Send notifications about project events to a Discord channel.")
end
def self.to_param
@ -18,13 +20,8 @@ class DiscordService < ChatNotificationService
end
def help
"This service sends notifications about project events to Discord channels.<br />
To set up this service:
<ol>
<li><a href='https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks'>Setup a custom Incoming Webhook</a>.</li>
<li>Paste the <strong>Webhook URL</strong> into the field below.</li>
<li>Select events below to enable notifications.</li>
</ol>"
docs_link = link_to _('How do I set up this service?'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/discord_notifications'), target: '_blank', rel: 'noopener noreferrer'
s_('Send notifications about project events to a Discord channel. %{docs_link}').html_safe % { docs_link: docs_link.html_safe }
end
def event_field(event)
@ -36,13 +33,12 @@ class DiscordService < ChatNotificationService
end
def self.supported_events
%w[push issue confidential_issue merge_request note confidential_note tag_push
pipeline wiki_page]
%w[push issue confidential_issue merge_request note confidential_note tag_push pipeline wiki_page]
end
def default_fields
[
{ type: "text", name: "webhook", placeholder: "e.g. https://discordapp.com/api/webhooks/…" },
{ type: "text", name: "webhook", placeholder: "https://discordapp.com/api/webhooks/…", help: "URL to the webhook for the Discord channel." },
{ type: "checkbox", name: "notify_only_broken_pipelines" },
{ type: 'select', name: 'branches_to_be_notified', choices: branch_choices }
]

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
module Sidebars
module Projects
class Context < ::Sidebars::Context
def initialize(current_user:, container:, **args)
super(current_user: current_user, container: container, project: container, **args)
end
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
module Sidebars
module Projects
module Menus
module Scope
class Menu < ::Sidebars::Menu
override :link
def link
project_path(context.project)
end
override :title
def title
context.project.name
end
end
end
end
end
end

View File

@ -3,9 +3,9 @@
module Sidebars
module Projects
class Panel < ::Sidebars::Panel
override :render_raw_menus_partial
def render_raw_scope_menu_partial
'layouts/nav/sidebar/project_scope_menu'
override :configure_menus
def configure_menus
set_scope_menu(Sidebars::Projects::Menus::Scope::Menu.new(context))
end
override :render_raw_menus_partial

View File

@ -17,7 +17,7 @@ class UserCallout < ApplicationRecord
threat_monitoring_info: 11, # EE-only
account_recovery_regular_check: 12, # EE-only
webhooks_moved: 13,
service_templates_deprecated: 14,
service_templates_deprecated_callout: 14,
admin_integrations_moved: 15,
web_ide_alert_dismissed: 16, # no longer in use
active_user_count_threshold: 18, # EE-only

View File

@ -1,7 +1,7 @@
%li.label-list-item{ id: dom_id(label) }
= render "shared/label_row", label: label.present(issuable_subject: nil)
.label-actions-list
= link_to edit_admin_label_path(label), class: 'btn gl-button btn-transparent label-action has-tooltip', title: _('Edit'), data: { placement: 'bottom' }, aria_label: _('Edit') do
= link_to edit_admin_label_path(label), class: 'btn btn-default gl-button btn-default-tertiary label-action has-tooltip', title: _('Edit'), data: { placement: 'bottom' }, aria_label: _('Edit') do
= sprite_icon('pencil')
= link_to admin_label_path(label), class: 'btn gl-button btn-transparent remove-row label-action has-tooltip', title: _('Delete'), data: { placement: 'bottom', confirm: "Delete this label? Are you sure?" }, aria_label: _('Delete'), method: :delete, remote: true do
= link_to admin_label_path(label), class: 'btn btn-default gl-button btn-default-tertiary hover-red js-remove-row label-action has-tooltip', title: _('Delete'), data: { placement: 'bottom', confirm: "Delete this label? Are you sure?" }, aria_label: _('Delete'), method: :delete, remote: true do
= sprite_icon('remove')

View File

@ -1,13 +1,13 @@
= form_tag(omniauth_authorize_path(:user, :crowd), id: 'new_crowd_user', class: 'gl-show-field-errors') do
.form-group
= label_tag :username, 'Username or email'
= text_field_tag :username, nil, { class: "form-control top", title: "This field is required", autofocus: "autofocus", required: true }
= label_tag :username, _('Username or email')
= text_field_tag :username, nil, { class: "form-control top", title: _("This field is required."), autofocus: "autofocus", required: true }
.form-group
= label_tag :password
= password_field_tag :password, nil, { class: "form-control bottom", title: "This field is required.", required: true }
= password_field_tag :password, nil, { class: "form-control bottom", title: _("This field is required."), required: true }
- if devise_mapping.rememberable?
.remember-me
%label{ for: "remember_me" }
= check_box_tag :remember_me, '1', false, id: 'remember_me'
%span Remember me
= submit_tag "Sign in", class: "gl-button btn-confirm btn"
%span= _('Remember me')
= submit_tag _("Sign in"), class: "gl-button btn-confirm btn"

View File

@ -10,7 +10,7 @@
%main.jira-connect-app.gl-px-5.gl-pt-7.gl-mx-auto
- if current_user.blank? && @subscriptions.empty?
.jira-connect-app-body.gl-text-center
.jira-connect-app-body.gl-px-5.gl-text-center
%h2= s_('JiraService|GitLab for Jira Configuration')
%p= s_('JiraService|Sign in to GitLab.com to get started.')
@ -22,26 +22,7 @@
- else
.js-jira-connect-app{ data: jira_connect_app_data(@subscriptions) }
.jira-connect-app-body
- if @subscriptions.present?
%table.subscriptions.gl-w-full
%thead
%tr
%th= _('Namespace')
%th= _('Added')
%th
%tbody
- @subscriptions.each do |subscription|
%tr
%td= subscription.namespace.full_path
%td= subscription.created_at
%td= link_to _('Remove'), jira_connect_subscription_path(subscription), class: 'js-jira-connect-remove-subscription'
- else
.gl-text-center
%h4= s_('Integrations|No linked namespaces')
%p= s_('Integrations|Namespaces are the GitLab groups and subgroups you link to this Jira instance.')
%p.jira-connect-app-body.gl-mt-7.gl-font-base.gl-text-center
%p.jira-connect-app-body.gl-px-5.gl-mt-7.gl-font-base.gl-text-center
%strong= s_('Integrations|Browser limitations')
- firefox_link_url = 'https://www.mozilla.org/en-US/firefox/'
- firefox_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: firefox_link_url }

View File

@ -11,6 +11,7 @@
= render "layouts/broadcast"
= render "layouts/header/read_only_banner"
= render "layouts/header/registration_enabled_callout"
= render "layouts/header/service_templates_deprecation_callout"
= render "layouts/nav/classification_level_banner"
= yield :flash_message
= render "shared/ping_consent"

View File

@ -0,0 +1,21 @@
- return unless show_service_templates_deprecated_callout?
- doc_link_start = "<a href=\"#{integrations_help_page_path}\" target='_blank' rel='noopener noreferrer'>".html_safe
- settings_link_start = "<a href=\"#{integrations_admin_application_settings_path}\">".html_safe
%div{ class: [container_class, @content_class, 'gl-pt-5!'] }
.gl-alert.gl-alert-warning.js-service-templates-deprecated-callout{ role: 'alert', data: { feature_id: UserCalloutsHelper::SERVICE_TEMPLATES_DEPRECATED_CALLOUT, dismiss_endpoint: user_callouts_path } }
= sprite_icon('warning', size: 16, css_class: 'gl-alert-icon')
%button.gl-alert-dismiss.js-close{ type: 'button', aria: { label: _('Close') }, data: { testid: 'close-service-templates-deprecated-callout' } }
= sprite_icon('close', size: 16)
.gl-alert-title
= s_('AdminSettings|Service templates are deprecated and will be removed in GitLab 14.0.')
.gl-alert-body
= html_escape_once(s_('AdminSettings|You should migrate to %{doc_link_start}Project integration management%{link_end}, available at %{settings_link_start}Settings &gt; Integrations.%{link_end}')).html_safe % { doc_link_start: doc_link_start, settings_link_start: settings_link_start, link_end: '</a>'.html_safe }
.gl-alert-actions
= link_to admin_application_settings_services_path, class: 'btn gl-alert-action btn-info btn-md gl-button' do
%span.gl-button-text
= s_('AdminSettings|See affected service templates')
= link_to "https://gitlab.com/gitlab-org/gitlab/-/issues/325905", class: 'btn gl-alert-action btn-default btn-md gl-button', target: '_blank', rel: 'noopener noreferrer' do
%span.gl-button-text
= _('Leave feedback')

View File

@ -1,6 +0,0 @@
.context-header
= link_to project_path(@project), title: @project.name do
.avatar-container.rect-avatar.s40.project-avatar
= project_icon(@project, alt: @project.name, class: 'avatar s40 avatar-tile', width: 40, height: 40)
.sidebar-context-title
= @project.name

View File

@ -52,11 +52,11 @@
- if branch.name == @project.repository.root_ref
- delete_default_branch_tooltip = s_('Branches|The default branch cannot be deleted')
%span.has-tooltip{ title: delete_default_branch_tooltip }
%button{ class: "gl-button btn btn-danger remove-row disabled", disabled: true, 'aria-label' => delete_default_branch_tooltip }
%button{ class: "gl-button btn btn-danger disabled", disabled: true, 'aria-label' => delete_default_branch_tooltip }
= sprite_icon("remove")
- elsif protected_branch?(@project, branch)
- if can?(current_user, :push_to_delete_protected_branch, @project)
%button{ class: "gl-button btn btn-danger remove-row has-tooltip",
%button{ class: "gl-button btn btn-danger has-tooltip",
title: s_('Branches|Delete protected branch'),
data: { toggle: "modal",
target: "#modal-delete-branch",
@ -67,11 +67,11 @@
- else
- delete_protected_branch_tooltip = s_('Branches|Only a project maintainer or owner can delete a protected branch')
%span.has-tooltip{ title: delete_protected_branch_tooltip }
%button{ class: "gl-button btn btn-danger remove-row disabled", disabled: true, 'aria-label' => delete_protected_branch_tooltip }
%button{ class: "gl-button btn btn-danger disabled", disabled: true, 'aria-label' => delete_protected_branch_tooltip }
= sprite_icon("remove")
- else
= link_to project_branch_path(@project, branch.name),
class: "gl-button btn btn-danger remove-row qa-remove-btn js-ajax-loading-spinner has-tooltip",
class: "gl-button btn btn-danger js-remove-row qa-remove-btn js-ajax-loading-spinner has-tooltip",
title: s_('Branches|Delete branch'),
method: :delete,
data: { confirm: s_("Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?") % { branch_name: branch.name } },

View File

@ -2,5 +2,5 @@
- tag = local_assigns.fetch(:tag, nil)
- return unless project && tag
%button{ type: "button", class: "js-remove-tag js-confirm-modal-button gl-button btn btn-danger btn-icon remove-row has-tooltip gl-ml-3 #{protected_tag?(project, tag) ? 'disabled' : ''}", title: s_('TagsPage|Delete tag'), data: { container: 'body', path: project_tag_path(@project, tag.name), modal_attributes: delete_tag_modal_attributes(tag.name) } }
%button{ type: "button", class: "js-remove-tag js-confirm-modal-button gl-button btn btn-danger btn-icon has-tooltip gl-ml-3 #{protected_tag?(project, tag) ? 'disabled' : ''}", title: s_('TagsPage|Delete tag'), data: { container: 'body', path: project_tag_path(@project, tag.name), modal_attributes: delete_tag_modal_attributes(tag.name) } }
= sprite_icon("remove")

View File

@ -38,7 +38,7 @@
= _('Promote to group label')
%li
%span
%button.text-danger.remove-row.js-delete-label-modal-button{ type: 'button', data: { label_name: label.name, subject_name: label.subject_name, destroy_path: label.destroy_path } }
%button.text-danger.js-delete-label-modal-button{ type: 'button', data: { label_name: label.name, subject_name: label.subject_name, destroy_path: label.destroy_path } }
= _('Delete')
- if current_user
%li.inline.label-subscription

View File

@ -22,29 +22,29 @@
= f.label :scopes, _('Scopes [Select 1 or more]'), class: 'label-bold'
%fieldset.form-group.form-check
= f.check_box :read_repository, class: 'form-check-input qa-deploy-token-read-repository'
= label_tag ("deploy_token_read_repository"), 'read_repository', class: 'label-bold form-check-label'
= f.label :read_repository, 'read_repository', class: 'label-bold form-check-label'
.text-secondary= s_('DeployTokens|Allows read-only access to the repository.')
- if container_registry_enabled?(group_or_project)
%fieldset.form-group.form-check
= f.check_box :read_registry, class: 'form-check-input qa-deploy-token-read-registry'
= label_tag ("deploy_token_read_registry"), 'read_registry', class: 'label-bold form-check-label'
= f.label :read_registry, 'read_registry', class: 'label-bold form-check-label'
.text-secondary= s_('DeployTokens|Allows read-only access to registry images.')
%fieldset.form-group.form-check
= f.check_box :write_registry, class: 'form-check-input'
= label_tag ("deploy_token_write_registry"), 'write_registry', class: 'label-bold form-check-label'
= f.label :write_registry, 'write_registry', class: 'label-bold form-check-label'
.text-secondary= s_('DeployTokens|Allows write access to registry images.')
- if packages_registry_enabled?(group_or_project)
%fieldset.form-group.form-check
= f.check_box :read_package_registry, class: 'form-check-input'
= label_tag ("deploy_token_read_package_registry"), 'read_package_registry', class: 'label-bold form-check-label'
= f.label :read_package_registry, 'read_package_registry', class: 'label-bold form-check-label'
.text-secondary= s_('DeployTokens|Allows read access to the package registry.')
%fieldset.form-group.form-check
= f.check_box :write_package_registry, class: 'form-check-input'
= label_tag ("deploy_token_write_package_registry"), 'write_package_registry', class: 'label-bold form-check-label'
= f.label :write_package_registry, 'write_package_registry', class: 'label-bold form-check-label'
.text-secondary= s_('DeployTokens|Allows write access to the package registry.')
.gl-mt-3

View File

@ -53,7 +53,7 @@
%strong
= s_('JiraService|Using Jira for issue tracking?')
%p.gl-text-center.gl-mb-0
- jira_docs_link_url = help_page_url('user/project/integrations/jira', anchor: 'view-jira-issues')
- jira_docs_link_url = help_page_url('integration/jira/issues', anchor: 'view-jira-issues')
- jira_docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: jira_docs_link_url }
= html_escape(s_('JiraService|%{jira_docs_link_start}Enable the Jira integration%{jira_docs_link_end} to view your Jira issues in GitLab.')) % { jira_docs_link_start: jira_docs_link_start.html_safe, jira_docs_link_end: '</a>'.html_safe }
%p.gl-text-center.gl-mb-0.gl-text-gray-500

View File

@ -0,0 +1,6 @@
.context-header
= link_to scope_menu.link, **scope_menu.container_html_options do
.avatar-container.rect-avatar.s40.project-avatar
= source_icon(scope_menu.container, alt: scope_menu.title, class: 'avatar s40 avatar-tile', width: 40, height: 40)
.sidebar-context-title
= scope_menu.title

View File

@ -1,6 +1,8 @@
%aside.nav-sidebar{ class: ('sidebar-collapsed-desktop' if collapsed_sidebar?), **sidebar_tracking_attributes_by_object(sidebar.container), 'aria-label': sidebar.aria_label }
.nav-sidebar-inner-scroll
- if sidebar.render_raw_scope_menu_partial
- if sidebar.scope_menu
= render partial: 'shared/nav/scope_menu', object: sidebar.scope_menu
- elsif sidebar.render_raw_scope_menu_partial
= render sidebar.render_raw_scope_menu_partial
%ul.sidebar-top-level-items.qa-project-sidebar

View File

@ -37,7 +37,7 @@ class BuildFinishedWorker # rubocop:disable Scalability/IdempotentWorker
ExpirePipelineCacheWorker.perform_async(build.pipeline_id)
ChatNotificationWorker.perform_async(build.id) if build.pipeline.chat?
if build.failed? && Feature.enabled?(:async_add_build_failure_todo, build.project, default_enabled: :yaml)
if build.failed?
::Ci::MergeRequests::AddTodoWhenBuildFailsWorker.perform_async(build.id)
end

View File

@ -0,0 +1,5 @@
---
title: Add index services on project and type where inherit is null
merge_request: 59168
author:
type: other

View File

@ -0,0 +1,4 @@
---
title: Fix MR diff file tree being hidden behind review bar
merge_request: 59150
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Remove pages_serve_from_migrated_zip feature flag
merge_request: 59002
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Support negated filtering of issues by iids, label_name, milestone_title, assignee_usernames and assignee_id in GraphQL
merge_request: 58154
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Track the different overflows for diff collections
merge_request: 57790
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Update Jira subscriptions list to use Vue
merge_request: 57561
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Add index on web_hook_id to partitioned web_hook_logs
merge_request: 59266
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Add global callout for Service template deprecation
merge_request: 58613
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Add new MergeRequests::SyncCodeOwnerApprovalRulesWorker
merge_request: 58512
author:
type: performance

View File

@ -0,0 +1,5 @@
---
title: Fix Assignee dropdown showing assignee(s) twice
merge_request: 57513
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Bump recommended Redis version from 4.0 to 5.0
merge_request: 59072
author: Takuya Noguchi
type: deprecated

View File

@ -0,0 +1,5 @@
---
title: Do not show sort by project in Package project page
merge_request: 59367
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Externalize strings in sessions/_new_crowd.html.haml
merge_request: 58269
author: nuwe1
type: other

View File

@ -0,0 +1,5 @@
---
title: Improve performance by moving TODO creation out of the jobs/request path
merge_request: 59022
author:
type: performance

View File

@ -0,0 +1,5 @@
---
title: Allow to disable exiftool depending on env variable.
merge_request:
author:
type: security

View File

@ -0,0 +1,5 @@
---
title: Fix EmptyLineAfterFinalLetItBe offenses in spec/serializers
merge_request: 58406
author: Huzaifa Iftikhar @huzaifaiftikhar
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Fix EmptyLineAfterFinalLetItBe offenses in spec/services/award_emojis
merge_request: 58407
author: Huzaifa Iftikhar @huzaifaiftikhar
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Fix EmptyLineAfterFinalLetItBe offenses in spec/services/environments
merge_request: 58418
author: Huzaifa Iftikhar @huzaifaiftikhar
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Rollout product_intelligence_metrics_names_suggestions feature flag
merge_request: 58995
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Bump minimum required Go version for workhorse to 1.15
merge_request: 59347
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Update Discord integration UI text
merge_request: 58842
author:
type: other

View File

@ -1,8 +0,0 @@
---
name: async_add_build_failure_todo
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57490/diffs
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326726
milestone: '13.11'
type: development
group: group::continuous integration
default_enabled: true

View File

@ -1,8 +0,0 @@
---
name: pages_serve_from_migrated_zip
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52573
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/300021
milestone: '13.9'
type: development
group: group::release
default_enabled: true

View File

@ -1,8 +0,0 @@
---
name: product_intelligence_metrics_names_suggestions
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55733
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/323460
milestone: '13.10'
type: development
group: group::product intelligence
default_enabled: false

View File

@ -220,6 +220,8 @@
- 1
- - merge_requests_resolve_todos
- 1
- - merge_requests_sync_code_owner_approval_rules
- 1
- - metrics_dashboard_prune_old_annotations
- 1
- - metrics_dashboard_sync_dashboards

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class AddIndexOnWebHookIdToPartitionedWebHookLog < ActiveRecord::Migration[6.0]
include Gitlab::Database::PartitioningMigrationHelpers
DOWNTIME = false
WEB_HOOK_ID_INDEX_NAME = 'index_web_hook_logs_part_on_web_hook_id'
disable_ddl_transaction!
def up
add_concurrent_partitioned_index :web_hook_logs_part_0c5294f417,
:web_hook_id,
name: WEB_HOOK_ID_INDEX_NAME
end
def down
remove_concurrent_partitioned_index_by_name :web_hook_logs_part_0c5294f417, WEB_HOOK_ID_INDEX_NAME
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class AddIndexServicesOnProjectAndTypeWhereInheritNull < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
INDEX_NAME = 'index_services_on_project_and_type_where_inherit_null'
def up
add_concurrent_index(:services, [:project_id, :type], where: 'inherit_from_id IS NULL', name: INDEX_NAME)
end
def down
remove_concurrent_index_by_name(:services, INDEX_NAME)
end
end

View File

@ -0,0 +1 @@
d166250305c2939bea8cc1970faf50d86776d32270a80a429cce668a97280aad

View File

@ -0,0 +1 @@
843d9eabf8b67fe10d9eb453e887032d5b88b8594ae666bc6c6ac81e20e1ab53

View File

@ -23864,6 +23864,8 @@ CREATE INDEX index_service_desk_enabled_projects_on_id_creator_id_created_at ON
CREATE INDEX index_services_on_inherit_from_id ON services USING btree (inherit_from_id);
CREATE INDEX index_services_on_project_and_type_where_inherit_null ON services USING btree (project_id, type) WHERE (inherit_from_id IS NULL);
CREATE UNIQUE INDEX index_services_on_project_id_and_type_unique ON services USING btree (project_id, type);
CREATE INDEX index_services_on_template ON services USING btree (template);
@ -24258,6 +24260,8 @@ CREATE INDEX index_web_hook_logs_on_created_at_and_web_hook_id ON web_hook_logs
CREATE INDEX index_web_hook_logs_on_web_hook_id ON web_hook_logs USING btree (web_hook_id);
CREATE INDEX index_web_hook_logs_part_on_web_hook_id ON ONLY web_hook_logs_part_0c5294f417 USING btree (web_hook_id);
CREATE INDEX index_web_hooks_on_group_id ON web_hooks USING btree (group_id) WHERE ((type)::text = 'GroupHook'::text);
CREATE INDEX index_web_hooks_on_project_id ON web_hooks USING btree (project_id);

View File

@ -5,16 +5,16 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: howto
---
# Docker Registry for a secondary node **(PREMIUM SELF)**
# Docker Registry for a secondary site **(PREMIUM SELF)**
You can set up a [Docker Registry](https://docs.docker.com/registry/) on your
**secondary** Geo node that mirrors the one on the **primary** Geo node.
**secondary** Geo site that mirrors the one on the **primary** Geo site.
## Storage support
Docker Registry currently supports a few types of storage. If you choose a
distributed storage (`azure`, `gcs`, `s3`, `swift`, or `oss`) for your Docker
Registry on the **primary** node, you can use the same storage for a **secondary**
Registry on the **primary** site, you can use the same storage for a **secondary**
Docker Registry as well. For more information, read the
[Load balancing considerations](https://docs.docker.com/registry/deploying/#load-balancing-considerations)
when deploying the Registry, and how to set up the storage driver for the GitLab
@ -24,22 +24,22 @@ integrated [Container Registry](../../packages/container_registry.md#use-object-
You can enable a storage-agnostic replication so it
can be used for cloud or local storage. Whenever a new image is pushed to the
**primary** node, each **secondary** node will pull it to its own container
**primary** site, each **secondary** site will pull it to its own container
repository.
To configure Docker Registry replication:
1. Configure the [**primary** node](#configure-primary-node).
1. Configure the [**secondary** node](#configure-secondary-node).
1. Configure the [**primary** site](#configure-primary-site).
1. Configure the [**secondary** site](#configure-secondary-site).
1. Verify Docker Registry [replication](#verify-replication).
### Configure **primary** node
### Configure **primary** site
Make sure that you have Container Registry set up and working on
the **primary** node before following the next steps.
the **primary** site before following the next steps.
We need to make Docker Registry send notification events to the
**primary** node.
**primary** site.
1. SSH into your GitLab **primary** server and login as root:
@ -85,27 +85,29 @@ We need to make Docker Registry send notification events to the
gitlab-ctl reconfigure
```
### Configure **secondary** node
### Configure **secondary** site
Make sure you have Container Registry set up and working on
the **secondary** node before following the next steps.
the **secondary** site before following the next steps.
The following steps should be done on each **secondary** node you're
The following steps should be done on each **secondary** site you're
expecting to see the Docker images replicated.
Because we need to allow the **secondary** node to communicate securely with
the **primary** node Container Registry, we need to have a single key
pair for all the nodes. The **secondary** node will use this key to
Because we need to allow the **secondary** site to communicate securely with
the **primary** site Container Registry, we need to have a single key
pair for all the sites. The **secondary** site will use this key to
generate a short-lived JWT that is pull-only-capable to access the
**primary** node Container Registry.
**primary** site Container Registry.
1. SSH into the **secondary** node and login as the `root` user:
For each application node on the **secondary** site:
1. SSH into the node and login as the `root` user:
```shell
sudo -i
```
1. Copy `/var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key` from the **primary** to the **secondary** node.
1. Copy `/var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key` from the **primary** to the node.
1. Edit `/etc/gitlab/gitlab.rb`:
@ -114,7 +116,7 @@ generate a short-lived JWT that is pull-only-capable to access the
gitlab_rails['geo_registry_replication_primary_api_url'] = 'https://primary.example.com:5050/' # Primary registry address, it will be used by the secondary node to directly communicate to primary registry
```
1. Reconfigure the **secondary** node for the change to take effect:
1. Reconfigure the node for the change to take effect:
```shell
gitlab-ctl reconfigure
@ -123,6 +125,6 @@ generate a short-lived JWT that is pull-only-capable to access the
### Verify replication
To verify Container Registry replication is working, go to **Admin Area > Geo**
(`/admin/geo/nodes`) on the **secondary** node.
(`/admin/geo/nodes`) on the **secondary** site.
The initial replication, or "backfill", will probably still be in progress.
You can monitor the synchronization process on each Geo node from the **primary** node's **Geo Nodes** dashboard in your browser.
You can monitor the synchronization process on each Geo site from the **primary** site's **Geo Nodes** dashboard in your browser.

View File

@ -250,10 +250,11 @@ configuration option in `gitlab.yml`. These metrics are served from the
The following metrics are available:
| Metric | Type | Since | Description |
|:--------------------------------- |:--------- |:------------------------------------------------------------- |:-------------------------------------- |
| `db_load_balancing_hosts` | Gauge | [12.3](https://gitlab.com/gitlab-org/gitlab/-/issues/13630) | Current number of load balancing hosts |
| Metric | Type | Since | Description | Labels |
|:--------------------------------- |:--------- |:------------------------------------------------------------- |:-------------------------------------- |:--------------------------------------------------------- |
| `db_load_balancing_hosts` | Gauge | [12.3](https://gitlab.com/gitlab-org/gitlab/-/issues/13630) | Current number of load balancing hosts | |
| `sidekiq_load_balancing_count` | Counter | 13.11 | Sidekiq jobs using load balancing with data consistency set to :sticky or :delayed | `queue`, `boundary`, `external_dependencies`, `feature_category`, `job_status`, `urgency`, `data_consistency`, `database_chosen` |
## Database partitioning metrics **(PREMIUM SELF)**
The following metrics are available:

Some files were not shown because too many files have changed in this diff Show More