Mail support testing faze
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
<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>
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
faCloudArrowUp,
|
||||
faArrowUpRightFromSquare,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faFileContract } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faFileContract } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
const props = defineProps({
|
||||
kpis: Object,
|
||||
@@ -45,7 +45,12 @@ const kpiDefs = [
|
||||
icon: faCloudArrowUp,
|
||||
route: "imports.index",
|
||||
},
|
||||
{ key: "active_contracts", label: "Aktivne pogodbe", icon: faFileContract, route: "clientCase" },
|
||||
{
|
||||
key: "active_contracts",
|
||||
label: "Aktivne pogodbe",
|
||||
icon: faFileContract,
|
||||
route: "clientCase",
|
||||
},
|
||||
];
|
||||
|
||||
const page = usePage();
|
||||
@@ -97,6 +102,19 @@ function buildRelated(a) {
|
||||
const activityItems = computed(() =>
|
||||
(props.activities || []).map((a) => ({ ...a, links: buildRelated(a) }))
|
||||
);
|
||||
|
||||
// Format stale days label: never negative; '<1 dan' if 0<=value<1; else integer with proper suffix.
|
||||
function formatStaleDaysLabel(value) {
|
||||
const num = Number.parseFloat(value);
|
||||
if (Number.isNaN(num)) {
|
||||
return "—";
|
||||
}
|
||||
if (num < 1) {
|
||||
return "<1 dan";
|
||||
}
|
||||
const whole = Math.floor(num);
|
||||
return whole === 1 ? "1 dan" : whole + " dni";
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -269,8 +287,14 @@ const activityItems = computed(() =>
|
||||
<!-- Right side panels -->
|
||||
<div class="lg:col-span-2 space-y-8">
|
||||
<!-- System Health -->
|
||||
<div class="bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-xl shadow-sm p-6">
|
||||
<h3 class="text-sm font-semibold tracking-wide text-gray-700 dark:text-gray-200 uppercase mb-4">System Health</h3>
|
||||
<div
|
||||
class="bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-xl shadow-sm p-6"
|
||||
>
|
||||
<h3
|
||||
class="text-sm font-semibold tracking-wide text-gray-700 dark:text-gray-200 uppercase mb-4"
|
||||
>
|
||||
System Health
|
||||
</h3>
|
||||
<div
|
||||
v-if="systemHealth"
|
||||
class="grid sm:grid-cols-2 lg:grid-cols-4 gap-4 text-sm"
|
||||
@@ -326,8 +350,14 @@ const activityItems = computed(() =>
|
||||
</div>
|
||||
|
||||
<!-- Completed Field Jobs Trend (7 dni) -->
|
||||
<div class="bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-xl shadow-sm p-6">
|
||||
<h3 class="text-sm font-semibold tracking-wide text-gray-700 dark:text-gray-200 uppercase mb-4">Zaključena terenska dela (7 dni)</h3>
|
||||
<div
|
||||
class="bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-xl shadow-sm p-6"
|
||||
>
|
||||
<h3
|
||||
class="text-sm font-semibold tracking-wide text-gray-700 dark:text-gray-200 uppercase mb-4"
|
||||
>
|
||||
Zaključena terenska dela (7 dni)
|
||||
</h3>
|
||||
<div v-if="trends" class="h-24">
|
||||
<svg viewBox="0 0 140 60" class="w-full h-full">
|
||||
<defs>
|
||||
@@ -336,91 +366,228 @@ const activityItems = computed(() =>
|
||||
<stop offset="100%" stop-color="#6366f1" stop-opacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path v-if="trends.field_jobs_completed" :d="sparkline(trends.field_jobs_completed)" stroke="#6366f1" stroke-width="2" fill="none" stroke-linejoin="round" stroke-linecap="round" />
|
||||
<path
|
||||
v-if="trends.field_jobs_completed"
|
||||
:d="sparkline(trends.field_jobs_completed)"
|
||||
stroke="#6366f1"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
<div class="mt-2 flex gap-2 text-[10px] text-gray-400 dark:text-gray-500">
|
||||
<span v-for="(l,i) in trends.labels" :key="i" class="flex-1 truncate text-center">{{ l.slice(5) }}</span>
|
||||
<span
|
||||
v-for="(l, i) in trends.labels"
|
||||
:key="i"
|
||||
class="flex-1 truncate text-center"
|
||||
>{{ l.slice(5) }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="h-24 animate-pulse bg-gray-100 dark:bg-gray-700 rounded" />
|
||||
</div>
|
||||
|
||||
<!-- Stale Cases -->
|
||||
<div class="bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-xl shadow-sm p-6">
|
||||
<h3 class="text-sm font-semibold tracking-wide text-gray-700 dark:text-gray-200 uppercase mb-4">Stari primeri brez aktivnosti</h3>
|
||||
<ul v-if="staleCases" class="divide-y divide-gray-100 dark:divide-gray-700 text-sm">
|
||||
<li v-for="c in staleCases" :key="c.id" class="py-2 flex items-center justify-between">
|
||||
<div
|
||||
class="bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-xl shadow-sm p-6"
|
||||
>
|
||||
<h3
|
||||
class="text-sm font-semibold tracking-wide text-gray-700 dark:text-gray-200 uppercase mb-4"
|
||||
>
|
||||
Stari primeri brez aktivnosti
|
||||
</h3>
|
||||
<ul
|
||||
v-if="staleCases"
|
||||
class="divide-y divide-gray-100 dark:divide-gray-700 text-sm"
|
||||
>
|
||||
<li
|
||||
v-for="c in staleCases"
|
||||
:key="c.id"
|
||||
class="py-2 flex items-center justify-between"
|
||||
>
|
||||
<div class="min-w-0">
|
||||
<Link :href="route('clientCase.show', c.uuid)" class="text-indigo-600 dark:text-indigo-400 hover:underline font-medium">{{ c.client_ref || c.uuid.slice(0,8) }}</Link>
|
||||
<p class="text-[11px] text-gray-400 dark:text-gray-500">Staro: {{ c.days_stale }} dni</p>
|
||||
<Link
|
||||
:href="route('clientCase.show', c.uuid)"
|
||||
class="text-indigo-600 dark:text-indigo-400 hover:underline font-medium"
|
||||
>{{ c.client_ref || c.uuid.slice(0, 8) }}</Link
|
||||
>
|
||||
<p class="text-[11px] text-gray-400 dark:text-gray-500">
|
||||
Brez aktivnosti: {{ formatStaleDaysLabel(c.days_without_activity ?? c.days_stale) }}
|
||||
</p>
|
||||
</div>
|
||||
<span class="text-[10px] px-2 py-0.5 rounded bg-amber-50 dark:bg-amber-900/30 text-amber-600 dark:text-amber-300">Stale</span>
|
||||
<span
|
||||
class="text-[10px] px-2 py-0.5 rounded bg-amber-50 dark:bg-amber-900/30 text-amber-600 dark:text-amber-300"
|
||||
>Stale</span
|
||||
>
|
||||
</li>
|
||||
<li
|
||||
v-if="!staleCases.length"
|
||||
class="py-4 text-xs text-gray-500 text-center"
|
||||
>
|
||||
Ni starih primerov.
|
||||
</li>
|
||||
<li v-if="!staleCases.length" class="py-4 text-xs text-gray-500 text-center">Ni starih primerov.</li>
|
||||
</ul>
|
||||
<div v-else class="space-y-2 animate-pulse">
|
||||
<div v-for="n in 5" :key="n" class="h-5 bg-gray-100 dark:bg-gray-700 rounded" />
|
||||
<div
|
||||
v-for="n in 5"
|
||||
:key="n"
|
||||
class="h-5 bg-gray-100 dark:bg-gray-700 rounded"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Field Jobs Assigned Today -->
|
||||
<div class="bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-xl shadow-sm p-6">
|
||||
<h3 class="text-sm font-semibold tracking-wide text-gray-700 dark:text-gray-200 uppercase mb-4">Današnje dodelitve terenskih</h3>
|
||||
<ul v-if="fieldJobsAssignedToday" class="divide-y divide-gray-100 dark:divide-gray-700 text-sm">
|
||||
<li v-for="f in fieldJobsAssignedToday" :key="f.id" class="py-2 flex items-center justify-between">
|
||||
<div class="min-w-0">
|
||||
<p class="text-gray-700 dark:text-gray-300 text-sm">#{{ f.id }}</p>
|
||||
<p class="text-[11px] text-gray-400 dark:text-gray-500">{{ (f.assigned_at || f.created_at) ? new Date(f.assigned_at || f.created_at).toLocaleTimeString() : '' }}</p>
|
||||
</div>
|
||||
<span v-if="f.priority" class="text-[10px] px-2 py-0.5 rounded bg-rose-50 dark:bg-rose-900/30 text-rose-600 dark:text-rose-300">Prioriteta</span>
|
||||
</li>
|
||||
<li v-if="!fieldJobsAssignedToday.length" class="py-4 text-xs text-gray-500 text-center">Ni dodelitev.</li>
|
||||
</ul>
|
||||
<div v-else class="space-y-2 animate-pulse">
|
||||
<div v-for="n in 5" :key="n" class="h-5 bg-gray-100 dark:bg-gray-700 rounded" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Imports In Progress -->
|
||||
<div class="bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-xl shadow-sm p-6">
|
||||
<h3 class="text-sm font-semibold tracking-wide text-gray-700 dark:text-gray-200 uppercase mb-4">Uvozi v teku</h3>
|
||||
<ul v-if="importsInProgress" class="divide-y divide-gray-100 dark:divide-gray-700 text-sm">
|
||||
<li v-for="im in importsInProgress" :key="im.id" class="py-2 space-y-1">
|
||||
<div class="flex items-center justify-between">
|
||||
<p class="font-medium text-gray-700 dark:text-gray-300 truncate">{{ im.file_name }}</p>
|
||||
<span class="text-[10px] px-2 py-0.5 rounded-full bg-indigo-50 dark:bg-indigo-900/40 text-indigo-600 dark:text-indigo-300">{{ im.status }}</span>
|
||||
<div
|
||||
class="bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-xl shadow-sm p-6"
|
||||
>
|
||||
<h3
|
||||
class="text-sm font-semibold tracking-wide text-gray-700 dark:text-gray-200 uppercase mb-4"
|
||||
>
|
||||
Današnje dodelitve terenskih
|
||||
</h3>
|
||||
<ul
|
||||
v-if="fieldJobsAssignedToday"
|
||||
class="divide-y divide-gray-100 dark:divide-gray-700 text-sm"
|
||||
>
|
||||
<li
|
||||
v-for="f in fieldJobsAssignedToday"
|
||||
:key="f.id"
|
||||
class="py-2 flex items-center justify-between"
|
||||
>
|
||||
<div class="min-w-0">
|
||||
<p class="text-gray-700 dark:text-gray-300 text-sm">#{{ f.id }}</p>
|
||||
<p class="text-[11px] text-gray-400 dark:text-gray-500">
|
||||
{{
|
||||
f.assigned_at || f.created_at
|
||||
? new Date(f.assigned_at || f.created_at).toLocaleTimeString()
|
||||
: ""
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="w-full h-2 bg-gray-100 dark:bg-gray-700 rounded overflow-hidden">
|
||||
<div class="h-full bg-indigo-500 dark:bg-indigo-400" :style="{ width: (im.progress_pct || 0) + '%' }"></div>
|
||||
</div>
|
||||
<p class="text-[10px] text-gray-400 dark:text-gray-500">{{ im.imported_rows }}/{{ im.total_rows }} (veljavnih: {{ im.valid_rows }}, neveljavnih: {{ im.invalid_rows }})</p>
|
||||
<span
|
||||
v-if="f.priority"
|
||||
class="text-[10px] px-2 py-0.5 rounded bg-rose-50 dark:bg-rose-900/30 text-rose-600 dark:text-rose-300"
|
||||
>Prioriteta</span
|
||||
>
|
||||
</li>
|
||||
<li
|
||||
v-if="!fieldJobsAssignedToday.length"
|
||||
class="py-4 text-xs text-gray-500 text-center"
|
||||
>
|
||||
Ni dodelitev.
|
||||
</li>
|
||||
<li v-if="!importsInProgress.length" class="py-4 text-xs text-gray-500 text-center">Ni aktivnih uvozov.</li>
|
||||
</ul>
|
||||
<div v-else class="space-y-2 animate-pulse">
|
||||
<div v-for="n in 4" :key="n" class="h-5 bg-gray-100 dark:bg-gray-700 rounded" />
|
||||
<div
|
||||
v-for="n in 5"
|
||||
:key="n"
|
||||
class="h-5 bg-gray-100 dark:bg-gray-700 rounded"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Imports In Progress -->
|
||||
<div
|
||||
class="bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-xl shadow-sm p-6"
|
||||
>
|
||||
<h3
|
||||
class="text-sm font-semibold tracking-wide text-gray-700 dark:text-gray-200 uppercase mb-4"
|
||||
>
|
||||
Uvozi v teku
|
||||
</h3>
|
||||
<ul
|
||||
v-if="importsInProgress"
|
||||
class="divide-y divide-gray-100 dark:divide-gray-700 text-sm"
|
||||
>
|
||||
<li v-for="im in importsInProgress" :key="im.id" class="py-2 space-y-1">
|
||||
<div class="flex items-center justify-between">
|
||||
<p class="font-medium text-gray-700 dark:text-gray-300 truncate">
|
||||
{{ im.file_name }}
|
||||
</p>
|
||||
<span
|
||||
class="text-[10px] px-2 py-0.5 rounded-full bg-indigo-50 dark:bg-indigo-900/40 text-indigo-600 dark:text-indigo-300"
|
||||
>{{ im.status }}</span
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="w-full h-2 bg-gray-100 dark:bg-gray-700 rounded overflow-hidden"
|
||||
>
|
||||
<div
|
||||
class="h-full bg-indigo-500 dark:bg-indigo-400"
|
||||
:style="{ width: (im.progress_pct || 0) + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
<p class="text-[10px] text-gray-400 dark:text-gray-500">
|
||||
{{ im.imported_rows }}/{{ im.total_rows }} (veljavnih:
|
||||
{{ im.valid_rows }}, neveljavnih: {{ im.invalid_rows }})
|
||||
</p>
|
||||
</li>
|
||||
<li
|
||||
v-if="!importsInProgress.length"
|
||||
class="py-4 text-xs text-gray-500 text-center"
|
||||
>
|
||||
Ni aktivnih uvozov.
|
||||
</li>
|
||||
</ul>
|
||||
<div v-else class="space-y-2 animate-pulse">
|
||||
<div
|
||||
v-for="n in 4"
|
||||
:key="n"
|
||||
class="h-5 bg-gray-100 dark:bg-gray-700 rounded"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Active Document Templates -->
|
||||
<div class="bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-xl shadow-sm p-6">
|
||||
<h3 class="text-sm font-semibold tracking-wide text-gray-700 dark:text-gray-200 uppercase mb-4">Aktivne predloge dokumentov</h3>
|
||||
<ul v-if="activeTemplates" class="divide-y divide-gray-100 dark:divide-gray-700 text-sm">
|
||||
<li v-for="t in activeTemplates" :key="t.id" class="py-2 flex items-center justify-between">
|
||||
<div
|
||||
class="bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-xl shadow-sm p-6"
|
||||
>
|
||||
<h3
|
||||
class="text-sm font-semibold tracking-wide text-gray-700 dark:text-gray-200 uppercase mb-4"
|
||||
>
|
||||
Aktivne predloge dokumentov
|
||||
</h3>
|
||||
<ul
|
||||
v-if="activeTemplates"
|
||||
class="divide-y divide-gray-100 dark:divide-gray-700 text-sm"
|
||||
>
|
||||
<li
|
||||
v-for="t in activeTemplates"
|
||||
:key="t.id"
|
||||
class="py-2 flex items-center justify-between"
|
||||
>
|
||||
<div class="min-w-0">
|
||||
<p class="text-gray-700 dark:text-gray-300 font-medium truncate">{{ t.name }}</p>
|
||||
<p class="text-[11px] text-gray-400 dark:text-gray-500">v{{ t.version }} · {{ new Date(t.updated_at).toLocaleDateString() }}</p>
|
||||
<p class="text-gray-700 dark:text-gray-300 font-medium truncate">
|
||||
{{ t.name }}
|
||||
</p>
|
||||
<p class="text-[11px] text-gray-400 dark:text-gray-500">
|
||||
v{{ t.version }} · {{ new Date(t.updated_at).toLocaleDateString() }}
|
||||
</p>
|
||||
</div>
|
||||
<Link :href="route('admin.document-templates.edit', t.id)" class="text-[10px] px-2 py-0.5 rounded bg-indigo-50 dark:bg-indigo-900/40 text-indigo-600 dark:text-indigo-300 hover:bg-indigo-100 dark:hover:bg-indigo-800/60">Uredi</Link>
|
||||
<Link
|
||||
:href="route('admin.document-templates.edit', t.id)"
|
||||
class="text-[10px] px-2 py-0.5 rounded bg-indigo-50 dark:bg-indigo-900/40 text-indigo-600 dark:text-indigo-300 hover:bg-indigo-100 dark:hover:bg-indigo-800/60"
|
||||
>Uredi</Link
|
||||
>
|
||||
</li>
|
||||
<li
|
||||
v-if="!activeTemplates.length"
|
||||
class="py-4 text-xs text-gray-500 text-center"
|
||||
>
|
||||
Ni aktivnih predlog.
|
||||
</li>
|
||||
<li v-if="!activeTemplates.length" class="py-4 text-xs text-gray-500 text-center">Ni aktivnih predlog.</li>
|
||||
</ul>
|
||||
<div v-else class="space-y-2 animate-pulse">
|
||||
<div v-for="n in 5" :key="n" class="h-5 bg-gray-100 dark:bg-gray-700 rounded" />
|
||||
<div
|
||||
v-for="n in 5"
|
||||
:key="n"
|
||||
class="h-5 bg-gray-100 dark:bg-gray-700 rounded"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ...end of right side panels -->
|
||||
<!-- ...end of right side panels -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user