summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue2
-rw-r--r--app/assets/javascripts/content_editor/services/upload_helpers.js12
-rw-r--r--app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue2
-rw-r--r--app/assets/javascripts/issues/list/components/issues_list_app.vue3
-rw-r--r--app/assets/javascripts/issues/list/constants.js25
-rw-r--r--app/assets/javascripts/issues/list/utils.js81
-rw-r--r--app/assets/javascripts/merge_request_tabs.js20
-rw-r--r--app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue30
-rw-r--r--app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue9
-rw-r--r--app/assets/javascripts/pipelines/components/jobs/utils.js33
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_tabs.vue10
-rw-r--r--app/assets/javascripts/pipelines/constants.js2
-rw-r--r--app/assets/javascripts/pipelines/graphql/queries/get_failed_jobs.query.graphql4
-rw-r--r--app/assets/javascripts/pipelines/pipeline_tabs.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue7
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue1
-rw-r--r--app/assets/javascripts/work_items/components/work_item_description.vue16
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail.vue4
-rw-r--r--app/controllers/registrations_controller.rb1
-rw-r--r--app/helpers/ci/builds_helper.rb22
-rw-r--r--app/helpers/projects/pipeline_helper.rb1
-rw-r--r--app/models/project_setting.rb21
-rw-r--r--app/models/protected_branch/push_access_level.rb6
-rw-r--r--app/models/protected_tag/create_access_level.rb6
-rw-r--r--app/services/ci/runners/unregister_runner_manager_service.rb33
-rw-r--r--app/services/ci/runners/unregister_runner_service.rb3
-rw-r--r--app/views/projects/edit.html.haml2
-rw-r--r--app/views/users/show.html.haml9
28 files changed, 180 insertions, 187 deletions
diff --git a/app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue b/app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue
index a14d49922fb..1bfa635c03b 100644
--- a/app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue
+++ b/app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue
@@ -212,7 +212,7 @@ export default {
@show="updateMediaInfoToState"
@hidden="resetMediaInfo"
>
- <editor-state-observer @transaction="updateMediaInfoToState">
+ <editor-state-observer :debounce="0" @transaction="updateMediaInfoToState">
<gl-button-group v-if="!isEditing" class="gl-display-flex gl-align-items-center">
<gl-loading-icon v-if="showProgressIndicator" class="gl-pl-4 gl-pr-3" />
<input
diff --git a/app/assets/javascripts/content_editor/services/upload_helpers.js b/app/assets/javascripts/content_editor/services/upload_helpers.js
index de1a187b246..548f5cdf19c 100644
--- a/app/assets/javascripts/content_editor/services/upload_helpers.js
+++ b/app/assets/javascripts/content_editor/services/upload_helpers.js
@@ -9,7 +9,17 @@ export const acceptedMimes = {
ext: 'drawio.svg',
},
image: {
- mimes: ['image/jpeg', 'image/png', 'image/gif', 'image/jpg'],
+ mimes: [
+ 'image/jpeg',
+ 'image/png',
+ 'image/gif',
+ 'image/svg+xml',
+ 'image/webp',
+ 'image/tiff',
+ 'image/bmp',
+ 'image/vnd.microsoft.icon',
+ 'image/x-icon',
+ ],
},
audio: {
mimes: [
diff --git a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
index b4a9b37d487..b9e4d0df3f2 100644
--- a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
+++ b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
@@ -187,7 +187,6 @@ export default {
return {
hideUsers: this.isPublicVisibilityRestricted && !this.isSignedIn,
isSignedIn: this.isSignedIn,
- search: this.searchQuery,
sort: this.sortKey,
state: this.state,
...this.pageParams,
@@ -332,7 +331,6 @@ export default {
},
urlParams() {
return {
- search: this.searchQuery,
sort: urlSortParams[this.sortKey],
state: this.state,
...this.urlFilterParams,
diff --git a/app/assets/javascripts/issues/list/components/issues_list_app.vue b/app/assets/javascripts/issues/list/components/issues_list_app.vue
index 7d077603530..5fb83dfd1ab 100644
--- a/app/assets/javascripts/issues/list/components/issues_list_app.vue
+++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue
@@ -253,11 +253,11 @@ export default {
iid: isIidSearch ? this.searchQuery.slice(1) : undefined,
isProject: this.isProject,
isSignedIn: this.isSignedIn,
- search: isIidSearch ? undefined : this.searchQuery,
sort: this.sortKey,
state: this.state,
...this.pageParams,
...this.apiFilterParams,
+ search: isIidSearch ? undefined : this.searchQuery,
types: this.apiFilterParams.types || this.defaultWorkItemTypes,
};
},
@@ -484,7 +484,6 @@ export default {
},
urlParams() {
return {
- search: this.searchQuery,
sort: urlSortParams[this.sortKey],
state: this.state,
...this.urlFilterParams,
diff --git a/app/assets/javascripts/issues/list/constants.js b/app/assets/javascripts/issues/list/constants.js
index 990ba1c0621..cd0679e00bf 100644
--- a/app/assets/javascripts/issues/list/constants.js
+++ b/app/assets/javascripts/issues/list/constants.js
@@ -5,6 +5,7 @@ import {
FILTER_NONE,
FILTER_STARTED,
FILTER_UPCOMING,
+ FILTERED_SEARCH_TERM,
OPERATOR_IS,
OPERATOR_NOT,
OPERATOR_OR,
@@ -155,13 +156,13 @@ export const specialFilterValues = [
export const TYPE_TOKEN_OBJECTIVE_OPTION = {
icon: 'issue-type-objective',
- title: 'objective',
+ title: s__('WorkItem|Objective'),
value: 'objective',
};
export const TYPE_TOKEN_KEY_RESULT_OPTION = {
icon: 'issue-type-keyresult',
- title: 'key_result',
+ title: s__('WorkItem|Key Result'),
value: 'key_result',
};
@@ -175,13 +176,23 @@ export const defaultWorkItemTypes = [
];
export const defaultTypeTokenOptions = [
- { icon: 'issue-type-issue', title: 'issue', value: 'issue' },
- { icon: 'issue-type-incident', title: 'incident', value: 'incident' },
- { icon: 'issue-type-test-case', title: 'test_case', value: 'test_case' },
- { icon: 'issue-type-task', title: 'task', value: 'task' },
+ { icon: 'issue-type-issue', title: s__('WorkItem|Issue'), value: 'issue' },
+ { icon: 'issue-type-incident', title: s__('WorkItem|Incident'), value: 'incident' },
+ { icon: 'issue-type-test-case', title: s__('WorkItem|Test case'), value: 'test_case' },
+ { icon: 'issue-type-task', title: s__('WorkItem|Task'), value: 'task' },
];
-export const filters = {
+export const filtersMap = {
+ [FILTERED_SEARCH_TERM]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'search',
+ },
+ [URL_PARAM]: {
+ [undefined]: {
+ [NORMAL_FILTER]: 'search',
+ },
+ },
+ },
[TOKEN_TYPE_AUTHOR]: {
[API_PARAM]: {
[NORMAL_FILTER]: 'authorUsername',
diff --git a/app/assets/javascripts/issues/list/utils.js b/app/assets/javascripts/issues/list/utils.js
index b086640cd12..d053400dd03 100644
--- a/app/assets/javascripts/issues/list/utils.js
+++ b/app/assets/javascripts/issues/list/utils.js
@@ -1,4 +1,3 @@
-import { createTerm } from '@gitlab/ui/src/components/base/filtered_search/filtered_search_utils';
import { isPositiveInteger } from '~/lib/utils/number_utils';
import { getParameterByName } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
@@ -28,7 +27,7 @@ import {
CREATED_DESC,
DUE_DATE_ASC,
DUE_DATE_DESC,
- filters,
+ filtersMap,
HEALTH_STATUS_ASC,
HEALTH_STATUS_DESC,
LABEL_PRIORITY_ASC,
@@ -196,10 +195,10 @@ export const getSortOptions = ({
return sortOptions;
};
-const tokenTypes = Object.keys(filters);
+const tokenTypes = Object.keys(filtersMap);
const getUrlParams = (tokenType) =>
- Object.values(filters[tokenType][URL_PARAM]).flatMap((filterObj) => Object.values(filterObj));
+ Object.values(filtersMap[tokenType][URL_PARAM]).flatMap((filterObj) => Object.values(filterObj));
const urlParamKeys = tokenTypes.flatMap(getUrlParams);
@@ -207,11 +206,11 @@ const getTokenTypeFromUrlParamKey = (urlParamKey) =>
tokenTypes.find((tokenType) => getUrlParams(tokenType).includes(urlParamKey));
const getOperatorFromUrlParamKey = (tokenType, urlParamKey) =>
- Object.entries(filters[tokenType][URL_PARAM]).find(([, filterObj]) =>
+ Object.entries(filtersMap[tokenType][URL_PARAM]).find(([, filterObj]) =>
Object.values(filterObj).includes(urlParamKey),
)[0];
-const convertToFilteredTokens = (locationSearch) =>
+export const getFilterTokens = (locationSearch) =>
Array.from(new URLSearchParams(locationSearch).entries())
.filter(([key]) => urlParamKeys.includes(key))
.map(([key, data]) => {
@@ -223,26 +222,8 @@ const convertToFilteredTokens = (locationSearch) =>
};
});
-const convertToFilteredSearchTerms = (locationSearch) =>
- new URLSearchParams(locationSearch)
- .get('search')
- ?.split(' ')
- .map((word) => ({
- type: FILTERED_SEARCH_TERM,
- value: {
- data: word,
- },
- })) || [];
-
-export const getFilterTokens = (locationSearch) => {
- if (!locationSearch) {
- return [createTerm()];
- }
- const filterTokens = convertToFilteredTokens(locationSearch);
- const searchTokens = convertToFilteredSearchTerms(locationSearch);
- const tokens = filterTokens.concat(searchTokens);
- return tokens.length ? tokens : [createTerm()];
-};
+const isNotEmptySearchToken = (token) =>
+ !(token.type === FILTERED_SEARCH_TERM && !token.value.data);
const isSpecialFilter = (type, data) => {
const isAssigneeIdParam =
@@ -293,22 +274,20 @@ export const convertToApiParams = (filterTokens) => {
const not = new Map();
const or = new Map();
- filterTokens
- .filter((token) => token.type !== FILTERED_SEARCH_TERM)
- .forEach((token) => {
- const filterType = getFilterType(token);
- const apiField = filters[token.type][API_PARAM][filterType];
- let obj;
- if (token.value.operator === OPERATOR_NOT) {
- obj = not;
- } else if (token.value.operator === OPERATOR_OR) {
- obj = or;
- } else {
- obj = params;
- }
- const data = formatData(token);
- obj.set(apiField, obj.has(apiField) ? [obj.get(apiField), data].flat() : data);
- });
+ filterTokens.filter(isNotEmptySearchToken).forEach((token) => {
+ const filterType = getFilterType(token);
+ const apiField = filtersMap[token.type][API_PARAM][filterType];
+ let obj;
+ if (token.value.operator === OPERATOR_NOT) {
+ obj = not;
+ } else if (token.value.operator === OPERATOR_OR) {
+ obj = or;
+ } else {
+ obj = params;
+ }
+ const data = formatData(token);
+ obj.set(apiField, obj.has(apiField) ? [obj.get(apiField), data].flat() : data);
+ });
if (not.size) {
params.set('not', Object.fromEntries(not));
@@ -322,16 +301,14 @@ export const convertToApiParams = (filterTokens) => {
};
export const convertToUrlParams = (filterTokens) => {
- const urlParamsMap = filterTokens
- .filter((token) => token.type !== FILTERED_SEARCH_TERM)
- .reduce((acc, token) => {
- const filterType = getFilterType(token);
- const urlParam = filters[token.type][URL_PARAM][token.value.operator]?.[filterType];
- return acc.set(
- urlParam,
- acc.has(urlParam) ? [acc.get(urlParam), token.value.data].flat() : token.value.data,
- );
- }, new Map());
+ const urlParamsMap = filterTokens.filter(isNotEmptySearchToken).reduce((acc, token) => {
+ const filterType = getFilterType(token);
+ const urlParam = filtersMap[token.type][URL_PARAM][token.value.operator]?.[filterType];
+ return acc.set(
+ urlParam,
+ acc.has(urlParam) ? [acc.get(urlParam), token.value.data].flat() : token.value.data,
+ );
+ }, new Map());
return Object.fromEntries(urlParamsMap);
};
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index 124b14a9845..201499f8509 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -183,6 +183,8 @@ const pageBundles = {
export default class MergeRequestTabs {
constructor({ action, setUrl, stubLocation } = {}) {
+ const containers = document.querySelectorAll('.content-wrapper .container-fluid');
+ this.contentWrapper = containers[containers.length - 1];
this.mergeRequestTabs = document.querySelector('.merge-request-tabs-container');
this.mergeRequestTabsAll =
this.mergeRequestTabs && this.mergeRequestTabs.querySelectorAll
@@ -208,7 +210,7 @@ export default class MergeRequestTabs {
this.diffsLoaded = false;
this.diffsClass = null;
this.commitsLoaded = false;
- this.fixedLayoutPref = null;
+ this.isFixedLayoutPreferred = this.contentWrapper.classList.contains('container-limited');
this.eventHub = createEventHub();
this.loadedPages = { [action]: true };
@@ -561,22 +563,12 @@ export default class MergeRequestTabs {
return action === 'diffs' || action === 'new/diffs';
}
- expandViewContainer(removeLimited = true) {
- const $wrapper = $('.content-wrapper .container-fluid').not('.breadcrumbs');
- if (this.fixedLayoutPref === null) {
- this.fixedLayoutPref = $wrapper.hasClass('container-limited');
- }
- if (this.diffViewType() === 'parallel' || removeLimited) {
- $wrapper.removeClass('container-limited');
- } else {
- $wrapper.toggleClass('container-limited', this.fixedLayoutPref);
- }
+ expandViewContainer() {
+ this.contentWrapper.classList.remove('container-limited');
}
resetViewContainer() {
- if (this.fixedLayoutPref !== null) {
- $('.content-wrapper .container-fluid').toggleClass('container-limited', this.fixedLayoutPref);
- }
+ this.contentWrapper.classList.toggle('container-limited', this.isFixedLayoutPreferred);
}
// Expand the issuable sidebar unless the user explicitly collapsed it
diff --git a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue b/app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue
index 21b585933b8..c24862f828b 100644
--- a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue
+++ b/app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue
@@ -2,9 +2,7 @@
import { GlLoadingIcon } from '@gitlab/ui';
import { s__ } from '~/locale';
import { createAlert } from '~/alert';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import GetFailedJobsQuery from '../../graphql/queries/get_failed_jobs.query.graphql';
-import { prepareFailedJobs } from './utils';
import FailedJobsTable from './failed_jobs_table.vue';
export default {
@@ -20,12 +18,6 @@ export default {
default: '',
},
},
- props: {
- failedJobsSummary: {
- type: Array,
- required: true,
- },
- },
apollo: {
failedJobs: {
query: GetFailedJobsQuery,
@@ -36,15 +28,16 @@ export default {
};
},
update({ project }) {
- if (project?.pipeline?.jobs?.nodes) {
- return project.pipeline.jobs.nodes.map((job) => {
- return { normalizedId: getIdFromGraphQLId(job.id), ...job };
- });
- }
- return [];
- },
- result() {
- this.preparedFailedJobs = prepareFailedJobs(this.failedJobs, this.failedJobsSummary);
+ const jobNodes = project?.pipeline?.jobs?.nodes || [];
+
+ return jobNodes.map((job) => {
+ return {
+ ...job,
+ // this field is needed for the slot row-details
+ // on the failed_jobs_table.vue component
+ _showDetails: true,
+ };
+ });
},
error() {
createAlert({ message: s__('Jobs|There was a problem fetching the failed jobs.') });
@@ -54,7 +47,6 @@ export default {
data() {
return {
failedJobs: [],
- preparedFailedJobs: [],
};
},
computed: {
@@ -68,6 +60,6 @@ export default {
<template>
<div>
<gl-loading-icon v-if="loading" size="lg" class="gl-mt-4" />
- <failed-jobs-table v-else :failed-jobs="preparedFailedJobs" />
+ <failed-jobs-table v-else :failed-jobs="failedJobs" />
</div>
</template>
diff --git a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue b/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue
index 778f014bcd3..80c08d7c613 100644
--- a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue
+++ b/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue
@@ -52,6 +52,9 @@ export default {
showErrorMessage() {
createAlert({ message: s__('Job|There was a problem retrying the failed job.') });
},
+ failureSummary(trace) {
+ return trace ? trace.htmlSummary : s__('Job|No job log');
+ },
},
};
</script>
@@ -90,8 +93,8 @@ export default {
</div>
</template>
- <template #cell(failure)="{ item }">
- <span>{{ item.failure }}</span>
+ <template #cell(failureMessage)="{ item }">
+ <span data-testid="job-failure-message">{{ item.failureMessage }}</span>
</template>
<template #cell(actions)="{ item }">
@@ -110,7 +113,7 @@ export default {
class="gl-w-full gl-text-left gl-border-none"
data-testid="job-log"
>
- <code v-safe-html="item.failureSummary" class="gl-reset-bg gl-p-0" >
+ <code v-safe-html="failureSummary(item.trace)" class="gl-reset-bg gl-p-0" data-testid="job-trace-summary">
</code>
</pre>
</template>
diff --git a/app/assets/javascripts/pipelines/components/jobs/utils.js b/app/assets/javascripts/pipelines/components/jobs/utils.js
deleted file mode 100644
index c8414d44d14..00000000000
--- a/app/assets/javascripts/pipelines/components/jobs/utils.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- We get the failure and failure summary from Rails which has
- a summary failure log. Here we combine that data with the data
- from GraphQL to display the log.
-
- failedJobs is from GraphQL
- failedJobsSummary is from Rails
- */
-
-export const prepareFailedJobs = (failedJobs = [], failedJobsSummary = []) => {
- const combinedJobs = [];
-
- if (failedJobs.length > 0 && failedJobsSummary.length > 0) {
- failedJobs.forEach((failedJob) => {
- const foundJob = failedJobsSummary.find(
- (failedJobSummary) => failedJob.normalizedId === failedJobSummary.id,
- );
-
- if (foundJob) {
- combinedJobs.push({
- ...failedJob,
- failure: foundJob?.failure,
- failureSummary: foundJob?.failure_summary,
- // this field is needed for the slot row-details
- // on the failed_jobs_table.vue component
- _showDetails: true,
- });
- }
- });
- }
-
- return combinedJobs;
-};
diff --git a/app/assets/javascripts/pipelines/components/pipeline_tabs.vue b/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
index 3798863ae60..d2ec3c352fe 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
@@ -31,13 +31,7 @@ export default {
GlTab,
GlTabs,
},
- inject: [
- 'defaultTabValue',
- 'failedJobsCount',
- 'failedJobsSummary',
- 'totalJobCount',
- 'testsCount',
- ],
+ inject: ['defaultTabValue', 'failedJobsCount', 'totalJobCount', 'testsCount'],
data() {
return {
activeTab: this.defaultTabValue,
@@ -110,7 +104,7 @@ export default {
<span class="gl-mr-2">{{ $options.i18n.tabs.failedJobsTitle }}</span>
<gl-badge size="sm" data-testid="failed-builds-counter">{{ failedJobsCount }}</gl-badge>
</template>
- <router-view :failed-jobs-summary="failedJobsSummary" />
+ <router-view />
</gl-tab>
<gl-tab
:active="isActive($options.tabNames.tests)"
diff --git a/app/assets/javascripts/pipelines/constants.js b/app/assets/javascripts/pipelines/constants.js
index ca146ac1e87..abeeea1f888 100644
--- a/app/assets/javascripts/pipelines/constants.js
+++ b/app/assets/javascripts/pipelines/constants.js
@@ -93,7 +93,7 @@ export const DEFAULT_FIELDS = [
columnClass: 'gl-w-20p',
},
{
- key: 'failure',
+ key: 'failureMessage',
label: __('Failure'),
columnClass: 'gl-w-40p',
},
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_failed_jobs.query.graphql b/app/assets/javascripts/pipelines/graphql/queries/get_failed_jobs.query.graphql
index 14e9a838f4b..13c9f0ff8ee 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_failed_jobs.query.graphql
+++ b/app/assets/javascripts/pipelines/graphql/queries/get_failed_jobs.query.graphql
@@ -34,6 +34,10 @@ query getFailedJobs($fullPath: ID!, $pipelineIid: ID!) {
readBuild
updateBuild
}
+ trace {
+ htmlSummary
+ }
+ failureMessage
}
}
}
diff --git a/app/assets/javascripts/pipelines/pipeline_tabs.js b/app/assets/javascripts/pipelines/pipeline_tabs.js
index f9b0c43303d..33bdedee764 100644
--- a/app/assets/javascripts/pipelines/pipeline_tabs.js
+++ b/app/assets/javascripts/pipelines/pipeline_tabs.js
@@ -28,7 +28,6 @@ export const createAppOptions = (selector, apolloProvider, router) => {
exposeSecurityDashboard,
exposeLicenseScanningData,
failedJobsCount,
- failedJobsSummary,
projectPath,
graphqlResourceEtag,
pipelineIid,
@@ -80,7 +79,6 @@ export const createAppOptions = (selector, apolloProvider, router) => {
exposeSecurityDashboard: parseBoolean(exposeSecurityDashboard),
exposeLicenseScanningData: parseBoolean(exposeLicenseScanningData),
failedJobsCount,
- failedJobsSummary: JSON.parse(failedJobsSummary),
graphqlResourceEtag,
pipelineIid,
pipelineProjectPath,
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
index fe4f2d407f7..88062bf245f 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
@@ -99,6 +99,11 @@ export default {
required: false,
default: false,
},
+ termsAsTokens: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -356,7 +361,9 @@ export default {
:close-button-title="__('Close')"
:clear-recent-searches-text="__('Clear recent searches')"
:no-recent-searches-text="__(`You don't have any recent searches`)"
+ :search-text-option-label="__('Search for this text')"
:show-friendly-text="showFriendlyText"
+ :terms-as-tokens="termsAsTokens"
class="flex-grow-1"
@history-item-selected="handleHistoryItemSelected"
@clear="onClear"
diff --git a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue
index 3ac6aaf8b86..95108933a0b 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue
+++ b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue
@@ -317,6 +317,7 @@ export default {
:show-checkbox="showBulkEditSidebar"
:checkbox-checked="allIssuablesChecked"
:show-friendly-text="showFilteredSearchFriendlyText"
+ terms-as-tokens
class="gl-flex-grow-1 gl-border-t-none row-content-block"
data-qa-selector="issuable_search_container"
@checked-input="handleAllIssuablesCheckedInput"
diff --git a/app/assets/javascripts/work_items/components/work_item_description.vue b/app/assets/javascripts/work_items/components/work_item_description.vue
index 141dac9573c..942f5d4a9f0 100644
--- a/app/assets/javascripts/work_items/components/work_item_description.vue
+++ b/app/assets/javascripts/work_items/components/work_item_description.vue
@@ -10,9 +10,10 @@ import Tracking from '~/tracking';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
-import { getWorkItemQuery, autocompleteDataSources, markdownPreviewPath } from '../utils';
+import { autocompleteDataSources, markdownPreviewPath } from '../utils';
import workItemDescriptionSubscription from '../graphql/work_item_description.subscription.graphql';
import updateWorkItemMutation from '../graphql/update_work_item.mutation.graphql';
+import workItemByIidQuery from '../graphql/work_item_by_iid.query.graphql';
import { i18n, TRACKING_CATEGORY_SHOW, WIDGET_TYPE_DESCRIPTION } from '../constants';
import WorkItemDescriptionRendered from './work_item_description_rendered.vue';
@@ -36,11 +37,6 @@ export default {
type: String,
required: true,
},
- fetchByIid: {
- type: Boolean,
- required: false,
- default: false,
- },
queryVariables: {
type: Object,
required: true,
@@ -66,17 +62,15 @@ export default {
},
apollo: {
workItem: {
- query() {
- return getWorkItemQuery(this.fetchByIid);
- },
+ query: workItemByIidQuery,
variables() {
return this.queryVariables;
},
update(data) {
- return this.fetchByIid ? data.workspace.workItems.nodes[0] : data.workItem;
+ return data.workspace.workItems.nodes[0];
},
skip() {
- return !this.queryVariables.id && !this.queryVariables.iid;
+ return !this.queryVariables.iid;
},
result() {
if (this.isEditing) {
diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue
index 766dabecb45..270730dba03 100644
--- a/app/assets/javascripts/work_items/components/work_item_detail.vue
+++ b/app/assets/javascripts/work_items/components/work_item_detail.vue
@@ -679,7 +679,6 @@ export default {
:progress="workItemProgress.progress"
:work-item-id="workItem.id"
:work-item-type="workItemType"
- :fetch-by-iid="fetchByIid"
:query-variables="queryVariables"
@error="updateError = $event"
/>
@@ -690,7 +689,6 @@ export default {
:can-update="canUpdate"
:work-item-id="workItem.id"
:work-item-type="workItemType"
- :fetch-by-iid="fetchByIid"
:query-variables="queryVariables"
:full-path="fullPath"
@error="updateError = $event"
@@ -702,7 +700,6 @@ export default {
:can-update="canUpdate"
:work-item-id="workItem.id"
:work-item-type="workItemType"
- :fetch-by-iid="fetchByIid"
:query-variables="queryVariables"
:full-path="fullPath"
@error="updateError = $event"
@@ -711,7 +708,6 @@ export default {
v-if="hasDescriptionWidget"
:work-item-id="workItem.id"
:full-path="fullPath"
- :fetch-by-iid="fetchByIid"
:query-variables="queryVariables"
class="gl-pt-5"
@error="updateError = $event"
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 70698c0dcb2..5c67e056d66 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -190,6 +190,7 @@ class RegistrationsController < Devise::RegistrationsController
flash[:alert] = _('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.')
flash.delete :recaptcha_error
add_gon_variables
+ set_minimum_password_length
render action: 'new'
end
diff --git a/app/helpers/ci/builds_helper.rb b/app/helpers/ci/builds_helper.rb
index afd0af18ba7..8a00c0f3eb0 100644
--- a/app/helpers/ci/builds_helper.rb
+++ b/app/helpers/ci/builds_helper.rb
@@ -2,18 +2,6 @@
module Ci
module BuildsHelper
- def build_summary(build, skip: false)
- if build.has_trace?
- if skip
- link_to _('View job log'), pipeline_job_url(build.pipeline, build)
- else
- build.trace.html(last_lines: 10).html_safe
- end
- else
- _('No job log')
- end
- end
-
def sidebar_build_class(build, current_build)
build_class = []
build_class << 'active' if build.id === current_build.id
@@ -36,15 +24,5 @@ module Ci
description: project_job_url(@project, @build)
}
end
-
- def prepare_failed_jobs_summary_data(failed_builds)
- failed_builds.map do |build|
- {
- id: build.id,
- failure: build.present.callout_failure_message,
- failure_summary: build_summary(build)
- }
- end.to_json
- end
end
end
diff --git a/app/helpers/projects/pipeline_helper.rb b/app/helpers/projects/pipeline_helper.rb
index c5cbe79caf7..0239253d8f0 100644
--- a/app/helpers/projects/pipeline_helper.rb
+++ b/app/helpers/projects/pipeline_helper.rb
@@ -7,7 +7,6 @@ module Projects
def js_pipeline_tabs_data(project, pipeline, _user)
{
failed_jobs_count: pipeline.failed_builds.count,
- failed_jobs_summary: prepare_failed_jobs_summary_data(pipeline.failed_builds),
project_path: project.full_path,
graphql_resource_etag: graphql_etag_pipeline_path(pipeline),
metrics_path: namespace_project_ci_prometheus_metrics_histograms_path(namespace_id: project.namespace, project_id: project, format: :json),
diff --git a/app/models/project_setting.rb b/app/models/project_setting.rb
index 6a60015cc26..1256ef0f2fc 100644
--- a/app/models/project_setting.rb
+++ b/app/models/project_setting.rb
@@ -10,6 +10,27 @@ class ProjectSetting < ApplicationRecord
scope :for_projects, ->(projects) { where(project_id: projects) }
+ attr_encrypted :cube_api_key,
+ mode: :per_attribute_iv,
+ key: Settings.attr_encrypted_db_key_base_32,
+ algorithm: 'aes-256-gcm',
+ encode: false,
+ encode_iv: false
+
+ attr_encrypted :jitsu_administrator_password,
+ mode: :per_attribute_iv,
+ key: Settings.attr_encrypted_db_key_base_32,
+ algorithm: 'aes-256-gcm',
+ encode: false,
+ encode_iv: false
+
+ attr_encrypted :product_analytics_clickhouse_connection_string,
+ mode: :per_attribute_iv,
+ key: Settings.attr_encrypted_db_key_base_32,
+ algorithm: 'aes-256-gcm',
+ encode: false,
+ encode_iv: false
+
enum squash_option: {
never: 0,
always: 1,
diff --git a/app/models/protected_branch/push_access_level.rb b/app/models/protected_branch/push_access_level.rb
index 66fe57be25f..c86ca5723fa 100644
--- a/app/models/protected_branch/push_access_level.rb
+++ b/app/models/protected_branch/push_access_level.rb
@@ -21,6 +21,12 @@ class ProtectedBranch::PushAccessLevel < ApplicationRecord
end
end
+ def humanize
+ return "Deploy key" if deploy_key.present?
+
+ super
+ end
+
def check_access(user)
if user && deploy_key.present?
return user.can?(:read_project, project) && enabled_deploy_key_for_user?(deploy_key, user)
diff --git a/app/models/protected_tag/create_access_level.rb b/app/models/protected_tag/create_access_level.rb
index abb233d3800..785e7559212 100644
--- a/app/models/protected_tag/create_access_level.rb
+++ b/app/models/protected_tag/create_access_level.rb
@@ -19,6 +19,12 @@ class ProtectedTag::CreateAccessLevel < ApplicationRecord
end
end
+ def humanize
+ return "Deploy key" if deploy_key.present?
+
+ super
+ end
+
def check_access(user)
return false if access_level == Gitlab::Access::NO_ACCESS
diff --git a/app/services/ci/runners/unregister_runner_manager_service.rb b/app/services/ci/runners/unregister_runner_manager_service.rb
new file mode 100644
index 00000000000..ecf6aba09c7
--- /dev/null
+++ b/app/services/ci/runners/unregister_runner_manager_service.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Ci
+ module Runners
+ class UnregisterRunnerManagerService
+ attr_reader :runner, :author, :system_id
+
+ # @param [Ci::Runner] runner the runner to unregister/destroy
+ # @param [User, authentication token String] author the user or the authentication token authorizing the removal
+ # @param [String] system_id ID of the system being unregistered
+ def initialize(runner, author, system_id:)
+ @runner = runner
+ @author = author
+ @system_id = system_id
+ end
+
+ def execute
+ return system_id_missing_error if system_id.blank?
+
+ runner_manager = runner.runner_managers.find_by_system_xid!(system_id)
+ runner_manager.destroy!
+
+ ServiceResponse.success
+ end
+
+ private
+
+ def system_id_missing_error
+ ServiceResponse.error(message: '`system_id` needs to be specified for runners created in the UI.')
+ end
+ end
+ end
+end
diff --git a/app/services/ci/runners/unregister_runner_service.rb b/app/services/ci/runners/unregister_runner_service.rb
index 742b21f77df..d186bd421d5 100644
--- a/app/services/ci/runners/unregister_runner_service.rb
+++ b/app/services/ci/runners/unregister_runner_service.rb
@@ -13,7 +13,8 @@ module Ci
end
def execute
- @runner&.destroy
+ runner.destroy!
+
ServiceResponse.success
end
end
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index b0eef923411..a81afa5f450 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -61,6 +61,8 @@
= render 'projects/service_desk_settings'
+= render_if_exists 'product_analytics/project_settings', expanded: expanded
+
%section.settings.advanced-settings.no-animate#js-project-advanced-settings{ class: ('expanded' if expanded), data: { qa_selector: 'advanced_settings_content' } }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Advanced')
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index f49bb525776..1ebf02ffd39 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -122,9 +122,12 @@
- if display_public_email?(@user)
= render 'middle_dot_divider', stacking: true do
= link_to @user.public_email, "mailto:#{@user.public_email}", itemprop: 'email'
- - if @user.bio.present? && @user.confirmed? && !@user.blocked?
- %p.profile-user-bio.gl-mb-3
- = @user.bio
+
+ -# Ensure this stays indented one level less than the social links
+ -# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118314
+ - if @user.bio.present? && @user.confirmed? && !@user.blocked?
+ %p.profile-user-bio.gl-mb-3
+ = @user.bio
- if !profile_tabs.empty? && !Feature.enabled?(:profile_tabs_vue, current_user)
.scrolling-tabs-container{ class: [('gl-display-none' if show_super_sidebar?)] }