migration(bvn): update modals and modal system

This commit is contained in:
axolotle 2024-03-17 16:06:08 +01:00
parent 915023de1d
commit 622e5be061
19 changed files with 146 additions and 69 deletions

View file

@ -53,6 +53,8 @@
</main> </main>
</ViewLockOverlay> </ViewLockOverlay>
<BModalOrchestrator />
<!-- HISTORY CONSOLE --> <!-- HISTORY CONSOLE -->
<HistoryConsole /> <HistoryConsole />

View file

@ -0,0 +1,42 @@
import { h } from 'vue'
import { useModalController, BModal } from 'bootstrap-vue-next'
import { VueShowdown } from 'vue-showdown'
export function useAutoModal() {
const { confirm, show } = useModalController()
return function (
message,
props_,
{ markdown = false, cancelable = true } = {},
) {
const props = {
okTitle: this.$t('ok'),
cancelTitle: this.$t('cancel'),
centered: true,
okOnly: !cancelable,
...(markdown
? { headerBgVariant: 'warning', headerClass: 'text-black' }
: {
hideHeader: true,
bodyBgVariant: 'warning',
bodyClass: ['fw-bold', 'rounded-top', 'text-black'],
}),
...props_,
}
const fn = cancelable ? confirm : show
return fn?.({
props,
component: h(BModal, null, {
default: () =>
markdown
? h(VueShowdown, {
markdown: message,
options: { headerLevelStart: 3 },
})
: message,
}),
})
}
}

View file

@ -29,41 +29,6 @@ app.use(VueShowdownPlugin, {
}, },
}) })
// Ugly wrapper for `$bvModal.msgBoxConfirm` to set default i18n button titles
// FIXME find or wait for a better way
app.config.globalProperties.$askConfirmation = function (message, props) {
return this.$bvModal.msgBoxConfirm(message, {
okTitle: this.$t('ok'),
cancelTitle: this.$t('cancel'),
bodyBgVariant: 'warning',
centered: true,
bodyClass: [
'font-weight-bold',
'rounded-top',
store.state.dark ? 'text-white' : 'text-black',
],
...props,
})
}
app.config.globalProperties.$askMdConfirmation = function (
markdown,
props,
ok = false,
) {
const content = this.$createElement('vue-showdown', {
props: { markdown, flavor: 'github', options: { headerLevelStart: 4 } },
})
return this.$bvModal['msgBox' + (ok ? 'Ok' : 'Confirm')](content, {
okTitle: this.$t('yes'),
cancelTitle: this.$t('cancel'),
headerBgVariant: 'warning',
headerClass: store.state.dark ? 'text-white' : 'text-black',
centered: true,
...props,
})
}
// Register global components // Register global components
const globalComponentsModules = import.meta.glob( const globalComponentsModules = import.meta.glob(
['@/components/globals/*.vue', '@/components/globals/*/*.vue'], ['@/components/globals/*.vue', '@/components/globals/*/*.vue'],

View file

@ -45,7 +45,9 @@
// Utilities // Utilities
@import '~bootstrap/scss/utilities/api'; @import '~bootstrap/scss/utilities/api';
@import '~bootstrap-vue-next/src/styles/styles.scss'; // @import '~bootstrap-vue-next/src/styles/styles.scss';
// FIXME modals doesn't appears if we import the scss
@import 'bootstrap-vue-next/dist/bootstrap-vue-next.css';
// Import fonts // Import fonts
@import 'font'; @import 'font';

View file

@ -92,6 +92,7 @@
import { useVuelidate } from '@vuelidate/core' import { useVuelidate } from '@vuelidate/core'
import api from '@/api' import api from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
import { DomainForm } from '@/views/_partials' import { DomainForm } from '@/views/_partials'
import LoginView from '@/views/LoginView.vue' import LoginView from '@/views/LoginView.vue'
import { formatFormData } from '@/helpers/yunohostArguments' import { formatFormData } from '@/helpers/yunohostArguments'
@ -114,6 +115,7 @@ export default {
setup() { setup() {
return { return {
v$: useVuelidate(), v$: useVuelidate(),
modalConfirm: useAutoModal(),
} }
}, },
@ -179,7 +181,7 @@ export default {
}, },
async setUser() { async setUser() {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_postinstall', { domain: this.domain }), this.$t('confirm_postinstall', { domain: this.domain }),
) )
if (!confirmed) return if (!confirmed) return

View file

@ -223,6 +223,7 @@
import { useVuelidate } from '@vuelidate/core' import { useVuelidate } from '@vuelidate/core'
import CardDeckFeed from '@/components/CardDeckFeed.vue' import CardDeckFeed from '@/components/CardDeckFeed.vue'
import { useAutoModal } from '@/composables/useAutoModal'
import { required, appRepoUrl } from '@/helpers/validators' import { required, appRepoUrl } from '@/helpers/validators'
import { randint } from '@/helpers/commons' import { randint } from '@/helpers/commons'
@ -243,6 +244,7 @@ export default {
setup() { setup() {
return { return {
v$: useVuelidate(), v$: useVuelidate(),
modalConfirm: useAutoModal(),
} }
}, },
@ -403,7 +405,7 @@ export default {
async onInstallClick(appId) { async onInstallClick(appId) {
const app = this.apps.find((app) => app.id === appId) const app = this.apps.find((app) => app.id === appId)
if (!app.decent_quality) { if (!app.decent_quality) {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_install_app_' + app.state), this.$t('confirm_install_app_' + app.state),
) )
if (!confirmed) return if (!confirmed) return
@ -413,7 +415,7 @@ export default {
// INSTALL CUSTOM APP // INSTALL CUSTOM APP
async onCustomInstallClick() { async onCustomInstallClick() {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_install_custom_app'), this.$t('confirm_install_custom_app'),
) )
if (!confirmed) return if (!confirmed) return

View file

@ -343,8 +343,8 @@
id="uninstall-modal" id="uninstall-modal"
:title="$t('confirm_uninstall', { name: id })" :title="$t('confirm_uninstall', { name: id })"
header-bg-variant="warning" header-bg-variant="warning"
header-class="text-black"
:body-class="{ 'd-none': !app.supports_purge }" :body-class="{ 'd-none': !app.supports_purge }"
body-bg-variant=""
@ok="uninstall" @ok="uninstall"
> >
<BFormGroup v-if="app.supports_purge"> <BFormGroup v-if="app.supports_purge">
@ -366,6 +366,7 @@ import { mapGetters } from 'vuex'
import { useVuelidate } from '@vuelidate/core' import { useVuelidate } from '@vuelidate/core'
import api, { objectToParams } from '@/api' import api, { objectToParams } from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
import { humanPermissionName } from '@/helpers/filters/human' import { humanPermissionName } from '@/helpers/filters/human'
import { helpers, required } from '@/helpers/validators' import { helpers, required } from '@/helpers/validators'
import { isEmptyValue } from '@/helpers/commons' import { isEmptyValue } from '@/helpers/commons'
@ -390,6 +391,7 @@ export default {
setup() { setup() {
return { return {
v$: useVuelidate(), v$: useVuelidate(),
modalConfirm: useAutoModal(),
} }
}, },
@ -646,7 +648,7 @@ export default {
}, },
async changeUrl() { async changeUrl() {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_app_change_url'), this.$t('confirm_app_change_url'),
) )
if (!confirmed) return if (!confirmed) return
@ -662,9 +664,7 @@ export default {
}, },
async setAsDefaultDomain(undo = false) { async setAsDefaultDomain(undo = false) {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(this.$t('confirm_app_default'))
this.$t('confirm_app_default'),
)
if (!confirmed) return if (!confirmed) return
api api

View file

@ -209,6 +209,7 @@
import { useVuelidate } from '@vuelidate/core' import { useVuelidate } from '@vuelidate/core'
import api, { objectToParams } from '@/api' import api, { objectToParams } from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
import { import {
formatYunoHostArguments, formatYunoHostArguments,
formatI18nField, formatI18nField,
@ -230,6 +231,7 @@ export default {
setup() { setup() {
return { return {
v$: useVuelidate(), v$: useVuelidate(),
modalConfirm: useAutoModal(),
} }
}, },
@ -379,7 +381,7 @@ export default {
async performInstall() { async performInstall() {
if ('path' in this.form && this.form.path === '/') { if ('path' in this.form && this.form.path === '/') {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_install_domain_root', { this.$t('confirm_install_domain_root', {
domain: this.form.domain, domain: this.form.domain,
}), }),
@ -405,15 +407,14 @@ export default {
if (postInstall) { if (postInstall) {
const message = const message =
this.$t('app.install.notifs.post.alert') + '\n\n' + postInstall this.$t('app.install.notifs.post.alert') + '\n\n' + postInstall
await this.$askMdConfirmation( await this.modalConfirm(
message, message,
{ {
title: this.$t('app.install.notifs.post.title', { title: this.$t('app.install.notifs.post.title', {
name: this.app.name, name: this.app.name,
}), }),
okTitle: this.$t('ok'),
}, },
true, { markdown: true, cancelable: false },
) )
} }
this.$router.push({ name: 'app-list' }) this.$router.push({ name: 'app-list' })

View file

@ -137,6 +137,7 @@
<script> <script>
import api from '@/api' import api from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
import { readableDate } from '@/helpers/filters/date' import { readableDate } from '@/helpers/filters/date'
import { humanSize } from '@/helpers/filters/human' import { humanSize } from '@/helpers/filters/human'
import { isEmptyValue } from '@/helpers/commons' import { isEmptyValue } from '@/helpers/commons'
@ -149,6 +150,12 @@ export default {
name: { type: String, required: true }, name: { type: String, required: true },
}, },
setup() {
return {
modalConfirm: useAutoModal(),
}
},
data() { data() {
return { return {
queries: [['GET', `backups/${this.name}?with_details`]], queries: [['GET', `backups/${this.name}?with_details`]],
@ -215,7 +222,7 @@ export default {
}, },
async restoreBackup() { async restoreBackup() {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_restore', { name: this.name }), this.$t('confirm_restore', { name: this.name }),
) )
if (!confirmed) return if (!confirmed) return
@ -245,7 +252,7 @@ export default {
}, },
async deleteBackup() { async deleteBackup() {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_delete', { name: this.name }), this.$t('confirm_delete', { name: this.name }),
) )
if (!confirmed) return if (!confirmed) return

View file

@ -145,6 +145,7 @@
<script> <script>
import api from '@/api' import api from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
import { isEmptyValue } from '@/helpers/commons' import { isEmptyValue } from '@/helpers/commons'
export default { export default {
@ -154,6 +155,12 @@ export default {
name: { type: String, required: true }, name: { type: String, required: true },
}, },
setup() {
return {
modalConfirm: useAutoModal(),
}
},
data() { data() {
return { return {
queries: [['GET', `domains/${this.name}/dns/suggest`]], queries: [['GET', `domains/${this.name}/dns/suggest`]],
@ -246,7 +253,7 @@ export default {
async pushDnsChanges() { async pushDnsChanges() {
if (this.force) { if (this.force) {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('domain.dns.push_force_confirm'), this.$t('domain.dns.push_force_confirm'),
) )
if (!confirmed) return if (!confirmed) return

View file

@ -125,8 +125,8 @@
:title="$t('confirm_delete', { name: this.name })" :title="$t('confirm_delete', { name: this.name })"
@ok="deleteDomain" @ok="deleteDomain"
header-bg-variant="warning" header-bg-variant="warning"
body-class="" header-class="text-black"
body-bg-variant="" :body-class="{ 'd-none': !isMainDynDomain }"
> >
<BFormGroup v-if="isMainDynDomain"> <BFormGroup v-if="isMainDynDomain">
<BFormCheckbox v-model="unsubscribeDomainFromDyndns"> <BFormCheckbox v-model="unsubscribeDomainFromDyndns">
@ -141,6 +141,7 @@
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import api, { objectToParams } from '@/api' import api, { objectToParams } from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
import { import {
formatFormData, formatFormData,
formatYunoHostConfigPanels, formatYunoHostConfigPanels,
@ -160,6 +161,12 @@ export default {
name: { type: String, required: true }, name: { type: String, required: true },
}, },
setup() {
return {
modalConfirm: useAutoModal(),
}
},
data() { data() {
return { return {
queries: [ queries: [
@ -279,7 +286,7 @@ export default {
}, },
async setAsDefaultDomain() { async setAsDefaultDomain() {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_change_maindomain'), this.$t('confirm_change_maindomain'),
) )
if (!confirmed) return if (!confirmed) return

View file

@ -134,6 +134,7 @@
<script> <script>
import api from '@/api' import api from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
import { isEmptyValue } from '@/helpers/commons' import { isEmptyValue } from '@/helpers/commons'
import TagsSelectizeItem from '@/components/globals/formItems/TagsSelectizeItem.vue' import TagsSelectizeItem from '@/components/globals/formItems/TagsSelectizeItem.vue'
@ -146,6 +147,12 @@ export default {
TagsSelectizeItem, TagsSelectizeItem,
}, },
setup() {
return {
modalConfirm: useAutoModal(),
}
},
data() { data() {
return { return {
queries: [ queries: [
@ -264,7 +271,7 @@ export default {
async onPermissionChanged({ option, groupName, action, applyMethod }) { async onPermissionChanged({ option, groupName, action, applyMethod }) {
const permId = this.permissions.find((perm) => perm.label === option).id const permId = this.permissions.find((perm) => perm.label === option).id
if (action === 'add' && ['sftp.main', 'ssh.main'].includes(permId)) { if (action === 'add' && ['sftp.main', 'ssh.main'].includes(permId)) {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_group_add_access_permission', { this.$t('confirm_group_add_access_permission', {
name: groupName, name: groupName,
perm: option, perm: option,
@ -310,7 +317,7 @@ export default {
}, },
async deleteGroup(groupName) { async deleteGroup(groupName) {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_delete', { name: groupName }), this.$t('confirm_delete', { name: groupName }),
) )
if (!confirmed) return if (!confirmed) return

View file

@ -83,6 +83,7 @@
<script> <script>
import api from '@/api' import api from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
import { distanceToNow } from '@/helpers/filters/date' import { distanceToNow } from '@/helpers/filters/date'
export default { export default {
@ -92,6 +93,12 @@ export default {
name: { type: String, required: true }, name: { type: String, required: true },
}, },
setup() {
return {
modalConfirm: useAutoModal(),
}
},
data() { data() {
return { return {
queries: [ queries: [
@ -132,7 +139,7 @@ export default {
}, },
async updateService(action) { async updateService(action) {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_service_' + action, { name: this.name }), this.$t('confirm_service_' + action, { name: this.name }),
) )
if (!confirmed) return if (!confirmed) return

View file

@ -121,6 +121,7 @@
import { useVuelidate } from '@vuelidate/core' import { useVuelidate } from '@vuelidate/core'
import api from '@/api' import api from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
import { required, integer, between } from '@/helpers/validators' import { required, integer, between } from '@/helpers/validators'
export default { export default {
@ -129,6 +130,7 @@ export default {
setup() { setup() {
return { return {
v$: useVuelidate(), v$: useVuelidate(),
modalConfirm: useAutoModal(),
} }
}, },
@ -214,7 +216,7 @@ export default {
}, },
async togglePort({ action, port, protocol, connection }) { async togglePort({ action, port, protocol, connection }) {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_firewall_' + action, { this.$t('confirm_firewall_' + action, {
port, port,
protocol, protocol,
@ -244,7 +246,7 @@ export default {
async toggleUpnp(value) { async toggleUpnp(value) {
const action = this.upnpEnabled ? 'disable' : 'enable' const action = this.upnpEnabled ? 'disable' : 'enable'
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_upnp_' + action), this.$t('confirm_upnp_' + action),
) )
if (!confirmed) return if (!confirmed) return

View file

@ -88,11 +88,18 @@
<script> <script>
import api from '@/api' import api from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
// FIXME not tested with pending migrations (disclaimer and stuff) // FIXME not tested with pending migrations (disclaimer and stuff)
export default { export default {
name: 'ToolMigrations', name: 'ToolMigrations',
setup() {
return {
modalConfirm: useAutoModal(),
}
},
data() { data() {
return { return {
queries: [ queries: [
@ -136,7 +143,7 @@ export default {
}, },
async skipMigration(id) { async skipMigration(id) {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_migrations_skip'), this.$t('confirm_migrations_skip'),
) )
if (!confirmed) return if (!confirmed) return

View file

@ -35,13 +35,20 @@
<script> <script>
import api from '@/api' import api from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
export default { export default {
name: 'ToolPower', name: 'ToolPower',
setup() {
return {
modalConfirm: useAutoModal(),
}
},
methods: { methods: {
async triggerAction(action) { async triggerAction(action) {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_reboot_action_' + action), this.$t('confirm_reboot_action_' + action),
) )
if (!confirmed) return if (!confirmed) return

View file

@ -88,10 +88,11 @@
</YCard> </YCard>
<BModal <BModal
v-model="showPreUpgradeModal"
id="apps-pre-upgrade" id="apps-pre-upgrade"
:title="$t('app.upgrade.confirm.title')" :title="$t('app.upgrade.confirm.title')"
header-bg-variant="warning" header-bg-variant="warning"
:header-class="dark ? 'text-white' : 'text-black'" header-class="text-black"
:ok-title="$t('system_upgrade_btn')" :ok-title="$t('system_upgrade_btn')"
ok-variant="success" ok-variant="success"
:cancel-title="$t('cancel')" :cancel-title="$t('cancel')"
@ -139,6 +140,7 @@
<script> <script>
import api from '@/api' import api from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import CardCollapse from '@/components/CardCollapse.vue' import CardCollapse from '@/components/CardCollapse.vue'
@ -150,6 +152,12 @@ export default {
CardCollapse, CardCollapse,
}, },
setup() {
return {
modalConfirm: useAutoModal(),
}
},
data() { data() {
return { return {
queries: [['PUT', 'update/all', {}, 'update']], queries: [['PUT', 'update/all', {}, 'update']],
@ -158,6 +166,7 @@ export default {
apps: undefined, apps: undefined,
importantYunohostUpgrade: undefined, importantYunohostUpgrade: undefined,
pendingMigrations: undefined, pendingMigrations: undefined,
showPreUpgradeModal: false,
preUpgrade: { preUpgrade: {
apps: [], apps: [],
notifs: [], notifs: [],
@ -200,7 +209,7 @@ export default {
: '', : '',
})) }))
this.preUpgrade = { apps, hasNotifs: apps.some((app) => app.notif) } this.preUpgrade = { apps, hasNotifs: apps.some((app) => app.notif) }
this.$bvModal.show('apps-pre-upgrade') this.showPreUpgradeModal = true
}, },
async performAppsUpgrade(ids) { async performAppsUpgrade(ids) {
@ -224,7 +233,7 @@ export default {
if (postMessage) { if (postMessage) {
const message = const message =
this.$t('app.upgrade.notifs.post.alert') + '\n\n' + postMessage this.$t('app.upgrade.notifs.post.alert') + '\n\n' + postMessage
return this.$askMdConfirmation( return this.modalConfirm(
message, message,
{ {
title: this.$t('app.upgrade.notifs.post.title', { title: this.$t('app.upgrade.notifs.post.title', {
@ -233,7 +242,7 @@ export default {
okTitle: this.$t(isLast ? 'ok' : 'app.upgrade.continue'), okTitle: this.$t(isLast ? 'ok' : 'app.upgrade.continue'),
cancelTitle: this.$t('app.upgrade.stop'), cancelTitle: this.$t('app.upgrade.stop'),
}, },
isLast, { markdown: true, cancelable: !isLast },
) )
} else { } else {
return Promise.resolve(true) return Promise.resolve(true)
@ -248,7 +257,7 @@ export default {
}, },
async performSystemUpgrade() { async performSystemUpgrade() {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('confirm_update_system'), this.$t('confirm_update_system'),
) )
if (!confirmed) return if (!confirmed) return

View file

@ -23,6 +23,7 @@
<script> <script>
import api from '@/api' import api from '@/api'
import { useAutoModal } from '@/composables/useAutoModal'
import { useVuelidate } from '@vuelidate/core' import { useVuelidate } from '@vuelidate/core'
import { formatFormData } from '@/helpers/yunohostArguments' import { formatFormData } from '@/helpers/yunohostArguments'
@ -34,6 +35,7 @@ export default {
setup() { setup() {
return { return {
v$: useVuelidate(), v$: useVuelidate(),
modalConfirm: useAutoModal(),
} }
}, },
@ -89,7 +91,7 @@ export default {
methods: { methods: {
async onSubmit() { async onSubmit() {
if (this.form.delete) { if (this.form.delete) {
const confirmed = await this.$askConfirmation( const confirmed = await this.modalConfirm(
this.$t('users_import_confirm_destructive'), this.$t('users_import_confirm_destructive'),
{ okTitle: this.$t('users_import_delete_others') }, { okTitle: this.$t('users_import_delete_others') },
) )

View file

@ -83,8 +83,7 @@
:title="$t('confirm_delete', { name: user.username })" :title="$t('confirm_delete', { name: user.username })"
@ok="deleteUser" @ok="deleteUser"
header-bg-variant="warning" header-bg-variant="warning"
body-class="" header-class="text-black"
body-bg-variant=""
> >
<BFormGroup> <BFormGroup>
<BFormCheckbox v-model="purge"> <BFormCheckbox v-model="purge">