mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
Merge branch 'dev' into uniformize-actionmap-api
This commit is contained in:
commit
e15956c3fe
11 changed files with 140 additions and 28 deletions
|
@ -7,8 +7,8 @@ import i18n from '@/i18n'
|
|||
|
||||
|
||||
class APIError extends Error {
|
||||
constructor (request, { url, status, statusText }, errorData) {
|
||||
super(errorData.error || i18n.t('error_server_unexpected'))
|
||||
constructor (request, { url, status, statusText }, { error }) {
|
||||
super(error ? error.replace('\n', '<br>') : i18n.t('error_server_unexpected'))
|
||||
const urlObj = new URL(url)
|
||||
this.name = 'APIError'
|
||||
this.code = status
|
||||
|
@ -47,6 +47,7 @@ class APIBadRequestError extends APIError {
|
|||
constructor (method, response, errorData) {
|
||||
super(method, response, errorData)
|
||||
this.name = 'APIBadRequestError'
|
||||
this.key = errorData.error_key
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,10 @@
|
|||
<slot name="default" />
|
||||
|
||||
<slot name="server-error">
|
||||
<b-alert variant="danger" :show="serverError !== ''" v-html="serverError" />
|
||||
<b-alert
|
||||
variant="danger" class="my-3"
|
||||
:show="serverError !== ''" v-html="serverError"
|
||||
/>
|
||||
</slot>
|
||||
</b-form>
|
||||
</template>
|
||||
|
|
|
@ -315,6 +315,9 @@
|
|||
"permission_show_tile_enabled": "Visible as tile in user portal",
|
||||
"port": "Port",
|
||||
"ports": "Ports",
|
||||
"postinstall": {
|
||||
"force": "Force the post-install"
|
||||
},
|
||||
"postinstall_domain": "This is the first domain name linked to your YunoHost server, but also the one which will be used by your server's users to access the authentication portal. Accordingly, it will be visible by everyone, so choose it carefully.",
|
||||
"postinstall_intro_1": "Congratulations! YunoHost has been successfully installed.",
|
||||
"postinstall_intro_2": "Two more configuration steps are required to activate you server's services.",
|
||||
|
|
|
@ -150,11 +150,15 @@ export default {
|
|||
'END_REQUEST' ({ commit }, { request, success, wait }) {
|
||||
let status = success ? 'success' : 'error'
|
||||
if (success && (request.warnings || request.errors)) {
|
||||
const messages = request.messages
|
||||
if (messages.length && messages[messages.length - 1].color === 'warning') {
|
||||
request.showWarningMessage = true
|
||||
}
|
||||
status = 'warning'
|
||||
}
|
||||
|
||||
commit('UPDATE_REQUEST', { request, key: 'status', value: status })
|
||||
if (wait) {
|
||||
if (wait && !request.showWarningMessage) {
|
||||
// Remove the overlay after a short delay to allow an error to display withtout flickering.
|
||||
setTimeout(() => {
|
||||
commit('SET_WAITING', false)
|
||||
|
@ -219,6 +223,11 @@ export default {
|
|||
}
|
||||
}
|
||||
commit('SET_ERROR', null)
|
||||
},
|
||||
|
||||
'DISMISS_WARNING' ({ commit, state }, request) {
|
||||
commit('SET_WAITING', false)
|
||||
delete request.showWarningMessage
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -32,9 +32,13 @@
|
|||
export default {
|
||||
name: 'Login',
|
||||
|
||||
props: {
|
||||
skipInstallCheck: { type: Boolean, default: false }
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
disabled: true,
|
||||
disabled: !this.skipInstallCheck,
|
||||
password: '',
|
||||
isValid: null,
|
||||
apiError: undefined
|
||||
|
@ -51,6 +55,7 @@ export default {
|
|||
},
|
||||
|
||||
created () {
|
||||
if (this.skipInstallCheck) return
|
||||
this.$store.dispatch('CHECK_INSTALL').then(installed => {
|
||||
if (installed) {
|
||||
this.disabled = false
|
||||
|
|
|
@ -12,43 +12,63 @@
|
|||
<span v-html="$t('postinstall_intro_3')" />
|
||||
</p>
|
||||
|
||||
<b-button size="lg" variant="primary" @click="step = 'domain'">
|
||||
<b-button size="lg" variant="primary" @click="goToStep('domain')">
|
||||
{{ $t('begin') }}
|
||||
</b-button>
|
||||
</template>
|
||||
|
||||
<!-- DOMAIN SETUP STEP -->
|
||||
<template v-else-if="step === 'domain'">
|
||||
<domain-form @submit="setDomain" :title="$t('postinstall_set_domain')" :submit-text="$t('next')">
|
||||
<domain-form
|
||||
:title="$t('postinstall_set_domain')" :submit-text="$t('next')" :server-error="serverError"
|
||||
@submit="setDomain"
|
||||
>
|
||||
<template #disclaimer>
|
||||
<p class="alert alert-info" v-t="'postinstall_domain'" />
|
||||
</template>
|
||||
</domain-form>
|
||||
|
||||
<b-button variant="primary" @click="step = 'start'" class="mt-3">
|
||||
<b-button variant="primary" @click="goToStep('start')" class="mt-3">
|
||||
<icon iname="chevron-left" /> {{ $t('previous') }}
|
||||
</b-button>
|
||||
</template>
|
||||
|
||||
<!-- PASSWORD SETUP STEP -->
|
||||
<template v-else-if="step === 'password'">
|
||||
<password-form :title="$t('postinstall_set_password')" :submit-text="$t('next')" @submit="setPassword">
|
||||
<password-form
|
||||
:title="$t('postinstall_set_password')" :submit-text="$t('next')" :server-error="serverError"
|
||||
@submit="setPassword"
|
||||
>
|
||||
<template #disclaimer>
|
||||
<p class="alert alert-warning" v-t="'postinstall_password'" />
|
||||
</template>
|
||||
</password-form>
|
||||
|
||||
<b-button variant="primary" @click="step = 'domain'" class="mt-3">
|
||||
<b-button variant="primary" @click="goToStep('domain')" class="mt-3">
|
||||
<icon iname="chevron-left" /> {{ $t('previous') }}
|
||||
</b-button>
|
||||
</template>
|
||||
|
||||
<template v-else-if="step === 'rootfsspace-error'">
|
||||
<card no-body header-class="d-none" footer-bg-variant="danger">
|
||||
<b-card-body class="alert alert-danger m-0">
|
||||
{{ serverError }}
|
||||
</b-card-body>
|
||||
|
||||
<template #buttons>
|
||||
<b-button variant="light" size="sm" @click="performPostInstall(true)">
|
||||
<icon iname="warning" /> {{ $t('postinstall.force') }}
|
||||
</b-button>
|
||||
</template>
|
||||
</card>
|
||||
</template>
|
||||
|
||||
<!-- POST-INSTALL SUCCESS STEP -->
|
||||
<template v-else-if="step === 'login'">
|
||||
<p class="alert alert-success">
|
||||
<icon iname="thumbs-up" /> {{ $t('installation_complete') }}
|
||||
</p>
|
||||
<login />
|
||||
<login skip-install-check />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -71,14 +91,20 @@ export default {
|
|||
return {
|
||||
step: 'start',
|
||||
domain: undefined,
|
||||
password: undefined
|
||||
password: undefined,
|
||||
serverError: ''
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
goToStep (step) {
|
||||
this.serverError = ''
|
||||
this.step = step
|
||||
},
|
||||
|
||||
setDomain ({ domain }) {
|
||||
this.domain = domain
|
||||
this.step = 'password'
|
||||
this.goToStep('password')
|
||||
},
|
||||
|
||||
async setPassword ({ password }) {
|
||||
|
@ -90,12 +116,23 @@ export default {
|
|||
this.performPostInstall()
|
||||
},
|
||||
|
||||
performPostInstall () {
|
||||
performPostInstall (force = false) {
|
||||
// FIXME does the api will throw an error for bad passwords ?
|
||||
const { domain, password } = this
|
||||
api.post('postinstall', { domain, password }, 'postinstall').then(() => {
|
||||
api.post('postinstall' + (force ? '?force_diskspace' : ''), { domain: this.domain, password: this.password }).then(data => {
|
||||
// Display success message and allow the user to login
|
||||
this.step = 'login'
|
||||
this.goToStep('login')
|
||||
}).catch(err => {
|
||||
if (err.name !== 'APIBadRequestError') throw err
|
||||
if (err.key === 'postinstall_low_rootfsspace') {
|
||||
this.step = 'rootfsspace-error'
|
||||
} else if (err.key.includes('password')) {
|
||||
this.step = 'password'
|
||||
} else if (['domain', 'dyndns'].some(word => err.key.includes(word))) {
|
||||
this.step = 'domain'
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
this.serverError = err.message
|
||||
})
|
||||
}
|
||||
},
|
||||
|
|
|
@ -61,9 +61,7 @@ export default {
|
|||
props: {
|
||||
title: { type: String, required: true },
|
||||
submitText: { type: String, default: null },
|
||||
serverError: { type: String, default: '' },
|
||||
// Do not query the api (used by postinstall)
|
||||
noStore: { type: Boolean, default: false }
|
||||
serverError: { type: String, default: '' }
|
||||
},
|
||||
|
||||
data () {
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
<query-header :request="error || currentRequest" status-size="lg" />
|
||||
</b-card-header>
|
||||
|
||||
<component v-if="error" :is="'ErrorDisplay'" :request="error" />
|
||||
<component v-else :is="'WaitingDisplay'" :request="currentRequest" />
|
||||
<component :is="component.name" :request="component.request" />
|
||||
</b-card>
|
||||
</template>
|
||||
</b-overlay>
|
||||
|
@ -21,7 +20,7 @@
|
|||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { ErrorDisplay, WaitingDisplay } from '@/views/_partials'
|
||||
import { ErrorDisplay, WarningDisplay, WaitingDisplay } from '@/views/_partials'
|
||||
import QueryHeader from '@/components/QueryHeader'
|
||||
|
||||
export default {
|
||||
|
@ -29,16 +28,30 @@ export default {
|
|||
|
||||
components: {
|
||||
ErrorDisplay,
|
||||
WarningDisplay,
|
||||
WaitingDisplay,
|
||||
QueryHeader
|
||||
},
|
||||
|
||||
computed: mapGetters(['waiting', 'error', 'currentRequest'])
|
||||
computed: {
|
||||
...mapGetters(['waiting', 'error', 'currentRequest']),
|
||||
|
||||
component () {
|
||||
const { error, currentRequest: request } = this
|
||||
if (error) {
|
||||
return { name: 'ErrorDisplay', request: error }
|
||||
} else if (request.showWarningMessage) {
|
||||
return { name: 'WarningDisplay', request }
|
||||
} else {
|
||||
return { name: 'WaitingDisplay', request }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// Style for `ErrorDisplay` and `WaitingDisplay`'s cards
|
||||
// Style for `*Display`'s cards
|
||||
.card-overlay {
|
||||
position: sticky;
|
||||
top: 10vh;
|
||||
|
|
43
app/src/views/_partials/WarningDisplay.vue
Normal file
43
app/src/views/_partials/WarningDisplay.vue
Normal file
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<!-- This card receives style from `ViewLockOverlay` if used inside it -->
|
||||
<div>
|
||||
<b-card-body body-class="alert alert-warning" v-html="warning.text" />
|
||||
|
||||
<b-card-footer footer-bg-variant="warning">
|
||||
<b-button
|
||||
variant="light" size="sm"
|
||||
v-t="'ok'" @click="dismiss"
|
||||
/>
|
||||
</b-card-footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'WarningDisplay',
|
||||
|
||||
props: {
|
||||
request: { type: Object, required: true }
|
||||
},
|
||||
|
||||
computed: {
|
||||
warning () {
|
||||
const messages = this.request.messages
|
||||
return messages[messages.length - 1]
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
dismiss () {
|
||||
this.$store.dispatch('DISMISS_WARNING', this.request)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-body {
|
||||
padding-bottom: 1.5rem !important;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
|
@ -1,4 +1,5 @@
|
|||
export { default as ErrorDisplay } from './ErrorDisplay'
|
||||
export { default as WarningDisplay } from './WarningDisplay'
|
||||
export { default as WaitingDisplay } from './WaitingDisplay'
|
||||
|
||||
export { default as HistoryConsole } from './HistoryConsole'
|
||||
|
|
|
@ -121,7 +121,7 @@ export default {
|
|||
}
|
||||
// Check that every migration's disclaimer has been checked.
|
||||
if (Object.values(this.checked).every(value => value === true)) {
|
||||
api.put('migrations', { accept_disclaimer: true }, 'migrations.run').then(() => {
|
||||
api.post('migrations/run?accept_disclaimer', 'migrations.run').then(() => {
|
||||
this.$refs.view.fetchQueries()
|
||||
})
|
||||
}
|
||||
|
@ -130,8 +130,7 @@ export default {
|
|||
async skipMigration (id) {
|
||||
const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_migrations_skip'))
|
||||
if (!confirmed) return
|
||||
|
||||
api.put('migrations/' + id, { skip: '' }, 'migration.skip').then(() => {
|
||||
api.post('/migrations/run', { skip: '', targets: id }, 'migration.skip').then(() => {
|
||||
this.$refs.view.fetchQueries()
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue