Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
7f408a3831
commit
a3dfd311f4
|
|
@ -555,6 +555,7 @@
|
|||
when: never
|
||||
- <<: *if-merge-request
|
||||
changes: *db-patterns
|
||||
when: manual
|
||||
|
||||
.rails:rules:ee-and-foss-unit:
|
||||
rules:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
25
CHANGELOG.md
25
CHANGELOG.md
|
|
@ -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)
|
||||
|
|
|
|||
4
Gemfile
4
Gemfile
|
|
@ -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'
|
||||
|
|
|
|||
13
Gemfile.lock
13
Gemfile.lock
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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!');
|
||||
});
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
mutation issueSetSubscription($input: IssueSetSubscriptionInput!) {
|
||||
issueSetSubscription(input: $input) {
|
||||
updateIssuableSubscription: issueSetSubscription(input: $input) {
|
||||
issue {
|
||||
subscribed
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', initDeprecatedRemoveRowBehavior);
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', initDeprecatedRemoveRowBehavior);
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', initDeprecatedRemoveRowBehavior);
|
||||
|
|
@ -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',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
mutation epicSetSubscription($input: EpicSetSubscriptionInput!) {
|
||||
updateIssuableSubscription: epicSetSubscription(input: $input) {
|
||||
epic {
|
||||
subscribed
|
||||
}
|
||||
errors
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@
|
|||
color: $blue-600;
|
||||
}
|
||||
|
||||
&.remove-row:hover {
|
||||
&.hover-red:hover {
|
||||
color: $red-500;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.'
|
||||
|
||||
|
|
|
|||
|
|
@ -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.'
|
||||
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 > 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')
|
||||
|
|
@ -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
|
||||
|
|
@ -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 } },
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add index services on project and type where inherit is null
|
||||
merge_request: 59168
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Fix MR diff file tree being hidden behind review bar
|
||||
merge_request: 59150
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove pages_serve_from_migrated_zip feature flag
|
||||
merge_request: 59002
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Track the different overflows for diff collections
|
||||
merge_request: 57790
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update Jira subscriptions list to use Vue
|
||||
merge_request: 57561
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add index on web_hook_id to partitioned web_hook_logs
|
||||
merge_request: 59266
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add global callout for Service template deprecation
|
||||
merge_request: 58613
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add new MergeRequests::SyncCodeOwnerApprovalRulesWorker
|
||||
merge_request: 58512
|
||||
author:
|
||||
type: performance
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix Assignee dropdown showing assignee(s) twice
|
||||
merge_request: 57513
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Bump recommended Redis version from 4.0 to 5.0
|
||||
merge_request: 59072
|
||||
author: Takuya Noguchi
|
||||
type: deprecated
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Do not show sort by project in Package project page
|
||||
merge_request: 59367
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Externalize strings in sessions/_new_crowd.html.haml
|
||||
merge_request: 58269
|
||||
author: nuwe1
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Improve performance by moving TODO creation out of the jobs/request path
|
||||
merge_request: 59022
|
||||
author:
|
||||
type: performance
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Allow to disable exiftool depending on env variable.
|
||||
merge_request:
|
||||
author:
|
||||
type: security
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix EmptyLineAfterFinalLetItBe offenses in spec/serializers
|
||||
merge_request: 58406
|
||||
author: Huzaifa Iftikhar @huzaifaiftikhar
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix EmptyLineAfterFinalLetItBe offenses in spec/services/award_emojis
|
||||
merge_request: 58407
|
||||
author: Huzaifa Iftikhar @huzaifaiftikhar
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix EmptyLineAfterFinalLetItBe offenses in spec/services/environments
|
||||
merge_request: 58418
|
||||
author: Huzaifa Iftikhar @huzaifaiftikhar
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Rollout product_intelligence_metrics_names_suggestions feature flag
|
||||
merge_request: 58995
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Bump minimum required Go version for workhorse to 1.15
|
||||
merge_request: 59347
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update Discord integration UI text
|
||||
merge_request: 58842
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
d166250305c2939bea8cc1970faf50d86776d32270a80a429cce668a97280aad
|
||||
|
|
@ -0,0 +1 @@
|
|||
843d9eabf8b67fe10d9eb453e887032d5b88b8594ae666bc6c6ac81e20e1ab53
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue