Extract a shared ManageMenu; add notFoundOr for the repeated 404 pattern

ManageMenu.vue holds what ProjectManageMenu and CardManageMenu had
copy-pasted between them almost verbatim: the dropdown, the confirm
modal, both useDialog wirings, menuOpen/confirmingDelete/deleting
state. Each is now a thin wrapper supplying only what's genuinely
entity-specific -- the Configure route, the delete labels, and (as
confirmDelete) what deleting actually does, since that differs more
than the UI around it (which stores to refresh, where to navigate).
The confirmation body text comes through the default slot, since a
project's names its card count and a card's doesn't.

notFoundOr(e, notFoundMessage, fallbackMessage) in lib/api.ts replaces
the identical "404 -> fixed message, else -> the error's own message,
else -> a fallback" block that ProjectView, ProjectConfigureView,
CardView, and CardConfigureView had each written out by hand.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-05 01:25:37 +01:00
co-authored by Claude Sonnet 5
parent 6c7b78ad4b
commit 367a98308a
8 changed files with 174 additions and 226 deletions
+11
View File
@@ -38,6 +38,17 @@ export class ApiError extends Error {
}
}
/**
* A message for a caught error: a fixed one for "not found" (404), the
* server's own message for any other API error, and a fallback for
* anything else (e.g. a network failure) -- the shape every view's initial
* load uses to turn a failed fetch into what it shows the user.
*/
export function notFoundOr(e: unknown, notFoundMessage: string, fallbackMessage: string): string {
if (e instanceof ApiError && e.status === 404) return notFoundMessage
return e instanceof ApiError ? e.message : fallbackMessage
}
interface RequestOptions {
method?: string
body?: unknown