Various improvements.

This commit is contained in:
Antoine Nguyen
2025-09-05 13:32:00 +02:00
parent f3d341455f
commit e584ad6be2
4 changed files with 166 additions and 69 deletions
@@ -27,17 +27,37 @@
:placeholder="$gettext('Search in messages')"
variant="outlined"
single-line
flat
hide-details
density="compact"
class="flex-grow-0 w-33 mr-4"
clearable
density="compact"
@click:clear="fetchContent"
@keyup.enter="fetchContent"
>
<template #prepend-inner>
<v-btn icon variant="flat" size="small">
<v-icon icon="mdi-magnify"></v-icon>
<v-menu activator="parent">
<v-card>
<v-card-text>
<v-radio-group v-model="searchCriteria">
<v-radio
:label="$gettext('From address')"
value="from_addr"
></v-radio>
<v-radio
:label="$gettext('Subject')"
value="subject"
></v-radio>
<v-radio :label="$gettext('To')" value="to"></v-radio>
<v-radio
:label="$gettext('both')"
value="both"
></v-radio>
</v-radio-group>
</v-card-text>
</v-card>
</v-menu>
</v-btn>
</template>
</v-text-field>
@@ -87,6 +107,36 @@
</v-list>
</v-menu>
</v-btn>
<v-select
v-model="typeFilter"
variant="outlined"
:items="messageTypes"
class="ml-2 flex-grow-0"
density="compact"
item-title="label"
item-value="key"
chips
hide-details
@update:model-value="fetchContent"
>
<template #chip="{ props, item }">
<span class="mr-2">{{ $gettext('Display') }}</span>
<v-chip
v-bind="props"
:color="item.raw.color"
:text="item.raw.label"
label
></v-chip>
</template>
<template #item="{ props, item }">
<v-list-item v-bind="props" title="">
<v-chip :color="item.raw.color" label>
{{ item.raw.label }}
</v-chip>
</v-list-item>
</template>
</v-select>
</div>
</template>
<template #[`item.type`]="{ item }">
@@ -128,9 +178,25 @@ const itemsPerPageR = ref(10)
const loading = ref(false)
const messages = ref([])
const search = ref('')
const searchCriteria = ref('both')
const selected = ref([])
const sortByR = ref([])
const totalMessages = ref(0)
const typeFilter = ref('all')
const messageTypes = [
{ color: '', key: 'all', label: 'All' },
{ color: 'success', key: 'C', label: 'Clean' },
{ color: 'error', key: 'S', label: 'Spam' },
{ color: 'warning', key: 'Y', label: 'Spammy' },
{ color: 'error', key: 'V', label: 'Virus' },
{ color: 'warning', key: 'H', label: 'Bad Header' },
{ color: 'warning', key: 'M', label: 'Bad MIME' },
{ color: 'warning', key: 'B', label: 'Banned' },
{ color: 'warning', key: 'O', label: 'Over sized' },
{ color: 'warning', key: 'T', label: 'MTA error' },
{ color: '', key: 'U', label: 'Unchecked' },
]
const headers = [
{ title: '', key: 'type' },
@@ -184,6 +250,10 @@ const _fetchContent = async () => {
}
if (search.value !== '') {
params.search = search.value
params.criteria = searchCriteria.value
}
if (typeFilter.value !== 'all') {
params.msgtype = typeFilter.value
}
try {
const resp = await api.getQuarantineContent(params)
@@ -262,8 +332,6 @@ const markSelectionAsSpam = async () => {
const markSelectionAsHam = async () => {
await markSelection('ham')
}
const submitSearch = () => {}
</script>
<style lang="scss">
@@ -0,0 +1,9 @@
<template>
<ConnectedLayout>
<template #navbar>&nbsp;</template>
</ConnectedLayout>
</template>
<script setup>
import ConnectedLayout from '@/layouts/connected/ConnectedLayout.vue'
</script>
+1 -1
View File
@@ -428,7 +428,7 @@ const routes = [
},
{
path: 'quarantine',
component: () => import('@/layouts/user/UserLayout.vue'),
component: () => import('@/layouts/quarantine/QuarantineLayout.vue'),
meta: {
requiresAuth: true,
},
+84 -64
View File
@@ -1,68 +1,88 @@
<template>
<div class="bg-white rounded-lg pa-4 position-relative h-100">
<v-toolbar color="white">
<v-btn icon="mdi-arrow-left" size="small" variant="flat" @click="close" />
<v-btn
class="ml-2"
color="success"
variant="tonal"
icon="mdi-check"
size="small"
:title="$gettext('Release message')"
:loading="loading"
@click="releaseMessage"
>
</v-btn>
<v-btn
class="ml-2"
color="error"
variant="tonal"
icon="mdi-trash-can"
size="small"
:title="$gettext('Delete message')"
:loading="loading"
@click="deleteMessage"
>
</v-btn>
<v-btn class="ml-2" variant="tonal" icon size="small">
<v-icon icon="mdi-cog" />
<v-menu activator="parent">
<v-list density="compact">
<v-list-item
:title="$gettext('Mark as spam')"
@click="markAsSpam"
/>
<v-list-item
:title="$gettext('Mark as non-spam')"
@click="markAsHam"
/>
</v-list>
</v-menu>
</v-btn>
<v-btn
class="ml-2"
variant="tonal"
size="small"
:loading="loading"
@click="toggleFullHeaders"
>
<span v-if="!fullHeaders">
{{ $gettext('View full headers') }}
</span>
<span v-else>
{{ $gettext('Hide full headers') }}
</span>
</v-btn>
</v-toolbar>
<div class="pa-4 bg-grey-lighten-3 rounded">
<v-row v-for="header in headers" :key="header.name" no-gutters>
<v-col cols="2" class="font-weight-bold">
{{ header.name }}
</v-col>
<v-col cols="10">{{ header.value }}</v-col>
</v-row>
<div>
<div class="text-h5 ml-4">
{{ $gettext('Quarantine') }}
</div>
<div class="bg-white rounded-lg pa-4 position-relative mt-6 h-100">
<v-toolbar color="white">
<v-btn
icon="mdi-arrow-left"
size="small"
variant="flat"
@click="close"
/>
<v-btn
class="ml-2"
color="success"
variant="tonal"
icon="mdi-check"
size="small"
:title="$gettext('Release message')"
:loading="loading"
@click="releaseMessage"
>
</v-btn>
<v-btn
class="ml-2"
color="error"
variant="tonal"
icon="mdi-trash-can"
size="small"
:title="$gettext('Delete message')"
:loading="loading"
@click="deleteMessage"
>
</v-btn>
<v-btn class="ml-2" variant="tonal" icon size="small">
<v-icon icon="mdi-cog" />
<v-menu activator="parent">
<v-list density="compact">
<v-list-item
:title="$gettext('Mark as spam')"
@click="markAsSpam"
/>
<v-list-item
:title="$gettext('Mark as non-spam')"
@click="markAsHam"
/>
</v-list>
</v-menu>
</v-btn>
<v-btn
class="ml-2"
variant="tonal"
size="small"
:loading="loading"
@click="toggleFullHeaders"
>
<span v-if="!fullHeaders">
{{ $gettext('View full headers') }}
</span>
<span v-else>
{{ $gettext('Hide full headers') }}
</span>
</v-btn>
</v-toolbar>
<v-alert
v-if="message.qtype"
:title="message.qtype"
:text="message.qreason"
type="error"
variant="tonal"
class="mb-4"
density="compact"
/>
<div class="pa-4 bg-grey-lighten-3 rounded">
<v-row v-for="header in headers" :key="header.name" no-gutters>
<v-col cols="2" class="font-weight-bold">
{{ header.name }}
</v-col>
<v-col cols="10">{{ header.value }}</v-col>
</v-row>
</div>
<div class="mt-4" v-html="message.body" />
</div>
<div class="mt-4" v-html="message.body" />
</div>
</template>
@@ -160,6 +180,6 @@ const markAsHam = async () => {
await mark('ham', $gettext('Message marked as non-spam'))
}
const resp = await api.getMessageContent(route.params.mailid)
const resp = await api.getMessageContent(route.params.mailid, route.params.rcpt)
message.value = resp.data
</script>