diff --git a/app/assets/javascripts/merge_request/components/status_box.vue b/app/assets/javascripts/merge_request/components/status_box.vue index fd99802caff..b2754dd4ad6 100644 --- a/app/assets/javascripts/merge_request/components/status_box.vue +++ b/app/assets/javascripts/merge_request/components/status_box.vue @@ -5,12 +5,14 @@ import mrEventHub from '../eventhub'; const CLASSES = { opened: 'status-box-open', + locked: 'status-box-open', closed: 'status-box-mr-closed', merged: 'status-box-mr-merged', }; const STATUS = { opened: [__('Open'), 'issue-open-m'], + locked: [__('Open'), 'issue-open-m'], closed: [__('Closed'), 'close'], merged: [__('Merged'), 'git-merge'], }; diff --git a/app/assets/javascripts/monitoring/components/charts/single_stat.vue b/app/assets/javascripts/monitoring/components/charts/single_stat.vue index a8ab41ebf26..4cf583fed18 100644 --- a/app/assets/javascripts/monitoring/components/charts/single_stat.vue +++ b/app/assets/javascripts/monitoring/components/charts/single_stat.vue @@ -45,12 +45,18 @@ export default { } if (this.graphData?.maxValue) { - formatter = getFormatter(SUPPORTED_FORMATS.percent); - return formatter(this.queryResult / Number(this.graphData.maxValue), defaultPrecision); + formatter = getFormatter(SUPPORTED_FORMATS.number); + return formatter( + (this.queryResult / Number(this.graphData.maxValue)) * 100, + defaultPrecision, + ); } formatter = getFormatter(SUPPORTED_FORMATS.number); - return `${formatter(this.queryResult, defaultPrecision)}${this.queryInfo.unit ?? ''}`; + return `${formatter(this.queryResult, defaultPrecision)}`; + }, + unit() { + return this.graphData?.maxValue ? '%' : this.queryInfo.unit; }, graphTitle() { return this.queryInfo.label; @@ -60,6 +66,6 @@ export default { diff --git a/app/assets/javascripts/pages/projects/commit/pipelines/index.js b/app/assets/javascripts/pages/projects/commit/pipelines/index.js index eaf340f2725..f542014c5b9 100644 --- a/app/assets/javascripts/pages/projects/commit/pipelines/index.js +++ b/app/assets/javascripts/pages/projects/commit/pipelines/index.js @@ -1,5 +1,7 @@ import { initCommitBoxInfo } from '~/projects/commit_box/info'; import initPipelines from '~/commit/pipelines/pipelines_bundle'; +import initCommitActions from '~/projects/commit'; initCommitBoxInfo(); initPipelines(); +initCommitActions(); diff --git a/app/assets/javascripts/pages/projects/commit/show/index.js b/app/assets/javascripts/pages/projects/commit/show/index.js index 5cfdb125e4f..5a3b486fd40 100644 --- a/app/assets/javascripts/pages/projects/commit/show/index.js +++ b/app/assets/javascripts/pages/projects/commit/show/index.js @@ -14,8 +14,7 @@ import flash from '~/flash'; import { __ } from '~/locale'; import loadAwardsHandler from '~/awards_handler'; import { initCommitBoxInfo } from '~/projects/commit_box/info'; -import initRevertCommitTrigger from '~/projects/commit/init_revert_commit_trigger'; -import initRevertCommitModal from '~/projects/commit/init_revert_commit_modal'; +import initCommitActions from '~/projects/commit'; const hasPerfBar = document.querySelector('.with-performance-bar'); const performanceHeight = hasPerfBar ? 35 : 0; @@ -47,5 +46,4 @@ if (filesContainer.length) { new Diff(); } loadAwardsHandler(); -initRevertCommitModal(); -initRevertCommitTrigger(); +initCommitActions(); diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js index 133608b9801..1c6f0b3f036 100644 --- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js +++ b/app/assets/javascripts/pipelines/pipeline_details_bundle.js @@ -136,10 +136,13 @@ export default async function () { createTestDetails(); createDagApp(); + const canShowNewPipelineDetails = + gon.features.graphqlPipelineDetails || gon.features.graphqlPipelineDetailsUsers; + const { dataset } = document.querySelector(SELECTORS.PIPELINE_DETAILS); let mediator; - if (!gon.features.graphqlPipelineHeader || !gon.features.graphqlPipelineDetails) { + if (!gon.features.graphqlPipelineHeader || !canShowNewPipelineDetails) { try { const { default: PipelinesMediator } = await import( /* webpackChunkName: 'PipelinesMediator' */ './pipeline_details_mediator' @@ -151,7 +154,7 @@ export default async function () { } } - if (gon.features.graphqlPipelineDetails) { + if (canShowNewPipelineDetails) { try { const { createPipelinesDetailApp } = await import( /* webpackChunkName: 'createPipelinesDetailApp' */ './pipeline_details_graph' diff --git a/app/assets/javascripts/projects/commit/components/branches_dropdown.vue b/app/assets/javascripts/projects/commit/components/branches_dropdown.vue index 3ecc3f1d1d3..36da4128450 100644 --- a/app/assets/javascripts/projects/commit/components/branches_dropdown.vue +++ b/app/assets/javascripts/projects/commit/components/branches_dropdown.vue @@ -68,6 +68,7 @@ export default { autocomplete="off" :debounce="250" :placeholder="$options.i18n.searchPlaceholder" + data-testid="dropdown-search-box" @input="searchTermChanged" /> diff --git a/app/assets/javascripts/projects/commit/constants.js b/app/assets/javascripts/projects/commit/constants.js index 233f43d56b9..b47c744e5fb 100644 --- a/app/assets/javascripts/projects/commit/constants.js +++ b/app/assets/javascripts/projects/commit/constants.js @@ -2,6 +2,10 @@ import { s__, __ } from '~/locale'; export const OPEN_REVERT_MODAL = 'openRevertModal'; export const REVERT_MODAL_ID = 'revert-commit-modal'; +export const REVERT_LINK_TEST_ID = 'revert-commit-link'; +export const OPEN_CHERRY_PICK_MODAL = 'openCherryPickModal'; +export const CHERRY_PICK_MODAL_ID = 'cherry-pick-commit-modal'; +export const CHERRY_PICK_LINK_TEST_ID = 'cherry-pick-commit-link'; export const I18N_MODAL = { startMergeRequest: s__('ChangeTypeAction|Start a %{newMergeRequest} with these changes'), @@ -20,6 +24,11 @@ export const I18N_REVERT_MODAL = { actionPrimaryText: s__('ChangeTypeAction|Revert'), }; +export const I18N_CHERRY_PICK_MODAL = { + branchLabel: s__('ChangeTypeAction|Pick into branch'), + actionPrimaryText: s__('ChangeTypeAction|Cherry-pick'), +}; + export const PREPENDED_MODAL_TEXT = s__( 'ChangeTypeAction|This will create a new commit in order to revert the existing changes.', ); diff --git a/app/assets/javascripts/projects/commit/index.js b/app/assets/javascripts/projects/commit/index.js new file mode 100644 index 00000000000..d5d7e62ce32 --- /dev/null +++ b/app/assets/javascripts/projects/commit/index.js @@ -0,0 +1,11 @@ +import initRevertCommitTrigger from './init_revert_commit_trigger'; +import initRevertCommitModal from './init_revert_commit_modal'; +import initCherryPickCommitTrigger from './init_cherry_pick_commit_trigger'; +import initCherryPickCommitModal from './init_cherry_pick_commit_modal'; + +export default () => { + initRevertCommitModal(); + initRevertCommitTrigger(); + initCherryPickCommitModal(); + initCherryPickCommitTrigger(); +}; diff --git a/app/assets/javascripts/projects/commit/init_cherry_pick_commit_modal.js b/app/assets/javascripts/projects/commit/init_cherry_pick_commit_modal.js new file mode 100644 index 00000000000..0bac569e5b7 --- /dev/null +++ b/app/assets/javascripts/projects/commit/init_cherry_pick_commit_modal.js @@ -0,0 +1,51 @@ +import Vue from 'vue'; +import CommitFormModal from './components/form_modal.vue'; +import { parseBoolean } from '~/lib/utils/common_utils'; +import createStore from './store'; +import { + I18N_MODAL, + I18N_CHERRY_PICK_MODAL, + OPEN_CHERRY_PICK_MODAL, + CHERRY_PICK_MODAL_ID, +} from './constants'; + +export default function initInviteMembersModal() { + const el = document.querySelector('.js-cherry-pick-commit-modal'); + if (!el) { + return false; + } + + const { + title, + endpoint, + branch, + pushCode, + branchCollaboration, + existingBranch, + branchesEndpoint, + } = el.dataset; + + const store = createStore({ + endpoint, + branchesEndpoint, + branch, + pushCode: parseBoolean(pushCode), + branchCollaboration: parseBoolean(branchCollaboration), + defaultBranch: branch, + modalTitle: title, + existingBranch, + }); + + return new Vue({ + el, + store, + render: (createElement) => + createElement(CommitFormModal, { + props: { + i18n: { ...I18N_CHERRY_PICK_MODAL, ...I18N_MODAL }, + openModal: OPEN_CHERRY_PICK_MODAL, + modalId: CHERRY_PICK_MODAL_ID, + }, + }), + }); +} diff --git a/app/assets/javascripts/projects/commit/init_cherry_pick_commit_trigger.js b/app/assets/javascripts/projects/commit/init_cherry_pick_commit_trigger.js new file mode 100644 index 00000000000..942451dc96a --- /dev/null +++ b/app/assets/javascripts/projects/commit/init_cherry_pick_commit_trigger.js @@ -0,0 +1,20 @@ +import Vue from 'vue'; +import CommitFormTrigger from './components/form_trigger.vue'; +import { OPEN_CHERRY_PICK_MODAL, CHERRY_PICK_LINK_TEST_ID } from './constants'; + +export default function initInviteMembersTrigger() { + const el = document.querySelector('.js-cherry-pick-commit-trigger'); + + if (!el) { + return false; + } + + const { displayText } = el.dataset; + + return new Vue({ + el, + provide: { displayText, testId: CHERRY_PICK_LINK_TEST_ID }, + render: (createElement) => + createElement(CommitFormTrigger, { props: { openModal: OPEN_CHERRY_PICK_MODAL } }), + }); +} diff --git a/app/assets/javascripts/projects/commit/init_revert_commit_trigger.js b/app/assets/javascripts/projects/commit/init_revert_commit_trigger.js index 0bb57f22663..dc5168524ca 100644 --- a/app/assets/javascripts/projects/commit/init_revert_commit_trigger.js +++ b/app/assets/javascripts/projects/commit/init_revert_commit_trigger.js @@ -1,6 +1,6 @@ import Vue from 'vue'; -import RevertCommitTrigger from './components/form_trigger.vue'; -import { OPEN_REVERT_MODAL } from './constants'; +import CommitFormTrigger from './components/form_trigger.vue'; +import { OPEN_REVERT_MODAL, REVERT_LINK_TEST_ID } from './constants'; export default function initInviteMembersTrigger() { const el = document.querySelector('.js-revert-commit-trigger'); @@ -13,8 +13,8 @@ export default function initInviteMembersTrigger() { return new Vue({ el, - provide: { displayText }, + provide: { displayText, testId: REVERT_LINK_TEST_ID }, render: (createElement) => - createElement(RevertCommitTrigger, { props: { openModal: OPEN_REVERT_MODAL } }), + createElement(CommitFormTrigger, { props: { openModal: OPEN_REVERT_MODAL } }), }); } diff --git a/app/assets/javascripts/vue_merge_request_widget/components/terraform/terraform_plan.vue b/app/assets/javascripts/vue_merge_request_widget/components/terraform/terraform_plan.vue index b74e036d9d9..5f65d1fa49a 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/terraform/terraform_plan.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/terraform/terraform_plan.vue @@ -15,6 +15,16 @@ export default { type: Object, }, }, + i18n: { + changes: s__( + 'Terraform|Reported Resource Changes: %{addNum} to add, %{changeNum} to change, %{deleteNum} to delete', + ), + generationErrored: s__('Terraform|Generating the report caused an error.'), + namedReportFailed: s__('Terraform|The report %{name} failed to generate.'), + namedReportGenerated: s__('Terraform|The report %{name} was generated in your pipelines.'), + reportFailed: s__('Terraform|A report failed to generate.'), + reportGenerated: s__('Terraform|A report was generated in your pipelines.'), + }, computed: { addNum() { return Number(this.plan.create); @@ -30,23 +40,21 @@ export default { }, reportChangeText() { if (this.validPlanValues) { - return s__( - 'Terraform|Reported Resource Changes: %{addNum} to add, %{changeNum} to change, %{deleteNum} to delete', - ); + return this.$options.i18n.changes; } - return s__('Terraform|Generating the report caused an error.'); + return this.$options.i18n.generationErrored; }, reportHeaderText() { if (this.validPlanValues) { return this.plan.job_name - ? s__('Terraform|The Terraform report %{name} was generated in your pipelines.') - : s__('Terraform|A Terraform report was generated in your pipelines.'); + ? this.$options.i18n.namedReportGenerated + : this.$options.i18n.reportGenerated; } return this.plan.job_name - ? s__('Terraform|The Terraform report %{name} failed to generate.') - : s__('Terraform|A Terraform report failed to generate.'); + ? this.$options.i18n.namedReportFailed + : this.$options.i18n.reportFailed; }, validPlanValues() { return this.addNum + this.changeNum + this.deleteNum >= 0; diff --git a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js index 809932b0f29..44c3fc34ba6 100644 --- a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js +++ b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js @@ -84,7 +84,7 @@ export const tributeConfig = { value.type === groupType ? last(value.name.split(' / ')) : `${value.name}${value.username}`, menuItemLimit: memberLimit, menuItemTemplate: ({ original }) => { - const commonClasses = 'gl-avatar gl-avatar-s24 gl-flex-shrink-0'; + const commonClasses = 'gl-avatar gl-avatar-s32 gl-flex-shrink-0'; const noAvatarClasses = `${commonClasses} gl-rounded-small gl-display-flex gl-align-items-center gl-justify-content-center`; @@ -111,7 +111,7 @@ export const tributeConfig = { return `
${avatar} -
+
${escape(displayName)}${count}
${escape(parentGroupOrUsername)}
diff --git a/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue b/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue index a6c7b59aa71..b6b32167ed6 100644 --- a/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue +++ b/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue @@ -1,13 +1,10 @@