Fixed various frontend issues

This commit is contained in:
Antoine Nguyen
2025-07-03 14:34:28 +02:00
parent f01e966420
commit d9f37acb2b
12 changed files with 90 additions and 53 deletions
+4 -3
View File
@@ -1,6 +1,7 @@
<template>
<router-view />
<Suspense>
<router-view />
</Suspense>
</template>
<script setup>
</script>
<script setup></script>
@@ -34,8 +34,8 @@
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn @click="close">{{ $gettext('Close') }}</v-btn>
<v-btn color="primary" type="submit">
<v-btn :loading="working" @click="close">{{ $gettext('Close') }}</v-btn>
<v-btn color="primary" type="submit" :loading="working">
{{ submitLabel }}
</v-btn>
</v-card-actions>
@@ -64,14 +64,17 @@ const { $gettext } = useGettext()
const busStore = useBusStore()
onMounted(() => {
calendar.value = { ...props.initialCalendar }
shared.value = props.initialCalendar.domain !== undefined
if (props.initialCalendar) {
calendar.value = { ...props.initialCalendar }
shared.value = props.initialCalendar.domain !== undefined
}
})
const calendar = ref({})
const shared = ref(false)
const formErrors = ref({})
const formRef = ref()
const working = ref(false)
const submitLabel = computed(() => {
if (calendar.value.pk) {
@@ -93,19 +96,27 @@ async function submit() {
return
}
let msg
if (calendar.value.pk) {
await calendarsApi.updateUserCalendar(calendar.value.pk, calendar.value)
msg = $gettext('Calendar updated')
} else {
await calendarsApi.createUserCalendar(calendar.value)
msg = $gettext('Calendar created')
working.value = true
try {
if (calendar.value.pk) {
await calendarsApi.updateUserCalendar(calendar.value.pk, calendar.value)
msg = $gettext('Calendar updated')
} else {
await calendarsApi.createUserCalendar(calendar.value)
msg = $gettext('Calendar created')
}
if (
props.initialCalendar &&
props.initialCalendar.color !== calendar.value.color
) {
emit('colorChanged', calendar.value)
}
close()
busStore.displayNotification({
msg,
})
} finally {
working.value = false
}
if (props.initialCalendar.color !== calendar.value.color) {
emit('colorChanged', calendar.value)
}
close()
busStore.displayNotification({
msg,
})
}
</script>
+19 -14
View File
@@ -82,8 +82,8 @@
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn @click="close">{{ $gettext('Close') }}</v-btn>
<v-btn color="primary" type="submit">
<v-btn :loading="working" @click="close">{{ $gettext('Close') }}</v-btn>
<v-btn color="primary" type="submit" :loading="working">
{{ $gettext('Save') }}
</v-btn>
</v-card-actions>
@@ -119,6 +119,7 @@ const userCalendars = ref([])
const form = ref({})
const formErrors = ref({})
const formRef = ref()
const working = ref(false)
const title = computed(() => {
return props.event ? $gettext('Edit event') : $gettext('New event')
@@ -148,7 +149,6 @@ watch(
'yyyy-MM-dd HH:mm'
)
form.value.end = DateTime.fromISO(value.end).toFormat('yyyy-MM-dd HH:mm')
console.log(form.value)
api.getAttendees().then((resp) => {
attendees.value = resp.data
})
@@ -166,17 +166,22 @@ async function saveEvent() {
if (!valid) {
return
}
var data = JSON.parse(JSON.stringify(form.value))
if (!props.event) {
api.createUserEvent(form.value.calendar, data).then(() => {
busStore.displayNotification({ msg: $gettext('Event added') })
close()
})
} else {
api.patchUserEvent(form.value.calendar, props.event.id, data).then(() => {
busStore.displayNotification({ msg: $gettext('Event updated') })
close()
})
working.value = true
try {
var data = JSON.parse(JSON.stringify(form.value))
if (!props.event) {
api.createUserEvent(form.value.calendar, data).then(() => {
busStore.displayNotification({ msg: $gettext('Event added') })
close()
})
} else {
api.patchUserEvent(form.value.calendar, props.event.id, data).then(() => {
busStore.displayNotification({ msg: $gettext('Event updated') })
close()
})
}
} finally {
working.value = false
}
}
+7 -3
View File
@@ -78,9 +78,13 @@ const { $gettext } = useGettext()
const applications = ref([])
const userInitials = computed(() => {
return props.user.first_name && props.user.last_name
? `${props.user.first_name[0].toUpperCase()}${props.user.last_name[0].toUpperCase()}`
: props.user.username.slice(0, 2).toUpperCase()
if (props.user.first_name && props.user.last_name) {
return `${props.user.first_name[0].toUpperCase()}${props.user.last_name[0].toUpperCase()}`
}
if (props.user.username) {
props.user.username.slice(0, 2).toUpperCase()
}
return ''
})
const userMenuItems = computed(() => {
@@ -5,14 +5,12 @@
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useGettext } from 'vue3-gettext'
import { useRouter } from 'vue-router'
import { useAuthStore, useParametersStore } from '@/stores'
import parametersApi from '@/api/parameters'
import capabilitiesApi from '@/api/capabilities'
import ConnectedLayout from '@/layouts/connected/ConnectedLayout.vue'
const { $gettext } = useGettext()
const router = useRouter()
const authStore = useAuthStore()
const parametersStore = useParametersStore()
@@ -149,11 +149,10 @@ function openMailbox(mailbox) {
})
}
const fetchUserMailboxes = () => {
api.getUserMailboxes().then((resp) => {
userMailboxes.value = resp.data.mailboxes
hdelimiter.value = resp.data.hdelimiter
})
const fetchUserMailboxes = async () => {
const resp = await api.getUserMailboxes()
userMailboxes.value = resp.data.mailboxes
hdelimiter.value = resp.data.hdelimiter
}
const openComposeForm = () => {
@@ -213,8 +212,7 @@ watch(
}
)
fetchUserMailboxes()
api.getUserMailboxQuota(route.query.mailbox || 'INBOX').then((resp) => {
mailboxQuota.value = resp.data
})
await fetchUserMailboxes()
const resp = await api.getUserMailboxQuota(route.query.mailbox || 'INBOX')
mailboxQuota.value = resp.data
</script>
+13 -1
View File
@@ -25,6 +25,9 @@ const routes = [
{
path: '/admin',
component: () => import('@/layouts/admin/AdminLayout.vue'),
meta: {
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
},
children: [
{
path: '',
@@ -287,6 +290,7 @@ const routes = [
component: () => import('@/layouts/user/UserLayout.vue'),
meta: {
requiresAuth: true,
requiresMailbox: true,
},
children: [
{
@@ -304,6 +308,7 @@ const routes = [
component: () => import('@/layouts/user/UserLayout.vue'),
meta: {
requiresAuth: true,
requiresMailbox: true,
},
children: [
{
@@ -312,6 +317,7 @@ const routes = [
component: () => import('@/views/calendars/CalendarView.vue'),
meta: {
requiresAuth: true,
requiresMailbox: true,
},
},
],
@@ -321,6 +327,7 @@ const routes = [
component: () => import('@/layouts/webmail/WebmailLayout.vue'),
meta: {
requiresAuth: true,
requiresMailbox: true,
},
children: [
{
@@ -329,6 +336,7 @@ const routes = [
component: () => import('@/views/webmail/MailboxView.vue'),
meta: {
requiresAuth: true,
requiresMailbox: true,
},
},
{
@@ -337,6 +345,7 @@ const routes = [
component: () => import('@/views/webmail/EmailView.vue'),
meta: {
requiresAuth: true,
requiresMailbox: true,
},
},
{
@@ -345,6 +354,7 @@ const routes = [
component: () => import('@/views/webmail/ComposeEmailView.vue'),
meta: {
requiresAuth: true,
requiresMailbox: true,
},
},
{
@@ -353,6 +363,7 @@ const routes = [
component: () => import('@/views/webmail/ReplyEmailView.vue'),
meta: {
requiresAuth: true,
requiresMailbox: true,
},
},
{
@@ -361,6 +372,7 @@ const routes = [
component: () => import('@/views/webmail/ForwardEmailView.vue'),
meta: {
requiresAuth: true,
requiresMailbox: true,
},
},
],
@@ -391,7 +403,7 @@ router.beforeEach(async (to, from, next) => {
if (isAuth) {
if (to.meta.allowedRoles !== undefined) {
if (to.meta.allowedRoles.indexOf(authStore.authUser.role) === -1) {
next({ name: 'Dashboard' })
next({ name: 'AccountSettings' })
return
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ import domainApi from '@/api/domains'
export const useDomainsStore = defineStore('domains', () => {
const domainsLoaded = ref(false)
const domains = ref({})
const domains = ref([])
async function $reset() {
domainsLoaded.value = false
@@ -14,7 +14,7 @@
</template>
<script setup>
import { computed, ref } from 'vue'
import { computed, ref, watch } from 'vue'
import { useGettext } from 'vue3-gettext'
import { useRoute } from 'vue-router'
import ParametersForm from '@/components/tools/ParametersForm'
@@ -39,6 +39,10 @@ function loadParams(app) {
})
}
watch(route, (toRoute) => {
loadParams(toRoute.params.app)
})
loadParams(route.params.app)
</script>
@@ -11,12 +11,15 @@ import DomainEditForm from '@/components/admin/domains/DomainEditForm'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
import domainsApi from '@/api/domains'
import { useDomainsStore } from '@/stores'
const { $gettext } = useGettext()
const route = useRoute()
const domainsStore = useDomainsStore()
const domain = ref({})
domainsStore.getDomains()
domainsApi.getDomain(route.params.id).then((resp) => {
domain.value = resp.data
})
@@ -252,8 +252,9 @@ async function deleteCalendar(calendarPk) {
}
await api.deleteUserCalendar(calendarPk)
const fullc = calendarRef.value.getApi()
const evtSource = fullc.getEventSourceById(`user-${calendar.pk}`)
const evtSource = fullc.getEventSourceById(`user-${calendarPk}`)
evtSource.remove()
fetchUserCalendars()
busStore.displayNotification({ msg: $gettext('Calendar deleted') })
}
@@ -14,7 +14,7 @@ def cleanup_and_rename(apps, schema_editor):
# Rename parameters
LocalConfig = apps.get_model("core", "LocalConfig")
cfg = LocalConfig.objects.first()
if not cfg:
if not cfg or "postfix_autoreply" not in cfg._parameters:
return
cfg._parameters["autoreply"] = copy.deepcopy(cfg._parameters["postfix_autoreply"])
del cfg._parameters["postfix_autoreply"]