DRY pass #2, batch 8: stale comments (#5372)

useNoteList no longer names a Search view; the desktop adapter's M10.7 plan
gave way to sync under the local core; local.ts's sharing comment sat above
settings; AccountList and password_resets still said there was no mail path;
NoteEditor kept an orphan checklist-flag comment, a textarea comment from
before blocks, and the link-preview comment above the file picker; the
serialize docstring's growth plan is now what it holds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 15:03:50 -04:00
co-authored by Claude Opus 5.5
parent e911f1d757
commit 2ce68f578a
7 changed files with 17 additions and 23 deletions
+2 -3
View File
@@ -2,9 +2,8 @@
// `api/client` in stores/views. // `api/client` in stores/views.
// //
// The desktop shell runs fully offline against the on-device SQLite core // The desktop shell runs fully offline against the on-device SQLite core
// (`local.ts`, over Tauri `invoke`); the web build uses REST. A server-connected // (`local.ts`, over Tauri `invoke`); the web build uses REST. A desktop linked to a
// desktop (opt-in sync) comes in M10.7 — at which point this becomes // server still reads and writes locally: the core syncs underneath.
// `isDesktop() && !hasConfiguredServer() ? local : rest`.
import { isDesktop } from "../desktop/bridge"; import { isDesktop } from "../desktop/bridge";
import { rest } from "./rest"; import { rest } from "./rest";
+3 -2
View File
@@ -84,14 +84,15 @@ export const local: Repo = {
titles: () => invoke<TitleEntry[]>("notes_titles"), titles: () => invoke<TitleEntry[]>("notes_titles"),
}, },
// Sharing is between accounts on a server, so these go to the linked one (#5175). // The server's admin settings aren't reached from the desktop, linked or not.
// Unlinked, each rejects with the core's explanation, which the dialog shows.
settings: { settings: {
list: () => Promise.reject<ServerSetting[]>(new Error(NEEDS_SERVER)), list: () => Promise.reject<ServerSetting[]>(new Error(NEEDS_SERVER)),
save: () => Promise.reject<ServerSetting[]>(new Error(NEEDS_SERVER)), save: () => Promise.reject<ServerSetting[]>(new Error(NEEDS_SERVER)),
sendTestEmail: () => Promise.reject<{ to: string }>(new Error(NEEDS_SERVER)), sendTestEmail: () => Promise.reject<{ to: string }>(new Error(NEEDS_SERVER)),
}, },
// Sharing is between accounts on a server, so these go to the linked one (#5175).
// Unlinked, each rejects with the core's explanation, which the dialog shows.
shares: { shares: {
directory: () => invoke<Directory>("shares_directory"), directory: () => invoke<Directory>("shares_directory"),
list: (noteId) => invoke<NoteShare[]>("shares_list", { noteId }), list: (noteId) => invoke<NoteShare[]>("shares_list", { noteId }),
+2 -1
View File
@@ -7,7 +7,8 @@ import OneTimeLink from "./OneTimeLink.vue";
import { useRowAction, useLoad } from "../composables/useAction"; import { useRowAction, useLoad } from "../composables/useAction";
// Admin: the accounts on this instance, and a password reset link for any of them // Admin: the accounts on this instance, and a password reset link for any of them
// (#5173). There is no mail path, so the admin hands the link over. // (#5173). The admin hands the link over; a person can also mail one to themselves
// when the server can send email (#5266).
interface Account { interface Account {
id: string; id: string;
+6 -12
View File
@@ -47,9 +47,6 @@ function setBody(text: string): void {
blocks.value = splitBlocks(text); blocks.value = splitBlocks(text);
} }
const labelList = ref<NoteLabel[]>(props.note ? [...props.note.labels] : []); const labelList = ref<NoteLabel[]>(props.note ? [...props.note.labels] : []);
// Whether this editor is showing the checklist. A note HAS a checklist (M13 step 2)
// rather than BEING one, so this is a view flag, not a property of the note: it turns
// on when the note already carries items, and when someone asks for one.
const saving = ref(false); const saving = ref(false);
const root = ref<HTMLElement | null>(null); const root = ref<HTMLElement | null>(null);
// One element per block, keyed by the block's id — the only thing about a block that // One element per block, keyed by the block's id — the only thing about a block that
@@ -489,12 +486,6 @@ async function uploadFile(file: File) {
} }
} }
// ---- link previews ----
//
// Nothing to trigger any more: the server unfurls a note's URLs in the background
// after each save (`unfurl_queue.py`) and the preview arrives on a later read. What
// is left here is removing one you don't want — the editor is the only place with
// room to offer that, and the card deliberately doesn't.
async function onFileChange(e: Event) { async function onFileChange(e: Event) {
const input = e.target as HTMLInputElement; const input = e.target as HTMLInputElement;
const file = input.files?.[0]; const file = input.files?.[0];
@@ -638,7 +629,10 @@ function revPreview(rev: NoteRevision): string {
device until you remove it. device until you remove it.
</p> </p>
<!-- Fetched automatically after each save; removable here and nowhere else. --> <!-- The server unfurls a note's URLs in the background after each save
(`unfurl_queue.py`) and the preview arrives on a later read. Removing one
happens here and nowhere else: the editor has room to offer it, and the
card deliberately doesn't. -->
<div v-if="liveNote.previews.length" class="flex flex-col gap-2"> <div v-if="liveNote.previews.length" class="flex flex-col gap-2">
<LinkPreview <LinkPreview
v-for="p in liveNote.previews" v-for="p in liveNote.previews"
@@ -698,8 +692,8 @@ function revPreview(rev: NoteRevision): string {
/> />
</template> </template>
</div> </div>
<!-- No checklist component. The items are lines of the textarea above, which <!-- No checklist component. The items are blocks above, each one line of the
is what lets a list sit between two paragraphs (M304). --> body, which is what lets a list sit between two paragraphs (M304). -->
<div v-if="labelList.length" class="flex flex-wrap gap-1.5 pt-1"> <div v-if="labelList.length" class="flex flex-wrap gap-1.5 pt-1">
<span <span
+2 -2
View File
@@ -2,12 +2,12 @@ import { ref, type Ref } from "vue";
import type { Note } from "../stores/notes"; import type { Note } from "../stores/notes";
import { errorMessage } from "../api/errors"; import { errorMessage } from "../api/errors";
// The load-a-list-of-notes scaffold every recall view (Search, Timeline, Reminders) // The load-a-list-of-notes scaffold every recall view (Timeline, Reminders)
// hand-rolled: an items ref + loading/error flags + a load() that fills them and never // hand-rolled: an items ref + loading/error flags + a load() that fills them and never
// leaves a half-state. The view supplies just the fetcher; wire the returned refs into // leaves a half-state. The view supplies just the fetcher; wire the returned refs into
// <AsyncState> and pass `items` to <EmptyState>/cards. // <AsyncState> and pass `items` to <EmptyState>/cards.
// //
// `fetcher` returns the notes to show (or [] — e.g. an empty search box). A thrown // `fetcher` returns the notes to show. A thrown
// ApiError's `.error` becomes the message; otherwise `fallbackError` is shown. // ApiError's `.error` becomes the message; otherwise `fallbackError` is shown.
export function useNoteList( export function useNoteList(
fetcher: () => Promise<Note[]>, fetcher: () => Promise<Note[]>,
+1 -2
View File
@@ -1,7 +1,6 @@
"""Password resets: an admin makes a one-hour link for an account (#5173). """Password resets: an admin makes a one-hour link for an account (#5173).
The app has no mail path, so a forgotten password used to need a hand on the database Before this, a forgotten password needed a hand on the database (#2939 §2). This reuses what invites established: a random token, only its hash
(#2939 §2). This reuses what invites established: a random token, only its hash
kept, the link shown once to the admin who hands it over. kept, the link shown once to the admin who hands it over.
Using the link sets a new password and signs the account out everywhere. Its web Using the link sets a new password and signs the account out everywhere. Its web
+1 -1
View File
@@ -2,7 +2,7 @@
shapes the API returns, so a field name or format is defined once. Each entity has a shapes the API returns, so a field name or format is defined once. Each entity has a
BASE serializer with the fields common to every context; callers layer on the BASE serializer with the fields common to every context; callers layer on the
extras their surface needs (usage count in the labels API, sync_revision/purged_at extras their surface needs (usage count in the labels API, sync_revision/purged_at
in sync deltas). Grows as sections adopt it (labels here; note/user/device later).""" in sync deltas). Labels and people so far."""
from __future__ import annotations from __future__ import annotations
from .common import iso from .common import iso