diff --git a/panel/lab/components/login/login-code/index.php b/panel/lab/components/login/login-code/index.php new file mode 100644 index 0000000000..939f9c01da --- /dev/null +++ b/panel/lab/components/login/login-code/index.php @@ -0,0 +1,5 @@ + 'k-login-code' +]; diff --git a/panel/lab/components/login/login-code/index.vue b/panel/lab/components/login/login-code/index.vue new file mode 100644 index 0000000000..a9581334a8 --- /dev/null +++ b/panel/lab/components/login/login-code/index.vue @@ -0,0 +1,15 @@ + diff --git a/panel/lab/components/login/login/index.php b/panel/lab/components/login/login/index.php new file mode 100644 index 0000000000..681fdf8c82 --- /dev/null +++ b/panel/lab/components/login/login/index.php @@ -0,0 +1,5 @@ + 'k-login' +]; diff --git a/panel/lab/components/login/login/index.vue b/panel/lab/components/login/login/index.vue new file mode 100644 index 0000000000..7b201b4df2 --- /dev/null +++ b/panel/lab/components/login/login/index.vue @@ -0,0 +1,26 @@ + diff --git a/panel/src/components/Forms/Login.vue b/panel/src/components/Forms/Login.vue index 27b2535048..7539690151 100644 --- a/panel/src/components/Forms/Login.vue +++ b/panel/src/components/Forms/Login.vue @@ -5,7 +5,7 @@ v-if="canToggle === true" class="k-login-toggler" type="button" - @click="toggleForm" + @click="toggle" > {{ toggleText }} @@ -19,14 +19,15 @@ /> -
- - - +
+ @@ -48,12 +48,18 @@ export const props = { /** * List of available login method names */ - methods: Array, + methods: { + type: Array, + default: () => [] + }, /** * Values to prefill the inputs - * @value { email: String, password: String } + * @value { email: String, password: String, remember: Boolean } */ - value: Object + value: { + type: Object, + default: () => ({}) + } } }; @@ -62,22 +68,36 @@ export default { emits: ["error"], data() { return { - currentForm: null, + mode: null, isLoading: false, user: { - email: this.value.email ?? "", - password: this.value.password ?? "", - remember: false + email: "", + password: "", + remember: false, + ...this.value } }; }, computed: { + alternateMode() { + if (this.form === "email-password") { + return "email"; + } + + return "email-password"; + }, canToggle() { + if (this.codeMode === null) { + return false; + } + + if (this.methods.includes("password") === false) { + return false; + } + return ( - this.codeMode !== null && - this.methods.includes("password") === true && - (this.methods.includes("password-reset") === true || - this.methods.includes("code") === true) + this.methods.includes("password-reset") === true || + this.methods.includes("code") === true ); }, codeMode() { @@ -90,7 +110,7 @@ export default { return null; }, fields() { - let fields = { + const fields = { email: { autofocus: true, label: this.$t("email"), @@ -114,8 +134,8 @@ export default { return fields; }, form() { - if (this.currentForm) { - return this.currentForm; + if (this.mode) { + return this.mode; } if (this.methods[0] === "password") { @@ -127,28 +147,30 @@ export default { isResetForm() { return this.codeMode === "password-reset" && this.form === "email"; }, + submitText() { + const suffix = this.isLoading ? " …" : ""; + + if (this.isResetForm) { + return this.$t("login.reset") + suffix; + } + + return this.$t("login") + suffix; + }, toggleText() { return this.$t( - "login.toggleText." + this.codeMode + "." + this.formOpposite(this.form) + "login.toggleText." + this.codeMode + "." + this.alternateMode ); } }, methods: { - formOpposite(input) { - if (input === "email-password") { - return "email"; - } else { - return "email-password"; - } - }, async login() { this.$emit("error", null); this.isLoading = true; // clear field data that is not needed for login - let user = Object.assign({}, this.user); + const user = { ...this.user }; - if (this.currentForm === "email") { + if (this.mode === "email") { user.password = null; } @@ -173,10 +195,35 @@ export default { this.isLoading = false; } }, - toggleForm() { - this.currentForm = this.formOpposite(this.form); + toggle() { + this.mode = this.alternateMode; this.$refs.fieldset.focus("email"); } } }; + + diff --git a/panel/src/components/Forms/LoginCode.vue b/panel/src/components/Forms/LoginCode.vue index 642dcf9b2d..bd9addd7d3 100644 --- a/panel/src/components/Forms/LoginCode.vue +++ b/panel/src/components/Forms/LoginCode.vue @@ -1,6 +1,6 @@ @@ -49,12 +48,18 @@ export const props = { /** * List of available login method names */ - methods: Array, + methods: { + type: Array, + default: () => [] + }, /** * Pending login data (user email, challenge type) * @value { email: String, challenge: String } */ - pending: Object, + pending: { + type: Object, + default: () => ({ challenge: "email" }) + }, /** * Code value to prefill the input */ @@ -68,27 +73,29 @@ export default { data() { return { code: this.value ?? "", - isLoadingBack: false, - isLoadingLogin: false + isLoading: false }; }, computed: { mode() { - if (this.methods.includes("password-reset") === true) { - return "password-reset"; + return this.methods.includes("password-reset") + ? "password-reset" + : "login"; + }, + submitText() { + const suffix = this.isLoading ? " …" : ""; + + if (this.mode === "password-reset") { + return this.$t("login.reset") + suffix; } - return "login"; + return this.$t("login") + suffix; } }, methods: { - async back() { - this.isLoadingBack = true; - this.$go("/logout"); - }, async login() { this.$emit("error", null); - this.isLoadingLogin = true; + this.isLoading = true; try { await this.$api.auth.verifyCode(this.code); @@ -106,7 +113,7 @@ export default { } catch (error) { this.$emit("error", error); } finally { - this.isLoadingLogin = false; + this.isLoading = false; } } } diff --git a/panel/src/components/Views/Login/LoginView.vue b/panel/src/components/Views/Login/LoginView.vue index 4552b4d817..4118caa96b 100644 --- a/panel/src/components/Views/Login/LoginView.vue +++ b/panel/src/components/Views/Login/LoginView.vue @@ -1,7 +1,9 @@