Bugfixeds

This commit is contained in:
Justin Visser 2026-03-01 22:54:23 +01:00
parent a5165dc3ba
commit 4403c9ebde
20 changed files with 199 additions and 85 deletions

View file

@ -13,7 +13,7 @@ function buildItem(overrides: Partial<PublicationItem> = {}): PublicationItem {
citation_count: 42,
pub_url: "https://example.com/pub",
pdf_url: null,
pdf_status: null,
pdf_status: "untracked",
is_read: false,
is_favorite: false,
is_new_in_latest_run: true,

View file

@ -1,4 +1,4 @@
import { computed, ref, watch } from "vue";
import { computed, onScopeDispose, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import {
listPublications,
@ -271,6 +271,10 @@ export function usePublicationData() {
}, 300);
});
onScopeDispose(() => {
if (searchDebounceTimer !== null) clearTimeout(searchDebounceTimer);
});
// --- Run-triggered refresh watcher ---
watch(

View file

@ -36,10 +36,8 @@ async function refreshForSection(): Promise<void> {
return;
}
if (props.section === SECTION_REPAIRS) {
await Promise.all([
usersRef.value?.load(),
repairsRef.value?.load(),
]);
await usersRef.value?.load();
await repairsRef.value?.load();
return;
}
if (props.section === SECTION_PDF && pdfQueueRef.value) {

View file

@ -7,6 +7,7 @@ import AppHelpHint from "@/components/ui/AppHelpHint.vue";
import AppRefreshButton from "@/components/ui/AppRefreshButton.vue";
import AppSelect from "@/components/ui/AppSelect.vue";
import AppTable from "@/components/ui/AppTable.vue";
import RequestStateAlerts from "@/components/patterns/RequestStateAlerts.vue";
import {
listAdminPdfQueue,
requeueAdminPdfLookup,
@ -15,7 +16,7 @@ import {
} from "@/features/admin_dbops";
import { useRequestState } from "@/composables/useRequestState";
const { clearAlerts, assignError, setSuccess } = useRequestState();
const { errorMessage, errorRequestId, successMessage, clearAlerts, assignError, setSuccess } = useRequestState();
const refreshingPdfQueue = ref(false);
const requeueingPublicationId = ref<number | null>(null);
@ -131,7 +132,17 @@ defineExpose({ load });
</script>
<template>
<AppCard class="space-y-3">
<section class="grid gap-4">
<RequestStateAlerts
:success-message="successMessage"
:error-message="errorMessage"
:error-request-id="errorRequestId"
success-title="PDF queue operation complete"
error-title="PDF queue operation failed"
@dismiss-success="successMessage = null"
/>
<AppCard class="space-y-3">
<div class="flex flex-wrap items-center justify-between gap-2">
<div class="flex items-center gap-1">
<h2 class="text-lg font-semibold text-ink-primary">PDF Gathering Queue</h2>
@ -200,4 +211,5 @@ defineExpose({ load });
</div>
</div>
</AppCard>
</section>
</template>

View file

@ -9,6 +9,7 @@ import AppInput from "@/components/ui/AppInput.vue";
import AppRefreshButton from "@/components/ui/AppRefreshButton.vue";
import AppSelect from "@/components/ui/AppSelect.vue";
import AppTable from "@/components/ui/AppTable.vue";
import RequestStateAlerts from "@/components/patterns/RequestStateAlerts.vue";
import {
dropAllPublications,
listAdminDbRepairJobs,
@ -34,7 +35,7 @@ const DROP_PUBLICATIONS_CONFIRM_TEXT = "DROP ALL PUBLICATIONS";
type RepairScopeMode = typeof SCOPE_SINGLE_USER | typeof SCOPE_ALL_USERS;
const { clearAlerts, assignError, setSuccess } = useRequestState();
const { errorMessage, errorRequestId, successMessage, clearAlerts, assignError, setSuccess } = useRequestState();
const refreshingJobs = ref(false);
const runningRepair = ref(false);
@ -246,6 +247,15 @@ defineExpose({ load });
<template>
<section class="grid gap-4">
<RequestStateAlerts
:success-message="successMessage"
:error-message="errorMessage"
:error-request-id="errorRequestId"
success-title="Repair operation complete"
error-title="Repair operation failed"
@dismiss-success="successMessage = null"
/>
<AppCard class="space-y-3">
<div class="flex items-center gap-1">
<h2 class="text-lg font-semibold text-ink-primary">Publication Link Repair</h2>

View file

@ -335,14 +335,23 @@ async function onStartRun(): Promise<void> {
pub.successMessage.value = null;
pub.errorMessage.value = null;
pub.errorRequestId.value = null;
const result = await runStatus.startManualCheck();
if (result.kind === "started") { pub.successMessage.value = `Run #${result.runId} started.`; return; }
if (result.kind === "already_running") {
pub.successMessage.value = result.runId ? `Run #${result.runId} is already in progress.` : "A run is already in progress.";
return;
try {
const result = await runStatus.startManualCheck();
if (result.kind === "started") { pub.successMessage.value = `Run #${result.runId} started.`; return; }
if (result.kind === "already_running") {
pub.successMessage.value = result.runId ? `Run #${result.runId} is already in progress.` : "A run is already in progress.";
return;
}
pub.errorMessage.value = result.message;
pub.errorRequestId.value = result.requestId;
} catch (error) {
if (error instanceof ApiRequestError) {
pub.errorMessage.value = error.message;
pub.errorRequestId.value = error.requestId;
} else {
pub.errorMessage.value = "Unable to start manual run.";
}
}
pub.errorMessage.value = result.message;
pub.errorRequestId.value = result.requestId;
}
// --- Lifecycle ---