Kaynağa Gözat

added search to the activity log

Bernn 1 hafta önce
ebeveyn
işleme
75c5f067e5
1 değiştirilmiş dosya ile 88 ekleme ve 12 silme
  1. 88 12
      log.php

+ 88 - 12
log.php

@@ -5,15 +5,35 @@ require_once __DIR__ . '/lib/render.php';
 $actor = current_actor('ICG');
 $actor = current_actor('ICG');
 
 
 $job_filter = isset($_GET['job']) ? (int) $_GET['job'] : 0;
 $job_filter = isset($_GET['job']) ? (int) $_GET['job'] : 0;
-$limit = isset($_GET['limit']) ? max(50, min(1000, (int) $_GET['limit'])) : 200;
+$q          = trim((string) ($_GET['q'] ?? ''));
+$limit      = isset($_GET['limit']) ? max(50, min(1000, (int) $_GET['limit'])) : 200;
+
+$clauses = [];
+$params  = [];
 
 
-$where = '1=1';
-$params = [];
 if ($job_filter > 0) {
 if ($job_filter > 0) {
-    $where = 'h.job_id = ?';
-    $params[] = $job_filter;
+    $clauses[] = 'h.job_id = ?';
+    $params[]  = $job_filter;
+}
+
+if ($q !== '') {
+    // SQLite LIKE is case-insensitive for ASCII. Escape user wildcards so a
+    // literal "%" or "_" doesn't blow the search open.
+    $needle = '%' . strtr($q, ['\\' => '\\\\', '%' => '\\%', '_' => '\\_']) . '%';
+    $clauses[] =
+        "(j.job         LIKE ? ESCAPE '\\'
+       OR j.material    LIKE ? ESCAPE '\\'
+       OR j.description LIKE ? ESCAPE '\\'
+       OR v.name        LIKE ? ESCAPE '\\'
+       OR h.actor       LIKE ? ESCAPE '\\'
+       OR h.field       LIKE ? ESCAPE '\\'
+       OR h.old_value   LIKE ? ESCAPE '\\'
+       OR h.new_value   LIKE ? ESCAPE '\\')";
+    array_push($params, $needle, $needle, $needle, $needle, $needle, $needle, $needle, $needle);
 }
 }
 
 
+$where = $clauses ? implode(' AND ', $clauses) : '1=1';
+
 $sql = "
 $sql = "
     SELECT h.*, j.job AS job_label, j.description AS job_description,
     SELECT h.*, j.job AS job_label, j.description AS job_description,
            v.slug AS vendor_slug, v.name AS vendor_name
            v.slug AS vendor_slug, v.name AS vendor_name
@@ -28,6 +48,11 @@ $stmt = db()->prepare($sql);
 $stmt->execute($params);
 $stmt->execute($params);
 $rows = $stmt->fetchAll();
 $rows = $stmt->fetchAll();
 
 
+function preserve_qs(array $keep): string {
+    if (!$keep) return '';
+    return '?' . http_build_query($keep);
+}
+
 function fmt_long_date(?string $ts): string {
 function fmt_long_date(?string $ts): string {
     if (!$ts) return '';
     if (!$ts) return '';
     try {
     try {
@@ -108,6 +133,32 @@ table.log th {
 .log-filter a { color: var(--c-accent-strong); }
 .log-filter a { color: var(--c-accent-strong); }
 .log-desc  { max-width: 24em; }
 .log-desc  { max-width: 24em; }
 .log-muted { color: var(--c-muted); }
 .log-muted { color: var(--c-muted); }
+
+.log-search {
+    display: flex;
+    gap: 0.5rem;
+    align-items: center;
+    margin: 0.75rem 0 0.5rem;
+}
+.log-search input[type="text"] {
+    flex: 0 1 28rem;
+    font-size: 1rem;
+    padding: 0.4rem 0.6rem;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+}
+.log-search input[type="text"]:focus { outline: 2px solid var(--c-info); }
+.log-search button {
+    font-size: 0.95rem;
+    padding: 0.45rem 1rem;
+    border: 0;
+    border-radius: 4px;
+    background: var(--c-accent-strong);
+    color: #fff;
+    font-weight: 600;
+    cursor: pointer;
+}
+.log-clear { color: var(--c-muted); font-size: 0.9rem; }
 </style>
 </style>
 </head>
 </head>
 <body>
 <body>
@@ -117,14 +168,39 @@ table.log th {
     <span class="who"><a href="PDQ.php">&larr; Back to schedule</a></span>
     <span class="who"><a href="PDQ.php">&larr; Back to schedule</a></span>
 </div>
 </div>
 
 
-<?php if ($job_filter > 0): ?>
+<form class="log-search" method="get" action="log.php">
+    <input type="text" name="q" value="<?= h($q) ?>" placeholder="Search job, material, description, actor, status…" autofocus>
+    <?php if ($job_filter > 0): ?>
+        <input type="hidden" name="job" value="<?= (int) $job_filter ?>">
+    <?php endif; ?>
+    <button type="submit">Search</button>
+    <?php if ($q !== '' || $job_filter > 0): ?>
+        <a class="log-clear" href="log.php">Clear</a>
+    <?php endif; ?>
+</form>
+
 <p class="log-filter">
 <p class="log-filter">
-    Showing events for job #<?= (int) $job_filter ?>.
-    <a href="log.php">Show everything &rarr;</a>
+    <?php
+    $bits = [];
+    if ($job_filter > 0) {
+        $bits[] = 'job <strong>#' . (int) $job_filter . '</strong>';
+    }
+    if ($q !== '') {
+        $bits[] = 'matching <strong>&ldquo;' . h($q) . '&rdquo;</strong>';
+    }
+    if ($bits) {
+        echo count($rows) . ' event' . (count($rows) === 1 ? '' : 's') . ' ' . implode(' &middot; ', $bits) . '.';
+        if ($job_filter > 0) {
+            echo ' <a href="' . h(preserve_qs($q !== '' ? ['q' => $q] : [])) . '">drop job filter</a>';
+        }
+        if ($q !== '') {
+            echo ' <a href="' . h(preserve_qs($job_filter > 0 ? ['job' => $job_filter] : [])) . '">drop search</a>';
+        }
+    } else {
+        echo 'Latest ' . count($rows) . ' events. Click a job number to filter, or search above.';
+    }
+    ?>
 </p>
 </p>
-<?php else: ?>
-<p class="log-filter">Latest <?= count($rows) ?> events. Click a job number to filter.</p>
-<?php endif; ?>
 
 
 <table class="log">
 <table class="log">
     <thead>
     <thead>
@@ -148,7 +224,7 @@ table.log th {
         <tr>
         <tr>
             <td class="log-ts"><?= fmt_long_date($h['changed_at']) ?></td>
             <td class="log-ts"><?= fmt_long_date($h['changed_at']) ?></td>
             <td class="log-actor <?= $actorKlass ?>"><?= h($h['actor']) ?></td>
             <td class="log-actor <?= $actorKlass ?>"><?= h($h['actor']) ?></td>
-            <td class="log-job"><a href="?job=<?= (int) $h['job_id'] ?>"><?= $jobLabel ?></a></td>
+            <td class="log-job"><a href="<?= h(preserve_qs(['job' => (int) $h['job_id']] + ($q !== '' ? ['q' => $q] : []))) ?>"><?= $jobLabel ?></a></td>
             <td class="log-desc"><?= $desc === '' ? '<span class="log-muted">&mdash;</span>' : h($desc) ?></td>
             <td class="log-desc"><?= $desc === '' ? '<span class="log-muted">&mdash;</span>' : h($desc) ?></td>
             <td><?= fmt_event($h) ?></td>
             <td><?= fmt_event($h) ?></td>
         </tr>
         </tr>