diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-03 18:09:37 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-03 18:09:37 +0300 |
commit | 388e0fbbd00e04a10e3ac1084945aa18a781c40c (patch) | |
tree | ff8dff4f52d2432f37726d92f2efb8957a8609b7 /app/assets/javascripts | |
parent | aeee636c18f82107ec7a489f33c944c65ad5f34e (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
5 files changed, 224 insertions, 40 deletions
diff --git a/app/assets/javascripts/search/sidebar/components/archived_filter/index.vue b/app/assets/javascripts/search/sidebar/components/archived_filter/index.vue index dc92d7bfd58..250b3541bee 100644 --- a/app/assets/javascripts/search/sidebar/components/archived_filter/index.vue +++ b/app/assets/javascripts/search/sidebar/components/archived_filter/index.vue @@ -2,6 +2,7 @@ import { GlFormCheckboxGroup, GlFormCheckbox } from '@gitlab/ui'; import { mapState, mapActions } from 'vuex'; import Tracking from '~/tracking'; +import { parseBoolean } from '~/lib/utils/common_utils'; import { archivedFilterData, TRACKING_NAMESPACE, TRACKING_LABEL_CHECKBOX } from './data'; @@ -15,11 +16,12 @@ export default { ...mapState(['urlQuery']), selectedFilter: { get() { - return [Boolean(this.urlQuery?.include_archived)]; + return [parseBoolean(this.urlQuery?.include_archived)]; }, - set([value = '']) { - this.setQuery({ key: archivedFilterData.filterParam, value: `${value}` }); - this.trackSelectCheckbox(value); + set(value) { + const newValue = value?.pop() ?? false; + this.setQuery({ key: archivedFilterData.filterParam, value: newValue?.toString() }); + this.trackSelectCheckbox(newValue); }, }, }, diff --git a/app/assets/javascripts/sessions/new/components/email_verification.vue b/app/assets/javascripts/sessions/new/components/email_verification.vue index 87385b91c42..6a67c25b58f 100644 --- a/app/assets/javascripts/sessions/new/components/email_verification.vue +++ b/app/assets/javascripts/sessions/new/components/email_verification.vue @@ -12,10 +12,12 @@ import { I18N_RESEND_LINK, I18N_EMAIL_RESEND_SUCCESS, I18N_GENERIC_ERROR, + I18N_UPDATE_EMAIL, VERIFICATION_CODE_REGEX, SUCCESS_RESPONSE, FAILURE_RESPONSE, } from '../constants'; +import UpdateEmail from './update_email.vue'; export default { name: 'EmailVerification', @@ -25,6 +27,7 @@ export default { GlFormGroup, GlFormInput, GlButton, + UpdateEmail, }, props: { obfuscatedEmail: { @@ -39,12 +42,22 @@ export default { type: String, required: true, }, + isOfferEmailReset: { + type: Boolean, + required: true, + }, + updateEmailPath: { + type: String, + required: true, + }, }, data() { return { + email: this.obfuscatedEmail, verificationCode: '', submitted: false, verifyError: '', + showUpdateEmail: false, }; }, computed: { @@ -126,49 +139,73 @@ export default { this.submitted = false; this.$refs.input.$el.focus(); }, + updateEmail() { + this.showUpdateEmail = true; + }, + verifyToken(email = '') { + this.showUpdateEmail = false; + if (email.length) this.email = email; + this.$nextTick(this.resetForm); + }, }, i18n: { explanation: I18N_EXPLANATION, inputLabel: I18N_INPUT_LABEL, submitButton: I18N_SUBMIT_BUTTON, resendLink: I18N_RESEND_LINK, + updateEmail: I18N_UPDATE_EMAIL, }, }; </script> <template> - <gl-form @submit.prevent="verify"> - <section class="gl-mb-5"> - <gl-sprintf :message="$options.i18n.explanation"> - <template #email> - <strong>{{ obfuscatedEmail }}</strong> - </template> - </gl-sprintf> - </section> - <gl-form-group - :label="$options.i18n.inputLabel" - label-for="verification-code" - :state="inputValidation.state" - :invalid-feedback="inputValidation.message" - > - <gl-form-input - id="verification-code" - ref="input" - v-model="verificationCode" - autofocus - autocomplete="one-time-code" - inputmode="numeric" - maxlength="6" + <div> + <update-email + v-if="showUpdateEmail" + :update-email-path="updateEmailPath" + @verifyToken="verifyToken" + /> + <gl-form v-else @submit.prevent="verify"> + <section class="gl-mb-5"> + <gl-sprintf :message="$options.i18n.explanation"> + <template #email> + <strong>{{ email }}</strong> + </template> + </gl-sprintf> + </section> + <gl-form-group + :label="$options.i18n.inputLabel" + label-for="verification-code" :state="inputValidation.state" - /> - </gl-form-group> - <section class="gl-mt-5"> - <gl-button block variant="confirm" type="submit" :disabled="!inputValidation.state">{{ - $options.i18n.submitButton - }}</gl-button> - <gl-button block variant="link" class="gl-mt-3 gl-h-7" @click="resend">{{ - $options.i18n.resendLink - }}</gl-button> - </section> - </gl-form> + :invalid-feedback="inputValidation.message" + > + <gl-form-input + id="verification-code" + ref="input" + v-model="verificationCode" + autofocus + autocomplete="one-time-code" + inputmode="numeric" + maxlength="6" + :state="inputValidation.state" + /> + </gl-form-group> + <section class="gl-mt-5"> + <gl-button block variant="confirm" type="submit" :disabled="!inputValidation.state">{{ + $options.i18n.submitButton + }}</gl-button> + <gl-button block variant="link" class="gl-mt-3 gl-h-7" @click="resend">{{ + $options.i18n.resendLink + }}</gl-button> + <gl-button + v-if="isOfferEmailReset" + block + variant="link" + class="gl-mt-3 gl-h-7" + @click="updateEmail" + >{{ $options.i18n.updateEmail }}</gl-button + > + </section> + </gl-form> + </div> </template> diff --git a/app/assets/javascripts/sessions/new/components/update_email.vue b/app/assets/javascripts/sessions/new/components/update_email.vue new file mode 100644 index 00000000000..f63176e5513 --- /dev/null +++ b/app/assets/javascripts/sessions/new/components/update_email.vue @@ -0,0 +1,130 @@ +<script> +import { GlForm, GlFormGroup, GlFormInput, GlButton } from '@gitlab/ui'; +import { createAlert, VARIANT_SUCCESS } from '~/alert'; +import { isEmail } from '~/lib/utils/forms'; +import axios from '~/lib/utils/axios_utils'; +import { + I18N_EMAIL, + I18N_UPDATE_EMAIL, + I18N_CANCEL, + I18N_EMAIL_INVALID, + I18N_UPDATE_EMAIL_SUCCESS, + I18N_GENERIC_ERROR, + SUCCESS_RESPONSE, + FAILURE_RESPONSE, +} from '../constants'; + +export default { + name: 'UpdateEmail', + components: { + GlForm, + GlFormGroup, + GlFormInput, + GlButton, + }, + props: { + updateEmailPath: { + type: String, + required: true, + }, + }, + data() { + return { + email: '', + submitted: false, + verifyError: '', + }; + }, + computed: { + inputValidation() { + return { + state: !(this.submitted && this.invalidFeedback), + message: this.invalidFeedback, + }; + }, + invalidFeedback() { + if (!this.submitted) { + return ''; + } + + if (!isEmail(this.email)) { + return I18N_EMAIL_INVALID; + } + + return this.verifyError; + }, + }, + watch: { + email() { + this.verifyError = ''; + }, + }, + methods: { + updateEmail() { + this.submitted = true; + + if (!this.inputValidation.state) return; + + axios + .patch(this.updateEmailPath, { user: { email: this.email } }) + .then(this.handleResponse) + .catch(this.handleError); + }, + handleResponse(response) { + if (response.data.status === undefined) { + this.handleError(); + } else if (response.data.status === SUCCESS_RESPONSE) { + this.handleSuccess(); + } else if (response.data.status === FAILURE_RESPONSE) { + this.verifyError = response.data.message; + } + }, + handleSuccess() { + createAlert({ + message: I18N_UPDATE_EMAIL_SUCCESS, + variant: VARIANT_SUCCESS, + }); + this.$emit('verifyToken', this.email); + }, + handleError(error) { + createAlert({ + message: I18N_GENERIC_ERROR, + captureError: true, + error, + }); + }, + }, + i18n: { + email: I18N_EMAIL, + updateEmail: I18N_UPDATE_EMAIL, + cancel: I18N_CANCEL, + }, +}; +</script> + +<template> + <gl-form novalidate @submit.prevent="updateEmail"> + <gl-form-group + :label="$options.i18n.email" + label-for="update-email" + :state="inputValidation.state" + :invalid-feedback="inputValidation.message" + > + <gl-form-input + id="update-email" + v-model="email" + type="email" + autofocus + :state="inputValidation.state" + /> + </gl-form-group> + <section class="gl-mt-5"> + <gl-button block variant="confirm" type="submit" :disabled="!inputValidation.state">{{ + $options.i18n.updateEmail + }}</gl-button> + <gl-button block variant="link" class="gl-mt-3 gl-h-7" @click="$emit('verifyToken')">{{ + $options.i18n.cancel + }}</gl-button> + </section> + </gl-form> +</template> diff --git a/app/assets/javascripts/sessions/new/constants.js b/app/assets/javascripts/sessions/new/constants.js index 203a8aee1c4..dec96f78232 100644 --- a/app/assets/javascripts/sessions/new/constants.js +++ b/app/assets/javascripts/sessions/new/constants.js @@ -1,4 +1,4 @@ -import { s__ } from '~/locale'; +import { s__, __ } from '~/locale'; export const I18N_EXPLANATION = s__( "IdentityVerification|For added security, you'll need to verify your identity. We've sent a verification code to %{email}", @@ -13,6 +13,14 @@ export const I18N_GENERIC_ERROR = s__( 'IdentityVerification|Something went wrong. Please try again.', ); +export const I18N_EMAIL = __('Email'); +export const I18N_UPDATE_EMAIL = s__('IdentityVerification|Update email'); +export const I18N_CANCEL = __('Cancel'); +export const I18N_EMAIL_INVALID = s__('IdentityVerification|Please enter a valid email address.'); +export const I18N_UPDATE_EMAIL_SUCCESS = s__( + 'IdentityVerification|A new code has been sent to your updated email address.', +); + export const VERIFICATION_CODE_REGEX = /^\d{6}$/; export const SUCCESS_RESPONSE = 'success'; export const FAILURE_RESPONSE = 'failure'; diff --git a/app/assets/javascripts/sessions/new/index.js b/app/assets/javascripts/sessions/new/index.js index 51022a281e3..bf126b0e202 100644 --- a/app/assets/javascripts/sessions/new/index.js +++ b/app/assets/javascripts/sessions/new/index.js @@ -1,4 +1,5 @@ import Vue from 'vue'; +import { parseBoolean } from '~/lib/utils/common_utils'; import EmailVerification from './components/email_verification.vue'; export default () => { @@ -8,14 +9,20 @@ export default () => { return null; } - const { obfuscatedEmail, verifyPath, resendPath } = el.dataset; + const { obfuscatedEmail, verifyPath, resendPath, offerEmailReset, updateEmailPath } = el.dataset; return new Vue({ el, name: 'EmailVerificationRoot', render(createElement) { return createElement(EmailVerification, { - props: { obfuscatedEmail, verifyPath, resendPath }, + props: { + obfuscatedEmail, + verifyPath, + resendPath, + isOfferEmailReset: parseBoolean(offerEmailReset), + updateEmailPath, + }, }); }, }); |