From 7f98cf51aa49426815fe943a5a8dae2a96b59c01 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 31 Jul 2023 15:11:19 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- app/assets/javascripts/blob/line_highlighter.js | 2 +- .../dashboard/components/issues_dashboard_app.vue | 25 ++++ .../dashboard/queries/get_issues.query.graphql | 8 ++ .../queries/get_issues_counts.query.graphql | 16 +++ .../issues/list/components/issues_list_app.vue | 25 ++++ app/assets/javascripts/issues/list/constants.js | 32 +++++ .../issues/list/queries/get_issues.query.graphql | 12 ++ .../list/queries/get_issues_counts.query.graphql | 28 ++++ app/assets/javascripts/issues/list/utils.js | 4 +- .../super_sidebar/components/menu_section.vue | 10 +- .../extensions/code_quality/index.vue | 158 +++++++++++++++++++++ .../vue_merge_request_widget/mr_widget_options.vue | 14 -- .../components/filtered_search_bar/constants.js | 11 ++ .../filtered_search_bar/tokens/date_token.vue | 73 ++++++++++ .../vue_shared/components/web_ide_link.vue | 28 ++-- .../work_items/components/item_state.vue | 71 --------- .../components/notes/work_item_add_note.vue | 1 + .../components/notes/work_item_comment_form.vue | 81 +++-------- .../components/work_item_attributes_wrapper.vue | 8 -- .../components/work_item_created_updated.vue | 8 +- .../work_items/components/work_item_detail.vue | 10 ++ .../work_items/components/work_item_state.vue | 116 --------------- .../components/work_item_state_badge.vue | 41 ++++++ .../components/work_item_state_toggle_button.vue | 113 +++++++++++++++ app/helpers/issues_helper.rb | 3 +- app/models/ci/bridge.rb | 15 +- app/presenters/packages/npm/package_presenter.rb | 27 ---- app/services/ci/retry_job_service.rb | 2 +- .../deployments/create_for_build_service.rb | 69 --------- app/services/deployments/create_for_job_service.rb | 69 +++++++++ .../environments/create_for_build_service.rb | 40 ------ .../environments/create_for_job_service.rb | 40 ++++++ app/workers/ci/initial_pipeline_process_worker.rb | 2 +- 33 files changed, 721 insertions(+), 441 deletions(-) create mode 100644 app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.vue create mode 100644 app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/date_token.vue delete mode 100644 app/assets/javascripts/work_items/components/item_state.vue delete mode 100644 app/assets/javascripts/work_items/components/work_item_state.vue create mode 100644 app/assets/javascripts/work_items/components/work_item_state_badge.vue create mode 100644 app/assets/javascripts/work_items/components/work_item_state_toggle_button.vue delete mode 100644 app/presenters/packages/npm/package_presenter.rb delete mode 100644 app/services/deployments/create_for_build_service.rb create mode 100644 app/services/deployments/create_for_job_service.rb delete mode 100644 app/services/environments/create_for_build_service.rb create mode 100644 app/services/environments/create_for_job_service.rb (limited to 'app') diff --git a/app/assets/javascripts/blob/line_highlighter.js b/app/assets/javascripts/blob/line_highlighter.js index 1ec204b4034..4258d16b69f 100644 --- a/app/assets/javascripts/blob/line_highlighter.js +++ b/app/assets/javascripts/blob/line_highlighter.js @@ -153,7 +153,7 @@ LineHighlighter.prototype.highlightRange = function (range) { const results = []; const ref = range[0] <= range[1] ? range : range.reverse(); - for (let lineNumber = ref[0]; lineNumber <= ref[1]; lineNumber += 1) { + for (let lineNumber = range[0]; lineNumber <= ref[1]; lineNumber += 1) { results.push(this.highlightLine(lineNumber)); } 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 eb73f8e0182..9febebf7e55 100644 --- a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue +++ b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue @@ -36,6 +36,7 @@ import { getParameterByName } from '~/lib/utils/url_utility'; import { OPERATORS_IS, OPERATORS_IS_NOT_OR, + OPERATORS_AFTER_BEFORE, TOKEN_TITLE_ASSIGNEE, TOKEN_TITLE_AUTHOR, TOKEN_TITLE_CONFIDENTIAL, @@ -44,6 +45,8 @@ import { TOKEN_TITLE_MY_REACTION, TOKEN_TITLE_SEARCH_WITHIN, TOKEN_TITLE_TYPE, + TOKEN_TITLE_CREATED, + TOKEN_TITLE_CLOSED, TOKEN_TYPE_ASSIGNEE, TOKEN_TYPE_AUTHOR, TOKEN_TYPE_CONFIDENTIAL, @@ -52,6 +55,8 @@ import { TOKEN_TYPE_MY_REACTION, TOKEN_TYPE_SEARCH_WITHIN, TOKEN_TYPE_TYPE, + TOKEN_TYPE_CREATED, + TOKEN_TYPE_CLOSED, } from '~/vue_shared/components/filtered_search_bar/constants'; import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue'; import { DEFAULT_PAGE_SIZE, issuableListTabs } from '~/vue_shared/issuable/list/constants'; @@ -63,6 +68,7 @@ const EmojiToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue'); const LabelToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/label_token.vue'); +const DateToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/date_token.vue'); const MilestoneToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue'); @@ -89,6 +95,7 @@ export default { 'emptyStateWithoutFilterSvgPath', 'hasBlockedIssuesFeature', 'hasIssuableHealthStatusFeature', + 'hasIssueDateFilterFeature', 'hasIssueWeightsFeature', 'hasScopedLabelsFeature', 'initialSort', @@ -318,6 +325,24 @@ export default { fetchEmojis: this.fetchEmojis, recentSuggestionsStorageKey: 'dashboard-issues-recent-tokens-my_reaction', }); + + if (this.hasIssueDateFilterFeature) { + tokens.push({ + type: TOKEN_TYPE_CREATED, + title: TOKEN_TITLE_CREATED, + icon: 'history', + token: DateToken, + operators: OPERATORS_AFTER_BEFORE, + }); + + tokens.push({ + type: TOKEN_TYPE_CLOSED, + title: TOKEN_TITLE_CLOSED, + icon: 'history', + token: DateToken, + operators: OPERATORS_AFTER_BEFORE, + }); + } } tokens.sort((a, b) => a.title.localeCompare(b.title)); diff --git a/app/assets/javascripts/issues/dashboard/queries/get_issues.query.graphql b/app/assets/javascripts/issues/dashboard/queries/get_issues.query.graphql index 5c331fe95e2..51e38d44c85 100644 --- a/app/assets/javascripts/issues/dashboard/queries/get_issues.query.graphql +++ b/app/assets/javascripts/issues/dashboard/queries/get_issues.query.graphql @@ -23,6 +23,10 @@ query getDashboardIssues( $beforeCursor: String $firstPageSize: Int $lastPageSize: Int + $createdAfter: Time + $createdBefore: Time + $closedAfter: Time + $closedBefore: Time ) { issues( search: $search @@ -44,6 +48,10 @@ query getDashboardIssues( before: $beforeCursor first: $firstPageSize last: $lastPageSize + createdAfter: $createdAfter + createdBefore: $createdBefore + closedAfter: $closedAfter + closedBefore: $closedBefore ) @persist { nodes { __persist diff --git a/app/assets/javascripts/issues/dashboard/queries/get_issues_counts.query.graphql b/app/assets/javascripts/issues/dashboard/queries/get_issues_counts.query.graphql index b36f546e4ab..a91f15f0c04 100644 --- a/app/assets/javascripts/issues/dashboard/queries/get_issues_counts.query.graphql +++ b/app/assets/javascripts/issues/dashboard/queries/get_issues_counts.query.graphql @@ -12,6 +12,10 @@ query getDashboardIssuesCount( $in: [IssuableSearchableField!] $not: NegatedIssueFilterInput $or: UnionedIssueFilterInput + $createdAfter: Time + $createdBefore: Time + $closedAfter: Time + $closedBefore: Time ) { openedIssues: issues( state: opened @@ -28,6 +32,10 @@ query getDashboardIssuesCount( in: $in not: $not or: $or + createdAfter: $createdAfter + createdBefore: $createdBefore + closedAfter: $closedAfter + closedBefore: $closedBefore ) { count } @@ -46,6 +54,10 @@ query getDashboardIssuesCount( in: $in not: $not or: $or + createdAfter: $createdAfter + createdBefore: $createdBefore + closedAfter: $closedAfter + closedBefore: $closedBefore ) { count } @@ -64,6 +76,10 @@ query getDashboardIssuesCount( in: $in not: $not or: $or + createdAfter: $createdAfter + createdBefore: $createdBefore + closedAfter: $closedAfter + closedBefore: $closedBefore ) { count } 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 db3008c17a4..c4e906be94f 100644 --- a/app/assets/javascripts/issues/list/components/issues_list_app.vue +++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue @@ -40,6 +40,7 @@ import { OPERATORS_IS, OPERATORS_IS_NOT, OPERATORS_IS_NOT_OR, + OPERATORS_AFTER_BEFORE, TOKEN_TITLE_ASSIGNEE, TOKEN_TITLE_AUTHOR, TOKEN_TITLE_CONFIDENTIAL, @@ -51,6 +52,8 @@ import { TOKEN_TITLE_RELEASE, TOKEN_TITLE_SEARCH_WITHIN, TOKEN_TITLE_TYPE, + TOKEN_TITLE_CREATED, + TOKEN_TITLE_CLOSED, TOKEN_TYPE_ASSIGNEE, TOKEN_TYPE_AUTHOR, TOKEN_TYPE_CONFIDENTIAL, @@ -62,6 +65,8 @@ import { TOKEN_TYPE_RELEASE, TOKEN_TYPE_SEARCH_WITHIN, TOKEN_TYPE_TYPE, + TOKEN_TYPE_CREATED, + TOKEN_TYPE_CLOSED, } from '~/vue_shared/components/filtered_search_bar/constants'; import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue'; import { DEFAULT_PAGE_SIZE, issuableListTabs } from '~/vue_shared/issuable/list/constants'; @@ -125,6 +130,7 @@ const CrmContactToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/crm_contact_token.vue'); const CrmOrganizationToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/crm_organization_token.vue'); +const DateToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/date_token.vue'); export default { i18n, @@ -166,6 +172,7 @@ export default { 'hasAnyProjects', 'hasBlockedIssuesFeature', 'hasIssuableHealthStatusFeature', + 'hasIssueDateFilterFeature', 'hasIssueWeightsFeature', 'hasScopedLabelsFeature', 'initialEmail', @@ -460,6 +467,24 @@ export default { { icon: 'eye', value: 'no', title: this.$options.i18n.confidentialNo }, ], }); + + if (this.hasIssueDateFilterFeature) { + tokens.push({ + type: TOKEN_TYPE_CREATED, + title: TOKEN_TITLE_CREATED, + icon: 'history', + token: DateToken, + operators: OPERATORS_AFTER_BEFORE, + }); + + tokens.push({ + type: TOKEN_TYPE_CLOSED, + title: TOKEN_TITLE_CLOSED, + icon: 'history', + token: DateToken, + operators: OPERATORS_AFTER_BEFORE, + }); + } } if (this.canReadCrmContact) { diff --git a/app/assets/javascripts/issues/list/constants.js b/app/assets/javascripts/issues/list/constants.js index a7933803ed4..85e300b6474 100644 --- a/app/assets/javascripts/issues/list/constants.js +++ b/app/assets/javascripts/issues/list/constants.js @@ -9,6 +9,8 @@ import { OPERATOR_IS, OPERATOR_NOT, OPERATOR_OR, + OPERATOR_AFTER, + OPERATOR_BEFORE, TOKEN_TYPE_ASSIGNEE, TOKEN_TYPE_AUTHOR, TOKEN_TYPE_CONFIDENTIAL, @@ -24,6 +26,8 @@ import { TOKEN_TYPE_TYPE, TOKEN_TYPE_WEIGHT, TOKEN_TYPE_SEARCH_WITHIN, + TOKEN_TYPE_CREATED, + TOKEN_TYPE_CLOSED, } from '~/vue_shared/components/filtered_search_bar/constants'; import { WORK_ITEM_TYPE_ENUM_INCIDENT, @@ -416,4 +420,32 @@ export const filtersMap = { }, }, }, + [TOKEN_TYPE_CREATED]: { + [API_PARAM]: { + [NORMAL_FILTER]: 'createdBefore', + [ALTERNATIVE_FILTER]: 'createdAfter', + }, + [URL_PARAM]: { + [OPERATOR_AFTER]: { + [ALTERNATIVE_FILTER]: 'created_after', + }, + [OPERATOR_BEFORE]: { + [NORMAL_FILTER]: 'created_before', + }, + }, + }, + [TOKEN_TYPE_CLOSED]: { + [API_PARAM]: { + [NORMAL_FILTER]: 'closedBefore', + [ALTERNATIVE_FILTER]: 'closedAfter', + }, + [URL_PARAM]: { + [OPERATOR_AFTER]: { + [ALTERNATIVE_FILTER]: 'closed_after', + }, + [OPERATOR_BEFORE]: { + [NORMAL_FILTER]: 'closed_before', + }, + }, + }, }; diff --git a/app/assets/javascripts/issues/list/queries/get_issues.query.graphql b/app/assets/javascripts/issues/list/queries/get_issues.query.graphql index 1018848fb53..23410ea0f81 100644 --- a/app/assets/javascripts/issues/list/queries/get_issues.query.graphql +++ b/app/assets/javascripts/issues/list/queries/get_issues.query.graphql @@ -30,6 +30,10 @@ query getIssues( $afterCursor: String $firstPageSize: Int $lastPageSize: Int + $createdAfter: Time + $createdBefore: Time + $closedAfter: Time + $closedBefore: Time ) { group(fullPath: $fullPath) @skip(if: $isProject) @persist { id @@ -57,6 +61,10 @@ query getIssues( after: $afterCursor first: $firstPageSize last: $lastPageSize + createdAfter: $createdAfter + createdBefore: $createdBefore + closedAfter: $closedAfter + closedBefore: $closedBefore ) { __persist pageInfo { @@ -96,6 +104,10 @@ query getIssues( after: $afterCursor first: $firstPageSize last: $lastPageSize + createdAfter: $createdAfter + createdBefore: $createdBefore + closedAfter: $closedAfter + closedBefore: $closedBefore ) { __persist pageInfo { diff --git a/app/assets/javascripts/issues/list/queries/get_issues_counts.query.graphql b/app/assets/javascripts/issues/list/queries/get_issues_counts.query.graphql index fdb0eeb5970..7953dc423b6 100644 --- a/app/assets/javascripts/issues/list/queries/get_issues_counts.query.graphql +++ b/app/assets/javascripts/issues/list/queries/get_issues_counts.query.graphql @@ -18,6 +18,10 @@ query getIssuesCount( $crmOrganizationId: String $not: NegatedIssueFilterInput $or: UnionedIssueFilterInput + $createdAfter: Time + $createdBefore: Time + $closedAfter: Time + $closedBefore: Time ) { group(fullPath: $fullPath) @skip(if: $isProject) { id @@ -39,6 +43,10 @@ query getIssuesCount( crmOrganizationId: $crmOrganizationId not: $not or: $or + createdAfter: $createdAfter + createdBefore: $createdBefore + closedAfter: $closedAfter + closedBefore: $closedBefore ) { count } @@ -60,6 +68,10 @@ query getIssuesCount( crmOrganizationId: $crmOrganizationId not: $not or: $or + createdAfter: $createdAfter + createdBefore: $createdBefore + closedAfter: $closedAfter + closedBefore: $closedBefore ) { count } @@ -81,6 +93,10 @@ query getIssuesCount( crmOrganizationId: $crmOrganizationId not: $not or: $or + createdAfter: $createdAfter + createdBefore: $createdBefore + closedAfter: $closedAfter + closedBefore: $closedBefore ) { count } @@ -106,6 +122,10 @@ query getIssuesCount( crmOrganizationId: $crmOrganizationId not: $not or: $or + createdAfter: $createdAfter + createdBefore: $createdBefore + closedAfter: $closedAfter + closedBefore: $closedBefore ) { count } @@ -128,6 +148,10 @@ query getIssuesCount( crmOrganizationId: $crmOrganizationId not: $not or: $or + createdAfter: $createdAfter + createdBefore: $createdBefore + closedAfter: $closedAfter + closedBefore: $closedBefore ) { count } @@ -150,6 +174,10 @@ query getIssuesCount( crmOrganizationId: $crmOrganizationId not: $not or: $or + createdAfter: $createdAfter + createdBefore: $createdBefore + closedAfter: $closedAfter + closedBefore: $closedBefore ) { count } diff --git a/app/assets/javascripts/issues/list/utils.js b/app/assets/javascripts/issues/list/utils.js index 04ce9a4969b..37df0c8f9ff 100644 --- a/app/assets/javascripts/issues/list/utils.js +++ b/app/assets/javascripts/issues/list/utils.js @@ -6,6 +6,7 @@ import { FILTERED_SEARCH_TERM, OPERATOR_NOT, OPERATOR_OR, + OPERATOR_AFTER, TOKEN_TYPE_ASSIGNEE, TOKEN_TYPE_AUTHOR, TOKEN_TYPE_CONFIDENTIAL, @@ -246,8 +247,9 @@ export const isSpecialFilter = (type, data) => { const getFilterType = ({ type, value: { data, operator } }) => { const isUnionedAuthor = type === TOKEN_TYPE_AUTHOR && operator === OPERATOR_OR; const isUnionedLabel = type === TOKEN_TYPE_LABEL && operator === OPERATOR_OR; + const isAfter = operator === OPERATOR_AFTER; - if (isUnionedAuthor || isUnionedLabel) { + if (isUnionedAuthor || isUnionedLabel || isAfter) { return ALTERNATIVE_FILTER; } if (isSpecialFilter(type, data)) { diff --git a/app/assets/javascripts/super_sidebar/components/menu_section.vue b/app/assets/javascripts/super_sidebar/components/menu_section.vue index 37a6ab0122b..4e26750efc2 100644 --- a/app/assets/javascripts/super_sidebar/components/menu_section.vue +++ b/app/assets/javascripts/super_sidebar/components/menu_section.vue @@ -43,6 +43,7 @@ export default { isExpanded: Boolean(this.expanded || this.item.is_active), isMouseOverSection: false, isMouseOverFlyout: false, + keepFlyoutClosed: false, }; }, computed: { @@ -77,12 +78,17 @@ export default { watch: { isExpanded(newIsExpanded) { this.$emit('collapse-toggle', newIsExpanded); + this.keepFlyoutClosed = !this.newIsExpanded; }, }, methods: { handlePointerover(e) { this.isMouseOverSection = e.pointerType === 'mouse'; }, + handlePointerleave() { + this.isMouseOverSection = false; + this.keepFlyoutClosed = false; + }, }, }; @@ -99,7 +105,7 @@ export default { v-bind="buttonProps" @click="isExpanded = !isExpanded" @pointerover="handlePointerover" - @pointerleave="isMouseOverSection = false" + @pointerleave="handlePointerleave" > +import * as Sentry from '@sentry/browser'; +import { HTTP_STATUS_OK } from '~/lib/utils/http_status'; +import { SEVERITY_ICONS_MR_WIDGET } from '~/ci/reports/codequality_report/constants'; +import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; +import axios from '~/lib/utils/axios_utils'; +import MrWidget from '~/vue_merge_request_widget/components/widget/widget.vue'; +import { EXTENSION_ICONS } from '~/vue_merge_request_widget/constants'; +import { i18n, codeQualityPrefixes } from './constants'; + +const translations = i18n; + +export default { + name: 'WidgetCodeQuality', + components: { + MrWidget, + }, + i18n: translations, + props: { + mr: { + type: Object, + required: true, + }, + }, + data() { + return { + pollingFinished: false, + hasError: false, + collapsedData: {}, + poll: null, + }; + }, + computed: { + summary() { + const { new_errors, resolved_errors } = this.collapsedData; + + if (!this.pollingFinished) { + return { title: i18n.loading }; + } else if (this.hasError) { + return { title: i18n.error }; + } else if ( + this.collapsedData?.new_errors?.length >= 1 && + this.collapsedData?.resolved_errors?.length >= 1 + ) { + return { + title: i18n.improvementAndDegradationCopy( + i18n.findings(resolved_errors, codeQualityPrefixes.fixed), + i18n.findings(new_errors, codeQualityPrefixes.new), + ), + }; + } else if (this.collapsedData?.resolved_errors?.length >= 1) { + return { + title: i18n.singularCopy(i18n.findings(resolved_errors, codeQualityPrefixes.fixed)), + }; + } else if (this.collapsedData?.new_errors?.length >= 1) { + return { title: i18n.singularCopy(i18n.findings(new_errors, codeQualityPrefixes.new)) }; + } + return { title: i18n.noChanges }; + }, + expandedData() { + const fullData = []; + this.collapsedData?.new_errors?.forEach((e) => { + fullData.push({ + text: e.check_name + ? `${capitalizeFirstCharacter(e.severity)} - ${e.check_name} - ${e.description}` + : `${capitalizeFirstCharacter(e.severity)} - ${e.description}`, + link: { + href: e.web_url, + text: `${i18n.prependText} ${e.file_path}:${e.line}`, + }, + icon: { + name: SEVERITY_ICONS_MR_WIDGET[e.severity], + }, + }); + }); + + this.collapsedData?.resolved_errors?.forEach((e) => { + fullData.push({ + text: e.check_name + ? `${capitalizeFirstCharacter(e.severity)} - ${e.check_name} - ${e.description}` + : `${capitalizeFirstCharacter(e.severity)} - ${e.description}`, + supportingText: `${i18n.prependText} ${e.file_path}:${e.line}`, + icon: { + name: SEVERITY_ICONS_MR_WIDGET[e.severity], + }, + badge: { + variant: 'neutral', + text: i18n.fixed, + }, + }); + }); + + return fullData; + }, + statusIcon() { + if (this.collapsedData?.new_errors?.length >= 1) { + return EXTENSION_ICONS.warning; + } else if (this.collapsedData?.resolved_errors?.length >= 1) { + return EXTENSION_ICONS.success; + } + return EXTENSION_ICONS.neutral; + }, + shouldCollapse() { + const { new_errors: newErrors, resolved_errors: resolvedErrors } = this.collapsedData; + + if ((newErrors?.length === 0 && resolvedErrors?.length === 0) || this.hasError) { + return false; + } + return true; + }, + apiCodeQualityPath() { + return this.mr.codequalityReportsPath; + }, + }, + methods: { + setCollapsedError(err) { + this.hasError = true; + + Sentry.captureException(err); + }, + fetchCodeQuality() { + return axios + .get(this.apiCodeQualityPath) + .then(({ data, headers = {}, status }) => { + if (status === HTTP_STATUS_OK) { + this.pollingFinished = true; + } + if (data) { + this.collapsedData = data; + } + return { + headers, + status, + data, + }; + }) + .catch((e) => { + return this.setCollapsedError(e); + }); + }, + }, +}; + + + diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index 52a2f42f8ec..db48e68e8f6 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -56,7 +56,6 @@ import mergeRequestQueryVariablesMixin from './mixins/merge_request_query_variab import getStateQuery from './queries/get_state.query.graphql'; import getStateSubscription from './queries/get_state.subscription.graphql'; import accessibilityExtension from './extensions/accessibility'; -import codeQualityExtension from './extensions/code_quality'; import testReportExtension from './extensions/test_report'; import ReportWidgetContainer from './components/report_widget_container.vue'; import MrWidgetReadyToMerge from './components/states/new_ready_to_merge.vue'; @@ -215,9 +214,6 @@ export default { return !hasCI && mergeRequestAddCiConfigPath && !isDismissedSuggestPipeline; }, - shouldRenderCodeQuality() { - return this.mr?.codequalityReportsPath; - }, shouldRenderCollaborationStatus() { return this.mr.allowCollaboration && this.mr.isOpen; }, @@ -280,11 +276,6 @@ export default { this.initPostMergeDeploymentsPolling(); } }, - shouldRenderCodeQuality(newVal) { - if (newVal) { - this.registerCodeQualityExtension(); - } - }, shouldShowAccessibilityReport(newVal) { if (newVal) { this.registerAccessibilityExtension(); @@ -534,11 +525,6 @@ export default { registerExtension(accessibilityExtension); } }, - registerCodeQualityExtension() { - if (this.shouldRenderCodeQuality) { - registerExtension(codeQualityExtension); - } - }, registerTestReportExtension() { if (this.shouldRenderTestReport) { registerExtension(testReportExtension); diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js index 5b98af8c732..39fd3d62c3b 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js @@ -17,12 +17,19 @@ export const OPERATOR_NOT = '!='; export const OPERATOR_NOT_TEXT = __('is not one of'); export const OPERATOR_OR = '||'; export const OPERATOR_OR_TEXT = __('is one of'); +export const OPERATOR_AFTER = '≥'; +export const OPERATOR_AFTER_TEXT = __('on or after'); +export const OPERATOR_BEFORE = '<'; +export const OPERATOR_BEFORE_TEXT = __('before'); export const OPERATORS_IS = [{ value: OPERATOR_IS, description: OPERATOR_IS_TEXT }]; export const OPERATORS_NOT = [{ value: OPERATOR_NOT, description: OPERATOR_NOT_TEXT }]; export const OPERATORS_OR = [{ value: OPERATOR_OR, description: OPERATOR_OR_TEXT }]; +export const OPERATORS_AFTER = [{ value: OPERATOR_AFTER, description: OPERATOR_AFTER_TEXT }]; +export const OPERATORS_BEFORE = [{ value: OPERATOR_BEFORE, description: OPERATOR_BEFORE_TEXT }]; export const OPERATORS_IS_NOT = [...OPERATORS_IS, ...OPERATORS_NOT]; export const OPERATORS_IS_NOT_OR = [...OPERATORS_IS, ...OPERATORS_NOT, ...OPERATORS_OR]; +export const OPERATORS_AFTER_BEFORE = [...OPERATORS_AFTER, ...OPERATORS_BEFORE]; export const OPTION_NONE = { value: FILTER_NONE, text: __('None'), title: __('None') }; export const OPTION_ANY = { value: FILTER_ANY, text: __('Any'), title: __('Any') }; @@ -62,6 +69,8 @@ export const TOKEN_TITLE_STATUS = __('Status'); export const TOKEN_TITLE_TARGET_BRANCH = __('Target Branch'); export const TOKEN_TITLE_TYPE = __('Type'); export const TOKEN_TITLE_SEARCH_WITHIN = __('Search Within'); +export const TOKEN_TITLE_CREATED = __('Created date'); +export const TOKEN_TITLE_CLOSED = __('Closed date'); export const TOKEN_TYPE_APPROVED_BY = 'approved-by'; export const TOKEN_TYPE_ASSIGNEE = 'assignee'; @@ -88,3 +97,5 @@ export const TOKEN_TYPE_TARGET_BRANCH = 'target-branch'; export const TOKEN_TYPE_TYPE = 'type'; export const TOKEN_TYPE_WEIGHT = 'weight'; export const TOKEN_TYPE_SEARCH_WITHIN = 'in'; +export const TOKEN_TYPE_CREATED = 'created'; +export const TOKEN_TYPE_CLOSED = 'closed'; diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/date_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/date_token.vue new file mode 100644 index 00000000000..4446886dc88 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/date_token.vue @@ -0,0 +1,73 @@ + + + diff --git a/app/assets/javascripts/vue_shared/components/web_ide_link.vue b/app/assets/javascripts/vue_shared/components/web_ide_link.vue index 756d9b42e99..79d14b5f2d0 100644 --- a/app/assets/javascripts/vue_shared/components/web_ide_link.vue +++ b/app/assets/javascripts/vue_shared/components/web_ide_link.vue @@ -9,6 +9,7 @@ import { } from '@gitlab/ui'; import { s__, __ } from '~/locale'; import { visitUrl } from '~/lib/utils/url_utility'; +import Tracking from '~/tracking'; import ConfirmForkModal from '~/vue_shared/components/web_ide/confirm_fork_modal.vue'; import { KEY_EDIT, KEY_WEB_IDE, KEY_GITPOD, KEY_PIPELINE_EDITOR } from './constants'; @@ -28,6 +29,8 @@ export const i18n = { toggleText: __('Edit'), }; +const TRACKING_ACTION_NAME = 'click_consolidated_edit'; + export default { name: 'CEWebIdeLink', components: { @@ -40,6 +43,7 @@ export default { ConfirmForkModal, }, i18n, + mixins: [Tracking.mixin()], props: { isFork: { type: Boolean, @@ -181,9 +185,9 @@ export default { key: KEY_EDIT, text: __('Edit single file'), secondaryText: __('Edit this file only.'), - attrs: { - 'data-track-action': 'click_consolidated_edit', - 'data-track-label': 'edit', + tracking: { + action: TRACKING_ACTION_NAME, + label: 'single_file', }, ...handleOptions, }; @@ -223,9 +227,9 @@ export default { key: KEY_WEB_IDE, text: this.webIdeActionText, secondaryText: this.$options.i18n.webIdeText, - attrs: { - 'data-track-action': 'click_consolidated_edit_ide', - 'data-track-label': 'web_ide', + tracking: { + action: TRACKING_ACTION_NAME, + label: 'web_ide', }, ...handleOptions, }; @@ -253,9 +257,9 @@ export default { text: __('Edit in pipeline editor'), secondaryText, href: this.pipelineEditorUrl, - attrs: { - 'data-track-action': 'click_consolidated_pipeline_editor', - 'data-track-label': 'pipeline_editor', + tracking: { + action: TRACKING_ACTION_NAME, + label: 'pipeline_editor', }, }; }, @@ -277,6 +281,10 @@ export default { key: KEY_GITPOD, text: this.gitpodActionText, secondaryText, + tracking: { + action: TRACKING_ACTION_NAME, + label: 'gitpod', + }, ...handleOptions, }; }, @@ -311,6 +319,7 @@ export default { this[dataKey] = true; }, executeAction(action) { + this.track(action.tracking.action, { label: action.tracking.label }); action.handle?.(); }, }, @@ -335,7 +344,6 @@ export default { -import { GlFormGroup, GlFormSelect } from '@gitlab/ui'; -import { __ } from '~/locale'; -import { STATE_OPEN, STATE_CLOSED } from '../constants'; - -export default { - i18n: { - status: __('Status'), - }, - states: [ - { - value: STATE_OPEN, - text: __('Open'), - }, - { - value: STATE_CLOSED, - text: __('Closed'), - }, - ], - components: { - GlFormGroup, - GlFormSelect, - }, - props: { - state: { - type: String, - required: true, - }, - disabled: { - type: Boolean, - required: false, - default: false, - }, - }, - computed: { - currentState() { - return this.$options.states[this.state]; - }, - }, - methods: { - setState(newState) { - if (newState !== this.state) { - this.$emit('changed', newState); - } - }, - }, - labelId: 'work-item-state-select', -}; - - - diff --git a/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue b/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue index c330eccb186..66ad3d50287 100644 --- a/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue +++ b/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue @@ -265,6 +265,7 @@ export default { :comment-button-text="commentButtonText" @submitForm="updateWorkItem" @cancelEditing="cancelEditing" + @error="$emit('error', $event)" />