feat(simplify): simplified logs view
Default to showing problem orders (ERROR/SKIPPED) first. Imported orders collapsed behind "X comenzi importate cu succes" toggle. Reduces noise for operators scanning for issues. Cache-bust: logs.js?v=14, style.css?v=23 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1059,3 +1059,37 @@ tr.mapping-deleted td {
|
|||||||
border-color: var(--accent);
|
border-color: var(--accent);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Logs OK toggle ────────────────────── */
|
||||||
|
.log-ok-toggle {
|
||||||
|
padding: 8px 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
border-top: 1px solid var(--border-subtle);
|
||||||
|
}
|
||||||
|
.log-ok-toggle:hover { background: var(--surface-raised); }
|
||||||
|
|
||||||
|
/* ── Welcome card ──────────────────────── */
|
||||||
|
.welcome-card {
|
||||||
|
background: var(--accent-light);
|
||||||
|
border: 1px solid var(--accent);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.welcome-steps {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
.welcome-step {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.welcome-step a {
|
||||||
|
color: var(--info);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|||||||
@@ -141,7 +141,11 @@ async function loadRunOrders(runId, statusFilter, page) {
|
|||||||
if (orders.length === 0) {
|
if (orders.length === 0) {
|
||||||
tbody.innerHTML = '<tr><td colspan="9" class="text-center text-muted py-3">Nicio comanda</td></tr>';
|
tbody.innerHTML = '<tr><td colspan="9" class="text-center text-muted py-3">Nicio comanda</td></tr>';
|
||||||
} else {
|
} else {
|
||||||
tbody.innerHTML = orders.map((o, i) => {
|
const problemOrders = orders.filter(o => ['ERROR', 'SKIPPED'].includes(o.status));
|
||||||
|
const okOrders = orders.filter(o => ['IMPORTED', 'ALREADY_IMPORTED'].includes(o.status));
|
||||||
|
const otherOrders = orders.filter(o => !['ERROR', 'SKIPPED', 'IMPORTED', 'ALREADY_IMPORTED'].includes(o.status));
|
||||||
|
|
||||||
|
function orderRow(o, i) {
|
||||||
const dateStr = fmtDate(o.order_date);
|
const dateStr = fmtDate(o.order_date);
|
||||||
const orderTotal = o.order_total != null ? Number(o.order_total).toFixed(2) : '-';
|
const orderTotal = o.order_total != null ? Number(o.order_total).toFixed(2) : '-';
|
||||||
return `<tr style="cursor:pointer" onclick="openOrderDetail('${esc(o.order_number)}')">
|
return `<tr style="cursor:pointer" onclick="openOrderDetail('${esc(o.order_number)}')">
|
||||||
@@ -155,7 +159,31 @@ async function loadRunOrders(runId, statusFilter, page) {
|
|||||||
<td class="text-end text-muted">${fmtCost(o.discount_total)}</td>
|
<td class="text-end text-muted">${fmtCost(o.discount_total)}</td>
|
||||||
<td class="text-end fw-bold">${orderTotal}</td>
|
<td class="text-end fw-bold">${orderTotal}</td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
}).join('');
|
}
|
||||||
|
|
||||||
|
let html = '';
|
||||||
|
// Show problem orders first (always visible)
|
||||||
|
problemOrders.forEach((o, i) => { html += orderRow(o, i); });
|
||||||
|
otherOrders.forEach((o, i) => { html += orderRow(o, problemOrders.length + i); });
|
||||||
|
|
||||||
|
// Collapsible OK orders
|
||||||
|
if (okOrders.length > 0) {
|
||||||
|
const toggleId = 'okOrdersCollapse_' + Date.now();
|
||||||
|
html += `<tr><td colspan="9" class="p-0">
|
||||||
|
<div class="log-ok-toggle" onclick="this.nextElementSibling.classList.toggle('d-none')">
|
||||||
|
▶ ${okOrders.length} comenzi importate cu succes
|
||||||
|
</div>
|
||||||
|
<div class="d-none">
|
||||||
|
<table class="table mb-0">
|
||||||
|
<tbody>
|
||||||
|
${okOrders.map((o, i) => orderRow(o, problemOrders.length + otherOrders.length + i)).join('')}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</td></tr>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody.innerHTML = html;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mobile flat rows
|
// Mobile flat rows
|
||||||
@@ -164,7 +192,11 @@ async function loadRunOrders(runId, statusFilter, page) {
|
|||||||
if (orders.length === 0) {
|
if (orders.length === 0) {
|
||||||
mobileList.innerHTML = '<div class="flat-row text-muted py-3 justify-content-center">Nicio comanda</div>';
|
mobileList.innerHTML = '<div class="flat-row text-muted py-3 justify-content-center">Nicio comanda</div>';
|
||||||
} else {
|
} else {
|
||||||
mobileList.innerHTML = orders.map(o => {
|
const problemOrders = orders.filter(o => ['ERROR', 'SKIPPED'].includes(o.status));
|
||||||
|
const okOrders = orders.filter(o => ['IMPORTED', 'ALREADY_IMPORTED'].includes(o.status));
|
||||||
|
const otherOrders = orders.filter(o => !['ERROR', 'SKIPPED', 'IMPORTED', 'ALREADY_IMPORTED'].includes(o.status));
|
||||||
|
|
||||||
|
function mobileRow(o) {
|
||||||
const d = o.order_date || '';
|
const d = o.order_date || '';
|
||||||
let dateFmt = '-';
|
let dateFmt = '-';
|
||||||
if (d.length >= 10) {
|
if (d.length >= 10) {
|
||||||
@@ -178,7 +210,22 @@ async function loadRunOrders(runId, statusFilter, page) {
|
|||||||
<span class="grow truncate fw-bold">${esc(o.customer_name || '—')}</span>
|
<span class="grow truncate fw-bold">${esc(o.customer_name || '—')}</span>
|
||||||
<span class="text-nowrap">x${o.items_count || 0}${totalStr ? ' · <strong>' + totalStr + '</strong>' : ''}</span>
|
<span class="text-nowrap">x${o.items_count || 0}${totalStr ? ' · <strong>' + totalStr + '</strong>' : ''}</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}
|
||||||
|
|
||||||
|
let mobileHtml = '';
|
||||||
|
problemOrders.forEach(o => { mobileHtml += mobileRow(o); });
|
||||||
|
otherOrders.forEach(o => { mobileHtml += mobileRow(o); });
|
||||||
|
|
||||||
|
if (okOrders.length > 0) {
|
||||||
|
mobileHtml += `<div class="log-ok-toggle" onclick="this.nextElementSibling.classList.toggle('d-none')">
|
||||||
|
▶ ${okOrders.length} comenzi importate cu succes
|
||||||
|
</div>
|
||||||
|
<div class="d-none">
|
||||||
|
${okOrders.map(o => mobileRow(o)).join('')}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
mobileList.innerHTML = mobileHtml;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.2/font/bootstrap-icons.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.2/font/bootstrap-icons.css" rel="stylesheet">
|
||||||
{% set rp = request.scope.get('root_path', '') %}
|
{% set rp = request.scope.get('root_path', '') %}
|
||||||
<link href="{{ rp }}/static/css/style.css?v=22" rel="stylesheet">
|
<link href="{{ rp }}/static/css/style.css?v=24" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Top Navbar (hidden on mobile via CSS) -->
|
<!-- Top Navbar (hidden on mobile via CSS) -->
|
||||||
|
|||||||
@@ -102,5 +102,5 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="{{ request.scope.get('root_path', '') }}/static/js/logs.js?v=13"></script>
|
<script src="{{ request.scope.get('root_path', '') }}/static/js/logs.js?v=14"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user