feat(jobs/ui): hide consistency_batch, the main button is here

This commit is contained in:
Edouard Vanbelle
2026-07-29 23:21:39 +02:00
parent 8de50ec404
commit 07beb461d6
@@ -70,27 +70,42 @@
* iterates a HashMap so its order is non-deterministic — * iterates a HashMap so its order is non-deterministic —
* refreshing shuffles rows and hurts orientation. * refreshing shuffles rows and hurts orientation.
* *
* Two-tier sort: consistency tenants (including the * Two-tier sort:
* `consistency_batch` coordinator) group first, other tenants * 0. `*_consistency` tenants — alphabetical.
* follow. Alphabetical within each group. Keeps the consistency * 1. All other jobs — alphabetical.
* story visually together so an operator investigating *
* corruption doesn't have to scan the full list to find the * The `consistency_batch` coordinator is DELIBERATELY excluded
* related tenants. * from the table (see the filter in `loadJobs`). The top-bar
* "Run all consistency checks" + "Run deep" buttons already
* dispatch it — showing it as a table row too was pure
* duplication.
*/ */
function sortKey(name: string): [number, string] { function sortKey(name: string): [number, string] {
const isConsistency = name.endsWith('_consistency') || name === 'consistency_batch'; if (name.endsWith('_consistency')) return [0, name];
return [isConsistency ? 0 : 1, name]; return [1, name];
} }
async function loadJobs() { async function loadJobs() {
try { try {
const fetched = await listJobs(); const fetched = await listJobs();
jobs = fetched.slice().sort((a, b) => { jobs = fetched
const [ga, na] = sortKey(a.name); .slice()
const [gb, nb] = sortKey(b.name); // `consistency_batch` is served by the top-bar
if (ga !== gb) return ga - gb; // action buttons; hiding it here removes the
return na.localeCompare(nb); // duplicate table row. `hasBatch` still checks the
}); // full fetched list so the top buttons only render
// when the coordinator is actually registered.
.filter((j) => j.name !== 'consistency_batch')
.sort((a, b) => {
const [ga, na] = sortKey(a.name);
const [gb, nb] = sortKey(b.name);
if (ga !== gb) return ga - gb;
return na.localeCompare(nb);
});
// Track whether the coordinator is registered so the
// top-bar buttons can gate on it without checking `jobs`
// (which now filters it out).
hasBatch = fetched.some((j) => j.name === 'consistency_batch');
loadError = null; loadError = null;
} catch (e) { } catch (e) {
loadError = errorMessage(e); loadError = errorMessage(e);
@@ -426,7 +441,11 @@
// coordinator is registered (should always be true post-Slice 5, // coordinator is registered (should always be true post-Slice 5,
// but check defensively so the button doesn't appear on an old // but check defensively so the button doesn't appear on an old
// deployment before this component is upgraded). // deployment before this component is upgraded).
const hasBatch = $derived(jobs?.some((j) => j.name === 'consistency_batch') ?? false); // Coordinator registration flag — set imperatively in
// `loadJobs` because `jobs` no longer contains the
// `consistency_batch` row (filtered out to avoid duplicating the
// top-bar action buttons).
let hasBatch = $state(false);
</script> </script>
<section class="jobs-panel"> <section class="jobs-panel">
@@ -459,7 +478,7 @@
)} )}
onclick={() => onTrigger('consistency_batch', { deep: true })} onclick={() => onTrigger('consistency_batch', { deep: true })}
> >
<Icon name="search" /> <Icon name="play" />
{t('admin.jobs.run_deep', 'Run deep')} {t('admin.jobs.run_deep', 'Run deep')}
</button> </button>
</div> </div>