Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-11-02 12:09:49 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-11-02 12:09:49 +0300
commit157c4d9279f8ba1ad14debad9bdd017725bad316 (patch)
tree1a594f4a8a42c53fa0d55a65e067f133e387bce5
parente55fd66eae00abbfe53b24cf7f52f6ddfd0da8b1 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/analytics/devops_report/constants.js4
-rw-r--r--app/assets/javascripts/boards/boards_util.js4
-rw-r--r--app/assets/javascripts/boards/components/board_content_sidebar.vue10
-rw-r--r--app/assets/javascripts/boards/components/board_form.vue39
-rw-r--r--app/assets/javascripts/boards/components/boards_selector.vue26
-rw-r--r--app/assets/javascripts/boards/index.js2
-rw-r--r--app/assets/javascripts/boards/mount_multiple_boards_switcher.js8
-rw-r--r--app/assets/javascripts/graphql_shared/queries/group_users_search.query.graphql1
-rw-r--r--app/assets/javascripts/graphql_shared/queries/project_user_members_search.query.graphql1
-rw-r--r--app/assets/javascripts/sidebar/constants.js2
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js4
-rw-r--r--app/assets/javascripts/sidebar/queries/update_merge_request_labels.mutation.graphql1
-rw-r--r--app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue97
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue5
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue5
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_value.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/group_labels.query.graphql3
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/merge_request_labels.query.graphql14
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql1
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue10
-rw-r--r--app/assets/stylesheets/page_bundles/boards.scss4
-rw-r--r--app/controllers/projects/merge_requests_controller.rb1
-rw-r--r--app/finders/autocomplete/routes_finder.rb2
-rw-r--r--app/helpers/boards_helper.rb2
-rw-r--r--app/models/concerns/loaded_in_group_list.rb2
-rw-r--r--app/views/admin/dev_ops_report/show.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_admin.html.haml4
-rw-r--r--app/views/shared/boards/_switcher.html.haml4
-rw-r--r--doc/administration/geo/index.md13
-rw-r--r--doc/administration/monitoring/prometheus/puma_exporter.md2
-rw-r--r--doc/administration/object_storage.md8
-rw-r--r--doc/administration/operations/puma.md5
-rw-r--r--doc/development/contributing/issue_workflow.md2
-rw-r--r--doc/development/service_ping/index.md4
-rw-r--r--doc/user/admin_area/analytics/dev_ops_report.md14
-rw-r--r--doc/user/admin_area/analytics/index.md2
-rw-r--r--doc/user/group/devops_adoption/index.md2
-rw-r--r--doc/user/project/pages/getting_started/pages_ci_cd_template.md16
-rw-r--r--locale/gitlab.pot21
-rw-r--r--spec/finders/autocomplete/routes_finder_spec.rb57
-rw-r--r--spec/frontend/boards/components/board_form_spec.js3
-rw-r--r--spec/frontend/boards/components/boards_selector_spec.js4
-rw-r--r--spec/frontend/boards/mock_data.js41
-rw-r--r--spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_spec.js1
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js1
-rw-r--r--spec/helpers/boards_helper_spec.rb6
-rw-r--r--spec/models/concerns/loaded_in_group_list_spec.rb58
-rw-r--r--spec/support_specs/database/prevent_cross_database_modification_spec.rb103
52 files changed, 367 insertions, 279 deletions
diff --git a/app/assets/javascripts/analytics/devops_report/constants.js b/app/assets/javascripts/analytics/devops_report/constants.js
index b395d7eb464..6091fcb5724 100644
--- a/app/assets/javascripts/analytics/devops_report/constants.js
+++ b/app/assets/javascripts/analytics/devops_report/constants.js
@@ -2,10 +2,10 @@ import { __ } from '~/locale';
export const INTRO_COOKIE_KEY = 'dev_ops_report_intro_callout_dismissed';
-export const INTRO_BANNER_TITLE = __('Introducing Your DevOps Report');
+export const INTRO_BANNER_TITLE = __('Introducing Your DevOps Reports');
export const INTRO_BANNER_BODY = __(
- 'Your DevOps Report gives an overview of how you are using GitLab from a feature perspective. Use it to view how you compare with other organizations.',
+ 'Your DevOps Reports give an overview of how you are using GitLab from a feature perspective. Use them to view how you compare with other organizations, and how your teams compare against each other.',
);
export const INTRO_BANNER_ACTION_TEXT = __('Read more');
diff --git a/app/assets/javascripts/boards/boards_util.js b/app/assets/javascripts/boards/boards_util.js
index c10241d00d7..e6c91c7ac1f 100644
--- a/app/assets/javascripts/boards/boards_util.js
+++ b/app/assets/javascripts/boards/boards_util.js
@@ -1,4 +1,5 @@
import { sortBy, cloneDeep } from 'lodash';
+import { isGid } from '~/graphql_shared/utils';
import { ListType, MilestoneIDs } from './constants';
export function getMilestone() {
@@ -95,6 +96,9 @@ export function fullMilestoneId(id) {
}
export function fullLabelId(label) {
+ if (isGid(label.id)) {
+ return label.id;
+ }
if (label.project_id && label.project_id !== null) {
return `gid://gitlab/ProjectLabel/${label.id}`;
}
diff --git a/app/assets/javascripts/boards/components/board_content_sidebar.vue b/app/assets/javascripts/boards/components/board_content_sidebar.vue
index 63334e7b4d1..54668c9e88e 100644
--- a/app/assets/javascripts/boards/components/board_content_sidebar.vue
+++ b/app/assets/javascripts/boards/components/board_content_sidebar.vue
@@ -54,6 +54,9 @@ export default {
allowLabelEdit: {
default: false,
},
+ labelsFilterBasePath: {
+ default: '',
+ },
},
inheritAttrs: false,
computed: {
@@ -90,6 +93,11 @@ export default {
labelType() {
return this.isGroupBoard ? LabelType.group : LabelType.project;
},
+ labelsFilterPath() {
+ return this.isGroupBoard
+ ? this.labelsFilterBasePath.replace(':project_path', this.projectPathForActiveIssue)
+ : this.labelsFilterBasePath;
+ },
},
methods: {
...mapActions([
@@ -212,7 +220,7 @@ export default {
:footer-create-label-title="createLabelTitle"
:footer-manage-label-title="manageLabelTitle"
:labels-create-title="createLabelTitle"
- :labels-filter-base-path="projectPathForActiveIssue"
+ :labels-filter-base-path="labelsFilterPath"
:attr-workspace-path="attrWorkspacePath"
workspace-type="project"
:issuable-type="issuableType"
diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue
index e939f0c0ebe..64f598b4064 100644
--- a/app/assets/javascripts/boards/components/board_form.vue
+++ b/app/assets/javascripts/boards/components/board_form.vue
@@ -57,39 +57,16 @@ export default {
type: Boolean,
required: true,
},
- labelsPath: {
- type: String,
- required: true,
- },
- labelsWebUrl: {
- type: String,
- required: true,
- },
scopedIssueBoardFeatureEnabled: {
type: Boolean,
required: false,
default: false,
},
- projectId: {
- type: Number,
- required: false,
- default: 0,
- },
- groupId: {
- type: Number,
- required: false,
- default: 0,
- },
weights: {
type: Array,
required: false,
default: () => [],
},
- enableScopedLabels: {
- type: Boolean,
- required: false,
- default: false,
- },
currentBoard: {
type: Object,
required: true,
@@ -288,16 +265,7 @@ export default {
this.board.iteration_id = iterationId;
},
setBoardLabels(labels) {
- labels.forEach((label) => {
- if (label.set && !this.board.labels.find((l) => l.id === label.id)) {
- this.board.labels.push({
- ...label,
- textColor: label.text_color,
- });
- } else if (!label.set) {
- this.board.labels = this.board.labels.filter((selected) => selected.id !== label.id);
- }
- });
+ this.board.labels = labels;
},
setAssignee(assigneeId) {
this.$set(this.board, 'assignee', {
@@ -371,11 +339,6 @@ export default {
:collapse-scope="isNewForm"
:board="board"
:can-admin-board="canAdminBoard"
- :labels-path="labelsPath"
- :labels-web-url="labelsWebUrl"
- :enable-scoped-labels="enableScopedLabels"
- :project-id="projectId"
- :group-id="groupId"
:weights="weights"
@set-iteration="setIteration"
@set-board-labels="setBoardLabels"
diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue
index 98027917221..84de37c2ef1 100644
--- a/app/assets/javascripts/boards/components/boards_selector.vue
+++ b/app/assets/javascripts/boards/components/boards_selector.vue
@@ -64,22 +64,6 @@ export default {
type: Boolean,
required: true,
},
- labelsPath: {
- type: String,
- required: true,
- },
- labelsWebUrl: {
- type: String,
- required: true,
- },
- projectId: {
- type: Number,
- required: true,
- },
- groupId: {
- type: Number,
- required: true,
- },
scopedIssueBoardFeatureEnabled: {
type: Boolean,
required: true,
@@ -88,11 +72,6 @@ export default {
type: Array,
required: true,
},
- enabledScopedLabels: {
- type: Boolean,
- required: false,
- default: false,
- },
},
data() {
return {
@@ -354,14 +333,9 @@ export default {
<board-form
v-if="currentPage"
- :labels-path="labelsPath"
- :labels-web-url="labelsWebUrl"
- :project-id="projectId"
- :group-id="groupId"
:can-admin-board="canAdminBoard"
:scoped-issue-board-feature-enabled="scopedIssueBoardFeatureEnabled"
:weights="weights"
- :enable-scoped-labels="enabledScopedLabels"
:current-board="currentBoard"
:current-page="currentPage"
@cancel="cancel"
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index 9d34f5071ec..be363e8f05f 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -142,5 +142,7 @@ export default () => {
fullPath: $boardApp.dataset.fullPath,
rootPath: $boardApp.dataset.boardsEndpoint,
recentBoardsEndpoint: $boardApp.dataset.recentBoardsEndpoint,
+ allowScopedLabels: $boardApp.dataset.scopedLabels,
+ labelsManagePath: $boardApp.dataset.labelsManagePath,
});
};
diff --git a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js
index d74a772170b..43e1faa0785 100644
--- a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js
+++ b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js
@@ -13,6 +13,7 @@ const apolloProvider = new VueApollo({
export default (params = {}) => {
const boardsSwitcherElement = document.getElementById('js-multiple-boards-switcher');
+ const { dataset } = boardsSwitcherElement;
return new Vue({
el: boardsSwitcherElement,
components: {
@@ -24,18 +25,17 @@ export default (params = {}) => {
fullPath: params.fullPath,
rootPath: params.rootPath,
recentBoardsEndpoint: params.recentBoardsEndpoint,
+ allowScopedLabels: params.allowScopedLabels,
+ labelsManagePath: params.labelsManagePath,
+ allowLabelCreate: parseBoolean(dataset.canAdminBoard),
},
data() {
- const { dataset } = boardsSwitcherElement;
-
const boardsSelectorProps = {
...dataset,
currentBoard: JSON.parse(dataset.currentBoard),
hasMissingBoards: parseBoolean(dataset.hasMissingBoards),
canAdminBoard: parseBoolean(dataset.canAdminBoard),
multipleIssueBoardsAvailable: parseBoolean(dataset.multipleIssueBoardsAvailable),
- projectId: dataset.projectId ? Number(dataset.projectId) : 0,
- groupId: Number(dataset.groupId),
scopedIssueBoardFeatureEnabled: parseBoolean(dataset.scopedIssueBoardFeatureEnabled),
weights: JSON.parse(dataset.weights),
};
diff --git a/app/assets/javascripts/graphql_shared/queries/group_users_search.query.graphql b/app/assets/javascripts/graphql_shared/queries/group_users_search.query.graphql
index e345fe97281..5bcad29c1ce 100644
--- a/app/assets/javascripts/graphql_shared/queries/group_users_search.query.graphql
+++ b/app/assets/javascripts/graphql_shared/queries/group_users_search.query.graphql
@@ -3,6 +3,7 @@
query usersSearch($search: String!, $fullPath: ID!) {
workspace: group(fullPath: $fullPath) {
+ id
users: groupMembers(search: $search, relations: [DIRECT, INHERITED]) {
nodes {
user {
diff --git a/app/assets/javascripts/graphql_shared/queries/project_user_members_search.query.graphql b/app/assets/javascripts/graphql_shared/queries/project_user_members_search.query.graphql
index 1d9497d65ce..62ce27815c7 100644
--- a/app/assets/javascripts/graphql_shared/queries/project_user_members_search.query.graphql
+++ b/app/assets/javascripts/graphql_shared/queries/project_user_members_search.query.graphql
@@ -1,5 +1,6 @@
query searchProjectMembers($fullPath: ID!, $search: String) {
project(fullPath: $fullPath) {
+ id
projectMembers(search: $search) {
nodes {
user {
diff --git a/app/assets/javascripts/sidebar/constants.js b/app/assets/javascripts/sidebar/constants.js
index 61f8fce034d..ac34a75ac5c 100644
--- a/app/assets/javascripts/sidebar/constants.js
+++ b/app/assets/javascripts/sidebar/constants.js
@@ -37,6 +37,7 @@ import epicLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widge
import updateEpicLabelsMutation from '~/vue_shared/components/sidebar/labels_select_widget/graphql/epic_update_labels.mutation.graphql';
import groupLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/group_labels.query.graphql';
import issueLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/issue_labels.query.graphql';
+import mergeRequestLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/merge_request_labels.query.graphql';
import projectLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql';
import getAlertAssignees from '~/vue_shared/components/sidebar/queries/get_alert_assignees.query.graphql';
import getIssueAssignees from '~/vue_shared/components/sidebar/queries/get_issue_assignees.query.graphql';
@@ -128,6 +129,7 @@ export const issuableLabelsQueries = {
mutationName: 'updateIssue',
},
[IssuableType.MergeRequest]: {
+ issuableQuery: mergeRequestLabelsQuery,
mutation: updateMergeRequestLabelsMutation,
mutationName: 'mergeRequestSetLabels',
},
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index 9f5a2f4ebb0..898be4a97ce 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -260,6 +260,10 @@ export function mountSidebarLabels() {
variant: DropdownVariant.Sidebar,
canUpdate: parseBoolean(el.dataset.canEdit),
isClassicSidebar: true,
+ issuableType:
+ isInIssuePage() || isInIncidentPage() || isInDesignPage()
+ ? IssuableType.Issue
+ : IssuableType.MergeRequest,
},
render: (createElement) => createElement(SidebarLabels),
});
diff --git a/app/assets/javascripts/sidebar/queries/update_merge_request_labels.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_merge_request_labels.mutation.graphql
index 3c09daad793..016c31ea096 100644
--- a/app/assets/javascripts/sidebar/queries/update_merge_request_labels.mutation.graphql
+++ b/app/assets/javascripts/sidebar/queries/update_merge_request_labels.mutation.graphql
@@ -2,6 +2,7 @@ mutation mergeRequestSetLabels($input: MergeRequestSetLabelsInput!) {
mergeRequestSetLabels(input: $input) {
errors
mergeRequest {
+ id
labels {
nodes {
color
diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue
index 7859ef85dd8..4fbd9b93af0 100644
--- a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue
+++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue
@@ -45,7 +45,7 @@ export default {
default: false,
},
selected: {
- type: Object,
+ type: [Object, Array],
required: false,
default: () => {},
},
@@ -54,6 +54,11 @@ export default {
required: false,
default: '',
},
+ allowMultiselect: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
computed: {
isSearchEmpty() {
@@ -66,8 +71,14 @@ export default {
methods: {
selectOption(option) {
this.$emit('set-option', option || null);
+ if (!this.allowMultiselect) {
+ this.$refs.dropdown.hide();
+ }
},
isSelected(option) {
+ if (Array.isArray(this.selected)) {
+ return this.selected.some((label) => label.title === option.title);
+ }
return (
this.selected &&
((option.name && this.selected.name === option.name) ||
@@ -78,7 +89,7 @@ export default {
this.$refs.dropdown.show();
},
setFocus() {
- this.$refs.search.focusInput();
+ this.$refs.search?.focusInput();
},
setSearchTerm(search) {
this.$emit('set-search', search);
@@ -108,56 +119,60 @@ export default {
@shown="setFocus"
>
<template #header>
- <gl-search-box-by-type
- ref="search"
- :value="searchTerm"
- :placeholder="searchText"
- class="js-dropdown-input-field"
- @input="setSearchTerm"
- />
+ <slot name="header">
+ <gl-search-box-by-type
+ ref="search"
+ :value="searchTerm"
+ :placeholder="searchText"
+ class="js-dropdown-input-field"
+ @input="setSearchTerm"
+ />
+ </slot>
</template>
- <gl-dropdown-form class="gl-relative gl-min-h-7">
- <gl-loading-icon
- v-if="isLoading"
- size="md"
- class="gl-absolute gl-left-0 gl-top-0 gl-right-0"
- />
- <template v-else>
- <template v-if="isSearchEmpty && presetOptions.length > 0">
+ <slot name="default">
+ <gl-dropdown-form class="gl-relative gl-min-h-7">
+ <gl-loading-icon
+ v-if="isLoading"
+ size="md"
+ class="gl-absolute gl-left-0 gl-top-0 gl-right-0"
+ />
+ <template v-else>
+ <template v-if="isSearchEmpty && presetOptions.length > 0">
+ <gl-dropdown-item
+ v-for="option in presetOptions"
+ :key="option.id"
+ :is-checked="isSelected(option)"
+ :is-check-centered="true"
+ :is-check-item="true"
+ @click.native.capture.stop="selectOption(option)"
+ >
+ <slot name="preset-item" :item="option">
+ {{ option.title }}
+ </slot>
+ </gl-dropdown-item>
+ <gl-dropdown-divider />
+ </template>
<gl-dropdown-item
- v-for="option in presetOptions"
+ v-for="option in options"
:key="option.id"
:is-checked="isSelected(option)"
:is-check-centered="true"
:is-check-item="true"
- @click="selectOption(option)"
+ :avatar-url="avatarUrl(option)"
+ :secondary-text="secondaryText(option)"
+ data-testid="unselected-option"
+ @click.native.capture.stop="selectOption(option)"
>
- <slot name="preset-item" :item="option">
+ <slot name="item" :item="option">
{{ option.title }}
</slot>
</gl-dropdown-item>
- <gl-dropdown-divider />
+ <gl-dropdown-item v-if="noOptionsFound" class="gl-pl-6!">
+ {{ $options.i18n.noMatchingResults }}
+ </gl-dropdown-item>
</template>
- <gl-dropdown-item
- v-for="option in options"
- :key="option.id"
- :is-checked="isSelected(option)"
- :is-check-centered="true"
- :is-check-item="true"
- :avatar-url="avatarUrl(option)"
- :secondary-text="secondaryText(option)"
- data-testid="unselected-option"
- @click="selectOption(option)"
- >
- <slot name="item" :item="option">
- {{ option.title }}
- </slot>
- </gl-dropdown-item>
- <gl-dropdown-item v-if="noOptionsFound" class="gl-pl-6!">
- {{ $options.i18n.noMatchingResults }}
- </gl-dropdown-item>
- </template>
- </gl-dropdown-form>
+ </gl-dropdown-form>
+ </slot>
<template #footer>
<slot name="footer"></slot>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
index ba10dc1d85c..f7485de0342 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
@@ -53,10 +53,6 @@ export default {
type: String,
required: true,
},
- issuableType: {
- type: String,
- required: true,
- },
isVisible: {
type: Boolean,
required: false,
@@ -209,7 +205,6 @@ export default {
v-model="localSelectedLabels"
:search-key="searchKey"
:allow-multiselect="allowMultiselect"
- :issuable-type="issuableType"
:full-path="fullPath"
:workspace-type="workspaceType"
:attr-workspace-path="attrWorkspacePath"
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue
index 661e6ab600f..da626a21b14 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue
@@ -32,11 +32,6 @@ export default {
type: String,
required: true,
},
- issuableType: {
- type: String,
- required: false,
- default: undefined,
- },
workspaceType: {
type: String,
required: true,
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue
index c4560914822..e9a2d7747e2 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue
@@ -23,10 +23,6 @@ export default {
type: Boolean,
required: true,
},
- issuableType: {
- type: String,
- required: true,
- },
localSelectedLabels: {
type: Array,
required: true,
@@ -119,13 +115,7 @@ export default {
({ id }) => id !== getIdFromGraphQLId(label.id) && id !== label.id,
);
} else {
- labels = [
- ...this.localSelectedLabels,
- {
- ...label,
- id: getIdFromGraphQLId(label.id),
- },
- ];
+ labels = [...this.localSelectedLabels, label];
}
this.$emit('input', labels);
},
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue
index 92a4fcd4660..10064b01648 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue
@@ -39,7 +39,7 @@ export default {
},
methods: {
focusInput() {
- this.$refs.searchInput.focusInput();
+ this.$refs.searchInput?.focusInput();
},
},
};
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_value.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_value.vue
index 71d3d87cce5..aed5bc303ee 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_value.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_value.vue
@@ -1,7 +1,6 @@
<script>
import { GlLabel } from '@gitlab/ui';
import { sortBy } from 'lodash';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { isScopedLabel } from '~/lib/utils/common_utils';
export default {
@@ -47,7 +46,7 @@ export default {
return this.allowScopedLabels && isScopedLabel(label);
},
removeLabel(labelId) {
- this.$emit('onLabelRemove', getIdFromGraphQLId(labelId));
+ this.$emit('onLabelRemove', labelId);
},
},
};
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/group_labels.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/group_labels.query.graphql
index 0ece58590ca..ce1a69f84c0 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/group_labels.query.graphql
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/group_labels.query.graphql
@@ -2,7 +2,8 @@
query groupLabels($fullPath: ID!, $searchTerm: String) {
workspace: group(fullPath: $fullPath) {
- labels(searchTerm: $searchTerm, onlyGroupLabels: true) {
+ id
+ labels(searchTerm: $searchTerm, onlyGroupLabels: true, includeAncestorGroups: true) {
nodes {
...Label
}
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/merge_request_labels.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/merge_request_labels.query.graphql
new file mode 100644
index 00000000000..dd80e89c8a7
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/merge_request_labels.query.graphql
@@ -0,0 +1,14 @@
+#import "~/graphql_shared/fragments/label.fragment.graphql"
+
+query mergeRequestLabels($fullPath: ID!, $iid: String!) {
+ workspace: project(fullPath: $fullPath) {
+ issuable: mergeRequest(iid: $iid) {
+ id
+ labels {
+ nodes {
+ ...Label
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql
index 82624535f89..a7c24620aad 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql
@@ -2,6 +2,7 @@
query projectLabels($fullPath: ID!, $searchTerm: String) {
workspace: project(fullPath: $fullPath) {
+ id
labels(searchTerm: $searchTerm, includeAncestorGroups: true) {
nodes {
...Label
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue
index 86af7277108..97a65c13933 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue
@@ -207,7 +207,7 @@ export default {
return {
iid: currentIid,
groupPath: this.fullPath,
- addLabelIds: labelIds,
+ addLabelIds: labelIds.map((id) => getIdFromGraphQLId(id)),
removeLabelIds: this.issuableLabelIds
.filter((id) => !labelIds.includes(id))
.map((id) => getIdFromGraphQLId(id)),
@@ -232,8 +232,8 @@ export default {
}
this.$emit('updateSelectedLabels', {
- id: data[mutationName]?.[this.issuableType].id,
- labels: data[mutationName]?.[this.issuableType].labels?.nodes,
+ id: data[mutationName]?.[this.issuableType]?.id,
+ labels: data[mutationName]?.[this.issuableType]?.labels?.nodes,
});
})
.catch((error) =>
@@ -268,7 +268,7 @@ export default {
case IssuableType.Epic:
return {
iid: this.iid,
- removeLabelIds: [labelId],
+ removeLabelIds: [getIdFromGraphQLId(labelId)],
groupPath: this.fullPath,
};
default:
@@ -341,7 +341,6 @@ export default {
:labels-create-title="labelsCreateTitle"
:selected-labels="issuableLabels"
:variant="variant"
- :issuable-type="issuableType"
:is-visible="edit"
:full-path="fullPath"
:workspace-type="workspaceType"
@@ -364,7 +363,6 @@ export default {
:labels-create-title="labelsCreateTitle"
:selected-labels="issuableLabels"
:variant="variant"
- :issuable-type="issuableType"
:full-path="fullPath"
:workspace-type="workspaceType"
:attr-workspace-path="attrWorkspacePath"
diff --git a/app/assets/stylesheets/page_bundles/boards.scss b/app/assets/stylesheets/page_bundles/boards.scss
index a3ec2167b13..d4c59a6ab0c 100644
--- a/app/assets/stylesheets/page_bundles/boards.scss
+++ b/app/assets/stylesheets/page_bundles/boards.scss
@@ -470,6 +470,10 @@
.labels-select-wrapper.is-embedded .labels-select-wrapper.is-embedded {
width: auto;
}
+
+ .show.dropdown .dropdown-menu {
+ @include gl-w-full;
+ }
}
.board-header-collapsed-info-icon:hover {
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index b5cc589bddd..e71edae42e7 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -42,6 +42,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:restructured_mr_widget, project, default_enabled: :yaml)
push_frontend_feature_flag(:mr_changes_fluid_layout, project, default_enabled: :yaml)
push_frontend_feature_flag(:mr_attention_requests, project, default_enabled: :yaml)
+ push_frontend_feature_flag(:labels_widget, project, default_enabled: :yaml)
# Usage data feature flags
push_frontend_feature_flag(:users_expanding_widgets_usage_data, @project, default_enabled: :yaml)
diff --git a/app/finders/autocomplete/routes_finder.rb b/app/finders/autocomplete/routes_finder.rb
index b3f2693b273..858a4b69376 100644
--- a/app/finders/autocomplete/routes_finder.rb
+++ b/app/finders/autocomplete/routes_finder.rb
@@ -30,7 +30,7 @@ module Autocomplete
class NamespacesOnly < self
def routables
- return Namespace.all if current_user.admin?
+ return Namespace.without_project_namespaces if current_user.admin?
current_user.namespaces
end
diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb
index 33d5bae88f4..c26a73028b9 100644
--- a/app/helpers/boards_helper.rb
+++ b/app/helpers/boards_helper.rb
@@ -43,7 +43,7 @@ module BoardsHelper
def build_issue_link_base
if board.group_board?
- "#{group_path(@board.group)}/:project_path/issues"
+ "/:project_path/-/issues"
else
project_issues_path(@project)
end
diff --git a/app/models/concerns/loaded_in_group_list.rb b/app/models/concerns/loaded_in_group_list.rb
index 848ef63f1c2..98f6ad58434 100644
--- a/app/models/concerns/loaded_in_group_list.rb
+++ b/app/models/concerns/loaded_in_group_list.rb
@@ -41,9 +41,11 @@ module LoadedInGroupList
namespaces = Namespace.arel_table
children = namespaces.alias('children')
+ # TODO 6473: remove the filtering of the Namespaces::ProjectNamespace see https://gitlab.com/groups/gitlab-org/-/epics/6473
namespaces.project(Arel.star.count.as('preloaded_subgroup_count'))
.from(children)
.where(children[:parent_id].eq(namespaces[:id]))
+ .where(children[:type].is_distinct_from(Namespaces::ProjectNamespace.sti_name))
end
def member_count_sql
diff --git a/app/views/admin/dev_ops_report/show.html.haml b/app/views/admin/dev_ops_report/show.html.haml
index c16ef7af76d..f8fc7b42691 100644
--- a/app/views/admin/dev_ops_report/show.html.haml
+++ b/app/views/admin/dev_ops_report/show.html.haml
@@ -1,4 +1,4 @@
-- page_title _('DevOps Report')
+- page_title _('DevOps Reports')
- add_page_specific_style 'page_bundles/dev_ops_report'
.container
diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml
index 842fb23d24a..f820f911d61 100644
--- a/app/views/layouts/nav/sidebar/_admin.html.haml
+++ b/app/views/layouts/nav/sidebar/_admin.html.haml
@@ -66,9 +66,9 @@
= _('Analytics')
%li.divider.fly-out-top-item
= nav_link(controller: :dev_ops_report) do
- = link_to admin_dev_ops_report_path, title: _('DevOps Report') do
+ = link_to admin_dev_ops_report_path, title: _('DevOps Reports') do
%span
- = _('DevOps Report')
+ = _('DevOps Reports')
= nav_link(controller: :usage_trends) do
= link_to admin_usage_trends_path, title: _('Usage Trends') do
%span
diff --git a/app/views/shared/boards/_switcher.html.haml b/app/views/shared/boards/_switcher.html.haml
index 18e0ca20cf7..e46a270cb93 100644
--- a/app/views/shared/boards/_switcher.html.haml
+++ b/app/views/shared/boards/_switcher.html.haml
@@ -9,9 +9,5 @@
has_missing_boards: (!multiple_boards_available? && current_board_parent.boards.size > 1).to_s,
can_admin_board: can?(current_user, :admin_issue_board, parent).to_s,
multiple_issue_boards_available: parent.multiple_issue_boards_available?.to_s,
- labels_path: labels_filter_path_with_defaults(only_group_labels: true, include_descendant_groups: true),
- labels_web_url: parent.is_a?(Project) ? project_labels_path(@project) : group_labels_path(@group),
- project_id: @project&.id,
- group_id: @group&.id,
scoped_issue_board_feature_enabled: Gitlab.ee? && parent.feature_available?(:scoped_issue_board) ? 'true' : 'false',
weights: weights.to_json } }
diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md
index 7999699acc5..134a7dfac5f 100644
--- a/doc/administration/geo/index.md
+++ b/doc/administration/geo/index.md
@@ -131,12 +131,13 @@ and we recommend you use:
The following table lists basic ports that must be open between the **primary** and **secondary** sites for Geo.
-| **Primary** site | **Secondary** site | Protocol |
-|:-----------------|:-------------------|:-------------|
-| 80 | 80 | HTTP |
-| 443 | 443 | TCP or HTTPS |
-| 22 | 22 | TCP |
-| 5432 | | PostgreSQL |
+| Source site | Source port | Destination site | Destination port | Protocol |
+|-------------|-------------|------------------|------------------|-------------|
+| Primary | Any | Secondary | 80 | TCP (HTTP) |
+| Primary | Any | Secondary | 443 | TCP (HTTPS) |
+| Secondary | Any | Primary | 80 | TCP (HTTP) |
+| Secondary | Any | Primary | 443 | TCP (HTTPS) |
+| Secondary | Any | Primary | 5432 | TCP |
See the full list of ports used by GitLab in [Package defaults](../package_information/defaults.md)
diff --git a/doc/administration/monitoring/prometheus/puma_exporter.md b/doc/administration/monitoring/prometheus/puma_exporter.md
index c348e74afaf..804c4243cfa 100644
--- a/doc/administration/monitoring/prometheus/puma_exporter.md
+++ b/doc/administration/monitoring/prometheus/puma_exporter.md
@@ -25,3 +25,5 @@ To enable the Puma exporter:
for the changes to take effect.
Prometheus begins collecting performance data from the Puma exporter exposed at `localhost:8083`.
+
+For more information on using Puma with GitLab, see [Puma](../../operations/puma.md).
diff --git a/doc/administration/object_storage.md b/doc/administration/object_storage.md
index 4fa8a86eef9..8576b429213 100644
--- a/doc/administration/object_storage.md
+++ b/doc/administration/object_storage.md
@@ -76,7 +76,13 @@ Mattermost. See the [full table for a complete list](#storage-specific-configura
However, backups can be configured with [server side encryption](../raketasks/backup_restore.md#s3-encrypted-buckets) separately.
Enabling consolidated object storage enables object storage for all object
-types. If you want to use local storage for specific object types, you can
+types. If not all buckets are specified, `sudo gitlab-ctl reconfigure` may fail with the error like:
+
+```plaintext
+Object storage for <object type> must have a bucket specified
+```
+
+If you want to use local storage for specific object types, you can
[selectively disable object storages](#selectively-disabling-object-storage).
Most types of objects, such as CI artifacts, LFS files, upload
diff --git a/doc/administration/operations/puma.md b/doc/administration/operations/puma.md
index 775761d655d..f1f02b606f5 100644
--- a/doc/administration/operations/puma.md
+++ b/doc/administration/operations/puma.md
@@ -224,3 +224,8 @@ in Puma when using the Linux package, and which ones have no corresponding count
| `unicorn['exporter_enabled']` | `puma['exporter_enabled']` |
| `unicorn['exporter_address']` | `puma['exporter_address']` |
| `unicorn['exporter_port']` | `puma['exporter_port']` |
+
+## Puma exporter
+
+You can use the Puma exporter to measure various Puma metrics. For more information, see
+[Puma exporter](../monitoring/prometheus/puma_exporter.md).
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index 5f3d9879110..6a7bbb2e302 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -168,7 +168,7 @@ their color is `#428BCA`.
`<Category Name>` is the category name as it is in the single source of truth for categories at
<https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/categories.yml>.
-For instance, the "DevOps Report" category is represented by the
+For instance, the "DevOps Reports" category is represented by the
~"Category:DevOps Reports" label in the `gitlab-org` group since its
`devops_reports.name` value is "DevOps Reports".
diff --git a/doc/development/service_ping/index.md b/doc/development/service_ping/index.md
index d14122f4bc3..cd702720319 100644
--- a/doc/development/service_ping/index.md
+++ b/doc/development/service_ping/index.md
@@ -55,7 +55,7 @@ We use the following terminology to describe the Service Ping components:
- The main purpose of Service Ping is to build a better GitLab. Data about how GitLab is used is collected to better understand feature/stage adoption and usage, which helps us understand how GitLab is adding value and helps our team better understand the reasons why people use GitLab and with this knowledge we're able to make better product decisions.
- As a benefit of having Service Ping active, GitLab lets you analyze the users' activities over time of your GitLab installation.
-- As a benefit of having Service Ping active, GitLab provides you with The DevOps Report,which gives you an overview of your entire instance's adoption of Concurrent DevOps from planning to monitoring.
+- As a benefit of having Service Ping active, GitLab provides you with [DevOps Score](../../user/admin_area/analytics/dev_ops_report.md#devops-score), which gives you an overview of your entire instance's adoption of Concurrent DevOps from planning to monitoring.
- You get better, more proactive support. (assuming that our TAMs and support organization used the data to deliver more value)
- You get insight and advice into how to get the most value out of your investment in GitLab. Wouldn't you want to know that a number of features or values are not being adopted in your organization?
- You get a report that illustrates how you compare against other similar organizations (anonymized), with specific advice and recommendations on how to improve your DevOps processes.
@@ -186,7 +186,7 @@ sequenceDiagram
S3 Bucket->>Snowflake DW: Import data
Snowflake DW->>Snowflake DW: Transform data using dbt
Snowflake DW->>Sisense Dashboards: Data available for querying
- Versions Application->>GitLab Instance: DevOps Report (Conversational Development Index)
+ Versions Application->>GitLab Instance: DevOps Score (Conversational Development Index)
```
## How Service Ping works
diff --git a/doc/user/admin_area/analytics/dev_ops_report.md b/doc/user/admin_area/analytics/dev_ops_report.md
index b5294bb265d..62fea3c266a 100644
--- a/doc/user/admin_area/analytics/dev_ops_report.md
+++ b/doc/user/admin_area/analytics/dev_ops_report.md
@@ -4,21 +4,21 @@ group: Optimize
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
-# DevOps Report **(FREE SELF)**
+# DevOps Reports **(FREE SELF)**
-> [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/20976) from Conversational Development Index in GitLab 12.6.
-
-The DevOps Report gives you an overview of your entire instance's adoption of
+DevOps Reports give you an overview of your entire instance's adoption of
[Concurrent DevOps](https://about.gitlab.com/topics/concurrent-devops/)
from planning to monitoring.
-To see DevOps Report:
+To see DevOps Reports:
1. On the top bar, select **Menu > Admin**.
-1. On the left sidebar, select **Analytics > DevOps Report**.
+1. On the left sidebar, select **Analytics > DevOps Reports**.
## DevOps Score
+> [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/20976) from Conversational Development Index in GitLab 12.6.
+
NOTE:
To see the DevOps score, you must activate your GitLab instance's [Service Ping](../settings/usage_statistics.md#service-ping). This is because DevOps Score is a comparative tool, so your score data must be centrally processed by GitLab Inc. first.
@@ -72,4 +72,4 @@ DevOps Adoption allows you to:
- Identify specific groups that are lagging in their adoption of GitLab, so you can help them along in their DevOps journey.
- Find the groups that have adopted certain features, and can provide guidance to other groups on how to use those features.
-![DevOps Report](img/admin_devops_adoption_v14_2.png)
+![DevOps Adoption](img/admin_devops_adoption_v14_2.png)
diff --git a/doc/user/admin_area/analytics/index.md b/doc/user/admin_area/analytics/index.md
index dd1efc913fa..cd505e154c6 100644
--- a/doc/user/admin_area/analytics/index.md
+++ b/doc/user/admin_area/analytics/index.md
@@ -15,5 +15,5 @@ Administrators have access to instance-wide analytics:
There are several kinds of statistics:
-- [DevOps Report](dev_ops_report.md): Provides an overview of your entire instance's feature usage.
+- [DevOps Reports](dev_ops_report.md): Provides an overview of your entire instance's feature usage.
- [Usage Trends](usage_trends.md): Shows how much data your instance contains, and how that is changing.
diff --git a/doc/user/group/devops_adoption/index.md b/doc/user/group/devops_adoption/index.md
index e3b858aff7d..36ccfc1031f 100644
--- a/doc/user/group/devops_adoption/index.md
+++ b/doc/user/group/devops_adoption/index.md
@@ -48,7 +48,7 @@ With DevOps Adoption you can:
- Identify specific subgroups that are lagging in their adoption of GitLab, so you can help them along in their DevOps journey.
- Find the subgroups that have adopted certain features, and can provide guidance to other subgroups on how to use those features.
-![DevOps Report](img/group_devops_adoption_v14_2.png)
+![DevOps Adoption](img/group_devops_adoption_v14_2.png)
Feature adoption is based on usage in the previous calendar month. Data is updated on the first day
of each month. If the monthly update fails, it tries again daily until successful.
diff --git a/doc/user/project/pages/getting_started/pages_ci_cd_template.md b/doc/user/project/pages/getting_started/pages_ci_cd_template.md
index 55a57bd9e07..25382778b1d 100644
--- a/doc/user/project/pages/getting_started/pages_ci_cd_template.md
+++ b/doc/user/project/pages/getting_started/pages_ci_cd_template.md
@@ -16,15 +16,13 @@ Use a `.gitlab-ci.yml` template when you have an existing project that you want
Your GitLab repository should contain files specific to an SSG, or plain HTML. After you complete
these steps, you may have to do additional configuration for the Pages site to generate properly.
-1. On the left sidebar, select **Project information**.
-1. Click **Set up CI/CD**. If this button is not available, CI/CD is already configured for your project.
- You may want to browse the `.gitlab-ci.yml` files [in these projects instead](https://gitlab.com/pages).
-1. From the **Apply a template** list, choose a template for the SSG you're using.
- You can also choose plain HTML. If you don't find a corresponding template, you can view the
- [GitLab Pages group of sample projects](https://gitlab.com/pages).
- These projects contain `.gitlab-ci.yml` files that you can modify for your needs.
- You can also [learn how to write your own `.gitlab-ci.yml` file for GitLab Pages](pages_from_scratch.md).
-1. Save and commit the `.gitlab-ci.yml` file.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select the project's name.
+1. From the **Add** (**{plus}**) dropdown, select **New file**.
+1. From the **Select a template type** dropdown, select `.gitlab-ci.yml`.
+1. From the **Apply a template** dropdown, in the **Pages** section, select the name of your SSG.
+1. In the **Commit message** box, type the commit message.
+1. Select **Commit changes**.
If everything is configured correctly, the site can take approximately 30 minutes to deploy.
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e445b38eb6f..a30639a84af 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -5491,6 +5491,9 @@ msgstr ""
msgid "BoardScope|An error occurred while getting milestones, please try again."
msgstr ""
+msgid "BoardScope|An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "BoardScope|An error occurred while searching for users, please try again."
msgstr ""
@@ -5500,12 +5503,21 @@ msgstr ""
msgid "BoardScope|Any assignee"
msgstr ""
+msgid "BoardScope|Any label"
+msgstr ""
+
msgid "BoardScope|Assignee"
msgstr ""
+msgid "BoardScope|Choose labels"
+msgstr ""
+
msgid "BoardScope|Edit"
msgstr ""
+msgid "BoardScope|Labels"
+msgstr ""
+
msgid "BoardScope|Milestone"
msgstr ""
@@ -5518,6 +5530,9 @@ msgstr ""
msgid "BoardScope|Select assignee"
msgstr ""
+msgid "BoardScope|Select labels"
+msgstr ""
+
msgid "BoardScope|Select milestone"
msgstr ""
@@ -11765,7 +11780,7 @@ msgstr ""
msgid "DevOps Adoption"
msgstr ""
-msgid "DevOps Report"
+msgid "DevOps Reports"
msgstr ""
msgid "DevOps adoption"
@@ -18629,7 +18644,7 @@ msgstr ""
msgid "Interval Pattern"
msgstr ""
-msgid "Introducing Your DevOps Report"
+msgid "Introducing Your DevOps Reports"
msgstr ""
msgid "Invalid Insights config file detected"
@@ -39603,7 +39618,7 @@ msgstr ""
msgid "Your CSV import for project"
msgstr ""
-msgid "Your DevOps Report gives an overview of how you are using GitLab from a feature perspective. Use it to view how you compare with other organizations."
+msgid "Your DevOps Reports give an overview of how you are using GitLab from a feature perspective. Use them to view how you compare with other organizations, and how your teams compare against each other."
msgstr ""
msgid "Your GPG keys (%{count})"
diff --git a/spec/finders/autocomplete/routes_finder_spec.rb b/spec/finders/autocomplete/routes_finder_spec.rb
new file mode 100644
index 00000000000..c5b040a5640
--- /dev/null
+++ b/spec/finders/autocomplete/routes_finder_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Autocomplete::RoutesFinder do
+ describe '#execute' do
+ let_it_be(:user) { create(:user, username: 'user_path') }
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:group) { create(:group, path: 'path1') }
+ let_it_be(:group2) { create(:group, path: 'path2') }
+ let_it_be(:group3) { create(:group, path: 'not-matching') }
+ let_it_be(:project) { create(:project, path: 'path3', namespace: user.namespace) }
+ let_it_be(:project2) { create(:project, path: 'path4') }
+ let_it_be(:project_namespace) { create(:project_namespace, parent: group, path: 'path5') }
+
+ let(:current_user) { user }
+ let(:search) { 'path' }
+
+ before do
+ group.add_owner(user)
+ end
+
+ context 'for NamespacesOnly' do
+ subject { Autocomplete::RoutesFinder::NamespacesOnly.new(current_user, search: search).execute }
+
+ let(:user_route) { Route.find_by_path(user.username) }
+
+ it 'finds only user namespace and groups matching the search excluding project namespaces' do
+ is_expected.to match_array([group.route, user_route])
+ end
+
+ context 'when user is admin' do
+ let(:current_user) { admin }
+
+ it 'finds all namespaces matching the search excluding project namespaces' do
+ is_expected.to match_array([group.route, group2.route, user_route])
+ end
+ end
+ end
+
+ context 'for ProjectsOnly' do
+ subject { Autocomplete::RoutesFinder::ProjectsOnly.new(current_user, search: 'path').execute }
+
+ it 'finds only matching projects the user has access to' do
+ is_expected.to match_array([project.route])
+ end
+
+ context 'when user is admin' do
+ let(:current_user) { admin }
+
+ it 'finds all projects matching the search' do
+ is_expected.to match_array([project.route, project2.route])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/frontend/boards/components/board_form_spec.js b/spec/frontend/boards/components/board_form_spec.js
index 52f1907654a..51688c8f4f0 100644
--- a/spec/frontend/boards/components/board_form_spec.js
+++ b/spec/frontend/boards/components/board_form_spec.js
@@ -1,7 +1,6 @@
import { GlModal } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import setWindowLocation from 'helpers/set_window_location_helper';
-import { TEST_HOST } from 'helpers/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
import BoardForm from '~/boards/components/board_form.vue';
@@ -31,8 +30,6 @@ const currentBoard = {
const defaultProps = {
canAdminBoard: false,
- labelsPath: `${TEST_HOST}/labels/path`,
- labelsWebUrl: `${TEST_HOST}/-/labels`,
currentBoard,
currentPage: '',
};
diff --git a/spec/frontend/boards/components/boards_selector_spec.js b/spec/frontend/boards/components/boards_selector_spec.js
index bf317b51e83..e7e640faab3 100644
--- a/spec/frontend/boards/components/boards_selector_spec.js
+++ b/spec/frontend/boards/components/boards_selector_spec.js
@@ -78,10 +78,6 @@ describe('BoardsSelector', () => {
hasMissingBoards: false,
canAdminBoard: true,
multipleIssueBoardsAvailable: true,
- labelsPath: `${TEST_HOST}/labels/path`,
- labelsWebUrl: `${TEST_HOST}/labels`,
- projectId: 42,
- groupId: 19,
scopedIssueBoardFeatureEnabled: true,
weights: [],
},
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index 6a4f344bbfb..737a631242b 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -12,6 +12,7 @@ export const boardObj = {
id: 1,
name: 'test',
milestone_id: null,
+ labels: [],
};
export const listObj = {
@@ -609,3 +610,43 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones) => [
unique: true,
},
];
+
+export const mockLabel1 = {
+ id: 'gid://gitlab/GroupLabel/121',
+ title: 'To Do',
+ color: '#F0AD4E',
+ textColor: '#FFFFFF',
+ description: null,
+};
+
+export const mockLabel2 = {
+ id: 'gid://gitlab/GroupLabel/122',
+ title: 'Doing',
+ color: '#F0AD4E',
+ textColor: '#FFFFFF',
+ description: null,
+};
+
+export const mockProjectLabelsResponse = {
+ data: {
+ workspace: {
+ id: 'gid://gitlab/Project/1',
+ labels: {
+ nodes: [mockLabel1, mockLabel2],
+ },
+ },
+ __typename: 'Project',
+ },
+};
+
+export const mockGroupLabelsResponse = {
+ data: {
+ workspace: {
+ id: 'gid://gitlab/Group/1',
+ labels: {
+ nodes: [mockLabel1, mockLabel2],
+ },
+ },
+ __typename: 'Group',
+ },
+};
diff --git a/spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js b/spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js
index 016fe1f131e..b3af5fd3feb 100644
--- a/spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js
+++ b/spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js
@@ -34,6 +34,7 @@ describe('DropdownWidget component', () => {
// invokes `show` method of BDropdown used inside GlDropdown.
// Context: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54895#note_524281679
jest.spyOn(wrapper.vm, 'showDropdown').mockImplementation();
+ jest.spyOn(findDropdown().vm, 'hide').mockImplementation();
};
beforeEach(() => {
@@ -67,10 +68,7 @@ describe('DropdownWidget component', () => {
});
it('emits set-option event when clicking on an option', async () => {
- wrapper
- .findAll('[data-testid="unselected-option"]')
- .at(1)
- .vm.$emit('click', new Event('click'));
+ wrapper.findAll('[data-testid="unselected-option"]').at(1).trigger('click');
await wrapper.vm.$nextTick();
expect(wrapper.emitted('set-option')).toEqual([[wrapper.props().options[1]]]);
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view_spec.js
index 676651b6a7f..2980409fdce 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view_spec.js
@@ -10,7 +10,6 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
-import { IssuableType } from '~/issue_show/constants';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import { DropdownVariant } from '~/vue_shared/components/sidebar/labels_select_widget/constants';
import DropdownContentsLabelsView from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue';
@@ -57,7 +56,6 @@ describe('DropdownContentsLabelsView', () => {
propsData: {
...initialState,
localSelectedLabels,
- issuableType: IssuableType.Issue,
searchKey,
labelCreateType: 'project',
workspaceType: 'project',
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_spec.js
index 7e70287b195..8bcef347c96 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_spec.js
@@ -39,7 +39,6 @@ describe('DropdownContent', () => {
footerManageLabelTitle: 'manage',
dropdownButtonText: 'Labels',
variant: 'sidebar',
- issuableType: 'issue',
fullPath: 'test',
workspaceType: 'project',
labelCreateType: 'project',
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js
index 24e7896cfe5..5c5bf5f2187 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js
@@ -92,6 +92,7 @@ export const createLabelSuccessfulResponse = {
export const workspaceLabelsQueryResponse = {
data: {
workspace: {
+ id: 'gid://gitlab/Project/126',
labels: {
nodes: [
{
diff --git a/spec/helpers/boards_helper_spec.rb b/spec/helpers/boards_helper_spec.rb
index cb4b6915b20..ec949fde30e 100644
--- a/spec/helpers/boards_helper_spec.rb
+++ b/spec/helpers/boards_helper_spec.rb
@@ -23,14 +23,14 @@ RSpec.describe BoardsHelper do
it 'returns correct path for base group' do
assign(:board, group_board)
- expect(helper.build_issue_link_base).to eq('/base/:project_path/issues')
+ expect(helper.build_issue_link_base).to eq('/:project_path/-/issues')
end
it 'returns correct path for subgroup' do
subgroup = create(:group, parent: base_group, path: 'sub')
assign(:board, create(:board, group: subgroup))
- expect(helper.build_issue_link_base).to eq('/base/sub/:project_path/issues')
+ expect(helper.build_issue_link_base).to eq('/:project_path/-/issues')
end
end
end
@@ -149,7 +149,7 @@ RSpec.describe BoardsHelper do
end
it 'returns correct path for base group' do
- expect(helper.build_issue_link_base).to eq("/#{base_group.full_path}/:project_path/issues")
+ expect(helper.build_issue_link_base).to eq("/:project_path/-/issues")
end
it 'returns required label endpoints' do
diff --git a/spec/models/concerns/loaded_in_group_list_spec.rb b/spec/models/concerns/loaded_in_group_list_spec.rb
index c37943022ba..94a9a8cde12 100644
--- a/spec/models/concerns/loaded_in_group_list_spec.rb
+++ b/spec/models/concerns/loaded_in_group_list_spec.rb
@@ -3,49 +3,67 @@
require 'spec_helper'
RSpec.describe LoadedInGroupList do
- let(:parent) { create(:group) }
+ let_it_be(:parent) { create(:group) }
+ let_it_be(:group) { create(:group, parent: parent) }
+ let_it_be(:project) { create(:project, namespace: parent) }
- subject(:found_group) { Group.with_selects_for_list.find_by(id: parent.id) }
+ let(:archived_parameter) { nil }
- describe '.with_selects_for_list' do
- it 'includes the preloaded counts for groups' do
- create(:group, parent: parent)
- create(:project, namespace: parent)
- parent.add_developer(create(:user))
+ before do
+ parent.add_developer(create(:user))
+ end
- found_group = Group.with_selects_for_list.find_by(id: parent.id)
+ subject(:found_group) { Group.with_selects_for_list(archived: archived_parameter).find_by(id: parent.id) }
+ describe '.with_selects_for_list' do
+ it 'includes the preloaded counts for groups' do
expect(found_group.preloaded_project_count).to eq(1)
expect(found_group.preloaded_subgroup_count).to eq(1)
expect(found_group.preloaded_member_count).to eq(1)
end
+ context 'with project namespaces' do
+ let_it_be(:group1) { create(:group, parent: parent) }
+ let_it_be(:group2) { create(:group, parent: parent) }
+ let_it_be(:project_namespace) { create(:project_namespace, project: project) }
+
+ it 'does not include project_namespaces in the count of subgroups' do
+ expect(found_group.preloaded_subgroup_count).to eq(3)
+ expect(parent.subgroup_count).to eq(3)
+ end
+ end
+
context 'with archived projects' do
- it 'counts including archived projects when `true` is passed' do
- create(:project, namespace: parent, archived: true)
- create(:project, namespace: parent)
+ let_it_be(:archived_project) { create(:project, namespace: parent, archived: true) }
- found_group = Group.with_selects_for_list(archived: 'true').find_by(id: parent.id)
+ let(:archived_parameter) { true }
+ it 'counts including archived projects when `true` is passed' do
expect(found_group.preloaded_project_count).to eq(2)
end
- it 'counts only archived projects when `only` is passed' do
- create_list(:project, 2, namespace: parent, archived: true)
- create(:project, namespace: parent)
+ context 'when not counting archived projects' do
+ let(:archived_parameter) { false }
+
+ it 'counts projects without archived ones' do
+ expect(found_group.preloaded_project_count).to eq(1)
+ end
+ end
+
+ context 'with archived only' do
+ let_it_be(:archived_project2) { create(:project, namespace: parent, archived: true) }
- found_group = Group.with_selects_for_list(archived: 'only').find_by(id: parent.id)
+ let(:archived_parameter) { 'only' }
- expect(found_group.preloaded_project_count).to eq(2)
+ it 'counts only archived projects when `only` is passed' do
+ expect(found_group.preloaded_project_count).to eq(2)
+ end
end
end
end
describe '#children_count' do
it 'counts groups and projects' do
- create(:group, parent: parent)
- create(:project, namespace: parent)
-
expect(found_group.children_count).to eq(2)
end
end
diff --git a/spec/support_specs/database/prevent_cross_database_modification_spec.rb b/spec/support_specs/database/prevent_cross_database_modification_spec.rb
index e2b3abe426d..365f1f32858 100644
--- a/spec/support_specs/database/prevent_cross_database_modification_spec.rb
+++ b/spec/support_specs/database/prevent_cross_database_modification_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Database::PreventCrossDatabaseModification' do
let_it_be(:pipeline, refind: true) { create(:ci_pipeline) }
let_it_be(:project, refind: true) { create(:project) }
- shared_examples 'succeessful examples' do
+ shared_examples 'successful examples' do
context 'outside transaction' do
it { expect { run_queries }.not_to raise_error }
end
@@ -36,7 +36,7 @@ RSpec.describe 'Database::PreventCrossDatabaseModification' do
project.reload
end
- include_examples 'succeessful examples'
+ include_examples 'successful examples'
end
context 'when only CI data is modified' do
@@ -45,7 +45,7 @@ RSpec.describe 'Database::PreventCrossDatabaseModification' do
project.reload
end
- include_examples 'succeessful examples'
+ include_examples 'successful examples'
end
context 'when other data is modified' do
@@ -54,38 +54,42 @@ RSpec.describe 'Database::PreventCrossDatabaseModification' do
project.touch
end
- include_examples 'succeessful examples'
+ include_examples 'successful examples'
end
- describe 'with_cross_database_modification_prevented block' do
- it 'raises error when CI and other data is modified' do
- expect do
- with_cross_database_modification_prevented do
- Project.transaction do
- project.touch
- pipeline.touch
- end
- end
- end.to raise_error /Cross-database data modification/
+ context 'when both CI and other data is modified' do
+ def run_queries
+ project.touch
+ pipeline.touch
end
- it 'raises an error when an undefined gitlab_schema table is modified with another table' do
- expect do
- with_cross_database_modification_prevented do
- Project.transaction do
+ context 'outside transaction' do
+ it { expect { run_queries }.not_to raise_error }
+ end
+
+ context 'when data modification happens in a transaction' do
+ it 'raises error' do
+ Project.transaction do
+ expect { run_queries }.to raise_error /Cross-database data modification/
+ end
+ end
+
+ context 'when data modification happens in nested transactions' do
+ it 'raises error' do
+ Project.transaction(requires_new: true) do
project.touch
- project.connection.execute('UPDATE foo_bars_undefined_table SET a=1 WHERE id = -1')
+ Project.transaction(requires_new: true) do
+ expect { pipeline.touch }.to raise_error /Cross-database data modification/
+ end
end
end
- end.to raise_error /Cross-database data modification.*The gitlab_schema was undefined/
+ end
end
- end
- context 'when running tests with prevent_cross_database_modification', :prevent_cross_database_modification do
- context 'when both CI and other data is modified' do
+ context 'when executing a SELECT FOR UPDATE query' do
def run_queries
project.touch
- pipeline.touch
+ pipeline.lock!
end
context 'outside transaction' do
@@ -99,41 +103,11 @@ RSpec.describe 'Database::PreventCrossDatabaseModification' do
end
end
- context 'when data modification happens in nested transactions' do
- it 'raises error' do
- Project.transaction(requires_new: true) do
- project.touch
- Project.transaction(requires_new: true) do
- expect { pipeline.touch }.to raise_error /Cross-database data modification/
- end
- end
- end
- end
- end
+ context 'when the modification is inside a factory save! call' do
+ let(:runner) { create(:ci_runner, :project, projects: [build(:project)]) }
- context 'when executing a SELECT FOR UPDATE query' do
- def run_queries
- project.touch
- pipeline.lock!
- end
-
- context 'outside transaction' do
- it { expect { run_queries }.not_to raise_error }
- end
-
- context 'when data modification happens in a transaction' do
- it 'raises error' do
- Project.transaction do
- expect { run_queries }.to raise_error /Cross-database data modification/
- end
- end
-
- context 'when the modification is inside a factory save! call' do
- let(:runner) { create(:ci_runner, :project, projects: [build(:project)]) }
-
- it 'does not raise an error' do
- runner
- end
+ it 'does not raise an error' do
+ runner
end
end
end
@@ -145,7 +119,7 @@ RSpec.describe 'Database::PreventCrossDatabaseModification' do
project.save!
end
- include_examples 'succeessful examples'
+ include_examples 'successful examples'
end
describe '#allow_cross_database_modification_within_transaction' do
@@ -171,4 +145,15 @@ RSpec.describe 'Database::PreventCrossDatabaseModification' do
end
end
end
+
+ context 'when some table with a defined schema and another table with undefined gitlab_schema is modified' do
+ it 'raises an error including including message about undefined schema' do
+ expect do
+ Project.transaction do
+ project.touch
+ project.connection.execute('UPDATE foo_bars_undefined_table SET a=1 WHERE id = -1')
+ end
+ end.to raise_error /Cross-database data modification.*The gitlab_schema was undefined/
+ end
+ end
end