Merge pull request #552 from YunoHost/misc-fixes

Misc fixes
This commit is contained in:
Alexandre Aubin 2024-03-02 17:47:22 +01:00 committed by GitHub
commit f81008c150
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 63 additions and 53 deletions

View file

@ -18,7 +18,7 @@
<b-navbar-nav class="ml-auto"> <b-navbar-nav class="ml-auto">
<li class="nav-item"> <li class="nav-item">
<b-button <b-button
href="/yunohost/sso" :href="ssoLink"
variant="primary" size="sm" block variant="primary" size="sm" block
> >
{{ $t('user_interface_link') }} <icon iname="user" /> {{ $t('user_interface_link') }} <icon iname="user" />
@ -100,7 +100,8 @@ export default {
'transitions', 'transitions',
'transitionName', 'transitionName',
'waiting', 'waiting',
'theme' 'theme',
'ssoLink'
]) ])
}, },
@ -112,13 +113,7 @@ export default {
// This hook is only triggered at page first load // This hook is only triggered at page first load
created () { created () {
// From this hook the value of `connected` always come from the localStorage. this.$store.dispatch('ON_APP_CREATED')
// This state may be `true` but session may have expired, by querying
// yunohost infos, api may respond with `Unauthorized` in which case the `connected`
// state will be automaticly reseted and user will be prompt with the login view.
if (this.connected) {
this.$store.dispatch('GET_YUNOHOST_INFOS')
}
}, },
mounted () { mounted () {

View file

@ -79,16 +79,19 @@ export function adressToFormValue (address) {
* @param {Object} forms - A nested form used in config panels. * @param {Object} forms - A nested form used in config panels.
* @return {Boolean} - expression evaluation result. * @return {Boolean} - expression evaluation result.
*/ */
export function evaluateExpression (expression, forms) { export function evaluateExpression (expression, form, nested = true) {
if (!expression) return true if (!expression) return true
if (expression === '"false"') return false if (expression === '"false"') return false
const context = Object.values(forms).reduce((ctx, args) => { const context = nested
Object.entries(args).forEach(([id, value]) => { ? Object.values(form).reduce((merged, next) => ({ ...merged, ...next }))
ctx[id] = isObjectLiteral(value) && 'file' in value ? value.content : value : form
})
return ctx for (const key in context) {
}, {}) if (isObjectLiteral(context[key]) && 'file' in context[key]) {
context[key] = context[key].content
}
}
// Allow to use match(var,regexp) function // Allow to use match(var,regexp) function
const matchRe = /match(\s*(\w+)\s*,\s*"([^"]+)"\s*)/g const matchRe = /match(\s*(\w+)\s*,\s*"([^"]+)"\s*)/g
@ -107,9 +110,9 @@ export function evaluateExpression (expression, forms) {
} }
// Adds a property to an Object that will dynamically returns a expression evaluation result. // Adds a property to an Object that will dynamically returns a expression evaluation result.
function addEvaluationGetter (prop, obj, expr, ctx) { function addEvaluationGetter (prop, obj, expr, ctx, nested) {
Object.defineProperty(obj, prop, { Object.defineProperty(obj, prop, {
get: () => evaluateExpression(expr, ctx) get: () => evaluateExpression(expr, ctx, nested)
}) })
} }
@ -357,12 +360,12 @@ export function formatYunoHostArguments (args, forms) {
if (validation) validations[arg.id] = validation if (validation) validations[arg.id] = validation
errors[arg.id] = error errors[arg.id] = error
if ('visible' in arg && ![false, '"false"'].includes(arg.visible)) { if ('visible' in arg && typeof arg.visible === 'string') {
addEvaluationGetter('visible', field, arg.visible, forms) addEvaluationGetter('visible', field, arg.visible, forms || form, forms !== undefined)
} }
if ('enabled' in arg) { if ('enabled' in arg && typeof arg.enabled === 'string') {
addEvaluationGetter('enabled', field.props, arg.enabled, forms) addEvaluationGetter('enabled', field.props, arg.enabled, forms || form, forms !== undefined)
} }
} }

View file

@ -35,6 +35,10 @@ router.beforeEach((to, from, next) => {
if (store.getters.error) { if (store.getters.error) {
store.dispatch('DISMISS_ERROR', true) store.dispatch('DISMISS_ERROR', true)
} }
if (to.name === 'post-install' && store.getters.installed) {
return next('/')
}
// Allow if connected or route is not protected // Allow if connected or route is not protected
if (store.getters.connected || to.meta.noAuth) { if (store.getters.connected || to.meta.noAuth) {
next() next()

View file

@ -7,6 +7,7 @@ import { timeout, isEmptyValue, isObjectLiteral } from '@/helpers/commons'
export default { export default {
state: { state: {
host: window.location.host, // String host: window.location.host, // String
installed: null,
connected: localStorage.getItem('connected') === 'true', // Boolean connected: localStorage.getItem('connected') === 'true', // Boolean
yunohost: null, // Object { version, repo } yunohost: null, // Object { version, repo }
waiting: false, // Boolean waiting: false, // Boolean
@ -22,6 +23,10 @@ export default {
}, },
mutations: { mutations: {
'SET_INSTALLED' (state, boolean) {
state.installed = boolean
},
'SET_CONNECTED' (state, boolean) { 'SET_CONNECTED' (state, boolean) {
localStorage.setItem('connected', boolean) localStorage.setItem('connected', boolean)
state.connected = boolean state.connected = boolean
@ -106,23 +111,38 @@ export default {
}, },
actions: { actions: {
'CHECK_INSTALL' ({ dispatch }, retry = 2) { async 'ON_APP_CREATED' ({ dispatch, state }) {
await dispatch('CHECK_INSTALL')
if (!state.installed) {
router.push({ name: 'post-install' })
} else {
dispatch('CONNECT')
}
},
async 'CHECK_INSTALL' ({ dispatch, commit }, retry = 2) {
// this action will try to query the `/installed` route 3 times every 5 s with // this action will try to query the `/installed` route 3 times every 5 s with
// a timeout of the same delay. // a timeout of the same delay.
// FIXME need testing with api not responding // FIXME need testing with api not responding
return timeout(api.get('installed'), 5000).then(({ installed }) => { try {
const { installed } = await timeout(api.get('installed'), 5000)
commit('SET_INSTALLED', installed)
return installed return installed
}).catch(err => { } catch (err) {
if (retry > 0) { if (retry > 0) {
return dispatch('CHECK_INSTALL', --retry) return dispatch('CHECK_INSTALL', --retry)
} }
throw err throw err
}) }
}, },
'CONNECT' ({ commit, dispatch }) { async 'CONNECT' ({ commit, dispatch }) {
// If the user is not connected, the first action will throw
// and login prompt will be shown automaticly
await dispatch('GET_YUNOHOST_INFOS')
commit('SET_CONNECTED', true) commit('SET_CONNECTED', true)
dispatch('GET_YUNOHOST_INFOS') await dispatch('GET', { uri: 'domains', storeKey: 'domains' })
}, },
'RESET_CONNECTED' ({ commit }) { 'RESET_CONNECTED' ({ commit }) {
@ -350,6 +370,7 @@ export default {
getters: { getters: {
host: state => state.host, host: state => state.host,
installed: state => state.installed,
connected: state => state.connected, connected: state => state.connected,
yunohost: state => state.yunohost, yunohost: state => state.yunohost,
error: state => state.error, error: state => state.error,
@ -363,6 +384,9 @@ export default {
}, },
routerKey: state => state.routerKey, routerKey: state => state.routerKey,
breadcrumb: state => state.breadcrumb, breadcrumb: state => state.breadcrumb,
transitionName: state => state.transitionName transitionName: state => state.transitionName,
ssoLink: (state, getters) => {
return `//${getters.mainDomain ?? state.host}/yunohost/sso`
}
} }
} }

View file

@ -13,7 +13,7 @@
<template #buttons> <template #buttons>
<b-button <b-button
type="submit" variant="success" type="submit" variant="success"
:disabled="disabled" form="ynh-form" :disabled="!installed" form="ynh-form"
> >
{{ $t('login') }} {{ $t('login') }}
</b-button> </b-button>
@ -22,6 +22,7 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'
import { validationMixin } from 'vuelidate' import { validationMixin } from 'vuelidate'
import { alphalownumdot_, required, minLength } from '@/helpers/validators' import { alphalownumdot_, required, minLength } from '@/helpers/validators'
@ -31,13 +32,11 @@ export default {
mixins: [validationMixin], mixins: [validationMixin],
props: { props: {
skipInstallCheck: { type: Boolean, default: false },
forceReload: { type: Boolean, default: false } forceReload: { type: Boolean, default: false }
}, },
data () { data () {
return { return {
disabled: !this.skipInstallCheck,
serverError: '', serverError: '',
form: { form: {
username: '', username: '',
@ -63,6 +62,10 @@ export default {
} }
}, },
computed: {
...mapGetters(['installed'])
},
validations () { validations () {
return { return {
form: { form: {
@ -86,17 +89,6 @@ export default {
this.serverError = this.$i18n.t('wrong_password_or_username') this.serverError = this.$i18n.t('wrong_password_or_username')
}) })
} }
},
created () {
if (this.skipInstallCheck) return
this.$store.dispatch('CHECK_INSTALL').then(installed => {
if (installed) {
this.disabled = false
} else {
this.$router.push({ name: 'post-install' })
}
})
} }
} }
</script> </script>

View file

@ -75,7 +75,7 @@
<p class="alert alert-success"> <p class="alert alert-success">
<icon iname="thumbs-up" /> {{ $t('installation_complete') }} <icon iname="thumbs-up" /> {{ $t('installation_complete') }}
</p> </p>
<login skip-install-check /> <login />
</template> </template>
</div> </div>
</template> </template>
@ -201,14 +201,6 @@ export default {
confirmation: { required, passwordMatch: sameAs('password') } confirmation: { required, passwordMatch: sameAs('password') }
} }
} }
},
created () {
this.$store.dispatch('CHECK_INSTALL').then(installed => {
if (installed) {
this.$router.push({ name: 'home' })
}
})
} }
} }
</script> </script>

View file

@ -29,7 +29,7 @@
<template v-if="status === 'success'"> <template v-if="status === 'success'">
<b-alert variant="success" v-t="'api.reconnecting.success'" /> <b-alert variant="success" v-t="'api.reconnecting.success'" />
<login-view skip-install-check force-reload /> <login-view force-reload />
</template> </template>
</b-card-body> </b-card-body>
</template> </template>