273 lines
8.4 KiB
Vue
273 lines
8.4 KiB
Vue
<script setup>
|
|
import AdminLayout from "@/Layouts/AdminLayout.vue";
|
|
import DialogModal from "@/Components/DialogModal.vue";
|
|
import { Head, Link, useForm } from "@inertiajs/vue3";
|
|
import { ref, computed } from "vue";
|
|
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
|
import {
|
|
faPlus,
|
|
faFlask,
|
|
faBolt,
|
|
faArrowsRotate,
|
|
faToggleOn,
|
|
faToggleOff,
|
|
} from "@fortawesome/free-solid-svg-icons";
|
|
|
|
const props = defineProps({
|
|
profiles: { type: Array, default: () => [] },
|
|
});
|
|
|
|
const createOpen = ref(false);
|
|
const editTarget = ref(null);
|
|
|
|
const form = useForm({
|
|
name: "",
|
|
host: "",
|
|
port: 587,
|
|
encryption: "tls",
|
|
username: "",
|
|
password: "",
|
|
from_address: "",
|
|
from_name: "",
|
|
priority: 10,
|
|
});
|
|
|
|
function openCreate() {
|
|
form.reset();
|
|
createOpen.value = true;
|
|
editTarget.value = null;
|
|
}
|
|
|
|
function closeCreate() {
|
|
if (form.processing) return;
|
|
createOpen.value = false;
|
|
}
|
|
|
|
function submitCreate() {
|
|
form.post(route("admin.mail-profiles.store"), {
|
|
preserveScroll: true,
|
|
onSuccess: () => {
|
|
createOpen.value = false;
|
|
},
|
|
});
|
|
}
|
|
|
|
function toggleActive(p) {
|
|
window.axios
|
|
.post(route("admin.mail-profiles.toggle", p.id))
|
|
.then(() => window.location.reload());
|
|
}
|
|
|
|
function testConnection(p) {
|
|
window.axios
|
|
.post(route("admin.mail-profiles.test", p.id))
|
|
.then(() => window.location.reload());
|
|
}
|
|
|
|
const statusClass = (p) => {
|
|
if (p.test_status === "success") return "text-emerald-600";
|
|
if (p.test_status === "failed") return "text-rose-600";
|
|
if (p.test_status === "queued") return "text-amber-500";
|
|
return "text-gray-400";
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<AdminLayout title="Mail profili">
|
|
<Head title="Mail profili" />
|
|
<div class="flex items-center justify-between mb-6">
|
|
<h1 class="text-xl font-semibold text-gray-800 flex items-center gap-3">
|
|
Mail profili
|
|
<span class="text-xs font-medium text-gray-400">({{ profiles.length }})</span>
|
|
</h1>
|
|
<button
|
|
@click="openCreate"
|
|
class="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-indigo-600 text-white text-sm font-medium hover:bg-indigo-500 shadow"
|
|
>
|
|
<FontAwesomeIcon :icon="faPlus" class="w-4 h-4" /> Nov profil
|
|
</button>
|
|
</div>
|
|
<div class="rounded-lg border bg-white overflow-hidden shadow-sm">
|
|
<table class="w-full text-sm">
|
|
<thead class="bg-gray-50 text-gray-600 text-xs uppercase tracking-wider">
|
|
<tr>
|
|
<th class="px-3 py-2 text-left">Ime</th>
|
|
<th class="px-3 py-2 text-left">Host</th>
|
|
<th class="px-3 py-2">Port</th>
|
|
<th class="px-3 py-2">Enc</th>
|
|
<th class="px-3 py-2">Aktivno</th>
|
|
<th class="px-3 py-2">Test</th>
|
|
<th class="px-3 py-2">Zadnji uspeh</th>
|
|
<th class="px-3 py-2">Napaka</th>
|
|
<th class="px-3 py-2">Akcije</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr
|
|
v-for="p in profiles"
|
|
:key="p.id"
|
|
class="border-t last:border-b hover:bg-gray-50"
|
|
>
|
|
<td class="px-3 py-2 font-medium text-gray-800">{{ p.name }}</td>
|
|
<td class="px-3 py-2">{{ p.host }}</td>
|
|
<td class="px-3 py-2 text-center">{{ p.port }}</td>
|
|
<td class="px-3 py-2 text-center">{{ p.encryption || "—" }}</td>
|
|
<td class="px-3 py-2 text-center">
|
|
<button
|
|
@click="toggleActive(p)"
|
|
class="text-indigo-600 hover:text-indigo-800"
|
|
:title="p.active ? 'Onemogoči' : 'Omogoči'"
|
|
>
|
|
<FontAwesomeIcon
|
|
:icon="p.active ? faToggleOn : faToggleOff"
|
|
class="w-5 h-5"
|
|
/>
|
|
</button>
|
|
</td>
|
|
<td class="px-3 py-2 text-center">
|
|
<span :class="['font-medium', statusClass(p)]">{{
|
|
p.test_status || "—"
|
|
}}</span>
|
|
</td>
|
|
<td class="px-3 py-2 text-xs text-gray-500">
|
|
{{ p.last_success_at ? new Date(p.last_success_at).toLocaleString() : "—" }}
|
|
</td>
|
|
<td
|
|
class="px-3 py-2 text-xs text-rose-600 max-w-[160px] truncate"
|
|
:title="p.last_error_message"
|
|
>
|
|
{{ p.last_error_message || "—" }}
|
|
</td>
|
|
<td class="px-3 py-2 flex items-center gap-2">
|
|
<button
|
|
@click="testConnection(p)"
|
|
class="inline-flex items-center gap-1 text-xs px-2 py-1 rounded border text-amber-600 border-amber-300 bg-amber-50 hover:bg-amber-100"
|
|
>
|
|
<FontAwesomeIcon :icon="faFlask" class="w-3.5 h-3.5" /> Test
|
|
</button>
|
|
<button
|
|
class="inline-flex items-center gap-1 text-xs px-2 py-1 rounded border text-indigo-600 border-indigo-300 bg-indigo-50 hover:bg-indigo-100"
|
|
>
|
|
<FontAwesomeIcon :icon="faArrowsRotate" class="w-3.5 h-3.5" /> Shrani
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<DialogModal :show="createOpen" max-width="2xl" @close="closeCreate">
|
|
<template #title> Nov Mail profil </template>
|
|
<template #content>
|
|
<form @submit.prevent="submitCreate" id="create-mail-profile" class="space-y-5">
|
|
<div class="grid gap-4 grid-cols-2">
|
|
<div class="col-span-1">
|
|
<label class="label">Ime</label>
|
|
<input v-model="form.name" type="text" class="input" />
|
|
</div>
|
|
<div>
|
|
<label class="label">Host</label>
|
|
<input v-model="form.host" type="text" class="input" />
|
|
</div>
|
|
<div>
|
|
<label class="label">Port</label>
|
|
<input v-model="form.port" type="number" class="input" />
|
|
</div>
|
|
<div>
|
|
<label class="label">Encryption</label>
|
|
<select v-model="form.encryption" class="input">
|
|
<option value="">(None)</option>
|
|
<option value="tls">TLS</option>
|
|
<option value="ssl">SSL</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="label">Username</label>
|
|
<input v-model="form.username" type="text" class="input" />
|
|
</div>
|
|
<div>
|
|
<label class="label">Password</label>
|
|
<input
|
|
v-model="form.password"
|
|
type="password"
|
|
class="input"
|
|
autocomplete="new-password"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label class="label">From naslov</label>
|
|
<input v-model="form.from_address" type="email" class="input" />
|
|
</div>
|
|
<div>
|
|
<label class="label">From ime</label>
|
|
<input v-model="form.from_name" type="text" class="input" />
|
|
</div>
|
|
<div>
|
|
<label class="label">Prioriteta</label>
|
|
<input v-model="form.priority" type="number" class="input" />
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</template>
|
|
<template #footer>
|
|
<button
|
|
type="button"
|
|
@click="closeCreate"
|
|
class="px-4 py-2 text-sm rounded-md border bg-white hover:bg-gray-50"
|
|
>
|
|
Prekliči
|
|
</button>
|
|
<button
|
|
form="create-mail-profile"
|
|
type="submit"
|
|
:disabled="form.processing"
|
|
class="px-4 py-2 text-sm rounded-md bg-indigo-600 text-white hover:bg-indigo-500 disabled:opacity-50"
|
|
>
|
|
Shrani
|
|
</button>
|
|
</template>
|
|
</DialogModal>
|
|
</AdminLayout>
|
|
</template>
|
|
|
|
<style scoped>
|
|
/* Utility replacements for @apply not processed in SFC scope build pipeline */
|
|
.input {
|
|
width: 100%;
|
|
border-radius: 0.375rem;
|
|
border: 1px solid var(--tw-color-gray-300, #d1d5db);
|
|
padding: 0.5rem 0.75rem;
|
|
font-size: 0.875rem;
|
|
line-height: 1.25rem;
|
|
}
|
|
.input:focus {
|
|
outline: 2px solid transparent;
|
|
outline-offset: 2px;
|
|
--tw-ring-color: #6366f1;
|
|
border-color: #6366f1;
|
|
box-shadow: 0 0 0 1px #6366f1;
|
|
}
|
|
.label {
|
|
display: block;
|
|
font-size: 0.65rem;
|
|
font-weight: 600;
|
|
letter-spacing: 0.05em;
|
|
text-transform: uppercase;
|
|
color: #6b7280;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
@keyframes fade-in {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(8px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: none;
|
|
}
|
|
}
|
|
.animate-fade-in {
|
|
animation: fade-in 0.25s ease;
|
|
}
|
|
</style>
|