Browse Source

Merge pull request #304 from xxeisenberg/main

feat: improve job details interaction and accessibility
Emrik Östling 1 month ago
parent
commit
2a3b08487e
1 changed files with 120 additions and 18 deletions
  1. 120 18
      src/index.tsx

+ 120 - 18
src/index.tsx

@@ -107,6 +107,7 @@ class Jobs {
   date_created!: string;
   status!: string;
   num_files!: number;
+  files_detailed!: Filename[];
 }
 
 // enable WAL mode
@@ -1131,6 +1132,7 @@ const app = new Elysia({
         .all(job.id);
 
       job.finished_files = files.length;
+      job.files_detailed = files;
     }
 
     // filter out jobs with no files
@@ -1162,6 +1164,14 @@ const app = new Elysia({
               >
                 <thead>
                   <tr>
+                    <th
+                      class={`
+                        px-2 py-2
+                        sm:px-4
+                      `}
+                    >
+                      <span class="sr-only">Expand details</span>
+                    </th>
                     <th
                       class={`
                         px-2 py-2
@@ -1207,30 +1217,122 @@ const app = new Elysia({
                 </thead>
                 <tbody>
                   {userJobs.map((job) => (
-                    <tr>
-                      <td safe>
-                        {new Date(job.date_created).toLocaleTimeString()}
-                      </td>
-                      <td>{job.num_files}</td>
-                      <td class="max-sm:hidden">{job.finished_files}</td>
-                      <td safe>{job.status}</td>
-                      <td>
-                        <a
-                          class={`
-                            text-accent-500 underline
-                            hover:text-accent-400
-                          `}
-                          href={`${WEBROOT}/results/${job.id}`}
+                    <>
+                      <tr key={`job-${job.id}` as any} id={`job-row-${job.id}`}>
+                        <td
+                          class="job-details-toggle cursor-pointer"
+                          data-job-id={job.id}
                         >
-                          View
-                        </a>
-                      </td>
-                    </tr>
+                          <svg
+                            id={`arrow-${job.id}`}
+                            xmlns="http://www.w3.org/2000/svg"
+                            fill="none"
+                            viewBox="0 0 24 24"
+                            stroke-width="1.5"
+                            stroke="currentColor"
+                            class="inline-block h-4 w-4"
+                          >
+                            <path
+                              stroke-linecap="round"
+                              stroke-linejoin="round"
+                              d="M8.25 4.5l7.5 7.5-7.5 7.5"
+                            />
+                          </svg>
+                        </td>
+                        <td safe>
+                          {new Date(job.date_created).toLocaleTimeString()}
+                        </td>
+                        <td>{job.num_files}</td>
+                        <td class="max-sm:hidden">{job.finished_files}</td>
+                        <td safe>{job.status}</td>
+                        <td>
+                          <a
+                            class={`
+                              text-accent-500 underline
+                              hover:text-accent-400
+                            `}
+                            href={`${WEBROOT}/results/${job.id}`}
+                          >
+                            View
+                          </a>
+                        </td>
+                      </tr>
+                      <tr id={`details-${job.id}`} class="hidden">
+                        <td colspan="6">
+                          <div class="p-2 text-sm text-neutral-500">
+                            <div class="mb-1 font-semibold">
+                              Detailed File Information:
+                            </div>
+                            {job.files_detailed.map(
+                              (file: Filename, index: number) => (
+                                <div
+                                  key={String(file.id) as any}
+                                  class="flex items-center"
+                                >
+                                  <span
+                                    class="w-5/12 truncate"
+                                    title={file.file_name}
+                                    safe
+                                  >
+                                    {file.file_name}
+                                  </span>
+                                  <svg
+                                    xmlns="http://www.w3.org/2000/svg"
+                                    viewBox="0 0 20 20"
+                                    fill="currentColor"
+                                    class="w-4 h-4 inline-block mx-2 text-neutral-500"
+                                  >
+                                    <path
+                                      fill-rule="evenodd"
+                                      d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z"
+                                      clip-rule="evenodd"
+                                    />
+                                  </svg>
+                                  <span
+                                    class="w-5/12 truncate"
+                                    title={file.output_file_name}
+                                    safe
+                                  >
+                                    {file.output_file_name}
+                                  </span>
+                                </div>
+                              ),
+                            )}
+                          </div>
+                        </td>
+                      </tr>
+                    </>
                   ))}
                 </tbody>
               </table>
             </article>
           </main>
+          <script>
+            {`
+              document.addEventListener('DOMContentLoaded', () => {
+                const toggles = document.querySelectorAll('.job-details-toggle');
+                toggles.forEach(toggle => {
+                  toggle.addEventListener('click', function() {
+                    const jobId = this.dataset.jobId;
+                    const detailsRow = document.getElementById(\`details-\${jobId}\`);
+                    // The arrow SVG itself has the ID arrow-\${jobId}
+                    const arrow = document.getElementById(\`arrow-\${jobId}\`);
+
+                    if (detailsRow && arrow) {
+                      detailsRow.classList.toggle("hidden");
+                      if (detailsRow.classList.contains("hidden")) {
+                        // Right-facing arrow (collapsed)
+                        arrow.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />';
+                      } else {
+                        // Down-facing arrow (expanded)
+                        arrow.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />';
+                      }
+                    }
+                  });
+                });
+              });
+            `}
+          </script>
         </>
       </BaseHtml>
     );