diff options
Diffstat (limited to 'app')
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?)] } |