Browse Source

Use new vue components in login form

- Improve accessibility
- Simply code

Signed-off-by: Carl Schwan <carl@carlschwan.eu>
tags/v25.0.0beta5
Carl Schwan 1 year ago
parent
commit
df40fc9172
No account linked to committer's email address

+ 0
- 42
core/css/guest.css View File

@@ -108,14 +108,6 @@ form {
margin: auto;
padding: 0;
}
form fieldset {
width: 260px;
margin-top: 8px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
form #sqliteInformation {
margin-top: 0px;
margin-bottom: 20px;
@@ -160,9 +152,6 @@ form #datadirField legend {
.wrapper {
margin-top: 0;
}
.alternative-logins {
margin: auto;
}
}


@@ -262,9 +251,6 @@ input[type='email'] {
color: var(--color-text-lighter);
cursor: text;
font-family: inherit;
-webkit-appearance: textfield;
-moz-appearance: textfield;
box-sizing: content-box;
font-weight: normal;
margin-left: 0;
margin-right: 0;
@@ -491,34 +477,6 @@ form .warning input[type='checkbox']+label {
color: var(--color-primary-text);
}

/* Alternative Logins */
.alternative-logins legend {
margin-bottom: 10px;
}
.alternative-logins li {
height: 40px;
white-space: nowrap;
padding: 05px;
}
.alternative-logins a.button,
.alternative-logins li a {
width: 100%;
display: inline-block;
text-align: center;
box-sizing: border-box;
border: 2px solid var(--color-primary-text);
background-color: var(--color-primary);
color: var(--color-primary-text);
border-radius: 100px; /* --border-radius-pill */
}

.alternative-logins a.button:focus,
.alternative-logins li a:focus {
border: 2px solid var(--color-primary-hover);
background-image: linear-gradient(40deg, var(--color-primary) 0%, var(--color-primary-light) 100%);
background-position: initial;
}

/* fixes for update page TODO should be fixed some time in a proper way */
/* this is just for an error while updating the ownCloud instance */
.updateProgress .error {

+ 60
- 74
core/src/components/login/LoginForm.vue View File

@@ -21,11 +21,12 @@

<template>
<form ref="loginForm"
class="login-form"
method="post"
name="login"
:action="loginActionUrl"
@submit="submit">
<fieldset>
<fieldset class="login-form__fieldset">
<div v-if="apacheAuthFailed"
class="warning">
{{ t('core', 'Server side authentication failed!') }}<br>
@@ -52,65 +53,36 @@
<!-- the following div ensures that the spinner is always inside the #message div -->
<div style="clear: both;" />
</div>
<p class="grouptop"
:class="{shake: invalidPassword}">
<input id="user"
ref="user"
v-model="user"
type="text"
name="user"
autocapitalize="none"
autocorrect="off"
:autocomplete="autoCompleteAllowed ? 'on' : 'off'"
:placeholder="t('core', 'Username or email')"
:aria-label="t('core', 'Username or email')"
required
@change="updateUsername">
<label for="user" class="infield">{{ t('core', 'Username or email') }}</label>
</p>

<p class="groupbottom"
:class="{shake: invalidPassword}">
<input id="password"
ref="password"
:type="passwordInputType"
class="password-with-toggle"
name="password"
autocorrect="off"
autocapitalize="none"
:autocomplete="autoCompleteAllowed ? 'current-password' : 'off'"
:placeholder="t('core', 'Password')"
:aria-label="t('core', 'Password')"
required>
<label for="password"
class="infield">{{ t('core', 'Password') }}</label>
<NcButton class="toggle-password"
type="tertiary-no-background"
:aria-label="isPasswordHidden ? t('core', 'Show password') : t('core', 'Hide password')"
@click.stop.prevent="togglePassword">
<template #icon>
<Eye v-if="isPasswordHidden" :size="20" />
<EyeOff v-else :size="20" />
</template>
</NcButton>
</p>
<NcTextField id="user"
:label="t('core', 'Username or email')"
:labelVisible="true"
ref="user"
name="user"
:class="{shake: invalidPassword}"
:value.sync="user"
autocapitalize="none"
:spellchecking="false"
:autocomplete="autoCompleteAllowed ? 'username' : 'off'"
:aria-label="t('core', 'Username or email')"
required
@change="updateUsername" />

<NcPasswordField id="password"
ref="password"
name="password"
:labelVisible="true"
:class="{shake: invalidPassword}"
:value.sync="password"
:spellchecking="false"
autocapitalize="none"
:autocomplete="autoCompleteAllowed ? 'current-password' : 'off'"
:label="t('core', 'Password')"
:helperText="errorLabel"
:error="isError"
required />

<LoginButton :loading="loading" />

<p v-if="invalidPassword"
class="warning wrongPasswordMsg">
{{ t('core', 'Wrong username or password.') }}
</p>
<p v-else-if="userDisabled"
class="warning userDisabledMsg">
{{ t('core', 'User disabled') }}
</p>

<p v-if="throttleDelay && throttleDelay > 5000"
class="warning throttledMsg">
{{ t('core', 'We have detected multiple invalid login attempts from your IP. Therefore your next login is throttled up to 30 seconds.') }}
</p>

<input v-if="redirectUrl"
type="hidden"
name="redirect_url"
@@ -136,7 +108,9 @@
import jstz from 'jstimezonedetect'
import { generateUrl, imagePath } from '@nextcloud/router'

import NcButton from '@nextcloud/vue/dist/Components/NcButton'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcPasswordField from '@nextcloud/vue/dist/Components/NcPasswordField.js'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
import Eye from 'vue-material-design-icons/Eye'
import EyeOff from 'vue-material-design-icons/EyeOff'

@@ -150,6 +124,8 @@ export default {
Eye,
EyeOff,
LoginButton,
NcPasswordField,
NcTextField,
},

props: {
@@ -190,11 +166,26 @@ export default {
timezoneOffset: (-new Date().getTimezoneOffset() / 60),
user: this.username,
password: '',
passwordInputType: 'password',
}
},

computed: {
isError() {
return this.invalidPassword || this.userDisabled
|| (this.throttleDelay && this.throttleDelay > 5000)
},
errorLabel() {
if (this.invalidPassword) {
return t('core', 'Wrong username or password.')
}
if (this.userDisabled) {
return t('core', 'User disabled')
}
if (this.throttleDelay && this.throttleDelay > 5000) {
return t('core', 'We have detected multiple invalid login attempts from your IP. Therefore your next login is throttled up to 30 seconds.')
}
return undefined;
},
apacheAuthFailed() {
return this.errors.indexOf('apacheAuthFailed') !== -1
},
@@ -213,9 +204,6 @@ export default {
loginActionUrl() {
return generateUrl('login')
},
isPasswordHidden() {
return this.passwordInputType === 'password'
},
},

mounted() {
@@ -227,13 +215,6 @@ export default {
},

methods: {
togglePassword() {
if (this.passwordInputType === 'password') {
this.passwordInputType = 'text'
} else {
this.passwordInputType = 'password'
}
},
updateUsername() {
this.$emit('update:username', this.user)
},
@@ -246,10 +227,15 @@ export default {
</script>

<style lang="scss" scoped>
.toggle-password {
position: absolute;
top: 2px;
right: 10px;
color: var(--color-text-lighter);
.login-form {
text-align: left;
font-size: 1rem;

&__fieldset {
width: 100%;
display: flex;
flex-direction: column;
gap: 1rem;
}
}
</style>

+ 33
- 25
core/src/components/login/ResetPassword.vue View File

@@ -20,39 +20,35 @@
-->

<template>
<form @submit.prevent="submit">
<fieldset>
<p>
<input id="user"
v-model="user"
type="text"
name="user"
autocapitalize="off"
:placeholder="t('core', 'Username or email')"
:aria-label="t('core', 'Username or email')"
required
@change="updateUsername">
<form @submit.prevent="submit" class="login-form">
<fieldset class="login-form__fieldset">
<NcTextField id="user"
:value.sync="user"
name="user"
autocapitalize="off"
:label="t('core', 'Username or email')"
:labelVisible="true"
required
@change="updateUsername" />
<!--<?php p($_['user_autofocus'] ? 'autofocus' : ''); ?>
autocomplete="<?php p($_['login_form_autocomplete']); ?>" autocapitalize="none" autocorrect="off"-->
<label for="user" class="infield">{{ t('core', 'Username or email') }}</label>
</p>
<div id="reset-password-wrapper">
<LoginButton :value="t('core', 'Reset password')" />
</div>
<p v-if="message === 'send-success'"
class="notecard success">
<NcNoteCard v-if="message === 'send-success'"
type="success">
{{ t('core', 'A password reset message has been sent to the email address of this account. If you do not receive it, check your spam/junk folders or ask your local administrator for help.') }}
<br>
{{ t('core', 'If it is not there ask your local administrator.') }}
</p>
<p v-else-if="message === 'send-error'"
class="notecard error">
</NcNoteCard>
<NcNoteCard v-else-if="message === 'send-error'"
type="error">
{{ t('core', 'Couldn\'t send reset email. Please contact your administrator.') }}
</p>
<p v-else-if="message === 'reset-error'"
class="notecard error">
</NcNoteCard>
<NcNoteCard v-else-if="message === 'reset-error'"
type="error">
{{ t('core', 'Password cannot be changed. Please contact your administrator.') }}
</p>
</NcNoteCard>

<a href="#"
@click.prevent="$emit('abort')">
@@ -66,11 +62,15 @@
import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import LoginButton from './LoginButton.vue'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'

export default {
name: 'ResetPassword',
components: {
LoginButton,
NcNoteCard,
NcTextField,
},
props: {
username: {
@@ -131,7 +131,15 @@ export default {
</script>

<style scoped>
.update {
width: auto;
.login-form {
text-align: left;
font-size: 1rem;

&__fieldset {
width: 100%;
display: flex;
flex-direction: column;
gap: 1rem;
}
}
</style>

+ 9
- 8
core/src/views/Login.vue View File

@@ -192,6 +192,9 @@ export default {
</script>

<style lang="scss">
#login {
width: 300px;
}
.fade-enter-active, .fade-leave-active {
transition: opacity .3s;
}
@@ -205,15 +208,13 @@ export default {
border-radius: var(--border-radius);
}

.alternative-logins button {
margin-top: 12px;
margin-bottom: 12px;
&:first-child {
margin-top: 0;
}
.alternative-logins {
display: flex;
flex-direction: column;
gap: 0.75rem;

&:last-child {
margin-bottom: 0;
.button-vue {
box-sizing: border-box;
}
}
</style>

Loading…
Cancel
Save