mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-06-24 22:12:06 +02:00
Replace local form controls with 2fauth/formcontrols components
This commit is contained in:
parent
7213cec998
commit
b1b8e71cea
25
resources/js/app.js
vendored
25
resources/js/app.js
vendored
@ -49,17 +49,20 @@ import ResponsiveWidthWrapper from '@/layouts/ResponsiveWidthWrapper.vue'
|
||||
import FormWrapper from '@/layouts/FormWrapper.vue'
|
||||
import Footer from '@/layouts/Footer.vue'
|
||||
import Modal from '@/layouts/Modal.vue'
|
||||
import VueButton from '@/components/formElements/Button.vue'
|
||||
import ButtonBackCloseCancel from '@/components/formElements/ButtonBackCloseCancel.vue'
|
||||
import FieldError from '@/components/formElements/FieldError.vue'
|
||||
import FormField from '@/components/formElements/FormField.vue'
|
||||
import FormPasswordField from '@/components/formElements/FormPasswordField.vue'
|
||||
import FormSelect from '@/components/formElements/FormSelect.vue'
|
||||
import FormToggle from '@/components/formElements/FormToggle.vue'
|
||||
import FormCheckbox from '@/components/formElements/FormCheckbox.vue'
|
||||
import FormButtons from '@/components/formElements/FormButtons.vue'
|
||||
import Kicker from '@/components/Kicker.vue'
|
||||
|
||||
import {
|
||||
FormField,
|
||||
FormPasswordField,
|
||||
FormFieldError,
|
||||
FormCheckbox,
|
||||
FormSelect,
|
||||
FormToggle,
|
||||
FormButtons,
|
||||
NavigationButton,
|
||||
VueButton
|
||||
} from '@2fauth/formcontrols'
|
||||
|
||||
app
|
||||
.component('FontAwesomeIcon', FontAwesomeIcon)
|
||||
.component('ResponsiveWidthWrapper', ResponsiveWidthWrapper)
|
||||
@ -67,8 +70,8 @@ app
|
||||
.component('VueFooter', Footer)
|
||||
.component('Modal', Modal)
|
||||
.component('VueButton', VueButton)
|
||||
.component('ButtonBackCloseCancel', ButtonBackCloseCancel)
|
||||
.component('FieldError', FieldError)
|
||||
.component('NavigationButton', NavigationButton)
|
||||
.component('FormFieldError', FormFieldError)
|
||||
.component('FormField', FormField)
|
||||
.component('FormPasswordField', FormPasswordField)
|
||||
.component('FormSelect', FormSelect)
|
||||
|
@ -62,7 +62,7 @@
|
||||
<p class="control">
|
||||
<button type="button" class="button is-link is-rounded" @click="moveAccounts">{{ $t('commons.move') }}</button>
|
||||
</p>
|
||||
<ButtonBackCloseCancel action="cancel" :useLinkTag="false" @canceled="$emit('update:showDestinationGroupSelector', false)" />
|
||||
<NavigationButton action="cancel" :useLinkTag="false" @canceled="$emit('update:showDestinationGroupSelector', false)" />
|
||||
</VueFooter>
|
||||
</div>
|
||||
</template>
|
@ -45,7 +45,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<VueFooter :showButtons="true">
|
||||
<ButtonBackCloseCancel action="close" :useLinkTag="false" @closed="$emit('update:showGroupSwitch', false)" />
|
||||
<NavigationButton action="close" :useLinkTag="false" @closed="$emit('update:showGroupSwitch', false)" />
|
||||
</VueFooter>
|
||||
</div>
|
||||
</template>
|
@ -1,33 +0,0 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
color: {
|
||||
type: String,
|
||||
default: 'is-link'
|
||||
},
|
||||
nativeType: {
|
||||
type: String,
|
||||
default: 'submit'
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isDisabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
:type="nativeType"
|
||||
:disabled="isLoading || isDisabled"
|
||||
:class="{
|
||||
'button': true,
|
||||
[`${color}`]: true,
|
||||
'is-loading': isLoading,
|
||||
}">
|
||||
<slot />
|
||||
</button>
|
||||
</template>
|
@ -1,94 +0,0 @@
|
||||
<script setup>
|
||||
import { useColorMode } from '@vueuse/core'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const mode = useColorMode()
|
||||
|
||||
const props = defineProps({
|
||||
returnTo: {
|
||||
type: Object,
|
||||
default: { name: 'accounts' }
|
||||
},
|
||||
action: {
|
||||
type: String,
|
||||
default: 'close'
|
||||
},
|
||||
useLinkTag: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
isText: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isCapture: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isRounded: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
})
|
||||
|
||||
const classes = 'button'
|
||||
+ (mode.value === 'dark' && ! props.isText && ! props.isCapture ? ' is-dark' : '')
|
||||
+ (props.isText ? ' is-text' : '')
|
||||
+ (props.isCapture ? ' is-large is-warning' : '')
|
||||
+ (props.isRounded ? ' is-rounded' : '')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- back / close / cancel button -->
|
||||
<p v-if="useLinkTag" class="control">
|
||||
<RouterLink
|
||||
v-if="action == 'close'"
|
||||
id="btnClose"
|
||||
:to="returnTo"
|
||||
:class="classes"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
:aria-label="$t('commons.close_the_x_page', { pagetitle: $route.meta.title })"
|
||||
>
|
||||
{{ $t('commons.close') }}
|
||||
</RouterLink>
|
||||
<RouterLink
|
||||
v-else-if="action == 'back'"
|
||||
id="lnkBack"
|
||||
:to="returnTo"
|
||||
:class="classes"
|
||||
:aria-label="$t('commons.close_the_x_page', { pagetitle: $route.meta.title })"
|
||||
>
|
||||
{{ $t('commons.back') }}
|
||||
</RouterLink>
|
||||
<RouterLink
|
||||
v-else-if="action == 'cancel'"
|
||||
id="btnCancel"
|
||||
:to="returnTo"
|
||||
:class="classes"
|
||||
>
|
||||
{{ $t('commons.cancel') }}
|
||||
</RouterLink>
|
||||
</p>
|
||||
<p v-else class="control">
|
||||
<button
|
||||
v-if="action == 'close'"
|
||||
id="btnClose"
|
||||
:class="classes"
|
||||
@click="$emit('closed')"
|
||||
type="button"
|
||||
>
|
||||
{{ $t('commons.close') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="action == 'cancel'"
|
||||
id="btnCancel"
|
||||
:class="classes"
|
||||
@click="$emit('canceled')"
|
||||
type="button"
|
||||
>
|
||||
{{ $t('commons.cancel') }}
|
||||
</button>
|
||||
</p>
|
||||
</template>
|
@ -1,29 +0,0 @@
|
||||
<script setup>
|
||||
import { useValidationErrorIdGenerator } from '@/composables/helpers'
|
||||
|
||||
const props = defineProps({
|
||||
error: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
field: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
alertType: {
|
||||
type: String,
|
||||
default: 'is-danger'
|
||||
}
|
||||
})
|
||||
|
||||
const { valErrorId } = useValidationErrorIdGenerator(props.field)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div role="alert">
|
||||
<p :id="valErrorId"
|
||||
class="help"
|
||||
:class="alertType"
|
||||
v-html="error" />
|
||||
</div>
|
||||
</template>
|
@ -1,51 +0,0 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
showCancelButton: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isBusy: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isDisabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
caption: {
|
||||
type: String,
|
||||
default: 'commons.submit'
|
||||
},
|
||||
cancelLandingView: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: 'is-link'
|
||||
},
|
||||
submitId: {
|
||||
type: String,
|
||||
default: 'btnSubmit'
|
||||
},
|
||||
cancelId: {
|
||||
type: String,
|
||||
default: 'btnCancel'
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<VueButton :id="submitId" :color="color" :isLoading="isBusy" :disabled="isDisabled" >
|
||||
{{ $t(caption) }}
|
||||
</VueButton>
|
||||
</div>
|
||||
<div class="control" v-if="showCancelButton">
|
||||
<RouterLink :id="cancelId" :to="{ name: cancelLandingView }" class="button is-text">
|
||||
{{ $t('commons.cancel') }}
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@ -1,64 +0,0 @@
|
||||
<script setup>
|
||||
import { useIdGenerator } from '@/composables/helpers'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Boolean,
|
||||
fieldName: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
labelClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
help: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isIndented: Boolean,
|
||||
isDisabled: Boolean,
|
||||
isLocked: Boolean,
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const legendId = useIdGenerator('legend', props.fieldName).inputId
|
||||
const attrs = useAttrs()
|
||||
const model = computed({
|
||||
get() {
|
||||
return props.modelValue;
|
||||
},
|
||||
set(value) {
|
||||
emit("update:modelValue", value);
|
||||
},
|
||||
})
|
||||
|
||||
function toggleModel() {
|
||||
if (attrs['disabled'] != true) {
|
||||
model.value = !model.value
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="field is-flex">
|
||||
<div v-if="isIndented" class="mx-2 pr-1" :class="{ 'is-opacity-5' : isDisabled || isLocked }">
|
||||
<FontAwesomeIcon class="has-text-grey" :icon="['fas', 'chevron-right']" transform="rotate-135"/>
|
||||
</div>
|
||||
<div>
|
||||
<input :id="fieldName" type="checkbox" :name="fieldName" class="is-checkradio is-info" v-model="model" :disabled="isDisabled || isLocked" :aria-describedby="help ? legendId : undefined" />
|
||||
<label tabindex="0" :for="fieldName" class="label" :class="labelClass" v-on:keypress.space.prevent="toggleModel">
|
||||
{{ $t(label) }}<FontAwesomeIcon v-if="isLocked" :icon="['fas', 'lock']" class="ml-2" size="xs" />
|
||||
</label>
|
||||
<p :id="legendId" class="help" v-html="$t(help)" v-if="help" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@ -1,95 +0,0 @@
|
||||
<script setup>
|
||||
import { useIdGenerator, useValidationErrorIdGenerator } from '@/composables/helpers'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: [String, Number, Boolean],
|
||||
label: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
fieldName: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
},
|
||||
fieldError: [String],
|
||||
inputType: {
|
||||
type: String,
|
||||
default: 'text'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
help: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
hasOffset: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isDisabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maxLength: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
isIndented: Boolean,
|
||||
isLocked: Boolean,
|
||||
leftIcon: '',
|
||||
rightIcon: '',
|
||||
idSuffix: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
})
|
||||
|
||||
const { inputId } = useIdGenerator(props.inputType, props.fieldName + props.idSuffix)
|
||||
const { valErrorId } = useValidationErrorIdGenerator(props.fieldName)
|
||||
const legendId = useIdGenerator('legend', props.fieldName).inputId
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mb-3" :class="{ 'pt-3' : hasOffset, 'is-flex' : isIndented }">
|
||||
<div v-if="isIndented" class="mx-2 pr-1" :class="{ 'is-opacity-5' : isDisabled || isLocked }">
|
||||
<FontAwesomeIcon class="has-text-grey" :icon="['fas', 'chevron-right']" transform="rotate-135"/>
|
||||
</div>
|
||||
<div class="field" :class="{ 'is-flex-grow-5' : isIndented }">
|
||||
<label :for="inputId" class="label" :class="{ 'is-opacity-5' : isDisabled || isLocked }">
|
||||
{{ $t(label) }}<FontAwesomeIcon v-if="isLocked" :icon="['fas', 'lock']" class="ml-2" size="xs" />
|
||||
</label>
|
||||
<div class="control" :class="{ 'has-icons-left' : leftIcon, 'has-icons-right': rightIcon }">
|
||||
<input
|
||||
:disabled="isDisabled || isLocked"
|
||||
:id="inputId"
|
||||
:type="inputType"
|
||||
class="input"
|
||||
:value="modelValue"
|
||||
:placeholder="placeholder"
|
||||
v-bind="$attrs"
|
||||
v-on:input="$emit('update:modelValue', $event.target.value)"
|
||||
v-on:change="$emit('change:modelValue', $event.target.value)"
|
||||
:maxlength="maxLength"
|
||||
:aria-describedby="help ? legendId : undefined"
|
||||
:aria-invalid="fieldError != undefined"
|
||||
:aria-errormessage="fieldError != undefined ? valErrorId : undefined"
|
||||
/>
|
||||
<span v-if="leftIcon" class="icon is-small is-left">
|
||||
<FontAwesomeIcon :icon="['fas', leftIcon]" transform="rotate-75" size="xs" />
|
||||
</span>
|
||||
<span v-if="rightIcon" class="icon is-small is-right">
|
||||
<FontAwesomeIcon :icon="['fas', rightIcon]" transform="rotate-75" size="xs" />
|
||||
</span>
|
||||
</div>
|
||||
<FieldError v-if="fieldError != undefined" :error="fieldError" :field="fieldName" />
|
||||
<p :id="legendId" class="help" v-html="$t(help)" v-if="help"></p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@ -1,143 +0,0 @@
|
||||
<script setup>
|
||||
import { useIdGenerator, useValidationErrorIdGenerator } from '@/composables/helpers'
|
||||
import { UseColorMode } from '@vueuse/components'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: String,
|
||||
modelModifiers: { default: () => ({}) },
|
||||
isEditMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
fieldName: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
},
|
||||
fieldError: [String],
|
||||
inputType: {
|
||||
type: String,
|
||||
default: 'text'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
help: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
hasOffset: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isDisabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isExpanded: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
maxLength: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
idSuffix: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isLocked: Boolean,
|
||||
})
|
||||
|
||||
const { inputId } = useIdGenerator(props.inputType, props.fieldName + props.idSuffix)
|
||||
const { valErrorId } = useValidationErrorIdGenerator(props.fieldName)
|
||||
const legendId = useIdGenerator('legend', props.fieldName).inputId
|
||||
|
||||
const fieldIsLocked = ref(props.isDisabled || props.isEditMode || props.isLocked)
|
||||
const hasBeenTrimmed = ref(false)
|
||||
const componentKey = ref(0);
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
/**
|
||||
* Removes spaces from the input string
|
||||
*/
|
||||
function emitValue(e) {
|
||||
let value = e.target.value
|
||||
|
||||
|
||||
if (props.modelModifiers.trimAll) {
|
||||
value = value.replace(/\s+/g, '')
|
||||
}
|
||||
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
|
||||
function alertOnSpace(e) {
|
||||
let value = e.target.value
|
||||
hasBeenTrimmed.value = value.includes(' ')
|
||||
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
|
||||
function forceRefresh(e) {
|
||||
hasBeenTrimmed.value = e.target.value.includes(' ')
|
||||
componentKey.value += 1
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<label :for="inputId" class="label">
|
||||
{{ $t(label) }}<FontAwesomeIcon v-if="isLocked" :icon="['fas', 'lock']" class="ml-2" size="xs" />
|
||||
</label>
|
||||
<div class="field has-addons mb-0" :class="{ 'pt-3' : hasOffset }">
|
||||
<div class="control" :class="{ 'is-expanded': isExpanded }">
|
||||
<input
|
||||
:key="componentKey"
|
||||
:disabled="fieldIsLocked"
|
||||
:id="inputId"
|
||||
:type="inputType"
|
||||
class="input"
|
||||
:value="modelValue"
|
||||
:placeholder="placeholder"
|
||||
v-bind="$attrs"
|
||||
v-on:input="alertOnSpace"
|
||||
v-on:change="emitValue"
|
||||
v-on:blur="forceRefresh"
|
||||
:maxlength="maxLength"
|
||||
:aria-describedby="help ? legendId : undefined"
|
||||
:aria-invalid="fieldError != undefined"
|
||||
:aria-errormessage="fieldError != undefined ? valErrorId : undefined"
|
||||
/>
|
||||
</div>
|
||||
<UseColorMode v-slot="{ mode }" v-if="isEditMode">
|
||||
<div class="control" v-if="fieldIsLocked">
|
||||
<button type="button" class="button field-lock" :class="{'is-dark' : mode == 'dark'}" @click.stop="fieldIsLocked = false" :title="$t('twofaccounts.forms.unlock.title')">
|
||||
<span class="icon">
|
||||
<FontAwesomeIcon :icon="['fas', 'lock']" />
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="control" v-else>
|
||||
<button type="button" class="button field-unlock" :class="{'is-dark' : mode == 'dark'}" @click.stop="fieldIsLocked = true" :title="$t('twofaccounts.forms.lock.title')">
|
||||
<span class="icon has-text-danger">
|
||||
<FontAwesomeIcon :icon="['fas', 'lock-open']" />
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</UseColorMode>
|
||||
</div>
|
||||
<FieldError v-if="hasBeenTrimmed" :error="$t('twofaccounts.forms.spaces_are_ignored')" :field="'spaces'" :alertType="'is-warning'" />
|
||||
<FieldError v-if="fieldError != undefined" :error="fieldError" :field="fieldName" />
|
||||
<p :id="legendId" class="help" v-html="$t(help)" v-if="help"></p>
|
||||
</template>
|
@ -1,130 +0,0 @@
|
||||
<script setup>
|
||||
import { useIdGenerator, useValidationErrorIdGenerator } from '@/composables/helpers'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: true
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: [String],
|
||||
label: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
fieldName: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
},
|
||||
fieldError: [String],
|
||||
inputType: {
|
||||
type: String,
|
||||
default: 'password'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
help: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
hasOffset: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isDisabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showRules: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
idSuffix: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isLocked: Boolean,
|
||||
})
|
||||
|
||||
const { inputId } = useIdGenerator(props.inputType, props.fieldName + props.idSuffix)
|
||||
const { valErrorId } = useValidationErrorIdGenerator(props.fieldName)
|
||||
const legendId = useIdGenerator('legend', props.fieldName).inputId
|
||||
const currentType = ref(props.inputType)
|
||||
const hasCapsLockOn = ref(false)
|
||||
|
||||
const hasLowerCase = computed(() => {
|
||||
return /[a-z]/.test(props.modelValue)
|
||||
})
|
||||
const hasUpperCase = computed(() => {
|
||||
return /[A-Z]/.test(props.modelValue)
|
||||
})
|
||||
const hasNumber = computed(() => {
|
||||
return /[0-9]/.test(props.modelValue)
|
||||
})
|
||||
const hasSpecialChar = computed(() => {
|
||||
return /[^A-Za-z0-9]/.test(props.modelValue)
|
||||
})
|
||||
const IsLongEnough = computed(() => {
|
||||
return props.modelValue.length >= 8
|
||||
})
|
||||
|
||||
function checkCapsLock(event) {
|
||||
if (typeof event.getModifierState === 'function') {
|
||||
hasCapsLockOn.value = event.getModifierState('CapsLock') ? true : false
|
||||
}
|
||||
}
|
||||
|
||||
function setFieldType(event) {
|
||||
if (currentType.value != event) {
|
||||
currentType.value = event
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="field" :class="{ 'pt-3' : hasOffset }">
|
||||
<label :for="inputId" class="label">
|
||||
{{ $t(label) }}<FontAwesomeIcon v-if="isLocked" :icon="['fas', 'lock']" class="ml-2" size="xs" />
|
||||
</label>
|
||||
<div class="control has-icons-right">
|
||||
<input
|
||||
:disabled="isDisabled || isLocked"
|
||||
:id="inputId"
|
||||
:type="currentType"
|
||||
class="input"
|
||||
:value="modelValue"
|
||||
:placeholder="placeholder"
|
||||
v-bind="$attrs"
|
||||
v-on:input="$emit('update:modelValue', $event.target.value)"
|
||||
v-on:keyup="checkCapsLock"
|
||||
:aria-describedby="help ? legendId : undefined"
|
||||
:aria-invalid="fieldError != undefined"
|
||||
:aria-errormessage="fieldError != undefined ? valErrorId : undefined"
|
||||
/>
|
||||
<span v-if="currentType == 'password'" role="button" id="btnTogglePassword" tabindex="0" class="icon is-small is-right is-clickable" @keyup.enter="setFieldType('text')" @click="setFieldType('text')" :title="$t('auth.forms.reveal_password')">
|
||||
<font-awesome-icon :icon="['fas', 'eye-slash']" />
|
||||
</span>
|
||||
<span v-else role="button" id="btnTogglePassword" tabindex="0" class="icon is-small is-right is-clickable" @keyup.enter="setFieldType('password')" @click="setFieldType('password')" :title="$t('auth.forms.hide_password')">
|
||||
<font-awesome-icon :icon="['fas', 'eye']" />
|
||||
</span>
|
||||
</div>
|
||||
<p class="help is-warning" v-if="hasCapsLockOn" v-html="$t('auth.forms.caps_lock_is_on')" />
|
||||
<FieldError v-if="fieldError != undefined" :error="fieldError" :field="fieldName" />
|
||||
<p class="help" v-html="$t(help)" v-if="help" />
|
||||
<div v-if="showRules" :id="legendId" class="columns is-mobile is-size-7 mt-0">
|
||||
<div class="column is-one-third">
|
||||
<span class="has-text-weight-semibold">{{ $t("auth.forms.mandatory_rules") }}</span><br />
|
||||
<span class="is-underscored" id="valPwdIsLongEnough" :class="{'is-dot' : IsLongEnough}"></span>{{ $t('auth.forms.is_long_enough') }}<br/>
|
||||
</div>
|
||||
<div class="column">
|
||||
<span class="has-text-weight-semibold">{{ $t("auth.forms.optional_rules_you_should_follow") }}</span><br />
|
||||
<span class="is-underscored" id="valPwdHasLowerCase" :class="{'is-dot' : hasLowerCase}"></span>{{ $t('auth.forms.has_lower_case') }}<br/>
|
||||
<span class="is-underscored" id="valPwdHasUpperCase" :class="{'is-dot' : hasUpperCase}"></span>{{ $t('auth.forms.has_upper_case') }}<br/>
|
||||
<span class="is-underscored" id="valPwdHasSpecialChar" :class="{'is-dot' : hasSpecialChar}"></span>{{ $t('auth.forms.has_special_char') }}<br/>
|
||||
<span class="is-underscored" id="valPwdHasNumber" :class="{'is-dot' : hasNumber}"></span>{{ $t('auth.forms.has_number') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@ -1,66 +0,0 @@
|
||||
<script setup>
|
||||
import { useIdGenerator, useValidationErrorIdGenerator } from '@/composables/helpers'
|
||||
|
||||
const model = defineModel()
|
||||
const props = defineProps({
|
||||
label: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
fieldName: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
},
|
||||
fieldError: [String],
|
||||
options: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
help: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isIndented: Boolean,
|
||||
isDisabled: Boolean,
|
||||
isLocked: Boolean,
|
||||
idSuffix: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
})
|
||||
|
||||
const { inputId } = useIdGenerator('select', props.fieldName + props.idSuffix)
|
||||
const { valErrorId } = useValidationErrorIdGenerator(props.fieldName)
|
||||
const legendId = useIdGenerator('legend', props.fieldName + props.idSuffix).inputId
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="field is-flex">
|
||||
<div v-if="isIndented" class="mx-2 pr-1" :class="{ 'is-opacity-5' : isDisabled || isLocked }">
|
||||
<FontAwesomeIcon class="has-text-grey" :icon="['fas', 'chevron-right']" transform="rotate-135"/>
|
||||
</div>
|
||||
<div>
|
||||
<label :for="inputId" class="label" :class="{ 'is-opacity-5' : isDisabled || isLocked }">
|
||||
{{ $t(label) }}<FontAwesomeIcon v-if="isLocked" :icon="['fas', 'lock']" class="ml-2" size="xs" />
|
||||
</label>
|
||||
<div class="control">
|
||||
<div class="select">
|
||||
<select
|
||||
:id="inputId"
|
||||
v-model="model"
|
||||
:disabled="isDisabled || isLocked"
|
||||
:aria-describedby="help ? legendId : undefined"
|
||||
:aria-invalid="fieldError != undefined"
|
||||
:aria-errormessage="fieldError != undefined ? valErrorId : undefined"
|
||||
>
|
||||
<option v-for="option in options" :key="option.value" :value="option.value">{{ $t(option.text) }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<slot></slot>
|
||||
</div>
|
||||
<FieldError v-if="fieldError != undefined" :error="fieldError" :field="fieldName" />
|
||||
<p :id="legendId" class="help" v-html="$t(help)" v-if="help"></p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@ -1,89 +0,0 @@
|
||||
<script setup>
|
||||
import { useIdGenerator, useValidationErrorIdGenerator } from '@/composables/helpers'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: [String, Number, Boolean],
|
||||
label: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
fieldName: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
},
|
||||
fieldError: [String],
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
help: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
hasOffset: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isDisabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maxLength: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
isIndented: Boolean,
|
||||
isLocked: Boolean,
|
||||
leftIcon: '',
|
||||
rightIcon: '',
|
||||
idSuffix: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const { inputId } = useIdGenerator(props.inputType, props.fieldName + props.idSuffix)
|
||||
const { valErrorId } = useValidationErrorIdGenerator(props.fieldName)
|
||||
const legendId = useIdGenerator('legend', props.fieldName).inputId
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mb-3" :class="{ 'pt-3' : hasOffset, 'is-flex' : isIndented }">
|
||||
<div v-if="isIndented" class="mx-2 pr-1" :class="{ 'is-opacity-5' : isDisabled || isLocked }">
|
||||
<FontAwesomeIcon class="has-text-grey" :icon="['fas', 'chevron-right']" transform="rotate-135"/>
|
||||
</div>
|
||||
<div class="field" :class="{ 'is-flex-grow-5' : isIndented }">
|
||||
<label v-if="label" :for="inputId" class="label">
|
||||
{{ $t(label) }}<FontAwesomeIcon v-if="isLocked" :icon="['fas', 'lock']" class="ml-2" size="xs" />
|
||||
</label>
|
||||
<div class="control" :class="{ 'has-icons-left' : leftIcon, 'has-icons-right': rightIcon }">
|
||||
<textarea
|
||||
:disabled="isDisabled || isLocked"
|
||||
:id="inputId"
|
||||
class="textarea"
|
||||
:class="size"
|
||||
:value="modelValue"
|
||||
:placeholder="placeholder"
|
||||
v-bind="$attrs"
|
||||
v-on:input="$emit('update:modelValue', $event.target.value)"
|
||||
v-on:change="$emit('change:modelValue', $event.target.value)"
|
||||
:maxlength="maxLength"
|
||||
:aria-describedby="help ? legendId : undefined"
|
||||
:aria-invalid="fieldError != undefined"
|
||||
:aria-errormessage="fieldError != undefined ? valErrorId : undefined"
|
||||
/>
|
||||
</div>
|
||||
<FieldError v-if="fieldError != undefined" :error="fieldError" :field="fieldName" />
|
||||
<p :id="legendId" class="help" v-html="$t(help)" v-if="help"></p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@ -1,88 +0,0 @@
|
||||
<script setup>
|
||||
import { useIdGenerator, useValidationErrorIdGenerator } from '@/composables/helpers'
|
||||
import { UseColorMode } from '@vueuse/components'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: [String, Number, Boolean],
|
||||
choices: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
fieldName: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
fieldError: [String],
|
||||
hasOffset: Boolean,
|
||||
isDisabled: Boolean,
|
||||
isLocked: Boolean,
|
||||
label: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
help: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
})
|
||||
|
||||
// defines what events our component emits
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const { valErrorId } = useValidationErrorIdGenerator(props.fieldName)
|
||||
const legendId = useIdGenerator('legend', props.fieldName).inputId
|
||||
|
||||
function setRadio(event) {
|
||||
emit('update:modelValue', event)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="field" :class="{ 'pt-3': hasOffset }">
|
||||
<span v-if="label" class="label" :class="{ 'is-opacity-5' : isDisabled || isLocked }">
|
||||
{{ $t(label) }}<FontAwesomeIcon v-if="isLocked" :icon="['fas', 'lock']" class="ml-2" size="xs" />
|
||||
</span>
|
||||
<div
|
||||
id="rdoGroup"
|
||||
role="radiogroup"
|
||||
:aria-describedby="help ? legendId : undefined"
|
||||
:aria-invalid="fieldError != undefined"
|
||||
:aria-errormessage="fieldError != undefined ? valErrorId : undefined"
|
||||
class="is-toggle buttons"
|
||||
>
|
||||
<UseColorMode v-slot="{ mode }">
|
||||
<button
|
||||
v-for="choice in choices"
|
||||
:key="choice.value"
|
||||
:id="useIdGenerator('button',fieldName+choice.value).inputId"
|
||||
role="radio"
|
||||
type="button"
|
||||
class="button"
|
||||
:aria-checked="modelValue===choice.value"
|
||||
:disabled="isDisabled || isLocked"
|
||||
:class="{
|
||||
'is-link': modelValue===choice.value,
|
||||
'is-dark': mode==='dark',
|
||||
'is-multiline': choice.legend,
|
||||
}"
|
||||
v-on:click.stop="setRadio(choice.value)">
|
||||
<input
|
||||
:id="useIdGenerator('radio',choice.value).inputId"
|
||||
type="radio"
|
||||
class="is-hidden"
|
||||
:checked="modelValue===choice.value"
|
||||
:value="choice.value"
|
||||
:disabled="isDisabled || isLocked"
|
||||
/>
|
||||
<span v-if="choice.legend" v-html="$t(choice.legend)" class="is-block is-size-7" />
|
||||
<FontAwesomeIcon :icon="['fas',choice.icon]" v-if="choice.icon" class="mr-2" />
|
||||
<label :for="useIdGenerator('button',fieldName+choice.value).inputId" class="is-clickable">
|
||||
{{ $t(choice.text) }}
|
||||
</label>
|
||||
</button>
|
||||
</UseColorMode>
|
||||
</div>
|
||||
<FieldError v-if="fieldError != undefined" :error="fieldError" :field="fieldName" />
|
||||
<p :id="legendId" class="help" v-html="$t(help)" v-if="help" />
|
||||
</div>
|
||||
</template>
|
@ -50,7 +50,7 @@
|
||||
</section>
|
||||
</div>
|
||||
<VueFooter v-if="props.closable" :showButtons="true" :internalFooterType="'modal'">
|
||||
<ButtonBackCloseCancel action="close" :useLinkTag="false" @closed="closeModal" />
|
||||
<NavigationButton action="close" :useLinkTag="false" @closed="closeModal" />
|
||||
</VueFooter>
|
||||
</div>
|
||||
</template>
|
@ -63,7 +63,7 @@
|
||||
</ul>
|
||||
<!-- footer -->
|
||||
<VueFooter :showButtons="true">
|
||||
<ButtonBackCloseCancel :returnTo="{ path: returnTo }" action="back" />
|
||||
<NavigationButton action="back" @goback="router.push({ name: returnTo })" :previous-page-title="$t('title.' + returnTo)" />
|
||||
</VueFooter>
|
||||
</UseColorMode>
|
||||
</ResponsiveWidthWrapper>
|
||||
|
@ -80,7 +80,7 @@
|
||||
{{ $t('twofaccounts.forms.scan_qrcode') }}
|
||||
</button>
|
||||
</div>
|
||||
<FieldError v-if="form.errors.hasAny('qrcode')" :error="form.errors.get('qrcode')" :field="'qrcode'" />
|
||||
<FormFieldError v-if="form.errors.hasAny('qrcode')" :error="form.errors.get('qrcode')" :field="'qrcode'" />
|
||||
</div>
|
||||
<!-- alternative methods -->
|
||||
<div class="column is-full">
|
||||
@ -108,7 +108,7 @@
|
||||
</div>
|
||||
<!-- Footer -->
|
||||
<VueFooter :showButtons="true" >
|
||||
<ButtonBackCloseCancel :returnTo="{ name: 'accounts' }" action="back" v-if="!twofaccounts.isEmpty" />
|
||||
<NavigationButton v-if="!twofaccounts.isEmpty" action="back" @goback="router.push({ name: 'accounts' })" :previous-page-title="$t('title.accounts')" />
|
||||
</VueFooter>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -140,7 +140,7 @@
|
||||
</FormWrapper>
|
||||
</div>
|
||||
<VueFooter :showButtons="true">
|
||||
<ButtonBackCloseCancel :returnTo="{ name: returnTo }" action="close" />
|
||||
<NavigationButton action="close" @closed="router.push({ name: returnTo })" :current-page-title="$t('title.admin.appSetup')" />
|
||||
</VueFooter>
|
||||
</div>
|
||||
</template>
|
@ -86,9 +86,9 @@
|
||||
<!-- restrict registration -->
|
||||
<FormCheckbox v-model="appSettings.restrictRegistration" @update:model-value="val => useAppSettingsUpdater('restrictRegistration', val)" fieldName="restrictRegistration" :isDisabled="appSettings.disableRegistration" label="admin.forms.restrict_registration.label" help="admin.forms.restrict_registration.help" />
|
||||
<!-- restrict list -->
|
||||
<FormField v-model="appSettings.restrictList" @change:model-value="val => saveOrDeleteSetting('restrictList', val)" :fieldError="fieldErrors.restrictList" fieldName="restrictList" :isDisabled="!appSettings.restrictRegistration || appSettings.disableRegistration" label="admin.forms.restrict_list.label" help="admin.forms.restrict_list.help" :isIndented="true" />
|
||||
<FormField v-model="appSettings.restrictList" @change:model-value="val => saveOrDeleteSetting('restrictList', val)" :errorMessage="fieldErrors.restrictList" fieldName="restrictList" :isDisabled="!appSettings.restrictRegistration || appSettings.disableRegistration" label="admin.forms.restrict_list.label" help="admin.forms.restrict_list.help" :isIndented="true" />
|
||||
<!-- restrict rule -->
|
||||
<FormField v-model="appSettings.restrictRule" @change:model-value="val => saveOrDeleteSetting('restrictRule', val)" :fieldError="fieldErrors.restrictRule" fieldName="restrictRule" :isDisabled="!appSettings.restrictRegistration || appSettings.disableRegistration" label="admin.forms.restrict_rule.label" help="admin.forms.restrict_rule.help" :isIndented="true" leftIcon="slash" rightIcon="slash" />
|
||||
<FormField v-model="appSettings.restrictRule" @change:model-value="val => saveOrDeleteSetting('restrictRule', val)" :errorMessage="fieldErrors.restrictRule" fieldName="restrictRule" :isDisabled="!appSettings.restrictRegistration || appSettings.disableRegistration" label="admin.forms.restrict_rule.label" help="admin.forms.restrict_rule.help" :isIndented="true" leftIcon="Slash" rightIcon="Slash" />
|
||||
<!-- disable registration -->
|
||||
<FormCheckbox v-model="appSettings.disableRegistration" @update:model-value="val => useAppSettingsUpdater('disableRegistration', val)" fieldName="disableRegistration" label="admin.forms.disable_registration.label" help="admin.forms.disable_registration.help" />
|
||||
<!-- keep sso registration -->
|
||||
@ -97,7 +97,7 @@
|
||||
</FormWrapper>
|
||||
</div>
|
||||
<VueFooter :showButtons="true">
|
||||
<ButtonBackCloseCancel :returnTo="{ name: returnTo }" action="close" />
|
||||
<NavigationButton action="close" @closed="router.push({ name: returnTo })" :current-page-title="$t('title.admin.auth')" />
|
||||
</VueFooter>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -171,7 +171,7 @@
|
||||
<Spinner :isVisible="isFetching && users.length === 0" />
|
||||
<!-- footer -->
|
||||
<VueFooter :showButtons="true">
|
||||
<ButtonBackCloseCancel :returnTo="{ name: returnTo }" action="close" />
|
||||
<NavigationButton action="close" @closed="router.push({ name: returnTo })" :current-page-title="$t('title.admin.users')" />
|
||||
</VueFooter>
|
||||
</FormWrapper>
|
||||
</div>
|
||||
|
@ -40,8 +40,8 @@
|
||||
<AccessLogViewer :userId="props.userId" :lastOnly="false" :showSearch="true" :period="1" />
|
||||
<!-- footer -->
|
||||
<VueFooter :showButtons="true">
|
||||
<ButtonBackCloseCancel :returnTo="{ name: 'admin.manageUser', params: { userId: props.userId }}" action="back" />
|
||||
<ButtonBackCloseCancel :returnTo="{ name: 'accounts' }" action="close" />
|
||||
<NavigationButton action="back" @goback="router.push({ name: 'admin.manageUser', params: { userId: props.userId }})" :previous-page-title="$t('title.admin.manageUser')" />
|
||||
<NavigationButton action="close" @closed="router.push({ name: 'accounts' })" :current-page-title="$t('title.admin.logs.access')" />
|
||||
</VueFooter>
|
||||
</ResponsiveWidthWrapper>
|
||||
</template>
|
||||
|
@ -31,11 +31,11 @@
|
||||
<div>
|
||||
<FormWrapper title="admin.new_user">
|
||||
<form @submit.prevent="createUser" @keydown="registerForm.onKeydown($event)">
|
||||
<FormField v-model="registerForm.name" fieldName="name" :fieldError="registerForm.errors.get('name')" inputType="text" label="auth.forms.name" autocomplete="username" :maxLength="255" autofocus />
|
||||
<FormField v-model="registerForm.email" fieldName="email" :fieldError="registerForm.errors.get('email')" inputType="email" label="auth.forms.email" autocomplete="email" :maxLength="255" />
|
||||
<FormPasswordField v-model="registerForm.password" fieldName="password" :fieldError="registerForm.errors.get('password')" :showRules="true" label="auth.forms.password" autocomplete="new-password" />
|
||||
<FormField v-model="registerForm.name" fieldName="name" :errorMessage="registerForm.errors.get('name')" inputType="text" label="auth.forms.name" autocomplete="username" :maxLength="255" autofocus />
|
||||
<FormField v-model="registerForm.email" fieldName="email" :errorMessage="registerForm.errors.get('email')" inputType="email" label="auth.forms.email" autocomplete="email" :maxLength="255" />
|
||||
<FormPasswordField v-model="registerForm.password" fieldName="password" :errorMessage="registerForm.errors.get('password')" :showRules="true" label="auth.forms.password" autocomplete="new-password" />
|
||||
<FormCheckbox v-model="registerForm.is_admin" fieldName="is_admin" label="admin.forms.is_admin.label" help="admin.forms.is_admin.help" />
|
||||
<FormButtons :isBusy="registerForm.isBusy" :isDisabled="registerForm.isDisabled" :showCancelButton="true" :cancelLandingView="'admin.users'" caption="commons.create" submitId="btnCreateUser" />
|
||||
<FormButtons :isBusy="registerForm.isBusy" :isDisabled="registerForm.isDisabled" :showCancelButton="true" @cancel="router.push({ name: 'admin.users' })" submitLabel="commons.create" submitId="btnCreateUser" />
|
||||
</form>
|
||||
</FormWrapper>
|
||||
<!-- footer -->
|
||||
|
@ -316,8 +316,8 @@
|
||||
</div>
|
||||
<!-- footer -->
|
||||
<VueFooter :showButtons="true">
|
||||
<ButtonBackCloseCancel :returnTo="{ name: 'admin.users' }" action="back" />
|
||||
<ButtonBackCloseCancel :returnTo="{ name: 'accounts' }" action="close" />
|
||||
<NavigationButton action="back" @goback="router.push({ name: 'admin.users' })" :previous-page-title="$t('title.admin.users')" />
|
||||
<NavigationButton action="close" @closed="router.push({ name: 'accounts' })" :current-page-title="$t('title.admin.manageUser')" />
|
||||
</VueFooter>
|
||||
</ResponsiveWidthWrapper>
|
||||
</UseColorMode>
|
||||
|
@ -126,8 +126,8 @@
|
||||
{{ $t('auth.webauthn.use_security_device_to_sign_in') }}
|
||||
</div>
|
||||
<form id="frmWebauthnLogin" @submit.prevent="webauthnLogin" @keydown="form.onKeydown($event)">
|
||||
<FormField v-model="form.email" fieldName="email" :fieldError="form.errors.get('email')" inputType="email" label="auth.forms.email" autofocus />
|
||||
<FormButtons :isBusy="isBusy" caption="commons.continue" submitId="btnContinue"/>
|
||||
<FormField v-model="form.email" fieldName="email" :errorMessage="form.errors.get('email')" inputType="email" label="auth.forms.email" autofocus />
|
||||
<FormButtons :isBusy="isBusy" submitLabel="commons.continue" submitId="btnContinue"/>
|
||||
</form>
|
||||
<div class="nav-links">
|
||||
<p>
|
||||
@ -195,9 +195,9 @@
|
||||
<div v-if="$2fauth.isTestingApp" class="notification is-warning has-text-centered is-radiusless" v-html="$t('auth.forms.welcome_to_testing_app_use_those_credentials')" />
|
||||
<div v-if="appSettings.enableSso == true && appSettings.useSsoOnly == true" class="notification is-warning has-text-centered" v-html="$t('auth.forms.sso_only_form_restricted_to_admin')" />
|
||||
<form id="frmLegacyLogin" @submit.prevent="LegacysignIn" @keydown="form.onKeydown($event)">
|
||||
<FormField v-model="form.email" fieldName="email" :fieldError="form.errors.get('email')" inputType="email" label="auth.forms.email" autocomplete="username" autofocus />
|
||||
<FormPasswordField v-model="form.password" fieldName="password" :fieldError="form.errors.get('password')" label="auth.forms.password" autocomplete="current-password" />
|
||||
<FormButtons :isBusy="isBusy" caption="auth.sign_in" submitId="btnSignIn"/>
|
||||
<FormField v-model="form.email" fieldName="email" :errorMessage="form.errors.get('email')" inputType="email" label="auth.forms.email" autocomplete="username" autofocus />
|
||||
<FormPasswordField v-model="form.password" fieldName="password" :errorMessage="form.errors.get('password')" label="auth.forms.password" autocomplete="current-password" />
|
||||
<FormButtons :isBusy="isBusy" submitLabel="auth.sign_in" submitId="btnSignIn"/>
|
||||
</form>
|
||||
<div class="nav-links">
|
||||
<p>{{ $t('auth.forms.forgot_your_password') }}
|
||||
|
@ -83,8 +83,8 @@
|
||||
<div v-if="deviceId" class="field">
|
||||
<label id="lblDeviceRegistrationSuccess" class="label mb-5">{{ $t('auth.webauthn.device_successfully_registered') }} <font-awesome-icon :icon="['fas', 'check']" /></label>
|
||||
<form @submit.prevent="RenameDevice" @keydown="renameDeviceForm.onKeydown($event)">
|
||||
<FormField v-model="renameDeviceForm.name" fieldName="name" :fieldError="renameDeviceForm.errors.get('name')" inputType="text" placeholder="iPhone 12, TouchID, Yubikey 5C" label="auth.forms.name_this_device" />
|
||||
<FormButtons :isBusy="renameDeviceForm.isBusy" :isDisabled="renameDeviceForm.isDisabled" caption="commons.continue" />
|
||||
<FormField v-model="renameDeviceForm.name" fieldName="name" :errorMessage="renameDeviceForm.errors.get('name')" inputType="text" placeholder="iPhone 12, TouchID, Yubikey 5C" label="auth.forms.name_this_device" />
|
||||
<FormButtons :isBusy="renameDeviceForm.isBusy" :isDisabled="renameDeviceForm.isDisabled" submitLabel="commons.continue" />
|
||||
</form>
|
||||
</div>
|
||||
<div v-else class="field is-grouped">
|
||||
@ -101,10 +101,10 @@
|
||||
<!-- User registration form -->
|
||||
<FormWrapper v-else title="auth.register" punchline="auth.forms.register_punchline">
|
||||
<form @submit.prevent="register" @keydown="registerForm.onKeydown($event)">
|
||||
<FormField v-model="registerForm.name" fieldName="name" :fieldError="registerForm.errors.get('name')" inputType="text" label="auth.forms.name" autocomplete="username" :maxLength="255" autofocus />
|
||||
<FormField v-model="registerForm.email" fieldName="email" :fieldError="registerForm.errors.get('email')" inputType="email" label="auth.forms.email" autocomplete="email" :maxLength="255" />
|
||||
<FormPasswordField v-model="registerForm.password" fieldName="password" :fieldError="registerForm.errors.get('password')" :showRules="true" autocomplete="new-password" label="auth.forms.password" />
|
||||
<FormButtons :isBusy="registerForm.isBusy" :isDisabled="registerForm.isDisabled" caption="auth.register" submitId="btnRegister" />
|
||||
<FormField v-model="registerForm.name" fieldName="name" :errorMessage="registerForm.errors.get('name')" inputType="text" label="auth.forms.name" autocomplete="username" :maxLength="255" autofocus />
|
||||
<FormField v-model="registerForm.email" fieldName="email" :errorMessage="registerForm.errors.get('email')" inputType="email" label="auth.forms.email" autocomplete="email" :maxLength="255" />
|
||||
<FormPasswordField v-model="registerForm.password" fieldName="password" :errorMessage="registerForm.errors.get('password')" :showRules="true" autocomplete="new-password" label="auth.forms.password" />
|
||||
<FormButtons :isBusy="registerForm.isBusy" :isDisabled="registerForm.isDisabled" submitLabel="auth.register" submitId="btnRegister" />
|
||||
</form>
|
||||
<div class="nav-links">
|
||||
<p>{{ $t('auth.forms.already_register') }} <RouterLink id="lnkSignIn" :to="{ name: 'login' }" class="is-link">{{ $t('auth.sign_in') }}</RouterLink></p>
|
||||
|
@ -38,13 +38,13 @@
|
||||
<template>
|
||||
<FormWrapper :title="$t(isWebauthnReset ? 'auth.webauthn.account_recovery' : 'auth.forms.reset_password')" :punchline="$t(isWebauthnReset ? 'auth.webauthn.recovery_punchline' : 'auth.forms.reset_punchline')">
|
||||
<form @submit.prevent="requestPasswordReset" @keydown="form.onKeydown($event)">
|
||||
<FormField v-model="form.email" fieldName="email" :fieldError="form.errors.get('email')" label="auth.forms.email" autofocus />
|
||||
<FormField v-model="form.email" fieldName="email" :errorMessage="form.errors.get('email')" label="auth.forms.email" autofocus />
|
||||
<FormButtons
|
||||
:submitId="'btnSendResetPwd'"
|
||||
:isBusy="form.isBusy"
|
||||
:caption="$t(isWebauthnReset ? 'auth.webauthn.send_recovery_link' : 'auth.forms.send_password_reset_link')"
|
||||
:submitLabel="isWebauthnReset ? 'auth.webauthn.send_recovery_link' : 'auth.forms.send_password_reset_link'"
|
||||
:showCancelButton="true"
|
||||
cancelLandingView="login" />
|
||||
@cancel="router.push({ name: 'login' })" />
|
||||
</form>
|
||||
<VueFooter />
|
||||
</FormWrapper>
|
||||
|
@ -45,16 +45,16 @@
|
||||
<template>
|
||||
<FormWrapper :title="$t('auth.forms.new_password')">
|
||||
<form @submit.prevent="resetPassword" @keydown="form.onKeydown($event)">
|
||||
<FormField v-model="form.email" :isDisabled="true" fieldName="email" :fieldError="form.errors.get('email')" label="auth.forms.email" autofocus />
|
||||
<FormPasswordField v-model="form.password" fieldName="password" :fieldError="form.errors.get('password')" autocomplete="new-password" :showRules="true" label="auth.forms.new_password" />
|
||||
<FieldError v-if="form.errors.get('token') != undefined" :error="form.errors.get('token')" :field="form.token" />
|
||||
<FormField v-model="form.email" :isDisabled="true" fieldName="email" :errorMessage="form.errors.get('email')" label="auth.forms.email" autofocus />
|
||||
<FormPasswordField v-model="form.password" fieldName="password" :errorMessage="form.errors.get('password')" autocomplete="new-password" :showRules="true" label="auth.forms.new_password" />
|
||||
<FormFieldError v-if="form.errors.get('token') != undefined" :error="form.errors.get('token')" :field="form.token" />
|
||||
<FormButtons
|
||||
v-if="isPending"
|
||||
:submitId="'btnResetPwd'"
|
||||
:isBusy="form.isBusy"
|
||||
:caption="$t('auth.forms.change_password')"
|
||||
submitLabel="auth.forms.change_password"
|
||||
:showCancelButton="true"
|
||||
cancelLandingView="login" />
|
||||
@cancel="router.push({ name: 'login' })" />
|
||||
<RouterLink v-if="!isPending" id="btnContinue" :to="{ name: 'accounts' }" class="button is-link">{{ $t('commons.continue') }}</RouterLink>
|
||||
</form>
|
||||
<VueFooter />
|
||||
|
@ -48,7 +48,7 @@
|
||||
<div>
|
||||
<form @submit.prevent="recover" @keydown="form.onKeydown($event)">
|
||||
<FormCheckbox v-model="form.revokeAll" fieldName="revokeAll" label="auth.webauthn.disable_all_security_devices" help="auth.webauthn.disable_all_security_devices_help" />
|
||||
<FormPasswordField v-model="form.password" fieldName="password" :fieldError="form.errors.get('password')" autocomplete="current-password" :showRules="false" label="auth.forms.current_password.label" help="auth.forms.current_password.help" />
|
||||
<FormPasswordField v-model="form.password" fieldName="password" :errorMessage="form.errors.get('password')" autocomplete="current-password" :showRules="false" label="auth.forms.current_password.label" help="auth.forms.current_password.help" />
|
||||
<div class="field">
|
||||
<p>
|
||||
{{ $t('auth.forms.forgot_your_password') }}
|
||||
@ -61,9 +61,9 @@
|
||||
:submitId="'btnRecover'"
|
||||
:isBusy="form.isBusy"
|
||||
:isDisabled="form.isDisabled"
|
||||
:caption="$t('commons.continue')"
|
||||
submitLabel="commons.continue"
|
||||
:showCancelButton="true"
|
||||
cancelLandingView="login" />
|
||||
@cancel="router.push({ name: 'login' })" />
|
||||
</form>
|
||||
</div>
|
||||
<VueFooter />
|
||||
|
@ -68,13 +68,13 @@
|
||||
<template>
|
||||
<FormWrapper :title="isEditMode ? $t('groups.forms.rename_group') : $t('groups.forms.new_group')">
|
||||
<form @submit.prevent="handleSubmit" @keydown="form.onKeydown($event)">
|
||||
<FormField v-model="form.name" fieldName="name" :fieldError="form.errors.get('name')" label="commons.name" autofocus />
|
||||
<FormField v-model="form.name" fieldName="name" :errorMessage="form.errors.get('name')" label="commons.name" autofocus />
|
||||
<FormButtons
|
||||
:submitId="isEditMode ? 'btnEditGroup' : 'btnCreateGroup'"
|
||||
:isBusy="form.isBusy"
|
||||
:caption="isEditMode ? $t('commons.save') : $t('commons.create')"
|
||||
:submitLabel="isEditMode ? 'commons.save' : 'commons.create'"
|
||||
:showCancelButton="true"
|
||||
cancelLandingView="groups" />
|
||||
@cancel="router.push({ name: 'groups' })" />
|
||||
</form>
|
||||
</FormWrapper>
|
||||
</template>
|
@ -70,7 +70,7 @@
|
||||
</div>
|
||||
<!-- footer -->
|
||||
<VueFooter :showButtons="true">
|
||||
<ButtonBackCloseCancel :returnTo="{ name: 'accounts' }" action="close" />
|
||||
<NavigationButton action="close" @closed="router.push({ name: 'accounts' })" :current-page-title="$t('title.groups')" />
|
||||
</VueFooter>
|
||||
</ResponsiveWidthWrapper>
|
||||
</template>
|
@ -114,10 +114,10 @@
|
||||
<div v-if="$2fauth.config.proxyAuth" class="notification is-warning has-text-centered" v-html="$t('auth.user_account_controlled_by_proxy')" />
|
||||
<h4 class="title is-4 has-text-grey-light">{{ $t('settings.profile') }}</h4>
|
||||
<fieldset :disabled="$2fauth.config.proxyAuth || user.oauth_provider">
|
||||
<FormField v-model="formProfile.name" fieldName="name" :fieldError="formProfile.errors.get('name')" label="auth.forms.name" :maxLength="255" autocomplete="username" autofocus />
|
||||
<FormField v-model="formProfile.email" fieldName="email" :fieldError="formProfile.errors.get('email')" inputType="email" label="auth.forms.email" autocomplete="email" :maxLength="255" autofocus />
|
||||
<FormField v-model="formProfile.password" fieldName="password" :fieldError="formProfile.errors.get('password')" inputType="password" label="auth.forms.current_password.label" autocomplete="current-password" help="auth.forms.current_password.help" />
|
||||
<FormButtons :isBusy="formProfile.isBusy" caption="commons.update" />
|
||||
<FormField v-model="formProfile.name" fieldName="name" :errorMessage="formProfile.errors.get('name')" label="auth.forms.name" :maxLength="255" autocomplete="username" autofocus />
|
||||
<FormField v-model="formProfile.email" fieldName="email" :errorMessage="formProfile.errors.get('email')" inputType="email" label="auth.forms.email" autocomplete="email" :maxLength="255" autofocus />
|
||||
<FormField v-model="formProfile.password" fieldName="password" :errorMessage="formProfile.errors.get('password')" inputType="password" label="auth.forms.current_password.label" autocomplete="current-password" help="auth.forms.current_password.help" />
|
||||
<FormButtons :isBusy="formProfile.isBusy" submitLabel="commons.update" />
|
||||
</fieldset>
|
||||
</form>
|
||||
<form @submit.prevent="submitPassword" @keydown="formPassword.onKeydown($event)">
|
||||
@ -125,10 +125,10 @@
|
||||
<input hidden type="text" name="email" :value="formProfile.email" autocomplete="email" />
|
||||
<h4 class="title is-4 pt-6 has-text-grey-light">{{ $t('settings.change_password') }}</h4>
|
||||
<fieldset :disabled="$2fauth.config.proxyAuth || user.oauth_provider">
|
||||
<FormPasswordField v-model="formPassword.password" fieldName="password" :fieldError="formPassword.errors.get('password')" idSuffix="ForUpdate" autocomplete="new-password" :showRules="true" label="auth.forms.new_password" />
|
||||
<FormPasswordField v-model="formPassword.password_confirmation" :showRules="false" fieldName="password_confirmation" :fieldError="formPassword.errors.get('password_confirmation')" inputType="password" autocomplete="new-password" label="auth.forms.confirm_new_password" />
|
||||
<FormField v-model="formPassword.currentPassword" fieldName="currentPassword" :fieldError="formPassword.errors.get('currentPassword')" inputType="password" label="auth.forms.current_password.label" autocomplete="current-password" help="auth.forms.current_password.help" />
|
||||
<FormButtons :isBusy="formPassword.isBusy" submitId="btnSubmitChangePwd" caption="auth.forms.change_password" />
|
||||
<FormPasswordField v-model="formPassword.password" fieldName="password" :errorMessage="formPassword.errors.get('password')" idSuffix="ForUpdate" autocomplete="new-password" :showRules="true" label="auth.forms.new_password" />
|
||||
<FormPasswordField v-model="formPassword.password_confirmation" :showRules="false" fieldName="password_confirmation" :errorMessage="formPassword.errors.get('password_confirmation')" inputType="password" autocomplete="new-password" label="auth.forms.confirm_new_password" />
|
||||
<FormField v-model="formPassword.currentPassword" fieldName="currentPassword" :errorMessage="formPassword.errors.get('currentPassword')" inputType="password" label="auth.forms.current_password.label" autocomplete="current-password" help="auth.forms.current_password.help" />
|
||||
<FormButtons :isBusy="formPassword.isBusy" submitId="btnSubmitChangePwd" submitLabel="auth.forms.change_password" />
|
||||
</fieldset>
|
||||
</form>
|
||||
<form id="frmDeleteAccount" @submit.prevent="submitDelete" @keydown="formDelete.onKeydown($event)">
|
||||
@ -141,14 +141,14 @@
|
||||
<p>{{ $t('auth.forms.deleting_2fauth_account_does_not_impact_provider') }}</p>
|
||||
</div>
|
||||
<fieldset :disabled="$2fauth.config.proxyAuth">
|
||||
<FormField v-model="formDelete.password" fieldName="password" :fieldError="formDelete.errors.get('password')" inputType="password" idSuffix="ForDelete" autocomplete="new-password" label="auth.forms.current_password.label" help="auth.forms.current_password.help" />
|
||||
<FormButtons :isBusy="formDelete.isBusy" caption="auth.forms.delete_your_account" submitId="btnDeleteAccount" color="is-danger" />
|
||||
<FormField v-model="formDelete.password" fieldName="password" :errorMessage="formDelete.errors.get('password')" inputType="password" idSuffix="ForDelete" autocomplete="new-password" label="auth.forms.current_password.label" help="auth.forms.current_password.help" />
|
||||
<FormButtons :isBusy="formDelete.isBusy" submitLabel="auth.forms.delete_your_account" submitId="btnDeleteAccount" color="is-danger" />
|
||||
</fieldset>
|
||||
</form>
|
||||
</FormWrapper>
|
||||
</div>
|
||||
<VueFooter :showButtons="true">
|
||||
<ButtonBackCloseCancel :returnTo="{ name: returnTo }" action="close" />
|
||||
<NavigationButton action="close" @closed="router.push({ name: returnTo })" :current-page-title="$t('title.settings.account')" />
|
||||
</VueFooter>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -28,13 +28,13 @@
|
||||
<template>
|
||||
<FormWrapper title="auth.webauthn.rename_device">
|
||||
<form @submit.prevent="updateCredential" @keydown="form.onKeydown($event)">
|
||||
<FormField v-model="form.name" fieldName="name" :fieldError="form.errors.get('name')" inputType="text" label="commons.new_name" autofocus />
|
||||
<FormField v-model="form.name" fieldName="name" :errorMessage="form.errors.get('name')" inputType="text" label="commons.new_name" autofocus />
|
||||
<FormButtons
|
||||
:submitId="'btnEditCredential'"
|
||||
:isBusy="form.isBusy"
|
||||
:caption="$t('commons.save')"
|
||||
submitLabel="commons.save"
|
||||
:showCancelButton="true"
|
||||
cancelLandingView="settings.webauthn.devices"
|
||||
@cancel="router.push({ name: 'settings.webauthn.devices' })"
|
||||
/>
|
||||
</form>
|
||||
</FormWrapper>
|
||||
|
@ -191,7 +191,7 @@
|
||||
<Spinner :isVisible="isFetching && tokens.length === 0" />
|
||||
<!-- footer -->
|
||||
<VueFooter :showButtons="true">
|
||||
<ButtonBackCloseCancel :returnTo="{ name: returnTo }" action="close" />
|
||||
<NavigationButton action="close" @closed="router.push({ name: returnTo })" :current-page-title="$t('title.settings.oauth.tokens')" />
|
||||
</VueFooter>
|
||||
</FormWrapper>
|
||||
</div>
|
||||
@ -199,15 +199,15 @@
|
||||
<main class="main-section">
|
||||
<FormWrapper title="settings.forms.new_token">
|
||||
<form @submit.prevent="generatePAToken" @keydown="form.onKeydown($event)">
|
||||
<FormField v-model="form.name" fieldName="name" :fieldError="form.errors.get('name')" inputType="text" label="commons.name" autofocus />
|
||||
<FormField v-model="form.name" fieldName="name" :errorMessage="form.errors.get('name')" inputType="text" label="commons.name" autofocus />
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<VueButton :id="'btnGenerateToken'" :isLoading="form.isBusy" >
|
||||
<VueButton nativeType="submit" :id="'btnGenerateToken'" :isLoading="form.isBusy" >
|
||||
{{ $t('commons.generate') }}
|
||||
</VueButton>
|
||||
</div>
|
||||
<div class="control">
|
||||
<VueButton @click="cancelPATcreation" :nativeType="'button'" id="btnCancel" :color="'is-text'">
|
||||
<VueButton @click="cancelPATcreation" nativeType="button" id="btnCancel" :color="'is-text'">
|
||||
{{ $t('commons.cancel') }}
|
||||
</VueButton>
|
||||
</div>
|
||||
|
@ -15,13 +15,13 @@
|
||||
const returnTo = useStorage($2fauth.prefix + 'returnTo', 'accounts')
|
||||
|
||||
const layouts = [
|
||||
{ text: 'settings.forms.grid', value: 'grid', icon: 'th' },
|
||||
{ text: 'settings.forms.list', value: 'list', icon: 'list' },
|
||||
{ text: 'settings.forms.grid', value: 'grid', icon: 'Grid3X3' },
|
||||
{ text: 'settings.forms.list', value: 'list', icon: 'List' },
|
||||
]
|
||||
const themes = [
|
||||
{ text: 'settings.forms.light', value: 'light', icon: 'sun' },
|
||||
{ text: 'settings.forms.dark', value: 'dark', icon: 'moon' },
|
||||
{ text: 'settings.forms.automatic', value: 'system', icon: 'desktop' },
|
||||
{ text: 'settings.forms.light', value: 'light', icon: 'Sun' },
|
||||
{ text: 'settings.forms.dark', value: 'dark', icon: 'Moon' },
|
||||
{ text: 'settings.forms.automatic', value: 'system', icon: 'MonitorCheck' },
|
||||
]
|
||||
const iconCollections = [
|
||||
{ text: 'selfh.st', value: 'selfh', url: 'https://selfh.st/icons/', defaultVariant: 'regular' },
|
||||
@ -261,7 +261,7 @@
|
||||
</FormWrapper>
|
||||
</div>
|
||||
<VueFooter :showButtons="true">
|
||||
<ButtonBackCloseCancel :returnTo="{ name: returnTo }" action="close" />
|
||||
<NavigationButton action="close" @closed="router.push({ name: returnTo })" :current-page-title="$t('title.settings.options')" />
|
||||
</VueFooter>
|
||||
</div>
|
||||
</template>
|
@ -173,7 +173,7 @@
|
||||
</form>
|
||||
<!-- footer -->
|
||||
<VueFooter :showButtons="true">
|
||||
<ButtonBackCloseCancel :returnTo="{ name: returnTo }" action="close" />
|
||||
<NavigationButton action="close" @closed="router.push({ name: returnTo })" :current-page-title="$t('title.settings.webauthn.devices')" />
|
||||
</VueFooter>
|
||||
</FormWrapper>
|
||||
</div>
|
||||
|
@ -207,7 +207,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="fullscreen-footer">
|
||||
<ButtonBackCloseCancel action="cancel" :isCapture="true" :useLinkTag="false" @canceled="exitStream()" />
|
||||
<NavigationButton action="cancel" :isCapture="true" :useLinkTag="false" @canceled="exitStream()" />
|
||||
</div>
|
||||
</div>
|
||||
<modal v-model="showQrContent">
|
||||
|
@ -2,7 +2,7 @@
|
||||
import Form from '@/components/formElements/Form'
|
||||
import OtpDisplay from '@/components/OtpDisplay.vue'
|
||||
import QrContentDisplay from '@/components/QrContentDisplay.vue'
|
||||
import FormLockField from '@/components/formElements/FormLockField.vue'
|
||||
import { FormProtectedField } from '@2fauth/formcontrols'
|
||||
import twofaccountService from '@/services/twofaccountService'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useTwofaccounts } from '@/stores/twofaccounts'
|
||||
@ -450,7 +450,7 @@
|
||||
<div class="container preview has-text-centered">
|
||||
<div class="columns is-mobile">
|
||||
<div class="column">
|
||||
<FieldError v-if="iconForm.errors.hasAny('icon')" :error="iconForm.errors.get('icon')" :field="'icon'" class="help-for-file" />
|
||||
<FormFieldError v-if="iconForm.errors.hasAny('icon')" :error="iconForm.errors.get('icon')" :field="'icon'" class="help-for-file" />
|
||||
<label class="add-icon-button" v-if="!tempIcon">
|
||||
<input inert class="file-input" type="file" accept="image/*" v-on:change="uploadIcon" ref="iconInput">
|
||||
<FontAwesomeIcon :icon="['fas', 'image']" size="2x" />
|
||||
@ -478,9 +478,9 @@
|
||||
<div class="column quickform-footer">
|
||||
<div class="field is-grouped is-grouped-centered">
|
||||
<div class="control">
|
||||
<VueButton :isLoading="form.isBusy" >{{ $t('commons.save') }}</VueButton>
|
||||
<VueButton nativeType="submit" :isLoading="form.isBusy" >{{ $t('commons.save') }}</VueButton>
|
||||
</div>
|
||||
<ButtonBackCloseCancel action="cancel" :isText="true" :isRounded="false" :useLinkTag="false" @canceled="cancelCreation" />
|
||||
<NavigationButton action="cancel" :isText="true" :isRounded="false" :useLinkTag="false" @canceled="cancelCreation" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -505,11 +505,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<FieldError v-if="qrcodeForm.errors.hasAny('qrcode')" :error="qrcodeForm.errors.get('qrcode')" :field="'qrcode'" class="help-for-file" />
|
||||
<FormFieldError v-if="qrcodeForm.errors.hasAny('qrcode')" :error="qrcodeForm.errors.get('qrcode')" :field="'qrcode'" class="help-for-file" />
|
||||
<!-- service -->
|
||||
<FormField v-model="form.service" fieldName="service" :fieldError="form.errors.get('email')" :isDisabled="form.otp_type === 'steamtotp'" label="twofaccounts.service" :placeholder="$t('twofaccounts.forms.service.placeholder')" autofocus />
|
||||
<FormField v-model="form.service" fieldName="service" :errorMessage="form.errors.get('email')" :isDisabled="form.otp_type === 'steamtotp'" label="twofaccounts.service" :placeholder="$t('twofaccounts.forms.service.placeholder')" autofocus />
|
||||
<!-- account -->
|
||||
<FormField v-model="form.account" fieldName="account" :fieldError="form.errors.get('account')" label="twofaccounts.account" :placeholder="$t('twofaccounts.forms.account.placeholder')" />
|
||||
<FormField v-model="form.account" fieldName="account" :errorMessage="form.errors.get('account')" label="twofaccounts.account" :placeholder="$t('twofaccounts.forms.account.placeholder')" />
|
||||
<!-- icon upload -->
|
||||
<label for="filUploadIcon" class="label">{{ $t('twofaccounts.icon') }}</label>
|
||||
<!-- try my luck -->
|
||||
@ -538,7 +538,7 @@
|
||||
<div class="field is-grouped">
|
||||
<!-- try my luck button -->
|
||||
<div class="control">
|
||||
<VueButton @click="fetchLogo" :color="mode == 'dark' ? 'is-dark' : ''" :nativeType="'button'" :is-loading="fetchingLogo" :disabled="!form.service" aria-describedby="lgdTryMyLuck">
|
||||
<VueButton @click="fetchLogo" :color="mode == 'dark' ? 'is-dark' : ''" nativeType="button" :is-loading="fetchingLogo" :disabled="!form.service" aria-describedby="lgdTryMyLuck">
|
||||
<span class="icon is-small">
|
||||
<FontAwesomeIcon :icon="['fas', 'globe']" />
|
||||
</span>
|
||||
@ -565,16 +565,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<FieldError v-if="iconForm.errors.hasAny('icon')" :error="iconForm.errors.get('icon')" :field="'icon'" class="help-for-file" />
|
||||
<FormFieldError v-if="iconForm.errors.hasAny('icon')" :error="iconForm.errors.get('icon')" :field="'icon'" class="help-for-file" />
|
||||
<p id="lgdTryMyLuck" v-if="user.preferences.getOfficialIcons" class="help" v-html="$t('twofaccounts.forms.i_m_lucky_legend')"></p>
|
||||
</div>
|
||||
<!-- group -->
|
||||
<FormSelect v-if="groups.length > 0" v-model="form.group_id" :options="groups" fieldName="group_id" label="twofaccounts.forms.group.label" help="twofaccounts.forms.group.help" />
|
||||
<!-- otp type -->
|
||||
<FormToggle v-model="form.otp_type" :isDisabled="isEditMode" :choices="otp_types" fieldName="otp_type" :fieldError="form.errors.get('otp_type')" label="twofaccounts.forms.otp_type.label" help="twofaccounts.forms.otp_type.help" :hasOffset="true" />
|
||||
<FormToggle v-model="form.otp_type" :isDisabled="isEditMode" :choices="otp_types" fieldName="otp_type" :errorMessage="form.errors.get('otp_type')" label="twofaccounts.forms.otp_type.label" help="twofaccounts.forms.otp_type.help" :hasOffset="true" />
|
||||
<div v-if="form.otp_type != ''">
|
||||
<!-- secret -->
|
||||
<FormLockField :isEditMode="isEditMode" v-model.trimAll="form.secret" fieldName="secret" :fieldError="form.errors.get('secret')" label="twofaccounts.forms.secret.label" help="twofaccounts.forms.secret.help" />
|
||||
<FormProtectedField :enableProtection="isEditMode" v-model.trimAll="form.secret" fieldName="secret" :errorMessage="form.errors.get('secret')" label="twofaccounts.forms.secret.label" help="twofaccounts.forms.secret.help" />
|
||||
<!-- Options -->
|
||||
<div v-if="form.otp_type !== 'steamtotp'">
|
||||
<h2 class="title is-4 mt-5 mb-2">{{ $t('commons.options') }}</h2>
|
||||
@ -582,23 +582,23 @@
|
||||
{{ $t('twofaccounts.forms.options_help') }}
|
||||
</p>
|
||||
<!-- digits -->
|
||||
<FormToggle v-model="form.digits" :choices="digitsChoices" fieldName="digits" :fieldError="form.errors.get('digits')" label="twofaccounts.forms.digits.label" help="twofaccounts.forms.digits.help" />
|
||||
<FormToggle v-model="form.digits" :choices="digitsChoices" fieldName="digits" :errorMessage="form.errors.get('digits')" label="twofaccounts.forms.digits.label" help="twofaccounts.forms.digits.help" />
|
||||
<!-- algorithm -->
|
||||
<FormToggle v-model="form.algorithm" :choices="algorithms" fieldName="algorithm" :fieldError="form.errors.get('algorithm')" label="twofaccounts.forms.algorithm.label" help="twofaccounts.forms.algorithm.help" />
|
||||
<FormToggle v-model="form.algorithm" :choices="algorithms" fieldName="algorithm" :errorMessage="form.errors.get('algorithm')" label="twofaccounts.forms.algorithm.label" help="twofaccounts.forms.algorithm.help" />
|
||||
<!-- TOTP period -->
|
||||
<FormField v-if="form.otp_type === 'totp'" pattern="[0-9]{1,4}" :class="'is-third-width-field'" v-model="form.period" fieldName="period" :fieldError="form.errors.get('period')" label="twofaccounts.forms.period.label" help="twofaccounts.forms.period.help" :placeholder="$t('twofaccounts.forms.period.placeholder')" />
|
||||
<FormField v-if="form.otp_type === 'totp'" pattern="[0-9]{1,4}" :class="'is-third-width-field'" v-model="form.period" fieldName="period" :errorMessage="form.errors.get('period')" label="twofaccounts.forms.period.label" help="twofaccounts.forms.period.help" :placeholder="$t('twofaccounts.forms.period.placeholder')" />
|
||||
<!-- HOTP counter -->
|
||||
<FormLockField v-if="form.otp_type === 'hotp'" pattern="[0-9]{1,4}" :isEditMode="isEditMode" :isExpanded="false" v-model="form.counter" fieldName="counter" :fieldError="form.errors.get('counter')" label="twofaccounts.forms.counter.label" :placeholder="$t('twofaccounts.forms.counter.placeholder')" :help="isEditMode ? 'twofaccounts.forms.counter.help_lock' : 'twofaccounts.forms.counter.help'" />
|
||||
<FormProtectedField v-if="form.otp_type === 'hotp'" pattern="[0-9]{1,4}" :enableProtection="isEditMode" :isExpanded="false" v-model="form.counter" fieldName="counter" :errorMessage="form.errors.get('counter')" label="twofaccounts.forms.counter.label" :placeholder="$t('twofaccounts.forms.counter.placeholder')" :help="isEditMode ? 'twofaccounts.forms.counter.help_lock' : 'twofaccounts.forms.counter.help'" />
|
||||
</div>
|
||||
</div>
|
||||
<VueFooter :showButtons="true">
|
||||
<p class="control">
|
||||
<VueButton :id="isEditMode ? 'btnUpdate' : 'btnCreate'" :isLoading="form.isBusy" class="is-rounded" >{{ isEditMode ? $t('commons.save') : $t('commons.create') }}</VueButton>
|
||||
<VueButton nativeType="submit" :id="isEditMode ? 'btnUpdate' : 'btnCreate'" :isLoading="form.isBusy" class="is-rounded" >{{ isEditMode ? $t('commons.save') : $t('commons.create') }}</VueButton>
|
||||
</p>
|
||||
<p class="control" v-if="form.otp_type && form.secret">
|
||||
<button id="btnPreview" type="button" class="button is-success is-rounded" @click="previewOTP">{{ $t('twofaccounts.forms.test') }}</button>
|
||||
</p>
|
||||
<ButtonBackCloseCancel action="cancel" :useLinkTag="false" @canceled="cancelCreation" />
|
||||
<NavigationButton action="cancel" :useLinkTag="false" @canceled="cancelCreation" />
|
||||
</VueFooter>
|
||||
</form>
|
||||
<!-- modal -->
|
||||
|
@ -1,9 +1,9 @@
|
||||
<script setup>
|
||||
import Form from '@/components/formElements/Form'
|
||||
import FormTextarea from '@/components/formElements/FormTextarea.vue'
|
||||
import twofaccountService from '@/services/twofaccountService'
|
||||
import OtpDisplay from '@/components/OtpDisplay.vue'
|
||||
import Spinner from '@/components/Spinner.vue'
|
||||
import { FormTextarea } from '@2fauth/formcontrols'
|
||||
import { useNotifyStore } from '@/stores/notify'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useBusStore } from '@/stores/bus'
|
||||
@ -271,7 +271,7 @@
|
||||
<p class="subtitle is-6 is-size-7-mobile">{{ $t('twofaccounts.import.supported_formats_for_qrcode_upload') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<FieldError v-if="qrcodeForm.errors.hasAny('qrcode')" :error="qrcodeForm.errors.get('qrcode')" :field="'qrcode'" />
|
||||
<FormFieldError v-if="qrcodeForm.errors.hasAny('qrcode')" :error="qrcodeForm.errors.get('qrcode')" :field="'qrcode'" />
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<RouterLink id="btnCapture" :to="{ name: 'capture' }" class="card-footer-item">
|
||||
@ -298,7 +298,7 @@
|
||||
<p class="subtitle is-6 is-size-7-mobile">{{ $t('twofaccounts.import.supported_formats_for_file_upload') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<FieldError v-if="fileForm.errors.hasAny('file')" :error="fileForm.errors.get('file')" :field="'file'" />
|
||||
<FormFieldError v-if="fileForm.errors.hasAny('file')" :error="fileForm.errors.get('file')" :field="'file'" />
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a role="button" tabindex="0" class="card-footer-item is-relative" @click="fileInput.click()" @keyup.enter="fileInput.click()">
|
||||
@ -323,7 +323,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<FormTextarea v-model="directInput" :fieldError="directInputError" fieldName="payload" rows="5" :size="'is-small'" />
|
||||
<FormTextarea v-model="directInput" :errorMessage="directInputError" fieldName="payload" rows="5" :size="'is-small'" />
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
@ -458,7 +458,8 @@
|
||||
</span> -->
|
||||
</button>
|
||||
</p>
|
||||
<ButtonBackCloseCancel :returnTo="{ name: 'accounts' }" :action="importableCount > 0 ? 'cancel' : 'close'" />
|
||||
<NavigationButton v-if="importableCount > 0" action="cancel" @canceled="router.push({ name: 'accounts' })" />
|
||||
<NavigationButton v-else action="close" @closed="router.push({ name: 'accounts' })" :current-page-title="$t('title.importAccounts')" />
|
||||
</VueFooter>
|
||||
</ResponsiveWidthWrapper>
|
||||
<!-- modal -->
|
||||
|
@ -29,7 +29,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<VueFooter :showButtons="true" :internalFooterType="'modal'">
|
||||
<ButtonBackCloseCancel :returnTo="{ name: 'accounts' }" action="close" />
|
||||
<NavigationButton action="close" @closed="router.push({ name: 'accounts' })" :current-page-title="$t('title.showQRcode')" />
|
||||
</VueFooter>
|
||||
</div>
|
||||
</template>
|
@ -194,6 +194,7 @@
|
||||
"test.info": "This is an info",
|
||||
"test.success": "This is a success",
|
||||
"test.warn": "This is a warn",
|
||||
|
||||
"title.about": "About",
|
||||
"title.landing": "Landing",
|
||||
"title.options": "Options",
|
||||
@ -201,10 +202,42 @@
|
||||
"title.reset_extension": "Reset extension",
|
||||
"title.settings": "Settings",
|
||||
"title.setup": "Setup",
|
||||
"title.start": "Start",
|
||||
"title.twofauth_webext": "2FAuth webext",
|
||||
"title.unauthorized": "Unauthorized",
|
||||
"title.unlock": "Unlock",
|
||||
"title.start": "New account",
|
||||
"title.capture": "Flash QR",
|
||||
"title.accounts": "Accounts",
|
||||
"title.createAccount": "Create account",
|
||||
"title.importAccounts": "Import accounts",
|
||||
"title.editAccount": "Account edit",
|
||||
"title.showQRcode": "Account as QR code",
|
||||
"title.groups": "Groups",
|
||||
"title.createGroup": "Create group",
|
||||
"title.editGroup": "Group edit",
|
||||
"title.settings.options": "Options",
|
||||
"title.settings.account": "User account",
|
||||
"title.settings.oauth.tokens": "OAuth tokens",
|
||||
"title.settings.oauth.generatePAT": "New personal token",
|
||||
"title.settings.webauthn.editCredential": "Device edit",
|
||||
"title.settings.webauthn.devices": "WebAuthn devices",
|
||||
"title.login": "Login",
|
||||
"title.register": "Register",
|
||||
"title.autolock": "Auto lock",
|
||||
"title.password.request": "Reset password",
|
||||
"title.password.reset": "New password",
|
||||
"title.webauthn.lost": "Account recovery",
|
||||
"title.webauthn.recover": "Register a new device",
|
||||
"title.flooded": "Flood",
|
||||
"title.genericError": "Error",
|
||||
"title.404": "Item not found",
|
||||
"title.admin.appSetup": "App setup",
|
||||
"title.admin.auth": "Authentication",
|
||||
"title.admin.users": "Users management",
|
||||
"title.admin.createUser": "Create user",
|
||||
"title.admin.manageUser": "Manage user",
|
||||
"title.admin.logs.access": "Access log",
|
||||
|
||||
"tooltip.hide_password": "Hide password",
|
||||
"tooltip.lock": "Lock it",
|
||||
"tooltip.reveal_password": "Reveal password",
|
||||
|
Loading…
x
Reference in New Issue
Block a user