Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
14c802c4d3
commit
8318fc4ad7
|
|
@ -56,6 +56,7 @@ rails-production-server-boot-puma-cng:
|
|||
ruby_syntax:
|
||||
extends:
|
||||
- .preflight-job-base
|
||||
- .preflight:rules:ruby_syntax
|
||||
before_script:
|
||||
- source scripts/utils.sh
|
||||
image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION}
|
||||
|
|
|
|||
|
|
@ -327,6 +327,14 @@
|
|||
.lib-gitlab-patterns: &lib-gitlab-patterns
|
||||
- "{,ee/,jh/}lib/{,ee/,jh/}gitlab/**/*"
|
||||
|
||||
# Patterns to match pure Ruby code
|
||||
.ruby-patterns: &ruby-patterns
|
||||
- "**/Rakefile"
|
||||
- "**/Dangerfile"
|
||||
- "**/Gemfile"
|
||||
- "**/Guardfile"
|
||||
- "**/*.rb"
|
||||
|
||||
# Backend patterns + .ci-patterns
|
||||
.backend-patterns: &backend-patterns
|
||||
- "{,jh/}Gemfile{,.lock}"
|
||||
|
|
@ -2847,7 +2855,7 @@
|
|||
.preflight:rules:ruby_syntax:
|
||||
rules:
|
||||
- <<: *if-default-refs
|
||||
changes: *backend-patterns
|
||||
changes: *ruby-patterns
|
||||
|
||||
.preflight:rules:no-ee-check:
|
||||
rules:
|
||||
|
|
|
|||
|
|
@ -819,13 +819,6 @@ Layout/ArgumentAlignment:
|
|||
- 'ee/db/geo/migrate/20180405074130_add_partial_index_project_repository_verification.rb'
|
||||
- 'ee/db/geo/post_migrate/20210217020154_add_unique_index_on_container_repository_registry.rb'
|
||||
- 'ee/db/geo/post_migrate/20210217020156_add_unique_index_on_terraform_state_version_registry.rb'
|
||||
- 'ee/lib/ee/gitlab/background_migration/backfill_epic_cache_counts.rb'
|
||||
- 'ee/lib/ee/gitlab/background_migration/backfill_project_statistics_container_repository_size.rb'
|
||||
- 'ee/lib/ee/gitlab/background_migration/backfill_project_statistics_storage_size_without_uploads_size.rb'
|
||||
- 'ee/lib/ee/gitlab/background_migration/migrate_shared_vulnerability_scanners.rb'
|
||||
- 'ee/lib/ee/gitlab/background_migration/migrate_vulnerabilities_feedback_to_vulnerabilities_state_transition.rb'
|
||||
- 'ee/lib/ee/gitlab/background_migration/populate_latest_pipeline_ids.rb'
|
||||
- 'ee/lib/ee/gitlab/background_migration/populate_resolved_on_default_branch_column.rb'
|
||||
- 'ee/lib/ee/gitlab/import_sources.rb'
|
||||
- 'ee/lib/ee/gitlab/middleware/read_only/controller.rb'
|
||||
- 'ee/lib/ee/gitlab/scim/group/deprovisioning_service.rb'
|
||||
|
|
@ -857,15 +850,6 @@ Layout/ArgumentAlignment:
|
|||
- 'ee/spec/lib/ee/gitlab/application_context_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/auth/ldap/sync/admin_users_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/backfill_epic_cache_counts_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/backfill_project_statistics_storage_size_without_uploads_size_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/delete_invalid_epic_issues_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/fix_approval_project_rules_without_protected_branches_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/fix_security_scan_statuses_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/migrate_shared_vulnerability_scanners_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/migrate_vulnerabilities_feedback_to_vulnerabilities_state_transition_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/populate_approval_merge_request_rules_with_security_orchestration_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/background_migration/populate_approval_project_rules_with_security_orchestration_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/checks/push_rule_check_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/checks/push_rules/commit_check_spec.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/ci/config/entry/bridge_spec.rb'
|
||||
|
|
|
|||
2
Gemfile
2
Gemfile
|
|
@ -522,7 +522,7 @@ group :test do
|
|||
# Moved in `test` because https://gitlab.com/gitlab-org/gitlab/-/issues/217527
|
||||
gem 'derailed_benchmarks', require: false # rubocop:todo Gemfile/MissingFeatureCategory
|
||||
|
||||
gem 'gitlab_quality-test_tooling', '~> 1.14.1', require: false, feature_category: :tooling
|
||||
gem 'gitlab_quality-test_tooling', '~> 1.14.2', require: false, feature_category: :tooling
|
||||
end
|
||||
|
||||
gem 'octokit', '~> 6.0' # rubocop:todo Gemfile/MissingFeatureCategory
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@
|
|||
{"name":"gitlab-styles","version":"11.0.0","platform":"ruby","checksum":"0dd8ec066ce9955ac51d3616c6bfded30f75bb526f39ff392ece6f43d5b9406b"},
|
||||
{"name":"gitlab_chronic_duration","version":"0.12.0","platform":"ruby","checksum":"0d766944d415b5c831f176871ee8625783fc0c5bfbef2d79a3a616f207ffc16d"},
|
||||
{"name":"gitlab_omniauth-ldap","version":"2.2.0","platform":"ruby","checksum":"bb4d20acb3b123ed654a8f6a47d3fac673ece7ed0b6992edb92dca14bad2838c"},
|
||||
{"name":"gitlab_quality-test_tooling","version":"1.14.1","platform":"ruby","checksum":"667ccdd211ad1f3ba5bcba7e11e9d65e7d774e39bcaa1cbb667e58925fba3430"},
|
||||
{"name":"gitlab_quality-test_tooling","version":"1.14.2","platform":"ruby","checksum":"9ee343328d5e755b54d97729adc5a743abd83b05e9b28d9bbbe74f393b6cf658"},
|
||||
{"name":"globalid","version":"1.1.0","platform":"ruby","checksum":"b337e1746f0c8cb0a6c918234b03a1ddeb4966206ce288fbb57779f59b2d154f"},
|
||||
{"name":"gon","version":"6.4.0","platform":"ruby","checksum":"e3a618d659392890f1aa7db420f17c75fd7d35aeb5f8fe003697d02c4b88d2f0"},
|
||||
{"name":"google-apis-androidpublisher_v3","version":"0.34.0","platform":"ruby","checksum":"d7e1d7dd92f79c498fe2082222a1740d788e022e660c135564b3fd299cab5425"},
|
||||
|
|
|
|||
|
|
@ -741,7 +741,7 @@ GEM
|
|||
omniauth (>= 1.3, < 3)
|
||||
pyu-ruby-sasl (>= 0.0.3.3, < 0.1)
|
||||
rubyntlm (~> 0.5)
|
||||
gitlab_quality-test_tooling (1.14.1)
|
||||
gitlab_quality-test_tooling (1.14.2)
|
||||
activesupport (>= 6.1, < 7.1)
|
||||
amatch (~> 0.4.1)
|
||||
gitlab (~> 4.19)
|
||||
|
|
@ -1933,7 +1933,7 @@ DEPENDENCIES
|
|||
gitlab-utils!
|
||||
gitlab_chronic_duration (~> 0.12)
|
||||
gitlab_omniauth-ldap (~> 2.2.0)
|
||||
gitlab_quality-test_tooling (~> 1.14.1)
|
||||
gitlab_quality-test_tooling (~> 1.14.2)
|
||||
gon (~> 6.4.0)
|
||||
google-apis-androidpublisher_v3 (~> 0.34.0)
|
||||
google-apis-cloudbilling_v1 (~> 0.21.0)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ import { mapActions, mapGetters, mapState } from 'vuex';
|
|||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import { createAlert, VARIANT_SUCCESS } from '~/alert';
|
||||
import { EVENT_ISSUABLE_VUE_APP_CHANGE } from '~/issuable/constants';
|
||||
import { ISSUABLE_EDIT_DESCRIPTION } from '~/behaviors/shortcuts/keybindings';
|
||||
import { keysFor, ISSUABLE_EDIT_DESCRIPTION } from '~/behaviors/shortcuts/keybindings';
|
||||
import { shouldDisableShortcuts } from '~/behaviors/shortcuts/shortcuts_toggle';
|
||||
import { sanitize } from '~/lib/dompurify';
|
||||
import { STATUS_CLOSED, TYPE_ISSUE, issuableTypeText } from '~/issues/constants';
|
||||
import { ISSUE_STATE_EVENT_CLOSE, ISSUE_STATE_EVENT_REOPEN } from '~/issues/show/constants';
|
||||
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
|
||||
|
|
@ -192,10 +194,14 @@ export default {
|
|||
};
|
||||
},
|
||||
editShortcutKey() {
|
||||
return ISSUABLE_EDIT_DESCRIPTION.defaultKeys[0];
|
||||
return shouldDisableShortcuts() ? null : keysFor(ISSUABLE_EDIT_DESCRIPTION)[0];
|
||||
},
|
||||
editTooltip() {
|
||||
return `${this.$options.i18n.editTitleAndDescription} <kbd class="glat gl-ml-1" aria-hidden=true>${this.editShortcutKey}</kbd>`;
|
||||
const description = this.$options.i18n.editTitleAndDescription;
|
||||
const key = this.editShortcutKey;
|
||||
return shouldDisableShortcuts()
|
||||
? description
|
||||
: sanitize(`${description} <kbd class="flat gl-ml-1" aria-hidden=true>${key}</kbd>`);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
|
|
|
|||
|
|
@ -17,15 +17,14 @@ import { RESOURCE_TYPE_GROUPS, RESOURCE_TYPE_PROJECTS } from '../../constants';
|
|||
import GroupsView from '../../shared/components/groups_view.vue';
|
||||
import ProjectsView from '../../shared/components/projects_view.vue';
|
||||
import { onPageChange } from '../../shared/utils';
|
||||
import { QUERY_PARAM_END_CURSOR, QUERY_PARAM_START_CURSOR } from '../../shared/constants';
|
||||
import {
|
||||
DISPLAY_LISTBOX_ITEMS,
|
||||
QUERY_PARAM_END_CURSOR,
|
||||
QUERY_PARAM_START_CURSOR,
|
||||
SORT_DIRECTION_ASC,
|
||||
SORT_DIRECTION_DESC,
|
||||
SORT_ITEMS,
|
||||
SORT_ITEM_CREATED,
|
||||
FILTERED_SEARCH_TERM_KEY,
|
||||
} from '../constants';
|
||||
SORT_ITEM_NAME,
|
||||
} from '../../shared/constants';
|
||||
import { DISPLAY_LISTBOX_ITEMS, SORT_ITEMS, FILTERED_SEARCH_TERM_KEY } from '../constants';
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
|
|
@ -60,10 +59,13 @@ export default {
|
|||
return this.$options.sortItems.find((sortItem) => sortItem.value === this.sortName);
|
||||
},
|
||||
sortName() {
|
||||
return this.$route.query.sort_name || SORT_ITEM_CREATED.value;
|
||||
return this.$route.query.sort_name || SORT_ITEM_NAME.value;
|
||||
},
|
||||
sortDirection() {
|
||||
return this.$route.query.sort_direction || SORT_DIRECTION_ASC;
|
||||
},
|
||||
isAscending() {
|
||||
return this.$route.query.sort_direction !== SORT_DIRECTION_DESC;
|
||||
return this.sortDirection !== SORT_DIRECTION_DESC;
|
||||
},
|
||||
sortText() {
|
||||
return this.activeSortItem.text;
|
||||
|
|
@ -91,6 +93,21 @@ export default {
|
|||
? display
|
||||
: RESOURCE_TYPE_GROUPS;
|
||||
},
|
||||
search() {
|
||||
return (
|
||||
this.filteredSearchValue.find((token) => token.type === FILTERED_SEARCH_TERM)?.value
|
||||
?.data || ''
|
||||
);
|
||||
},
|
||||
routeQueryWithoutPagination() {
|
||||
const {
|
||||
[QUERY_PARAM_START_CURSOR]: startCursor,
|
||||
[QUERY_PARAM_END_CURSOR]: endCursor,
|
||||
...routeQuery
|
||||
} = this.$route.query;
|
||||
|
||||
return routeQuery;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
pushQuery(query) {
|
||||
|
|
@ -110,11 +127,11 @@ export default {
|
|||
return;
|
||||
}
|
||||
|
||||
this.pushQuery({ ...this.$route.query, sort_name: sortValue });
|
||||
this.pushQuery({ ...this.routeQueryWithoutPagination, sort_name: sortValue });
|
||||
},
|
||||
onSortDirectionChange(isAscending) {
|
||||
this.pushQuery({
|
||||
...this.$route.query,
|
||||
...this.routeQueryWithoutPagination,
|
||||
sort_direction: isAscending ? SORT_DIRECTION_ASC : SORT_DIRECTION_DESC,
|
||||
});
|
||||
},
|
||||
|
|
@ -182,6 +199,9 @@ export default {
|
|||
list-item-class="gl-px-5"
|
||||
:start-cursor="startCursor"
|
||||
:end-cursor="endCursor"
|
||||
:search="search"
|
||||
:sort-name="sortName"
|
||||
:sort-direction="sortDirection"
|
||||
@page-change="onPageChange"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { __ } from '~/locale';
|
||||
import { SORT_ITEM_NAME, SORT_ITEM_CREATED_AT, SORT_ITEM_UPDATED_AT } from '../shared/constants';
|
||||
|
||||
export const DISPLAY_QUERY_GROUPS = 'groups';
|
||||
export const DISPLAY_QUERY_PROJECTS = 'projects';
|
||||
|
|
@ -16,12 +17,4 @@ export const DISPLAY_LISTBOX_ITEMS = [
|
|||
},
|
||||
];
|
||||
|
||||
export const SORT_DIRECTION_ASC = 'asc';
|
||||
export const SORT_DIRECTION_DESC = 'desc';
|
||||
|
||||
export const SORT_ITEM_CREATED = {
|
||||
value: 'created',
|
||||
text: __('Created'),
|
||||
};
|
||||
|
||||
export const SORT_ITEMS = [SORT_ITEM_CREATED];
|
||||
export const SORT_ITEMS = [SORT_ITEM_NAME, SORT_ITEM_CREATED_AT, SORT_ITEM_UPDATED_AT];
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { s__, __ } from '~/locale';
|
|||
import GroupsList from '~/vue_shared/components/groups_list/groups_list.vue';
|
||||
import { DEFAULT_PER_PAGE } from '~/api';
|
||||
import groupsQuery from '../graphql/queries/groups.query.graphql';
|
||||
import { SORT_ITEM_NAME, SORT_DIRECTION_ASC } from '../constants';
|
||||
import { formatGroups } from '../utils';
|
||||
|
||||
export default {
|
||||
|
|
@ -57,32 +58,25 @@ export default {
|
|||
required: false,
|
||||
default: DEFAULT_PER_PAGE,
|
||||
},
|
||||
search: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
sortName: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: SORT_ITEM_NAME.value,
|
||||
},
|
||||
sortDirection: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: SORT_DIRECTION_ASC,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
const baseData = {
|
||||
groups: {},
|
||||
};
|
||||
|
||||
if (!this.startCursor && !this.endCursor) {
|
||||
return {
|
||||
...baseData,
|
||||
pagination: {
|
||||
first: this.perPage,
|
||||
after: null,
|
||||
last: null,
|
||||
before: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...baseData,
|
||||
pagination: {
|
||||
first: this.endCursor && this.perPage,
|
||||
after: this.endCursor,
|
||||
last: this.startCursor && this.perPage,
|
||||
before: this.startCursor,
|
||||
},
|
||||
groups: {},
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
|
|
@ -91,6 +85,8 @@ export default {
|
|||
variables() {
|
||||
return {
|
||||
id: this.organizationGid,
|
||||
search: this.search,
|
||||
sort: this.sort,
|
||||
...this.pagination,
|
||||
};
|
||||
},
|
||||
|
|
@ -104,13 +100,6 @@ export default {
|
|||
pageInfo,
|
||||
};
|
||||
},
|
||||
result() {
|
||||
this.$emit('page-change', {
|
||||
endCursor: this.pagination.after,
|
||||
startCursor: this.pagination.before,
|
||||
hasPreviousPage: this.pageInfo.hasPreviousPage,
|
||||
});
|
||||
},
|
||||
error(error) {
|
||||
createAlert({ message: this.$options.i18n.errorMessage, error, captureError: true });
|
||||
},
|
||||
|
|
@ -123,6 +112,26 @@ export default {
|
|||
pageInfo() {
|
||||
return this.groups.pageInfo || {};
|
||||
},
|
||||
pagination() {
|
||||
if (!this.startCursor && !this.endCursor) {
|
||||
return {
|
||||
first: this.perPage,
|
||||
after: null,
|
||||
last: null,
|
||||
before: null,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
first: this.endCursor && this.perPage,
|
||||
after: this.endCursor,
|
||||
last: this.startCursor && this.perPage,
|
||||
before: this.startCursor,
|
||||
};
|
||||
},
|
||||
sort() {
|
||||
return `${this.sortName}_${this.sortDirection}`.toUpperCase();
|
||||
},
|
||||
isLoading() {
|
||||
return this.$apollo.queries.groups.loading;
|
||||
},
|
||||
|
|
@ -147,20 +156,16 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
onNext(endCursor) {
|
||||
this.pagination = {
|
||||
first: this.perPage,
|
||||
after: endCursor,
|
||||
last: null,
|
||||
before: null,
|
||||
};
|
||||
this.$emit('page-change', {
|
||||
endCursor,
|
||||
startCursor: null,
|
||||
});
|
||||
},
|
||||
onPrev(startCursor) {
|
||||
this.pagination = {
|
||||
first: null,
|
||||
after: null,
|
||||
last: this.perPage,
|
||||
before: startCursor,
|
||||
};
|
||||
this.$emit('page-change', {
|
||||
endCursor: null,
|
||||
startCursor,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { s__, __ } from '~/locale';
|
|||
import ProjectsList from '~/vue_shared/components/projects_list/projects_list.vue';
|
||||
import { DEFAULT_PER_PAGE } from '~/api';
|
||||
import { createAlert } from '~/alert';
|
||||
import { SORT_ITEM_NAME, SORT_DIRECTION_ASC } from '../constants';
|
||||
import projectsQuery from '../graphql/queries/projects.query.graphql';
|
||||
import { formatProjects } from '../utils';
|
||||
|
||||
|
|
@ -61,32 +62,25 @@ export default {
|
|||
required: false,
|
||||
default: DEFAULT_PER_PAGE,
|
||||
},
|
||||
search: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
sortName: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: SORT_ITEM_NAME.value,
|
||||
},
|
||||
sortDirection: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: SORT_DIRECTION_ASC,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
const baseData = {
|
||||
projects: {},
|
||||
};
|
||||
|
||||
if (!this.startCursor && !this.endCursor) {
|
||||
return {
|
||||
...baseData,
|
||||
pagination: {
|
||||
first: this.perPage,
|
||||
after: null,
|
||||
last: null,
|
||||
before: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...baseData,
|
||||
pagination: {
|
||||
first: this.endCursor && this.perPage,
|
||||
after: this.endCursor,
|
||||
last: this.startCursor && this.perPage,
|
||||
before: this.startCursor,
|
||||
},
|
||||
projects: {},
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
|
|
@ -127,6 +121,23 @@ export default {
|
|||
pageInfo() {
|
||||
return this.projects.pageInfo || {};
|
||||
},
|
||||
pagination() {
|
||||
if (!this.startCursor && !this.endCursor) {
|
||||
return {
|
||||
first: this.perPage,
|
||||
after: null,
|
||||
last: null,
|
||||
before: null,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
first: this.endCursor && this.perPage,
|
||||
after: this.endCursor,
|
||||
last: this.startCursor && this.perPage,
|
||||
before: this.startCursor,
|
||||
};
|
||||
},
|
||||
isLoading() {
|
||||
return this.$apollo.queries.projects.loading;
|
||||
},
|
||||
|
|
@ -151,20 +162,16 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
onNext(endCursor) {
|
||||
this.pagination = {
|
||||
first: this.perPage,
|
||||
after: endCursor,
|
||||
last: null,
|
||||
before: null,
|
||||
};
|
||||
this.$emit('page-change', {
|
||||
endCursor,
|
||||
startCursor: null,
|
||||
});
|
||||
},
|
||||
onPrev(startCursor) {
|
||||
this.pagination = {
|
||||
first: null,
|
||||
after: null,
|
||||
last: this.perPage,
|
||||
before: startCursor,
|
||||
};
|
||||
this.$emit('page-change', {
|
||||
endCursor: null,
|
||||
startCursor,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { formValidators } from '@gitlab/ui/dist/utils';
|
||||
import { s__ } from '~/locale';
|
||||
import { s__, __ } from '~/locale';
|
||||
|
||||
export const FORM_FIELD_NAME = 'name';
|
||||
export const FORM_FIELD_ID = 'id';
|
||||
|
|
@ -26,3 +26,21 @@ export const FORM_FIELD_DESCRIPTION_VALIDATORS = [
|
|||
|
||||
export const QUERY_PARAM_START_CURSOR = 'start_cursor';
|
||||
export const QUERY_PARAM_END_CURSOR = 'end_cursor';
|
||||
|
||||
export const SORT_DIRECTION_ASC = 'asc';
|
||||
export const SORT_DIRECTION_DESC = 'desc';
|
||||
|
||||
export const SORT_ITEM_NAME = {
|
||||
value: 'name',
|
||||
text: __('Name'),
|
||||
};
|
||||
|
||||
export const SORT_ITEM_CREATED_AT = {
|
||||
value: 'created_at',
|
||||
text: __('Created'),
|
||||
};
|
||||
|
||||
export const SORT_ITEM_UPDATED_AT = {
|
||||
value: 'updated_at',
|
||||
text: __('Updated'),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
|
||||
query getOrganizationGroups(
|
||||
$id: OrganizationsOrganizationID!
|
||||
$search: String
|
||||
$sort: OrganizationGroupSort
|
||||
$first: Int
|
||||
$last: Int
|
||||
$before: String
|
||||
|
|
@ -8,7 +10,14 @@ query getOrganizationGroups(
|
|||
) {
|
||||
organization(id: $id) {
|
||||
id
|
||||
groups(first: $first, last: $last, before: $before, after: $after) {
|
||||
groups(
|
||||
first: $first
|
||||
search: $search
|
||||
sort: $sort
|
||||
last: $last
|
||||
before: $before
|
||||
after: $after
|
||||
) {
|
||||
nodes {
|
||||
id
|
||||
fullName
|
||||
|
|
|
|||
|
|
@ -39,10 +39,9 @@ export const formatGroups = (groups) =>
|
|||
export const onPageChange = ({
|
||||
startCursor,
|
||||
endCursor,
|
||||
hasPreviousPage,
|
||||
routeQuery: { start_cursor, end_cursor, ...routeQuery },
|
||||
}) => {
|
||||
if (startCursor && hasPreviousPage) {
|
||||
if (startCursor) {
|
||||
return {
|
||||
...routeQuery,
|
||||
[QUERY_PARAM_START_CURSOR]: startCursor,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ import { TYPE_ALERT, TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
|
|||
import { __, n__ } from '~/locale';
|
||||
import UserSelect from '~/vue_shared/components/user_select/user_select.vue';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { ISSUE_MR_CHANGE_ASSIGNEE } from '~/behaviors/shortcuts/keybindings';
|
||||
import { keysFor, ISSUE_MR_CHANGE_ASSIGNEE } from '~/behaviors/shortcuts/keybindings';
|
||||
import { shouldDisableShortcuts } from '~/behaviors/shortcuts/shortcuts_toggle';
|
||||
import { sanitize } from '~/lib/dompurify';
|
||||
import { assigneesQueries } from '../../queries/constants';
|
||||
import SidebarEditableItem from '../sidebar_editable_item.vue';
|
||||
import SidebarAssigneesRealtime from './assignees_realtime.vue';
|
||||
|
|
@ -158,10 +160,17 @@ export default {
|
|||
return this.issuable?.author;
|
||||
},
|
||||
assigneeShortcutDescription() {
|
||||
return ISSUE_MR_CHANGE_ASSIGNEE.description;
|
||||
return shouldDisableShortcuts() ? null : ISSUE_MR_CHANGE_ASSIGNEE.description;
|
||||
},
|
||||
assigneeShortcutKey() {
|
||||
return ISSUE_MR_CHANGE_ASSIGNEE.defaultKeys[0];
|
||||
return shouldDisableShortcuts() ? null : keysFor(ISSUE_MR_CHANGE_ASSIGNEE)[0];
|
||||
},
|
||||
assigneeTooltip() {
|
||||
const description = this.assigneeShortcutDescription;
|
||||
const key = this.assigneeShortcutKey;
|
||||
return shouldDisableShortcuts()
|
||||
? null
|
||||
: sanitize(`${description} <kbd class="flat gl-ml-1" aria-hidden=true>${key}</kbd>`);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -253,7 +262,7 @@ export default {
|
|||
:loading="isSettingAssignees"
|
||||
:initial-loading="isAssigneesLoading"
|
||||
:title="assigneeText"
|
||||
:edit-tooltip="`${assigneeShortcutDescription} <kbd class='flat ml-1' aria-hidden=true>${assigneeShortcutKey}</kbd>`"
|
||||
:edit-tooltip="assigneeTooltip"
|
||||
:edit-aria-label="assigneeShortcutDescription"
|
||||
:edit-keyshortcuts="assigneeShortcutKey"
|
||||
:is-dirty="isDirty"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
|||
import { TYPE_EPIC, TYPE_ISSUE, TYPE_MERGE_REQUEST, TYPE_TEST_CASE } from '~/issues/constants';
|
||||
|
||||
import { __ } from '~/locale';
|
||||
import { ISSUABLE_CHANGE_LABEL } from '~/behaviors/shortcuts/keybindings';
|
||||
import { keysFor, ISSUABLE_CHANGE_LABEL } from '~/behaviors/shortcuts/keybindings';
|
||||
import { shouldDisableShortcuts } from '~/behaviors/shortcuts/shortcuts_toggle';
|
||||
import { sanitize } from '~/lib/dompurify';
|
||||
import { issuableLabelsQueries } from '../../../queries/constants';
|
||||
import SidebarEditableItem from '../../sidebar_editable_item.vue';
|
||||
import { DEBOUNCE_DROPDOWN_DELAY, VARIANT_SIDEBAR } from './constants';
|
||||
|
|
@ -161,10 +163,17 @@ export default {
|
|||
return this.issuableSupportsLockOnMerge || this.issuable?.supportsLockOnMerge;
|
||||
},
|
||||
labelShortcutDescription() {
|
||||
return ISSUABLE_CHANGE_LABEL.description;
|
||||
return shouldDisableShortcuts() ? null : ISSUABLE_CHANGE_LABEL.description;
|
||||
},
|
||||
labelShortcutKey() {
|
||||
return ISSUABLE_CHANGE_LABEL.defaultKeys[0];
|
||||
return shouldDisableShortcuts() ? null : keysFor(ISSUABLE_CHANGE_LABEL)[0];
|
||||
},
|
||||
labelTooltip() {
|
||||
const description = this.labelShortcutDescription;
|
||||
const key = this.labelShortcutKey;
|
||||
return shouldDisableShortcuts()
|
||||
? null
|
||||
: sanitize(`${description} <kbd class="flat gl-ml-1" aria-hidden=true>${key}</kbd>`);
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
|
|
@ -382,7 +391,7 @@ export default {
|
|||
<sidebar-editable-item
|
||||
ref="editable"
|
||||
:title="__('Labels')"
|
||||
:edit-tooltip="`${labelShortcutDescription} <kbd class='flat ml-1' aria-hidden=true>${labelShortcutKey}</kbd>`"
|
||||
:edit-tooltip="labelTooltip"
|
||||
:edit-aria-label="labelShortcutDescription"
|
||||
:edit-keyshortcuts="labelShortcutKey"
|
||||
:loading="isLoading"
|
||||
|
|
|
|||
|
|
@ -268,11 +268,6 @@ export default {
|
|||
)
|
||||
);
|
||||
},
|
||||
autoMergeStateVisible() {
|
||||
if (!window.gon?.features?.mergeBlockedComponent) return false;
|
||||
|
||||
return this.mr.state === 'autoMergeEnabled' || this.mr.machineValue === 'AUTO_MERGE';
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'mr.machineValue': {
|
||||
|
|
@ -581,13 +576,15 @@ export default {
|
|||
</div>
|
||||
|
||||
<div class="mr-widget-section" data-testid="mr-widget-content">
|
||||
<mr-widget-auto-merge-enabled
|
||||
v-if="autoMergeStateVisible"
|
||||
:mr="mr"
|
||||
:service="service"
|
||||
class="gl-border-b-1 gl-border-b-solid gl-border-gray-100"
|
||||
/>
|
||||
<merge-checks v-if="mergeBlockedComponentEnabled" :mr="mr" :service="service" />
|
||||
<template v-if="mergeBlockedComponentEnabled">
|
||||
<mr-widget-auto-merge-enabled
|
||||
v-if="mr.autoMergeEnabled"
|
||||
:mr="mr"
|
||||
:service="service"
|
||||
class="gl-border-b-1 gl-border-b-solid gl-border-gray-100"
|
||||
/>
|
||||
<merge-checks :mr="mr" :service="service" />
|
||||
</template>
|
||||
<component :is="componentName" v-else :mr="mr" :service="service" />
|
||||
<ready-to-merge
|
||||
v-if="mr.commitsCount"
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export default function deviseState() {
|
|||
return stateKey.shaMismatch;
|
||||
}
|
||||
if (this.autoMergeEnabled && !this.mergeError) {
|
||||
return stateKey.autoMergeEnabled;
|
||||
return window.gon?.features?.mergeBlockedComponent ? null : stateKey.autoMergeEnabled;
|
||||
}
|
||||
if (
|
||||
this.detailedMergeStatus === DETAILED_MERGE_STATUS.MERGEABLE ||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ import { s__, __ } from '~/locale';
|
|||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import Tracking from '~/tracking';
|
||||
import ConfirmForkModal from '~/vue_shared/components/web_ide/confirm_fork_modal.vue';
|
||||
import { GO_TO_PROJECT_WEBIDE } from '~/behaviors/shortcuts/keybindings';
|
||||
import { keysFor, GO_TO_PROJECT_WEBIDE } from '~/behaviors/shortcuts/keybindings';
|
||||
import { shouldDisableShortcuts } from '~/behaviors/shortcuts/shortcuts_toggle';
|
||||
import { KEY_EDIT, KEY_WEB_IDE, KEY_GITPOD, KEY_PIPELINE_EDITOR } from './constants';
|
||||
|
||||
export const i18n = {
|
||||
|
|
@ -198,8 +199,11 @@ export default {
|
|||
...handleOptions,
|
||||
};
|
||||
},
|
||||
shortcutsDisabled() {
|
||||
return shouldDisableShortcuts();
|
||||
},
|
||||
webIdeActionShortcutKey() {
|
||||
return GO_TO_PROJECT_WEBIDE.defaultKeys[0];
|
||||
return keysFor(GO_TO_PROJECT_WEBIDE)[0];
|
||||
},
|
||||
webIdeActionText() {
|
||||
if (this.webIdeText) {
|
||||
|
|
@ -368,7 +372,9 @@ export default {
|
|||
<span data-testid="action-primary-text" class="gl-font-weight-bold">{{
|
||||
action.text
|
||||
}}</span>
|
||||
<kbd v-if="action.shortcut" class="flat">{{ action.shortcut }}</kbd>
|
||||
<kbd v-if="action.shortcut && !shortcutsDisabled" class="flat">{{
|
||||
action.shortcut
|
||||
}}</kbd>
|
||||
</span>
|
||||
<span data-testid="action-secondary-text" class="gl-font-sm gl-text-secondary">
|
||||
{{ action.secondaryText }}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
.whats-new-drawer {
|
||||
@include gl-shadow-none;
|
||||
box-shadow: none;
|
||||
overflow-y: hidden;
|
||||
width: 500px;
|
||||
|
||||
|
|
|
|||
|
|
@ -478,7 +478,7 @@ span.idiff {
|
|||
overflow: hidden;
|
||||
|
||||
.tree-list-parent::before {
|
||||
@include gl-content-empty;
|
||||
content: '';
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ label {
|
|||
border-color: var(--gray-700, $gray-700);
|
||||
|
||||
input {
|
||||
@include gl-shadow-none;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
font-family: $monospace-font;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
@include gl-justify-content-end;
|
||||
justify-content: flex-end;
|
||||
|
||||
i,
|
||||
svg {
|
||||
|
|
@ -115,12 +115,12 @@ td.line-numbers {
|
|||
.line-numbers:not(.line-links) a:focus-within::before,
|
||||
.line-links:hover a::before,
|
||||
.line-links:focus-within a::before {
|
||||
@include gl-visibility-visible;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
|
||||
.file-line-num {
|
||||
@include gl-justify-content-end;
|
||||
justify-content: flex-end;
|
||||
flex-grow: 1;
|
||||
padding-right: $gl-spacing-scale-3;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
// - app/helpers/ci/status_helper.rb
|
||||
.ci-icon-gl-icon-wrapper {
|
||||
border-radius: $gl-border-radius-full;
|
||||
@include gl-line-height-0;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
// Makes the borderless CI icons appear slightly bigger than the default 16px.
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@
|
|||
// GitLab UI's label component
|
||||
.gl-label,
|
||||
.gl-label-sm {
|
||||
@include gl-vertical-align-bottom;
|
||||
vertical-align: bottom;
|
||||
|
||||
&:focus:active {
|
||||
@include gl-reset-color;
|
||||
@include gl-shadow-none;
|
||||
color: inherit;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +51,6 @@
|
|||
}
|
||||
|
||||
.md code {
|
||||
@include gl-vertical-align-bottom;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,8 +134,8 @@ body {
|
|||
|
||||
.gl--flex-full {
|
||||
display: flex;
|
||||
@include gl-align-items-stretch;
|
||||
@include gl-overflow-hidden;
|
||||
align-items: stretch;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.fullscreen-layout {
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@
|
|||
}
|
||||
|
||||
.suggestions.md > .markdown-code-block {
|
||||
@include gl-static;
|
||||
position: static;
|
||||
}
|
||||
|
||||
.md-suggestion-header {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
.dropdown-menu {
|
||||
width: 100%;
|
||||
@include gl-max-w-none;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.gl-dropdown-item-check-icon {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[data-editor-loading] {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@include gl-justify-content-center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 0;
|
||||
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
display: flex;
|
||||
|
||||
.md {
|
||||
@include gl-overflow-scroll;
|
||||
overflow: scroll;
|
||||
padding-left: $gl-spacing-scale-6;
|
||||
padding-right: $gl-spacing-scale-6;
|
||||
padding-top: $gl-spacing-scale-4;
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
}
|
||||
|
||||
.gl-source-editor {
|
||||
@include gl-order-n1;
|
||||
order: -1;
|
||||
border-radius: 0 0 $border-radius-default $border-radius-default;
|
||||
}
|
||||
}
|
||||
|
|
@ -70,11 +70,11 @@
|
|||
.margin-view-overlays {
|
||||
.line-numbers {
|
||||
display: flex;
|
||||
@include gl-justify-content-end;
|
||||
justify-content: flex-end;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
@include gl-visibility-hidden;
|
||||
visibility: hidden;
|
||||
align-self: center;
|
||||
background-color: $gray-400;
|
||||
margin-right: $gl-spacing-scale-2;
|
||||
|
|
@ -88,16 +88,16 @@
|
|||
}
|
||||
|
||||
&:hover {
|
||||
@include gl-text-decoration-underline;
|
||||
text-decoration: underline;
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
&:hover::before {
|
||||
@include gl-visibility-visible;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
&:focus::before {
|
||||
@include gl-visibility-visible;
|
||||
visibility: visible;
|
||||
outline: auto;
|
||||
}
|
||||
|
||||
|
|
@ -112,11 +112,11 @@
|
|||
|
||||
// Remove custom focus from element
|
||||
.inputarea {
|
||||
@include gl-shadow-none;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.active-line-text {
|
||||
background-color: $orange-600;
|
||||
@include gl-opacity-3;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ $super-sidebar-transition-hint-duration: $super-sidebar-transition-duration / 4;
|
|||
|
||||
.user-bar-dropdown-toggle {
|
||||
padding: $gl-spacing-scale-2;
|
||||
@include gl-border-none;
|
||||
border-style: none;
|
||||
|
||||
&[aria-expanded='true'] {
|
||||
background-color: var(--super-sidebar-user-bar-button-hover-bg);
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@
|
|||
|
||||
p {
|
||||
line-height: 1.5;
|
||||
@include gl-reset-color;
|
||||
color: inherit;
|
||||
|
||||
&:last-child {
|
||||
margin: 0;
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@
|
|||
|
||||
@mixin line-link($color, $icon) {
|
||||
&::before {
|
||||
@include gl-visibility-hidden;
|
||||
visibility: hidden;
|
||||
align-self: center;
|
||||
margin-right: $gl-spacing-scale-1;
|
||||
width: $gl-spacing-scale-5;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ Shared styles for system note dot and icon styles used for MR, Issue, Work Item
|
|||
margin-left: 12px;
|
||||
margin-right: 8px;
|
||||
border: 2px solid var(--gray-50, $gray-50);
|
||||
|
||||
.gl-dark .modal-body & {
|
||||
border-color: var(--gray-100, $gray-100);
|
||||
}
|
||||
}
|
||||
|
||||
.system-note-icon {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
}
|
||||
|
||||
.toggle-sidebar-mobile-button {
|
||||
@include gl-right-0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu-toggle {
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@
|
|||
|
||||
.user-avatar-link {
|
||||
&:not(:last-of-type) {
|
||||
@include gl-mr-n3;
|
||||
margin-right: -$gl-spacing-scale-3;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@
|
|||
top: $calc-application-header-height;
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
@include gl-border-l-0;
|
||||
border-left-width: 0;
|
||||
}
|
||||
|
||||
&.right-sidebar-collapsed {
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ $t-gray-a-16-design-pin: rgba($black, 0.16);
|
|||
}
|
||||
|
||||
&.inactive {
|
||||
@include gl-opacity-5;
|
||||
opacity: 0.5;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
.file-editor {
|
||||
#editor,
|
||||
.editor {
|
||||
@include gl-border-0;
|
||||
border-width: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
.editor-loading-content {
|
||||
height: 100%;
|
||||
@include gl-border-0;
|
||||
border-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ $stroke-size: 1px;
|
|||
|
||||
.escalation-rule-row {
|
||||
@media (max-width: $breakpoint-lg) {
|
||||
@include gl-flex-wrap;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
color: var(--gray-500, $gray-500);
|
||||
|
||||
> .gl-tab-counter-badge {
|
||||
@include gl-reset-color;
|
||||
color: inherit;
|
||||
font-size: $gl-font-size-sm;
|
||||
background-color: var(--gray-50, $gray-50);
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
@include media-breakpoint-down(xs) {
|
||||
.list-header {
|
||||
@include gl-flex-direction-column-reverse;
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
.create-incident-button {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
.timeline-entry:not(:last-child) {
|
||||
.timeline-event-border {
|
||||
padding-bottom: $gl-spacing-scale-3;
|
||||
@include gl-border-gray-50;
|
||||
border-color: $gray-50;
|
||||
border-width: $gl-border-size-1;
|
||||
border-bottom-style: solid;
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@
|
|||
.timeline-entry:last-child,
|
||||
.create-timeline-event {
|
||||
.timeline-event-bottom-border {
|
||||
@include gl-border-b;
|
||||
border-bottom: solid $gl-border-size-1 $border-color;
|
||||
padding-top: $gl-spacing-scale-5;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@
|
|||
padding-left: $gl-spacing-scale-1;
|
||||
padding-right: $gl-spacing-scale-2;
|
||||
height: $gl-spacing-scale-5;
|
||||
@include gl-min-w-5;
|
||||
min-width: $gl-spacing-scale-5;
|
||||
line-height: 14px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ $comparison-empty-state-height: 62px;
|
|||
}
|
||||
|
||||
.survey-slide-up-enter-active {
|
||||
@include gl-transition-slow;
|
||||
transition: all $gl-transition-duration-slow ease;
|
||||
}
|
||||
|
||||
.mr-compare-dropdown {
|
||||
|
|
|
|||
|
|
@ -847,13 +847,13 @@ $tabs-holder-z-index: 250;
|
|||
}
|
||||
|
||||
.mr-widget-extension-icon::before {
|
||||
@include gl-content-empty;
|
||||
content: '';
|
||||
position: absolute;
|
||||
@include gl-left-50p;
|
||||
@include gl-top-half;
|
||||
@include gl-opacity-3;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
opacity: 0.3;
|
||||
border-style: solid;
|
||||
@include gl-border-4;
|
||||
border-width: $gl-border-size-4;
|
||||
border-radius: $gl-border-radius-full;
|
||||
|
||||
width: 24px;
|
||||
|
|
@ -862,11 +862,11 @@ $tabs-holder-z-index: 250;
|
|||
}
|
||||
|
||||
.mr-widget-extension-icon::after {
|
||||
@include gl-content-empty;
|
||||
content: '';
|
||||
position: absolute;
|
||||
border-radius: $gl-border-radius-full;
|
||||
@include gl-left-50p;
|
||||
@include gl-top-half;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
|
@ -981,7 +981,8 @@ $tabs-holder-z-index: 250;
|
|||
.detail-page-description,
|
||||
.merge-request-tabs-container {
|
||||
&.is-merge-request {
|
||||
@include gl-mx-auto;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: $fixed-layout-width - ($container-margin-xl * 2);
|
||||
}
|
||||
}
|
||||
|
|
@ -989,8 +990,9 @@ $tabs-holder-z-index: 250;
|
|||
|
||||
.container-fluid.diffs-container-limited {
|
||||
.flash-container {
|
||||
@include gl-mx-auto;
|
||||
@include gl-max-w-container-xl;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: $container-xl;
|
||||
padding-left: $gl-spacing-scale-5;
|
||||
padding-right: $gl-spacing-scale-5;
|
||||
}
|
||||
|
|
@ -1042,7 +1044,7 @@ $tabs-holder-z-index: 250;
|
|||
.mr-ready-merge-related-links a,
|
||||
.mr-widget-merge-details a,
|
||||
.mr-widget-author {
|
||||
@include gl-text-decoration-underline;
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
|
|
@ -1066,28 +1068,28 @@ $tabs-holder-z-index: 250;
|
|||
}
|
||||
|
||||
.mr-widget-status-icon-level-1::before {
|
||||
@include gl-content-empty;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
@include gl-bottom-0;
|
||||
@include gl-right-0;
|
||||
@include gl-opacity-3;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
opacity: 0.3;
|
||||
border-radius: $gl-border-radius-full;
|
||||
border-style: solid;
|
||||
@include gl-border-4;
|
||||
border-width: $gl-border-size-4;
|
||||
}
|
||||
|
||||
.mr-widget-status-icon-level-1::after {
|
||||
@include gl-content-empty;
|
||||
content: '';
|
||||
position: absolute;
|
||||
border-radius: $gl-border-radius-full;
|
||||
border-style: solid;
|
||||
@include gl-border-4;
|
||||
@include gl-left-2;
|
||||
@include gl-right-2;
|
||||
@include gl-top-2;
|
||||
@include gl-bottom-2;
|
||||
border-width: $gl-border-size-4;
|
||||
left: $gl-spacing-scale-2;
|
||||
right: $gl-spacing-scale-2;
|
||||
top: $gl-spacing-scale-2;
|
||||
bottom: $gl-spacing-scale-2;
|
||||
}
|
||||
|
||||
.memory-graph-container {
|
||||
|
|
@ -1202,11 +1204,11 @@ $tabs-holder-z-index: 250;
|
|||
|
||||
.discussion-collapsible {
|
||||
margin: 0;
|
||||
@include gl-border-l-0;
|
||||
@include gl-border-r-0;
|
||||
border-left-width: 0;
|
||||
border-right-width: 0;
|
||||
border-bottom-width: 0;
|
||||
@include gl-rounded-top-left-none;
|
||||
@include gl-rounded-top-right-none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ $column-right-gradient: linear-gradient(to right, $gradient-dark-gray 0%, $gradi
|
|||
.list-section .details-cell {
|
||||
&::after {
|
||||
height: 100%;
|
||||
@include gl-content-empty;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -$grid-size;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
}
|
||||
|
||||
.dashboard-card {
|
||||
@include gl-cursor-grab;
|
||||
cursor: grab;
|
||||
|
||||
&-header {
|
||||
&-warning {
|
||||
|
|
|
|||
|
|
@ -271,15 +271,15 @@
|
|||
|
||||
.projects-list {
|
||||
@include basic-list;
|
||||
@include gl-display-table;
|
||||
display: table;
|
||||
|
||||
.project-row {
|
||||
@include gl-display-table-row;
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
.project-cell {
|
||||
@include gl-display-table-cell;
|
||||
@include gl-vertical-align-top;
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
padding-top: $gl-spacing-scale-4;
|
||||
padding-bottom: $gl-spacing-scale-4;
|
||||
border-bottom: 1px solid var(--gray-50, $gray-50);
|
||||
|
|
@ -287,7 +287,7 @@
|
|||
|
||||
.project-row:last-of-type {
|
||||
.project-cell {
|
||||
@include gl-border-none;
|
||||
border-style: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -303,7 +303,7 @@
|
|||
}
|
||||
|
||||
.controls {
|
||||
@include gl-line-height-42;
|
||||
line-height: $gl-line-height-42;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +323,7 @@
|
|||
&:not(.compact) {
|
||||
.controls {
|
||||
@include media-breakpoint-up(lg) {
|
||||
@include gl-justify-content-start;
|
||||
justify-content: flex-start;
|
||||
padding-right: $gl-spacing-scale-9;
|
||||
|
||||
&:not(.with-pipeline-status) {
|
||||
|
|
@ -339,7 +339,7 @@
|
|||
.project-details {
|
||||
p,
|
||||
.commit-row-message {
|
||||
@include gl-white-space-normal;
|
||||
white-space: normal;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
/* stylelint-disable-next-line value-no-vendor-prefix */
|
||||
|
|
@ -350,7 +350,7 @@
|
|||
|
||||
.controls {
|
||||
@include media-breakpoint-up(sm) {
|
||||
@include gl-justify-content-end;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.icon-wrapper {
|
||||
|
|
@ -376,8 +376,8 @@
|
|||
&.compact {
|
||||
.description {
|
||||
width: 100%;
|
||||
@include gl-display-table;
|
||||
@include gl-table-layout-fixed;
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
|
|
@ -409,7 +409,7 @@
|
|||
@include media-breakpoint-down(md) {
|
||||
.updated-note {
|
||||
margin-top: $gl-spacing-scale-3;
|
||||
@include gl-text-right;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -431,7 +431,7 @@
|
|||
@include media-breakpoint-down(xs) {
|
||||
.updated-note {
|
||||
margin-top: 0;
|
||||
@include gl-text-left;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -325,7 +325,7 @@ $language-filter-max-height: 20rem;
|
|||
pre {
|
||||
padding: 0; // This overrides the existing style that will add space between each line.
|
||||
.line {
|
||||
@include gl-word-break-word;
|
||||
word-break: break-word;
|
||||
white-space: break-spaces;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
&.todo-pending.done-reversible {
|
||||
.todo-item,
|
||||
.todo-timestamp {
|
||||
@include gl-opacity-5;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.todo-avatar {
|
||||
|
|
@ -38,8 +38,8 @@
|
|||
|
||||
&:hover {
|
||||
border-top-width: $gl-border-size-1;
|
||||
@include gl-border-t-transparent;
|
||||
@include gl-border-t-solid;
|
||||
border-top-color: transparent;
|
||||
border-top-style: solid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -49,12 +49,12 @@
|
|||
|
||||
.todo-label a::before {
|
||||
// Make area of the todo item clickable by expanding the area around the todo link
|
||||
@include gl-content-empty;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
@include gl-right-0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
@include gl-bottom-0;
|
||||
bottom: 0;
|
||||
z-index: 9;
|
||||
}
|
||||
}
|
||||
|
|
@ -64,9 +64,9 @@
|
|||
|
||||
@include media-breakpoint-up(sm) {
|
||||
margin-right: 0;
|
||||
@include gl-text-overflow-ellipsis;
|
||||
@include gl-white-space-nowrap;
|
||||
@include gl-overflow-hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +82,7 @@
|
|||
padding-left: $gl-spacing-scale-1;
|
||||
padding-right: $gl-spacing-scale-1;
|
||||
margin: 0;
|
||||
@include gl-border-0;
|
||||
border-width: 0;
|
||||
border-radius: $gl-border-radius-base;
|
||||
display: inline-flex;
|
||||
background: var(--gray-50, $gray-50);
|
||||
|
|
@ -106,7 +106,7 @@
|
|||
|
||||
.todo-actions {
|
||||
position: absolute;
|
||||
@include gl-right-0;
|
||||
right: 0;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
position: relative;
|
||||
|
|
|
|||
|
|
@ -135,10 +135,10 @@ ul.related-merge-requests > li gl-emoji {
|
|||
|
||||
@include media-breakpoint-down(xs) {
|
||||
.btn.btn-confirm {
|
||||
@include gl-justify-content-start;
|
||||
justify-content: flex-start;
|
||||
|
||||
&.dropdown-toggle {
|
||||
@include gl-flex-grow-0;
|
||||
flex-grow: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ $system-note-icon-m-left: $avatar-m-left + $icon-size-diff / $avatar-m-ratio;
|
|||
|
||||
.main-notes-list::before {
|
||||
background: var(--gray-50, $gray-50);
|
||||
|
||||
.gl-dark .modal-body & {
|
||||
background: var(--gray-100, $gray-100);
|
||||
}
|
||||
}
|
||||
|
||||
.timeline-entry:not(.draft-note):last-child::before {
|
||||
|
|
@ -42,6 +46,10 @@ $system-note-icon-m-left: $avatar-m-left + $icon-size-diff / $avatar-m-ratio;
|
|||
.gl-dark & {
|
||||
background: var(--gray-10);
|
||||
}
|
||||
|
||||
.gl-dark .modal-body & {
|
||||
background: var(--gray-50, $gray-50);
|
||||
}
|
||||
|
||||
&.note-comment {
|
||||
top: 30px;
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@
|
|||
}
|
||||
|
||||
.gl-avatar {
|
||||
@include gl-border-none;
|
||||
border-style: none;
|
||||
box-shadow: inset 0 0 0 1px rgba($gray-950, $gl-avatar-border-opacity);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
.gl-single-stat.gl-display-flex.gl-flex-direction-column.gl-p-2
|
||||
.gl-display-flex.gl-align-items-center.gl-text-gray-700.gl-mb-2
|
||||
- if title_icon?
|
||||
= sprite_icon(@title_icon, css_class: 'gl-mr-2')
|
||||
%span.gl-font-base.gl-font-weight-normal{ data: { testid: 'title-text' } }
|
||||
= @title
|
||||
.gl-single-stat-content.gl-display-flex.gl-align-items-baseline.gl-font-weight-bold.gl-text-gray-900
|
||||
%span.gl-single-stat-number.gl-line-height-1{ class: unit_class, data: { testid: 'displayValue' } }
|
||||
%span{ data: { testid: 'non-animated-value' } }
|
||||
= @stat_value
|
||||
- if unit?
|
||||
%span.gl-font-sm.gl-mx-2.gl-transition-medium.gl-opacity-10{ data: { testid: 'unit' } }
|
||||
= @unit
|
||||
- if meta_icon? && !meta_text?
|
||||
= sprite_icon(@meta_icon, css_class: @text_color)
|
||||
- elsif meta_text?
|
||||
= render Pajamas::BadgeComponent.new(@meta_text,
|
||||
variant: @variant,
|
||||
icon: @meta_icon,
|
||||
data: { testid: 'meta-badge' })
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Pajamas
|
||||
class SingleStatComponent < Pajamas::Component
|
||||
# @param [String] title
|
||||
# @param [String] stat_value
|
||||
# @param [String] unit
|
||||
# @param [String] title_icon
|
||||
# @param [String] meta_text
|
||||
# @param [String] meta_icon
|
||||
# @param [Symbol] variant
|
||||
def initialize(
|
||||
title: nil,
|
||||
stat_value: nil,
|
||||
unit: nil,
|
||||
title_icon: nil,
|
||||
meta_text: nil,
|
||||
meta_icon: nil,
|
||||
text_color: nil,
|
||||
variant: :muted
|
||||
)
|
||||
@title = title
|
||||
@stat_value = stat_value
|
||||
@unit = unit
|
||||
@title_icon = title_icon.to_s.presence
|
||||
@meta_text = meta_text
|
||||
@meta_icon = meta_icon
|
||||
@text_color = text_color
|
||||
@variant = filter_attribute(variant.to_sym, Pajamas::BadgeComponent::VARIANT_OPTIONS, default: :muted)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
delegate :sprite_icon, to: :helpers
|
||||
|
||||
def unit_class
|
||||
"gl-mr-2" unless unit?
|
||||
end
|
||||
|
||||
def unit?
|
||||
@unit
|
||||
end
|
||||
|
||||
def title_icon?
|
||||
@title_icon
|
||||
end
|
||||
|
||||
def meta_icon?
|
||||
@meta_icon
|
||||
end
|
||||
|
||||
def meta_text?
|
||||
@meta_text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -5,7 +5,11 @@ module PreviewMarkdown
|
|||
|
||||
# rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
def preview_markdown
|
||||
result = PreviewMarkdownService.new(@project, current_user, markdown_service_params).execute
|
||||
result = PreviewMarkdownService.new(
|
||||
container: resource_parent,
|
||||
current_user: current_user,
|
||||
params: markdown_service_params
|
||||
).execute
|
||||
|
||||
render json: {
|
||||
body: view_context.markdown(result[:text], markdown_context_params),
|
||||
|
|
@ -19,6 +23,10 @@ module PreviewMarkdown
|
|||
|
||||
private
|
||||
|
||||
def resource_parent
|
||||
@project
|
||||
end
|
||||
|
||||
def projects_filter_params
|
||||
{
|
||||
issuable_reference_expansion_enabled: true,
|
||||
|
|
|
|||
|
|
@ -389,9 +389,9 @@ class GroupsController < Groups::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
override :markdown_service_params
|
||||
def markdown_service_params
|
||||
params.merge(group: group)
|
||||
override :resource_parent
|
||||
def resource_parent
|
||||
group
|
||||
end
|
||||
|
||||
override :has_project_list?
|
||||
|
|
@ -412,4 +412,4 @@ class GroupsController < Groups::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
GroupsController.prepend_mod_with('GroupsController')
|
||||
GroupsController.prepend_mod
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ class Projects::MergeRequests::DraftsController < Projects::MergeRequests::Appli
|
|||
|
||||
def render_draft_note(note)
|
||||
params = { target_id: merge_request.id, target_type: 'MergeRequest', text: note.note }
|
||||
result = PreviewMarkdownService.new(@project, current_user, params).execute
|
||||
result = PreviewMarkdownService.new(container: @project, current_user: current_user, params: params).execute
|
||||
markdown_params = { markdown_engine: result[:markdown_engine], issuable_reference_expansion_enabled: true }
|
||||
|
||||
note.rendered_note = view_context.markdown(result[:text], markdown_params)
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ module MergeRequestsHelper
|
|||
link_to_author = link_to_member(project, merge_request.author, size: 24, extra_class: 'gl-font-weight-bold gl-mr-2', avatar: false)
|
||||
copy_action_description = _('Copy branch name')
|
||||
copy_action_shortcut = 'b'
|
||||
copy_button_title = "#{copy_action_description} <kbd class='flat ml-1'>#{copy_action_shortcut}</kbd>"
|
||||
copy_button_title = "#{copy_action_description} <kbd class='flat ml-1' aria-hidden=true>#{copy_action_shortcut}</kbd>"
|
||||
copy_button = clipboard_button(text: merge_request.source_branch, title: copy_button_title, aria_keyshortcuts: copy_action_shortcut, aria_label: copy_action_description, class: 'gl-display-none! gl-md-display-inline-block! js-source-branch-copy')
|
||||
|
||||
target_branch = link_to merge_request.target_branch, project_tree_path(merge_request.target_project, merge_request.target_branch), title: merge_request.target_branch, class: 'ref-container gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mx-2'
|
||||
|
|
|
|||
|
|
@ -23,11 +23,10 @@ module Ci
|
|||
|
||||
scope :order_by_created_at_asc, -> { reorder(created_at: :asc) }
|
||||
scope :order_by_created_at_desc, -> { reorder(created_at: :desc) }
|
||||
# After we denormalize the `released_at` column, we won't need to use `joins(:release)` and keyset_order_*
|
||||
scope :order_by_released_at_asc, -> { joins(:release).keyset_order_by_released_at_asc }
|
||||
scope :order_by_released_at_desc, -> { joins(:release).keyset_order_by_released_at_desc }
|
||||
scope :order_by_released_at_asc, -> { reorder(released_at: :asc) }
|
||||
scope :order_by_released_at_desc, -> { reorder(released_at: :desc) }
|
||||
|
||||
delegate :sha, :released_at, :author_id, to: :release
|
||||
delegate :sha, :author_id, to: :release
|
||||
|
||||
before_create :sync_with_release
|
||||
after_destroy :update_catalog_resource
|
||||
|
|
@ -52,12 +51,9 @@ module Ci
|
|||
catalog_resources_table = Ci::Catalog::Resource.arel_table
|
||||
catalog_resources_id_list = catalog_resources.map { |resource| "(#{resource.id})" }.join(',')
|
||||
|
||||
# We need to use an alias for the `releases` table here so that it does not
|
||||
# conflict with `joins(:release)` in the `order_by_released_at_*` scope.
|
||||
join_query = Ci::Catalog::Resources::Version
|
||||
.where(catalog_resources_table[:id].eq(arel_table[:catalog_resource_id]))
|
||||
.joins("INNER JOIN releases AS rel ON rel.id = #{table_name}.release_id")
|
||||
.order(Arel.sql('rel.released_at DESC'))
|
||||
.order_by_released_at_desc
|
||||
.limit(1)
|
||||
|
||||
Ci::Catalog::Resources::Version
|
||||
|
|
@ -65,46 +61,6 @@ module Ci
|
|||
.joins("INNER JOIN LATERAL (#{join_query.to_sql}) #{table_name} ON TRUE")
|
||||
end
|
||||
|
||||
def keyset_order_by_released_at_asc
|
||||
keyset_order = Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: :released_at,
|
||||
column_expression: Release.arel_table[:released_at],
|
||||
order_expression: Release.arel_table[:released_at].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: :id,
|
||||
order_expression: Release.arel_table[:id].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
|
||||
reorder(keyset_order)
|
||||
end
|
||||
|
||||
def keyset_order_by_released_at_desc
|
||||
keyset_order = Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: :released_at,
|
||||
column_expression: Release.arel_table[:released_at],
|
||||
order_expression: Release.arel_table[:released_at].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: :id,
|
||||
order_expression: Release.arel_table[:id].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
|
||||
reorder(keyset_order)
|
||||
end
|
||||
|
||||
def order_by(order)
|
||||
case order.to_s
|
||||
when 'created_asc' then order_by_created_at_asc
|
||||
|
|
|
|||
|
|
@ -17,7 +17,11 @@ module Ci
|
|||
@removed_count = 0
|
||||
@locked_count = 0
|
||||
@start_at = Time.current
|
||||
@loop_limit = Feature.enabled?(:ci_job_artifacts_backlog_large_loop_limit) ? LARGE_LOOP_LIMIT : LOOP_LIMIT
|
||||
@loop_limit = if Feature.enabled?(:ci_job_artifacts_backlog_large_loop_limit, type: :ops)
|
||||
LARGE_LOOP_LIMIT
|
||||
else
|
||||
LOOP_LIMIT
|
||||
end
|
||||
end
|
||||
|
||||
def execute
|
||||
|
|
@ -35,9 +39,9 @@ module Ci
|
|||
unknown_status_build_ids = safely_ordered_ci_job_artifacts_locked_unknown_relation.pluck_job_id.uniq
|
||||
|
||||
locked_pipe_build_ids = ::Ci::Build
|
||||
.with_pipeline_locked_artifacts
|
||||
.id_in(unknown_status_build_ids)
|
||||
.pluck_primary_key
|
||||
.with_pipeline_locked_artifacts
|
||||
.id_in(unknown_status_build_ids)
|
||||
.pluck_primary_key
|
||||
|
||||
@locked_count += update_unknown_artifacts(locked_pipe_build_ids, Ci::JobArtifact.lockeds[:artifacts_locked])
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
module Groups
|
||||
class CreateService < Groups::BaseService
|
||||
include Organization::CurrentOrganization
|
||||
|
||||
def initialize(user, params = {})
|
||||
@current_user = user
|
||||
@params = params.dup
|
||||
|
|
@ -15,6 +17,8 @@ module Groups
|
|||
|
||||
@group = Group.new(params.except(*::NamespaceSetting.allowed_namespace_settings_params))
|
||||
|
||||
set_organization unless @params[:organization_id]
|
||||
|
||||
@group.build_namespace_settings
|
||||
handle_namespace_settings
|
||||
|
||||
|
|
@ -96,8 +100,6 @@ module Groups
|
|||
# We are unsetting this here to match behavior of invalid parent_id above and protect against possible
|
||||
# committing to the database of a value that isn't allowed.
|
||||
@group.organization = nil
|
||||
message = s_("CreateGroup|You don't have permission to create a group in the provided organization.")
|
||||
@group.errors.add(:organization_id, message)
|
||||
|
||||
return false
|
||||
end
|
||||
|
|
@ -105,6 +107,25 @@ module Groups
|
|||
true
|
||||
end
|
||||
|
||||
def can_create_group_in_organization?
|
||||
return true if can?(current_user, :create_group, @group.organization)
|
||||
|
||||
message = s_("CreateGroup|You don't have permission to create a group in the provided organization.")
|
||||
@group.errors.add(:organization_id, message)
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def matches_parent_organization?
|
||||
return true if @group.parent_id.blank?
|
||||
return true if @group.parent.organization_id == @group.organization_id
|
||||
|
||||
message = s_("CreateGroup|You can't create a group in a different organization than the parent group.")
|
||||
@group.errors.add(:organization_id, message)
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def organization_setting_valid?
|
||||
# we check for the params presence explicitly since:
|
||||
# 1. We have a default organization_id at db level set and organization exists and may not have the entry
|
||||
|
|
@ -115,7 +136,7 @@ module Groups
|
|||
return true if params[:organization_id].blank?
|
||||
return true if @group.organization.blank?
|
||||
|
||||
can?(current_user, :create_group, @group.organization)
|
||||
can_create_group_in_organization? && matches_parent_organization?
|
||||
end
|
||||
|
||||
def can_use_visibility_level?
|
||||
|
|
@ -139,6 +160,14 @@ module Groups
|
|||
@group.shared_runners_enabled = @group.parent.shared_runners_enabled
|
||||
@group.allow_descendants_override_disabled_shared_runners = @group.parent.allow_descendants_override_disabled_shared_runners
|
||||
end
|
||||
|
||||
def set_organization
|
||||
if @group.parent_id
|
||||
@group.organization = @group.parent.organization
|
||||
elsif current_organization
|
||||
@group.organization = current_organization
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PreviewMarkdownService < BaseService
|
||||
class PreviewMarkdownService < BaseContainerService
|
||||
def execute
|
||||
text, commands = explain_quick_actions(params[:text])
|
||||
users = find_user_references(text)
|
||||
|
|
@ -55,7 +55,7 @@ class PreviewMarkdownService < BaseService
|
|||
|
||||
def find_commands_target
|
||||
QuickActions::TargetService
|
||||
.new(container: project, current_user: current_user, params: { group: params[:group] })
|
||||
.new(container: container, current_user: current_user)
|
||||
.execute(target_type, target_id)
|
||||
end
|
||||
|
||||
|
|
@ -68,4 +68,4 @@ class PreviewMarkdownService < BaseService
|
|||
end
|
||||
end
|
||||
|
||||
PreviewMarkdownService.prepend_mod_with('PreviewMarkdownService')
|
||||
PreviewMarkdownService.prepend_mod
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/429557
|
|||
milestone: '16.6'
|
||||
type: development
|
||||
group: group::code review
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@ name: ci_job_artifacts_backlog_large_loop_limit
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76509
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/347151
|
||||
milestone: '14.10'
|
||||
type: development
|
||||
type: ops
|
||||
group: group::pipeline security
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
- title: "`omniauth-azure-oauth2` gem is deprecated"
|
||||
# The milestones for the deprecation announcement, and the removal.
|
||||
removal_milestone: "17.0"
|
||||
announcement_milestone: "16.9"
|
||||
# Change breaking_change to false if needed.
|
||||
breaking_change: true
|
||||
# The stage and GitLab username of the person reporting the change,
|
||||
# and a link to the deprecation issue
|
||||
reporter: hsutor
|
||||
stage: govern
|
||||
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/408989
|
||||
body: | # (required) Don't change this line.
|
||||
GitLab users can use the `omniauth-azure-oauth2` gem to authenticate with GitLab. In 17.0, this gem will be replaced with the `omniauth_openid_connect` gem. The new gem contains all of the same features as the old gem, but also has upstream maintenance and is better for security and centralized maintenance.
|
||||
|
||||
This change requires that users re-connect to the OAuth2 provider at time of migration. To avoid disruption, [add `omniauth_openid_connect` as a new provider](https://docs.gitlab.com/ee/administration/auth/oidc.html#configure-multiple-openid-connect-providers) any time before 17.0. Users will see a new login button and have to manually reconnect their credentials. If you do not implement the `omniauth_openid_connect` gem before 17.0, users will no longer be able to sign in using the Azure login button, and will have to sign in using their username and password, until the correct gem is implemented by the administrator.
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
table_name: p_ci_pipeline_variables
|
||||
classes:
|
||||
- Ci::PipelineVariable
|
||||
- Ci::PipelineVariable::Partitioned
|
||||
feature_categories:
|
||||
- continuous_integration
|
||||
description: Routing table for ci_pipeline_variables
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class NpmSettingsToDependencyProxyPackagesSettings < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
|
||||
milestone '16.9'
|
||||
|
||||
TABLE_NAME = :dependency_proxy_packages_settings
|
||||
|
||||
def up
|
||||
# using the table name so that Migration/AddLimitToTextColumns cop will not make rubocop fail.
|
||||
change_table :dependency_proxy_packages_settings do |t|
|
||||
t.text :npm_external_registry_url, null: true
|
||||
t.binary :encrypted_npm_external_registry_basic_auth, null: true
|
||||
t.binary :encrypted_npm_external_registry_basic_auth_iv, null: true
|
||||
t.binary :encrypted_npm_external_registry_auth_token, null: true
|
||||
t.binary :encrypted_npm_external_registry_auth_token_iv, null: true
|
||||
end
|
||||
|
||||
# using the table name so that Migration/AddLimitToTextColumns cop will not make rubocop fail.
|
||||
add_text_limit :dependency_proxy_packages_settings, :npm_external_registry_url, 255
|
||||
|
||||
constraint = check_constraint_name(TABLE_NAME.to_s, 'encrypted_npm_external_registry_basic_auth', 'max_length')
|
||||
add_check_constraint(TABLE_NAME, 'octet_length(encrypted_npm_external_registry_basic_auth) <= 1020', constraint)
|
||||
|
||||
constraint = check_constraint_name(TABLE_NAME.to_s, 'encrypted_npm_external_registry_basic_auth_iv', 'max_length')
|
||||
add_check_constraint(TABLE_NAME, 'octet_length(encrypted_npm_external_registry_basic_auth_iv) <= 1020', constraint)
|
||||
|
||||
constraint = check_constraint_name(TABLE_NAME.to_s, 'encrypted_npm_external_registry_auth_token', 'max_length')
|
||||
add_check_constraint(TABLE_NAME, 'octet_length(encrypted_npm_external_registry_auth_token) <= 1020', constraint)
|
||||
|
||||
constraint = check_constraint_name(TABLE_NAME.to_s, 'encrypted_npm_external_registry_auth_token_iv', 'max_length')
|
||||
add_check_constraint(TABLE_NAME, 'octet_length(encrypted_npm_external_registry_auth_token_iv) <= 1020', constraint)
|
||||
|
||||
constraint = check_constraint_name(TABLE_NAME.to_s, 'npm_credentials', 'one_set_or_empty')
|
||||
add_check_constraint(
|
||||
TABLE_NAME,
|
||||
'num_nulls(encrypted_npm_external_registry_basic_auth, encrypted_npm_external_registry_auth_token) > 0',
|
||||
constraint
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
change_table TABLE_NAME do |t|
|
||||
t.remove :npm_external_registry_url,
|
||||
:encrypted_npm_external_registry_basic_auth,
|
||||
:encrypted_npm_external_registry_basic_auth_iv,
|
||||
:encrypted_npm_external_registry_auth_token,
|
||||
:encrypted_npm_external_registry_auth_token_iv
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
de80bafabfdf3fb99d98f6dd2b2e38d41968913d68511543d7442958d8a7b864
|
||||
|
|
@ -16303,10 +16303,21 @@ CREATE TABLE dependency_proxy_packages_settings (
|
|||
encrypted_maven_external_registry_username_iv bytea,
|
||||
encrypted_maven_external_registry_password bytea,
|
||||
encrypted_maven_external_registry_password_iv bytea,
|
||||
npm_external_registry_url text,
|
||||
encrypted_npm_external_registry_basic_auth bytea,
|
||||
encrypted_npm_external_registry_basic_auth_iv bytea,
|
||||
encrypted_npm_external_registry_auth_token bytea,
|
||||
encrypted_npm_external_registry_auth_token_iv bytea,
|
||||
CONSTRAINT check_12c046b67f CHECK ((char_length(npm_external_registry_url) <= 255)),
|
||||
CONSTRAINT check_14a2818907 CHECK (((num_nulls(encrypted_maven_external_registry_username, encrypted_maven_external_registry_password) = 0) OR (num_nulls(encrypted_maven_external_registry_username, encrypted_maven_external_registry_password) = 2))),
|
||||
CONSTRAINT check_353c7ecafd CHECK ((octet_length(encrypted_maven_external_registry_username) <= 1020)),
|
||||
CONSTRAINT check_48643112c8 CHECK ((octet_length(encrypted_npm_external_registry_auth_token) <= 1020)),
|
||||
CONSTRAINT check_54126e21c1 CHECK ((octet_length(encrypted_npm_external_registry_basic_auth) <= 1020)),
|
||||
CONSTRAINT check_7fafb5606e CHECK ((octet_length(encrypted_npm_external_registry_basic_auth_iv) <= 1020)),
|
||||
CONSTRAINT check_93afb1690f CHECK ((num_nulls(encrypted_npm_external_registry_basic_auth, encrypted_npm_external_registry_auth_token) > 0)),
|
||||
CONSTRAINT check_ac55c514a5 CHECK ((char_length(maven_external_registry_url) <= 255)),
|
||||
CONSTRAINT check_c6f700648d CHECK ((octet_length(encrypted_maven_external_registry_password) <= 1020)),
|
||||
CONSTRAINT check_c8613a3d35 CHECK ((octet_length(encrypted_npm_external_registry_auth_token_iv) <= 1020)),
|
||||
CONSTRAINT check_cdf5f9a434 CHECK ((octet_length(encrypted_maven_external_registry_password_iv) <= 1020)),
|
||||
CONSTRAINT check_fd5def68ba CHECK ((octet_length(encrypted_maven_external_registry_username_iv) <= 1020))
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
---
|
||||
# Warning: gitlab.VersionHistory
|
||||
# Warning: gitlab.HistoryItems
|
||||
#
|
||||
# Ensures version history items are properly formatted.
|
||||
# Ensures history items are properly formatted.
|
||||
#
|
||||
extends: existence
|
||||
message: "Version history items should always start with '> -', even if there is only one item."
|
||||
message: "History items must always start with '> -', one item per line, even if there is only one item."
|
||||
link: https://docs.gitlab.com/ee/development/documentation/versions.html#add-a-version-history-item
|
||||
level: warning
|
||||
level: error
|
||||
scope: raw
|
||||
raw:
|
||||
- '(?m)(?<=^#+[^\n]*\n\n)> [^-]'
|
||||
- '(?m)(?<=^#+[^\n]*\n\n)> [^-]|'
|
||||
- '^> - [^\n]*\n[^\n>`]'
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ After configuring LDAP, to test the configuration, use the
|
|||
|
||||
### Basic configuration settings
|
||||
|
||||
> The `hosts` configuration setting was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/139) in GitLab 14.7.
|
||||
> - The `hosts` configuration setting was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/139) in GitLab 14.7.
|
||||
|
||||
The following basic settings are available:
|
||||
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ Example response:
|
|||
"external_pipeline_validation_service_token": null,
|
||||
"external_pipeline_validation_service_url": null,
|
||||
"jira_connect_application_key": null,
|
||||
"jira_connect_public_key_storage_enabled": false,
|
||||
"jira_connect_proxy_url": null,
|
||||
"silent_mode_enabled": false,
|
||||
"package_registry_allow_anyone_to_pull_option": true,
|
||||
|
|
@ -269,6 +270,7 @@ Example response:
|
|||
"external_pipeline_validation_service_url": null,
|
||||
"can_create_group": false,
|
||||
"jira_connect_application_key": "123",
|
||||
"jira_connect_public_key_storage_enabled": true,
|
||||
"jira_connect_proxy_url": "http://gitlab.example.com",
|
||||
"user_defaults_to_private_profile": true,
|
||||
"projects_api_rate_limit_unauthenticated": 400,
|
||||
|
|
@ -467,8 +469,9 @@ listed in the descriptions of the relevant settings.
|
|||
| `import_sources` | array of strings | no | Sources to allow project import from, possible values: `github`, `bitbucket`, `bitbucket_server`, `fogbugz`, `git`, `gitlab_project`, `gitea`, and `manifest`. |
|
||||
| `invisible_captcha_enabled` | boolean | no | Enable Invisible CAPTCHA spam detection during sign-up. Disabled by default. |
|
||||
| `issues_create_limit` | integer | no | Max number of issue creation requests per minute per user. Disabled by default.|
|
||||
| `jira_connect_application_key` | String | no | Application ID of the OAuth application that should be used to authenticate with the GitLab for Jira Cloud app |
|
||||
| `jira_connect_proxy_url` | String | no | URL of the GitLab instance that should be used as a proxy for the GitLab for Jira Cloud app |
|
||||
| `jira_connect_application_key` | String | no | ID of the OAuth application used to authenticate with the GitLab for Jira Cloud app. |
|
||||
| `jira_connect_public_key_storage_enabled` | boolean | no | Enable public key storage for the GitLab for Jira Cloud app. |
|
||||
| `jira_connect_proxy_url` | String | no | URL of the GitLab instance used as a proxy for the GitLab for Jira Cloud app. |
|
||||
| `keep_latest_artifact` | boolean | no | Prevent the deletion of the artifacts from the most recent successful jobs, regardless of the expiry time. Enabled by default. |
|
||||
| `local_markdown_version` | integer | no | Increase this value when any cached Markdown should be invalidated. |
|
||||
| `mailgun_signing_key` | string | no | The Mailgun HTTP webhook signing key for receiving events from webhook. |
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ stop_review:
|
|||
|
||||
#### Run a pipeline job when environment is stopped
|
||||
|
||||
> Feature flag `environment_stop_actions_include_all_finished_deployments` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/435128) in GitLab 16.9. Disabled by default.
|
||||
> - Feature flag `environment_stop_actions_include_all_finished_deployments` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/435128) in GitLab 16.9. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `environment_stop_actions_include_all_finished_deployments`.
|
||||
|
|
|
|||
|
|
@ -363,8 +363,12 @@ downstream projects. On self-managed instances, an administrator can change this
|
|||
|
||||
### How pipeline duration is calculated
|
||||
|
||||
Total running time for a given pipeline excludes retries and pending
|
||||
(queued) time.
|
||||
The total running time for a given pipeline excludes:
|
||||
|
||||
- The duration of the initial run for any job that is retried or manually re-run.
|
||||
- Any pending (queue) time.
|
||||
|
||||
That means that if a job is retried or manually re-run, only the duration of the latest run is included in the total running time.
|
||||
|
||||
Each job is represented as a `Period`, which consists of:
|
||||
|
||||
|
|
@ -373,26 +377,32 @@ Each job is represented as a `Period`, which consists of:
|
|||
|
||||
A simple example is:
|
||||
|
||||
- A (1, 3)
|
||||
- B (2, 4)
|
||||
- A (0, 2)
|
||||
- A' (2, 4)
|
||||
- This is retrying A
|
||||
- B (1, 3)
|
||||
- C (6, 7)
|
||||
|
||||
In the example:
|
||||
|
||||
- A begins at 1 and ends at 3.
|
||||
- B begins at 2 and ends at 4.
|
||||
- A begins at 0 and ends at 2.
|
||||
- A' begins at 2 and ends at 4.
|
||||
- B begins at 1 and ends at 3.
|
||||
- C begins at 6 and ends at 7.
|
||||
|
||||
Visually, it can be viewed as:
|
||||
|
||||
```plaintext
|
||||
0 1 2 3 4 5 6 7
|
||||
AAAAAAA
|
||||
BBBBBBB
|
||||
AAAAAAA
|
||||
BBBBBBB
|
||||
A'A'A'A
|
||||
CCCC
|
||||
```
|
||||
|
||||
The union of A, B, and C is (1, 4) and (6, 7). Therefore, the total running time is:
|
||||
Because A is retried, we ignore it and count only job A'.
|
||||
The union of B, A', and C is (1, 4) and (6, 7). Therefore, the total
|
||||
running time is:
|
||||
|
||||
```plaintext
|
||||
(4 - 1) + (7 - 6) => 4
|
||||
|
|
|
|||
|
|
@ -2441,9 +2441,12 @@ job1:
|
|||
|
||||
- [GitLab Runner configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section)
|
||||
|
||||
### `identity_provider` **(EXPERIMENT)**
|
||||
### `identity_provider`
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142054) in GitLab 16.9. This feature is an [Experiment](../../policy/experiment-beta-support.md).
|
||||
DETAILS:
|
||||
**Status:** Experiment
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142054) in GitLab 16.9. This feature is an [Experiment](../../policy/experiment-beta-support.md).
|
||||
|
||||
FLAG:
|
||||
On GitLab.com, this feature is not available.
|
||||
|
|
|
|||
|
|
@ -462,7 +462,6 @@ Elasticsearch is a distributed RESTful search engine built for the cloud.
|
|||
- [Source](../install/installation.md#install-gitaly)
|
||||
- Layer: Core Service (Data)
|
||||
- Process: `gitaly`
|
||||
- GitLab.com: [Service Architecture](https://handbook.gitlab.com/handbook/engineering/infrastructure/production/architecture/#service-architecture)
|
||||
|
||||
Gitaly is a service designed by GitLab to remove our need for NFS for Git storage in distributed deployments of GitLab (think GitLab.com or High Availability Deployments). As of 11.3.0, this service handles all Git level access in GitLab. You can read more about the project [in the project's README](https://gitlab.com/gitlab-org/gitaly).
|
||||
|
||||
|
|
@ -474,7 +473,6 @@ Gitaly is a service designed by GitLab to remove our need for NFS for Git storag
|
|||
- [Source](../install/installation.md#install-gitaly)
|
||||
- Layer: Core Service (Data)
|
||||
- Process: `praefect`
|
||||
- GitLab.com: [Service Architecture](https://handbook.gitlab.com/handbook/engineering/infrastructure/production/architecture/#service-architecture)
|
||||
|
||||
Praefect is a transparent proxy between each Git client and the Gitaly coordinating the replication of
|
||||
repository updates to secondary nodes.
|
||||
|
|
@ -553,7 +551,6 @@ GitLab CI/CD is the open-source continuous integration service included with Git
|
|||
- [Source](../install/installation.md#install-gitlab-shell)
|
||||
- [GDK](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/gitlab.yml.example)
|
||||
- Layer: Core Service (Processor)
|
||||
- GitLab.com: [Service Architecture](https://handbook.gitlab.com/handbook/engineering/infrastructure/production/architecture/#service-architecture)
|
||||
|
||||
[GitLab Shell](gitlab_shell/index.md) is a program designed at GitLab to handle SSH-based `git` sessions, and modifies the list of authorized keys. GitLab Shell is not a Unix shell nor a replacement for Bash or Zsh.
|
||||
|
||||
|
|
@ -566,7 +563,6 @@ GitLab CI/CD is the open-source continuous integration service included with Git
|
|||
- [Source](../install/installation.md#install-gitlab-workhorse)
|
||||
- Layer: Core Service (Processor)
|
||||
- Process: `gitlab-workhorse`
|
||||
- GitLab.com: [Service Architecture](https://handbook.gitlab.com/handbook/engineering/infrastructure/production/architecture/#service-architecture)
|
||||
|
||||
[GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/workhorse) is a program designed at GitLab to help alleviate pressure from Puma. You can read more about the [historical reasons for developing](https://about.gitlab.com/blog/2016/04/12/a-brief-history-of-gitlab-workhorse/). It's designed to act as a smart reverse proxy to help speed up GitLab as a whole.
|
||||
|
||||
|
|
@ -640,7 +636,6 @@ MinIO is an object storage server released under the GNU AGPL v3.0. It is compat
|
|||
- [Source](../install/installation.md#10-nginx)
|
||||
- Layer: Core Service (Processor)
|
||||
- Process: `nginx`
|
||||
- GitLab.com: [Service Architecture](https://handbook.gitlab.com/handbook/engineering/infrastructure/production/architecture/#service-architecture)
|
||||
|
||||
NGINX has an Ingress port for all HTTP requests and routes them to the appropriate sub-systems within GitLab. We are bundling an unmodified version of the popular open source webserver.
|
||||
|
||||
|
|
@ -733,7 +728,6 @@ Prometheus is a time-series tool that helps GitLab administrators expose metrics
|
|||
- [Source](../install/installation.md#8-redis)
|
||||
- Layer: Core Service (Data)
|
||||
- Process: `redis`
|
||||
- GitLab.com: [Service Architecture](https://handbook.gitlab.com/handbook/engineering/infrastructure/production/architecture/#service-architecture)
|
||||
|
||||
Redis is packaged to provide a place to store:
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ when FIPS mode is enabled.
|
|||
| Ubuntu 20.04 Libgcrypt Cryptographic Module | [3902](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3902) | EC2 instances | `gpg`, `sshd` |
|
||||
| Amazon Linux 2 Kernel Crypto API Cryptographic Module | [3709](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3709) | EKS nodes | Linux kernel |
|
||||
| Amazon Linux 2 OpenSSL Cryptographic Module | [3553](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3553) | EKS nodes | NGINX |
|
||||
| RedHat Enterprise Linux 8 OpenSSL Cryptographic Module | [4271](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4271) | EKS nodes | UBI containers: Workhorse, Pages, container registry, Rails (Puma/Sidekiq), Security Analyzers |
|
||||
| RedHat Enterprise Linux 8 OpenSSL Cryptographic Module | [4271](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4271) | EKS nodes | UBI containers: Workhorse, Pages, container registry, Rails (Puma/Sidekiq), Security Analyzers, `gitlab-sshd` |
|
||||
| RedHat Enterprise Linux 8 Libgcrypt Cryptographic Module | [3784](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3784) | EKS nodes | UBI containers: GitLab Shell, `gpg` |
|
||||
|
||||
### Supported Operating Systems
|
||||
|
|
|
|||
|
|
@ -587,7 +587,7 @@ If these commands return `undercover: ✅ No coverage is missing in latest chang
|
|||
|
||||
### `pajamas_adoption` job
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141368) in GitLab 16.8.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141368) in GitLab 16.8.
|
||||
|
||||
The `pajamas_adoption` job runs the [Pajamas Adoption Scanner](https://gitlab-org.gitlab.io/frontend/pajamas-adoption-scanner/) in merge requests to prevent regressions in the adoption of the [Pajamas Design System](https://design.gitlab.com/).
|
||||
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ The following Elasticsearch settings are available:
|
|||
| `Maximum bulk request size (MiB)` | Used by the GitLab Ruby and Go-based indexer processes. This setting indicates how much data must be collected (and stored in memory) in a given indexing process before submitting the payload to the Elasticsearch Bulk API. For the GitLab Go-based indexer, you should use this setting with `Bulk request concurrency`. `Maximum bulk request size (MiB)` must accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Go-based indexer from either the `gitlab-rake` command or the Sidekiq tasks. |
|
||||
| `Bulk request concurrency` | The Bulk request concurrency indicates how many of the GitLab Go-based indexer processes (or threads) can run in parallel to collect data to subsequently submit to the Elasticsearch Bulk API. This increases indexing performance, but fills the Elasticsearch bulk requests queue faster. This setting should be used together with the Maximum bulk request size setting (see above) and needs to accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Go-based indexer either from the `gitlab-rake` command or the Sidekiq tasks. |
|
||||
| `Client request timeout` | Elasticsearch HTTP client request timeout value in seconds. `0` means using the system default timeout value, which depends on the libraries that GitLab application is built upon. |
|
||||
| `Code indexing concurrency` | Maximum number of Elasticsearch code indexing background jobs allowed to run concurrently. This only applies to repository indexing operations. |
|
||||
|
||||
WARNING:
|
||||
Increasing the values of `Maximum bulk request size (MiB)` and `Bulk request concurrency` can negatively impact
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
There are cases where GitLab would like to validate the edge-cases of scale, support, and maintenance burden of features in their current form for every designed use case.
|
||||
There are also scenarios where a feature is not complete enough to be considered an [MVC](https://handbook.gitlab.com/handbook/product/product-principles/#the-minimal-viable-change-mvc).
|
||||
In these cases, GitLab has the option to release features as Experiment, Beta, or Limited Availability, and users can opt-in and test the new experience.
|
||||
In these cases, GitLab has the option to release features as Experiments or Beta features, and users can opt-in and test the new experience.
|
||||
Features might not be fully documented or supported in the Experiment or Beta phases.
|
||||
|
||||
Please note that some features may not be aligned to these recommendations if they were developed before the recommendations were in place or if the group determined an alternative implementation approach was needed.
|
||||
|
|
@ -92,11 +92,11 @@ The experimental features are only shown when people/organizations opt-in to exp
|
|||
All features that are available on GitLab.com are considered "in production".
|
||||
Because all Experiment, Beta, and Generally Available features are available on GitLab.com, they are all considered to be in production.
|
||||
|
||||
## Experiment, Beta and Limited Availability Exit Criteria
|
||||
## Experiment and Beta Exit Criteria
|
||||
|
||||
To ensure the phases before General Availability are as short as possible each phase of Experiment, Beta and LA should include exit criteria.
|
||||
This encourages rapid iteration and reduces [cycle time](https://handbook.gitlab.com/handbook/values/#reduce-cycle-time).
|
||||
GitLab Product Managers will take the following into account when deciding what exit criteria to apply to their Experimental, Beta, and Limited Availability features:
|
||||
GitLab Product Managers will take the following into account when deciding what exit criteria to apply to their Experimental and Beta features:
|
||||
|
||||
- **Time**: Define an end date at which point the feature will be General Availability.
|
||||
- Consider setting a time-bound target metric that will define readiness for exit into GA (e.g. X number of customers retained MoM over 6 months after launch of Experiment, X% growth of free and paid users in three months since launch Beta, etc.)
|
||||
|
|
|
|||
|
|
@ -12,4 +12,4 @@ Choose and manage the subscription that's right for you and your organization.
|
|||
|--|--|--|
|
||||
| [**Choose a GitLab subscription**](choosing_subscription.md) **{chevron-right}**<br><br> Options for accessing GitLab. | [**GitLab SaaS subscription**](gitlab_com/index.md) **{chevron-right}**<br><br> Seat usage, compute minutes, storage limits, renewal info. | [**GitLab self-managed subscription**](self_managed/index.md) **{chevron-right}**<br><br> Billable users, renewal and upgrade info. |
|
||||
| [**GitLab Dedicated**](gitlab_dedicated/index.md) **{chevron-right}**<br><br> Available features and benefits. | [**Community programs**](community_programs.md) **{chevron-right}**<br><br> Education, Open Source, Startups. | [**The Customers Portal**](customers_portal.md) **{chevron-right}**<br><br> Payment and company details. |
|
||||
| [**Quarterly reconciliation and annual true-ups**](quarterly_reconciliation.md) **{chevron-right}**<br><br> Billing examples.| [**Compute quota**](../ci/pipelines/cicd_minutes.md) **{chevron-right}**<br><br> Calculations, quotas, purchase information. | |
|
||||
| [**Quarterly reconciliation and annual true-ups**](quarterly_reconciliation.md) **{chevron-right}**<br><br> Billing examples.| [**Compute quota**](../ci/pipelines/cicd_minutes.md) **{chevron-right}**<br><br> Calculations, quotas, purchase information. | [**Subscription add-ons**](subscription-add-ons.md)<br><br> Purchase add-ons for AI features. |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
stage: Fulfillment
|
||||
group: Purchase
|
||||
description: Subscription add-ons, GitLab Duo Pro, seat assignment
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Subscription add-ons
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** SaaS, self-managed
|
||||
|
||||
You can purchase subscription add-ons to give users in your organization access to more GitLab features.
|
||||
Subscription add-ons are purchased as additional seats in your subscription.
|
||||
Access to features provided by subscription add-ons is managed through seat assignment. Subscription
|
||||
add-ons can be assigned to billable users only.
|
||||
|
||||
## Assign GitLab Duo Pro seats
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must purchase the GitLab Duo Pro add-on from the [GitLab Sales Team](https://about.gitlab.com/solutions/gitlab-duo-pro/sales/).
|
||||
|
||||
After you purchase GitLab Duo Pro, you can assign seats to billable users to grant access to the add-on.
|
||||
|
||||
### For GitLab.com
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your group.
|
||||
1. Select **Settings > Usage Quotas**.
|
||||
<!-- vale gitlab.Substitutions = NO -->
|
||||
1. Select the **Duo Pro** tab.
|
||||
<!-- vale gitlab.Substitutions = YES -->
|
||||
1. To the right of the user, turn on the toggle to assign or unassign
|
||||
GitLab Duo Pro.
|
||||
|
||||
### For self-managed
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must be an administrator.
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
<!-- vale gitlab.Substitutions = NO -->
|
||||
1. Select **Duo Pro**.
|
||||
- If the **Duo Pro** menu item is not available, synchronize your subscription
|
||||
after purchase:
|
||||
1. On the left sidebar, select **Subscription**.
|
||||
1. In **Subscription details**, to the right of **Last sync**, select
|
||||
synchronize subscription (**{retry}**).
|
||||
<!-- vale gitlab.Substitutions = YES -->
|
||||
1. To the right of the user, turn on the toggle to assign or unassign
|
||||
GitLab Duo Pro.
|
||||
|
|
@ -1664,6 +1664,22 @@ Multiple DORA metrics can now be queried simultaneously using a new metrics fiel
|
|||
|
||||
<div class="deprecation breaking-change" data-milestone="17.0">
|
||||
|
||||
### `omniauth-azure-oauth2` gem is deprecated
|
||||
|
||||
<div class="deprecation-notes">
|
||||
- Announced in GitLab <span class="milestone">16.9</span>
|
||||
- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
|
||||
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/408989).
|
||||
</div>
|
||||
|
||||
GitLab users can use the `omniauth-azure-oauth2` gem to authenticate with GitLab. In 17.0, this gem will be replaced with the `omniauth_openid_connect` gem. The new gem contains all of the same features as the old gem, but also has upstream maintenance and is better for security and centralized maintenance.
|
||||
|
||||
This change requires that users re-connect to the OAuth2 provider at time of migration. To avoid disruption, [add `omniauth_openid_connect` as a new provider](https://docs.gitlab.com/ee/administration/auth/oidc.html#configure-multiple-openid-connect-providers) any time before 17.0. Users will see a new login button and have to manually reconnect their credentials. If you do not implement the `omniauth_openid_connect` gem before 17.0, users will no longer be able to sign in using the Azure login button, and will have to sign in using their username and password, until the correct gem is implemented by the administrator.
|
||||
|
||||
</div>
|
||||
|
||||
<div class="deprecation breaking-change" data-milestone="17.0">
|
||||
|
||||
### `postgres_exporter['per_table_stats']` configuration setting
|
||||
|
||||
<div class="deprecation-notes">
|
||||
|
|
|
|||
|
|
@ -876,7 +876,7 @@ reported.
|
|||
|
||||
### View details of an API Fuzzing vulnerability
|
||||
|
||||
> Introduced in GitLab 13.7.
|
||||
> - Introduced in GitLab 13.7.
|
||||
|
||||
Faults detected by API Fuzzing occur in the live web application, and require manual investigation
|
||||
to determine if they are vulnerabilities. Fuzzing faults are included as vulnerabilities with a
|
||||
|
|
|
|||
|
|
@ -15,10 +15,8 @@ To run a DAST scan:
|
|||
|
||||
## Create a DAST CI/CD job
|
||||
|
||||
> - This template was [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62597) to DAST_VERSION: 2 in
|
||||
GitLab 14.0.
|
||||
> - This template was [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87183) to DAST_VERSION: 3 in
|
||||
GitLab 15.0.
|
||||
> - This template was [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62597) to DAST_VERSION: 2 in GitLab 14.0.
|
||||
> - This template was [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87183) to DAST_VERSION: 3 in GitLab 15.0.
|
||||
|
||||
To add DAST scanning to your application, use the DAST job defined
|
||||
in the GitLab DAST CI/CD template file. Updates to the template are provided with GitLab
|
||||
|
|
|
|||
|
|
@ -300,19 +300,13 @@ actions:
|
|||
## Understanding scan result policy approvals
|
||||
|
||||
> - The branch comparison logic for `scan_finding` was [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/428518) in GitLab 16.8 [with a flag](../../../administration/feature_flags.md) named `scan_result_policy_merge_base_pipeline`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `scan_result_policy_merge_base_pipeline`.
|
||||
On GitLab.com, this feature is not available.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/435297) in GitLab 16.9. Feature flag `scan_result_policy_merge_base_pipeline` removed.
|
||||
|
||||
### Scope of scan result policy comparison
|
||||
|
||||
- To determine when approval is required on a merge request, we compare completed pipelines for each supported pipeline source for the source and target branch (for example, `feature`/`main`). This ensures the most comprehensive evaluation of scan results.
|
||||
- For the source branch, the comparison pipeline is its latest completed `HEAD` pipeline.
|
||||
- For `license_finding` rules, we compare to a common ancestor's latest completed pipeline.
|
||||
- For `scan_finding` rules, the comparison pipeline may differ:
|
||||
- If the `scan_result_policy_merge_base_pipeline` feature flag is enabled, we compare to a common ancestor's latest completed pipeline.
|
||||
- Otherwise, we compare to the target branch's latest completed `HEAD` pipeline.
|
||||
- For the target branch, we compare to a common ancestor's latest completed pipeline.
|
||||
- Scan result policies considers all supported pipeline sources (based on the [`CI_PIPELINE_SOURCE` variable](../../../ci/variables/predefined_variables.md)) when comparing results from both the source and target branches when determining if a merge request requires approval. Pipeline sources `webide` and `parent_pipeline` are not supported.
|
||||
|
||||
### Accepting risk and ignoring vulnerabilities in future merge requests
|
||||
|
|
|
|||
|
|
@ -19,9 +19,11 @@ To temporarily grant Git access to your projects, you can use SSH certificates.
|
|||
## Add a CA certificate to a top-level group
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/421915) in GitLab 16.4 [with a flag](../feature_flags.md) named `ssh_certificates_rest_endpoints`. Disabled by default.
|
||||
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/424501) in GitLab 16.9.
|
||||
|
||||
FLAG:
|
||||
On GitLab.com, this feature is not available.
|
||||
On GitLab.com, this feature is available.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have the Owner role for the group.
|
||||
|
|
@ -64,9 +66,10 @@ The user certificates can only be used to access the projects within the top-lev
|
|||
## Enforce SSH certificates
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/421915) in GitLab 16.7 [with a flag](../feature_flags.md) named `enforce_ssh_certificates_via_settings`. Disabled by default.
|
||||
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/426235) in GitLab 16.9.
|
||||
|
||||
FLAG:
|
||||
On GitLab.com, this feature is not available.
|
||||
On GitLab.com, this feature is available.
|
||||
|
||||
You can enforce usage of SSH certificates and forbid users from authenticating using SSH
|
||||
keys and access tokens.
|
||||
|
|
|
|||
|
|
@ -485,7 +485,7 @@ system note in the OKR's comments, for example:
|
|||
|
||||
## Lock discussion
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/398649) in GitLab 16.9 [with a flag](../administration/feature_flags.md) named `work_items_mvc`. Disabled by default.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/398649) in GitLab 16.9 [with a flag](../administration/feature_flags.md) named `work_items_mvc`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../administration/feature_flags.md) named `work_items_mvc`.
|
||||
|
|
|
|||
|
|
@ -455,3 +455,27 @@ GitLab has approved this rule automatically to unblock the merge request.
|
|||
This issue occurs when an approval rule uses a Code Owner that is not a direct member of the project.
|
||||
|
||||
The workaround is to check that the group or user has been invited to the project.
|
||||
|
||||
### User or group not shown when viewing Code Owners for a directory
|
||||
|
||||
Code Owners might not show the intended user or group based on your configured rules when viewing a directory,
|
||||
but correctly show the Code Owners for files beneath the directory.
|
||||
|
||||
For example:
|
||||
|
||||
```plaintext
|
||||
* @dev-team
|
||||
docs/ @tech-writer-team
|
||||
```
|
||||
|
||||
All files beneath the `docs/` directory show `@tech-writer-team` as Code Owners, but the directory itself will show `@dev-team`.
|
||||
|
||||
This behavior occurs when viewing a directory because the [syntax rule](../../project/codeowners/reference.md#directory-paths)
|
||||
applies to all files beneath the directory, which does not include the directory itself. To resolve this, update the `CODEOWNERS` file to include the
|
||||
directory specifically along with all files beneath the directory. For example:
|
||||
|
||||
```plaintext
|
||||
* @dev-team
|
||||
docs @tech-writer-team
|
||||
docs/ @tech-writer-team
|
||||
```
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ use the default approval rules from the target (upstream) project, not the sourc
|
|||
|
||||
## Add an approval rule
|
||||
|
||||
> Approval rules for all protected branches introduced in GitLab 15.3.
|
||||
> - Approval rules for all protected branches introduced in GitLab 15.3.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
|
|
|
|||
|
|
@ -320,6 +320,7 @@ For a web developer writing a webpage for your company's website:
|
|||
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/387070) in GitLab 16.0.
|
||||
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126998) in GitLab 16.3 by default.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132355) in GitLab 16.5. Feature flag `mr_activity_filters` removed.
|
||||
> - Filtering bot comments [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128473) in GitLab 16.9.
|
||||
|
||||
To understand the history of a merge request, filter its activity feed to show you
|
||||
only the items that are relevant to you.
|
||||
|
|
@ -335,6 +336,7 @@ only the items that are relevant to you.
|
|||
|
||||
- Assignees & Reviewers
|
||||
- Approvals
|
||||
- Bot comments
|
||||
- Comments
|
||||
- Commits & branches
|
||||
- Edits
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ Each link as an asset has the following attributes:
|
|||
|-------------|--------------------------------------------------------------------------------------------------------------|----------|
|
||||
| `name` | The name of the link. | Yes |
|
||||
| `url` | The URL to download a file. | Yes |
|
||||
| `filepath` | The redirect link to the `url`. See [this section](#permanent-links-to-release-assets) for more information. | No |
|
||||
| `filepath` | The redirect link to the `url`. Must start with a slash (`/`). See [this section](#permanent-links-to-release-assets) for more information. | No |
|
||||
| `link_type` | The content kind of what users can download via `url`. See [this section](#link-types) for more information. | No |
|
||||
|
||||
#### Permanent link to latest release
|
||||
|
|
@ -101,7 +101,7 @@ to use the same URL. This is defined during [link creation](../../../api/release
|
|||
The format of the URL is:
|
||||
|
||||
```plaintext
|
||||
https://host/namespace/project/-/releases/:release/downloads/:filepath
|
||||
https://host/namespace/project/-/releases/:release/downloads:filepath
|
||||
```
|
||||
|
||||
If you have an asset for the `v11.9.0-rc2` release in the `gitlab-org`
|
||||
|
|
@ -128,22 +128,24 @@ If the release is private, you need to provide a Personal Access Token with eith
|
|||
a `private_token` query parameter or a `HTTP_PRIVATE_TOKEN` header when making the request. For example:
|
||||
|
||||
```shell
|
||||
curl --location --output filename "https://gitlab.example.com/my-group/my-project/-/releases/:release/downloads/:filepath?private_token=<your_access_token>"
|
||||
curl --location --output filename --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/my-group/my-project/-/releases/:release/downloads/:filepath"
|
||||
curl --location --output filename "https://gitlab.example.com/my-group/my-project/-/releases/myrelease/downloads</path-to-file>?private_token=<your_access_token>"
|
||||
curl --location --output filename --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/my-group/my-project/-/releases/myrelease/downloads</path-to-file>
|
||||
```
|
||||
|
||||
#### Permanent links to latest release assets
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16821) in GitLab 14.9.
|
||||
|
||||
The `filepath` from [permanent links to release assets](#permanent-links-to-release-assets) can be used in combination with [permanent link to the latest release](#permanent-link-to-latest-release). It is useful when we want to link a permanent URL to download an asset from the *latest release*.
|
||||
You can use the `filepath` from [permanent links to release assets](#permanent-links-to-release-assets) in combination with a [permanent link to the latest release](#permanent-link-to-latest-release). The `filepath` must start with a slash (`/`).
|
||||
|
||||
The format of the URL is:
|
||||
|
||||
```plaintext
|
||||
https://host/namespace/project/-/releases/permalink/latest/downloads/:filepath
|
||||
https://host/namespace/project/-/releases/permalink/latest/downloads:filepath
|
||||
```
|
||||
|
||||
You can use this format to provide a permanent link to an asset from the latest release.
|
||||
|
||||
If you have an asset with [`filepath`](../../../api/releases/links.md#create-a-release-link) for the `v11.9.0-rc2` latest release in the `gitlab-org`
|
||||
namespace and `gitlab-runner` project on `gitlab.com`, for example:
|
||||
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ system note in the task's comments, for example:
|
|||
|
||||
## Lock discussion
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/398649) in GitLab 16.9 [with a flag](../administration/feature_flags.md) named `work_items_mvc`. Disabled by default.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/398649) in GitLab 16.9 [with a flag](../administration/feature_flags.md) named `work_items_mvc`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../administration/feature_flags.md) named `work_items_mvc`.
|
||||
|
|
|
|||
|
|
@ -210,8 +210,9 @@ module API
|
|||
optional :group_runner_token_expiration_interval, type: Integer, desc: 'Token expiration interval for group runners, in seconds'
|
||||
optional :project_runner_token_expiration_interval, type: Integer, desc: 'Token expiration interval for project runners, in seconds'
|
||||
optional :pipeline_limit_per_project_user_sha, type: Integer, desc: "Maximum number of pipeline creation requests allowed per minute per user and commit. Set to 0 for unlimited requests per minute."
|
||||
optional :jira_connect_application_key, type: String, desc: "Application ID of the OAuth application that should be used to authenticate with the GitLab for Jira Cloud app"
|
||||
optional :jira_connect_proxy_url, type: String, desc: "URL of the GitLab instance that should be used as a proxy for the GitLab for Jira Cloud app"
|
||||
optional :jira_connect_application_key, type: String, desc: "ID of the OAuth application used to authenticate with the GitLab for Jira Cloud app."
|
||||
optional :jira_connect_public_key_storage_enabled, type: Boolean, desc: 'Enable public key storage for the GitLab for Jira Cloud app.'
|
||||
optional :jira_connect_proxy_url, type: String, desc: "URL of the GitLab instance used as a proxy for the GitLab for Jira Cloud app."
|
||||
optional :bulk_import_concurrent_pipeline_batch_limit, type: Integer, desc: 'Maximum simultaneous Direct Transfer pipeline batches to process'
|
||||
optional :bulk_import_enabled, type: Boolean, desc: 'Enable migrating GitLab groups and projects by direct transfer'
|
||||
optional :bulk_import_max_download_file, type: Integer, desc: 'Maximum download file size in MB when importing from source GitLab instances by direct transfer'
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ module Gitlab
|
|||
delegate :instrument, to: :logger
|
||||
|
||||
# We try to keep the number of parallel HTTP requests to a minimum to avoid overloading IO.
|
||||
MAX_PARALLEL_REMOTE_REQUESTS = 2
|
||||
MAX_PARALLEL_REMOTE_REQUESTS = 4
|
||||
|
||||
def initialize(
|
||||
project: nil, pipeline: nil, sha: nil, user: nil, parent_pipeline: nil, variables: nil,
|
||||
|
|
|
|||
|
|
@ -14703,6 +14703,9 @@ msgstr ""
|
|||
msgid "CreateGitTag|Set tag message"
|
||||
msgstr ""
|
||||
|
||||
msgid "CreateGroup|You can't create a group in a different organization than the parent group."
|
||||
msgstr ""
|
||||
|
||||
msgid "CreateGroup|You don't have permission to create a group in the provided organization."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/fonts": "^1.3.0",
|
||||
"@gitlab/svgs": "3.80.0",
|
||||
"@gitlab/ui": "^72.12.1",
|
||||
"@gitlab/ui": "^73.1.1",
|
||||
"@gitlab/visual-review-tools": "1.7.3",
|
||||
"@gitlab/web-ide": "^0.0.1-dev-20240125064919",
|
||||
"@mattiasbuelens/web-streams-adapter": "^0.1.0",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Pajamas::SingleStatComponent, type: :component, feature_category: :shared do
|
||||
let(:title) { "Single Stat" }
|
||||
let(:stat_value) { "9,000" }
|
||||
let(:title_icon) { nil }
|
||||
let(:unit) { nil }
|
||||
let(:meta_text) { nil }
|
||||
let(:variant) { :success }
|
||||
|
||||
before do
|
||||
render_inline(described_class.new(
|
||||
title: title,
|
||||
title_icon: title_icon,
|
||||
stat_value: stat_value,
|
||||
unit: unit,
|
||||
meta_text: meta_text
|
||||
))
|
||||
end
|
||||
|
||||
context "with default props" do
|
||||
it 'shows title' do
|
||||
expect(page).to have_css('[data-testid=title-text]', text: title)
|
||||
end
|
||||
|
||||
it 'shows stat_value' do
|
||||
expect(page).to have_css('[data-testid=non-animated-value]', text: stat_value)
|
||||
end
|
||||
|
||||
it 'does not show unit' do
|
||||
expect(page).not_to have_css('[data-testid=unit]')
|
||||
end
|
||||
|
||||
it 'does not show meta badge' do
|
||||
expect(page).not_to have_css('[data-testid=meta-badge]')
|
||||
end
|
||||
end
|
||||
|
||||
context "with title_icon" do
|
||||
let(:title_icon) { :tanuki }
|
||||
|
||||
it 'shows icon' do
|
||||
expect(page).to have_css('svg[data-testid=tanuki-icon]')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with unit' do
|
||||
let(:unit) { 'KB' }
|
||||
|
||||
it 'shows unit' do
|
||||
expect(page).to have_css('[data-testid=unit]', text: unit)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with meta_text' do
|
||||
let(:meta_text) { "You're doing great!" }
|
||||
|
||||
it 'shows badge with text' do
|
||||
expect(page).to have_css('[data-testid=meta-badge]', text: meta_text)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Pajamas
|
||||
class SingleStatComponentPreview < ViewComponent::Preview
|
||||
# SingleStat
|
||||
# ---
|
||||
#
|
||||
# See its design reference [here](https://design.gitlab.com/data-visualization/single-stat).
|
||||
#
|
||||
# @param title text
|
||||
# @param stat_value text
|
||||
# @param unit text
|
||||
# @param title_icon text
|
||||
# @param meta_text text
|
||||
# @param meta_icon text
|
||||
# @param variant select {{ Pajamas::BadgeComponent::VARIANT_OPTIONS }}
|
||||
# @param hide_units toggle
|
||||
def default(
|
||||
title: 'Single stat',
|
||||
stat_value: '9,001',
|
||||
unit: '',
|
||||
title_icon: 'chart',
|
||||
meta_text: '',
|
||||
meta_icon: 'check-circle',
|
||||
variant: :default
|
||||
)
|
||||
render Pajamas::SingleStatComponent.new(
|
||||
title: title,
|
||||
stat_value: stat_value,
|
||||
unit: unit,
|
||||
title_icon: title_icon,
|
||||
meta_text: meta_text,
|
||||
meta_icon: meta_icon,
|
||||
variant: variant
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -3,11 +3,13 @@ import App from '~/organizations/groups_and_projects/components/app.vue';
|
|||
import GroupsView from '~/organizations/shared/components/groups_view.vue';
|
||||
import ProjectsView from '~/organizations/shared/components/projects_view.vue';
|
||||
import { RESOURCE_TYPE_GROUPS, RESOURCE_TYPE_PROJECTS } from '~/organizations/constants';
|
||||
import { SORT_ITEMS } from '~/organizations/groups_and_projects/constants';
|
||||
import {
|
||||
SORT_ITEM_CREATED,
|
||||
SORT_ITEM_NAME,
|
||||
SORT_ITEM_CREATED_AT,
|
||||
SORT_DIRECTION_DESC,
|
||||
SORT_ITEMS,
|
||||
} from '~/organizations/groups_and_projects/constants';
|
||||
SORT_DIRECTION_ASC,
|
||||
} from '~/organizations/shared/constants';
|
||||
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
|
||||
import {
|
||||
FILTERED_SEARCH_TERM,
|
||||
|
|
@ -21,6 +23,9 @@ describe('GroupsAndProjectsApp', () => {
|
|||
const routerMock = {
|
||||
push: jest.fn(),
|
||||
};
|
||||
const mockEndCursor = 'mockEndCursor';
|
||||
const mockStartCursor = 'mockStartCursor';
|
||||
|
||||
let wrapper;
|
||||
|
||||
const createComponent = ({ routeQuery = { search: 'foo' } } = {}) => {
|
||||
|
|
@ -45,11 +50,24 @@ describe('GroupsAndProjectsApp', () => {
|
|||
'when `display` query string is $display',
|
||||
({ display, expectedComponent, expectedDisplayListboxSelectedProp }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({ routeQuery: { display } });
|
||||
createComponent({
|
||||
routeQuery: {
|
||||
display,
|
||||
search: 'foo',
|
||||
start_cursor: mockStartCursor,
|
||||
end_cursor: mockEndCursor,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('renders expected component', () => {
|
||||
expect(wrapper.findComponent(expectedComponent).exists()).toBe(true);
|
||||
it('renders expected component with correct props', () => {
|
||||
expect(wrapper.findComponent(expectedComponent).props()).toMatchObject({
|
||||
startCursor: mockStartCursor,
|
||||
endCursor: mockEndCursor,
|
||||
search: 'foo',
|
||||
sortName: SORT_ITEM_NAME.value,
|
||||
sortDirection: SORT_DIRECTION_ASC,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders display listbox with correct props', () => {
|
||||
|
|
@ -88,8 +106,8 @@ describe('GroupsAndProjectsApp', () => {
|
|||
|
||||
expect(findSort().props()).toMatchObject({
|
||||
isAscending: true,
|
||||
text: SORT_ITEM_CREATED.text,
|
||||
sortBy: SORT_ITEM_CREATED.value,
|
||||
text: 'Name',
|
||||
sortBy: SORT_ITEM_NAME.value,
|
||||
sortOptions: SORT_ITEMS,
|
||||
});
|
||||
});
|
||||
|
|
@ -124,28 +142,50 @@ describe('GroupsAndProjectsApp', () => {
|
|||
|
||||
describe('when sort item is changed', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
createComponent({
|
||||
routeQuery: {
|
||||
display: RESOURCE_TYPE_PROJECTS,
|
||||
start_cursor: mockStartCursor,
|
||||
end_cursor: mockEndCursor,
|
||||
search: 'foo',
|
||||
},
|
||||
});
|
||||
|
||||
findSort().vm.$emit('sortByChange', SORT_ITEM_CREATED.value);
|
||||
findSort().vm.$emit('sortByChange', SORT_ITEM_CREATED_AT.value);
|
||||
});
|
||||
|
||||
it('updates `sort_name` query string', () => {
|
||||
expect(routerMock.push).toHaveBeenCalledWith({
|
||||
query: { sort_name: SORT_ITEM_CREATED.value, search: 'foo' },
|
||||
query: {
|
||||
display: RESOURCE_TYPE_PROJECTS,
|
||||
sort_name: SORT_ITEM_CREATED_AT.value,
|
||||
search: 'foo',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when sort direction is changed', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
createComponent({
|
||||
routeQuery: {
|
||||
display: RESOURCE_TYPE_PROJECTS,
|
||||
start_cursor: mockStartCursor,
|
||||
end_cursor: mockEndCursor,
|
||||
search: 'foo',
|
||||
},
|
||||
});
|
||||
|
||||
findSort().vm.$emit('sortDirectionChange', false);
|
||||
});
|
||||
|
||||
it('updates `sort_direction` query string', () => {
|
||||
expect(routerMock.push).toHaveBeenCalledWith({
|
||||
query: { sort_direction: SORT_DIRECTION_DESC, search: 'foo' },
|
||||
query: {
|
||||
display: RESOURCE_TYPE_PROJECTS,
|
||||
sort_direction: SORT_DIRECTION_DESC,
|
||||
search: 'foo',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -163,9 +203,6 @@ describe('GroupsAndProjectsApp', () => {
|
|||
});
|
||||
|
||||
describe('when page is changed', () => {
|
||||
const mockEndCursor = 'mockEndCursor';
|
||||
const mockStartCursor = 'mockStartCursor';
|
||||
|
||||
describe('when going to next page', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ routeQuery: { display: RESOURCE_TYPE_PROJECTS } });
|
||||
|
|
@ -203,28 +240,6 @@ describe('GroupsAndProjectsApp', () => {
|
|||
query: { display: RESOURCE_TYPE_PROJECTS, start_cursor: mockStartCursor },
|
||||
});
|
||||
});
|
||||
|
||||
describe('when going to the first page', () => {
|
||||
it('removes `start_cursor` and `end_cursor` query string', () => {
|
||||
createComponent({
|
||||
routeQuery: {
|
||||
display: RESOURCE_TYPE_PROJECTS,
|
||||
start_cursor: mockStartCursor,
|
||||
end_cursor: mockEndCursor,
|
||||
},
|
||||
});
|
||||
|
||||
findProjectsView().vm.$emit('page-change', {
|
||||
endCursor: null,
|
||||
startCursor: mockStartCursor,
|
||||
hasPreviousPage: false,
|
||||
});
|
||||
|
||||
expect(routerMock.push).toHaveBeenCalledWith({
|
||||
query: { display: RESOURCE_TYPE_PROJECTS },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue