|
| 1 | +<script> |
| 2 | + import { page } from '$app/stores'; |
| 3 | + import { displayStandardErrorAlert } from '$lib/common/errors'; |
| 4 | + import TasksTable from '$lib/components/tasks/TasksTable.svelte'; |
| 5 | +
|
| 6 | + /** @type {import('$lib/components/common/StandardErrorAlert.svelte').default|undefined} */ |
| 7 | + let errorAlert; |
| 8 | +
|
| 9 | + /** @type {import('$lib/types').Task[]} */ |
| 10 | + let tasks = $page.data.tasks; |
| 11 | +
|
| 12 | + /** |
| 13 | + * Instead of replacing the whole tasks object on successful PATCH response, this compatibility map |
| 14 | + * is used to draw the state of checkboxes. This prevents the complete redraw of the table when the |
| 15 | + * compatibility of a single task change, avoiding to collapse the opened old versions rows. |
| 16 | + * @type {{[taskId: string]: boolean}} |
| 17 | + */ |
| 18 | + let compatibilities = Object.fromEntries(tasks.map((t) => [t.id, t.is_v2_compatible])); |
| 19 | +
|
| 20 | + /** @type {number|null} */ |
| 21 | + let editingTaskId = null; |
| 22 | +
|
| 23 | + /** |
| 24 | + * @param {Event} event |
| 25 | + * @param {import('$lib/types').Task} task |
| 26 | + */ |
| 27 | + async function setV2Compatible(event, task) { |
| 28 | + if (errorAlert) { |
| 29 | + errorAlert.hide(); |
| 30 | + } |
| 31 | + editingTaskId = task.id; |
| 32 | + const headers = new Headers(); |
| 33 | + headers.set('Content-Type', 'application/json'); |
| 34 | + const is_v2_compatible = !task.is_v2_compatible; |
| 35 | + const response = await fetch(`/api/admin/v2/task-v1/${task.id}`, { |
| 36 | + method: 'PATCH', |
| 37 | + headers, |
| 38 | + body: JSON.stringify({ is_v2_compatible }) |
| 39 | + }); |
| 40 | + if (response.ok) { |
| 41 | + // Update compatibilities map and task object |
| 42 | + compatibilities[task.id] = is_v2_compatible; |
| 43 | + task.is_v2_compatible = is_v2_compatible; |
| 44 | + compatibilities = compatibilities; |
| 45 | + } else { |
| 46 | + errorAlert = displayStandardErrorAlert( |
| 47 | + await response.json(), |
| 48 | + `errorAlert-tasksCompatibility` |
| 49 | + ); |
| 50 | + // reset input state in case of error |
| 51 | + if (event.target instanceof HTMLInputElement) { |
| 52 | + event.target.checked = !is_v2_compatible; |
| 53 | + } |
| 54 | + } |
| 55 | + editingTaskId = null; |
| 56 | + } |
| 57 | +</script> |
| 58 | + |
| 59 | +<div> |
| 60 | + <div class="d-flex justify-content-between align-items-center mb-3"> |
| 61 | + <h1 class="fw-light">v1/v2 tasks compatibility</h1> |
| 62 | + </div> |
| 63 | +</div> |
| 64 | + |
| 65 | +<div id="errorAlert-tasksCompatibility" /> |
| 66 | + |
| 67 | +<TasksTable {tasks}> |
| 68 | + <svelte:fragment slot="thead"> |
| 69 | + <thead> |
| 70 | + <tr> |
| 71 | + <th>Id</th> |
| 72 | + <th>Name</th> |
| 73 | + <th>Version</th> |
| 74 | + <th>V2 compatible</th> |
| 75 | + </tr> |
| 76 | + </thead> |
| 77 | + </svelte:fragment> |
| 78 | + <svelte:fragment slot="custom-columns-left" let:task> |
| 79 | + <td>{task.id}</td> |
| 80 | + </svelte:fragment> |
| 81 | + <svelte:fragment slot="custom-columns-right" let:task> |
| 82 | + <td> |
| 83 | + <div class="form-check form-switch"> |
| 84 | + <input |
| 85 | + class="form-check-input" |
| 86 | + type="checkbox" |
| 87 | + role="switch" |
| 88 | + id="task-{task.id}-compatible" |
| 89 | + on:change={(event) => setV2Compatible(event, task)} |
| 90 | + checked={compatibilities[task.id]} |
| 91 | + disabled={editingTaskId === task.id} |
| 92 | + /> |
| 93 | + <label class="form-check-label" for="task-{task.id}-compatible"> |
| 94 | + {compatibilities[task.id]} |
| 95 | + {#if editingTaskId === task.id} |
| 96 | + <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" /> |
| 97 | + {/if} |
| 98 | + </label> |
| 99 | + </div> |
| 100 | + </td> |
| 101 | + </svelte:fragment> |
| 102 | +</TasksTable> |
0 commit comments