diff --git a/frontend/src/adapters/index.ts b/frontend/src/adapters/index.ts index f7d07f5..7898d32 100644 --- a/frontend/src/adapters/index.ts +++ b/frontend/src/adapters/index.ts @@ -2,9 +2,8 @@ // `api/client` in stores/views. // // 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 -// desktop (opt-in sync) comes in M10.7 — at which point this becomes -// `isDesktop() && !hasConfiguredServer() ? local : rest`. +// (`local.ts`, over Tauri `invoke`); the web build uses REST. A desktop linked to a +// server still reads and writes locally: the core syncs underneath. import { isDesktop } from "../desktop/bridge"; import { rest } from "./rest"; diff --git a/frontend/src/adapters/local.ts b/frontend/src/adapters/local.ts index 78eff9d..cc937c0 100644 --- a/frontend/src/adapters/local.ts +++ b/frontend/src/adapters/local.ts @@ -84,14 +84,15 @@ export const local: Repo = { titles: () => invoke("notes_titles"), }, - // 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. + // The server's admin settings aren't reached from the desktop, linked or not. settings: { list: () => Promise.reject(new Error(NEEDS_SERVER)), save: () => Promise.reject(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: { directory: () => invoke("shares_directory"), list: (noteId) => invoke("shares_list", { noteId }), diff --git a/frontend/src/components/AccountList.vue b/frontend/src/components/AccountList.vue index 25c8a4e..050def3 100644 --- a/frontend/src/components/AccountList.vue +++ b/frontend/src/components/AccountList.vue @@ -7,7 +7,8 @@ import OneTimeLink from "./OneTimeLink.vue"; import { useRowAction, useLoad } from "../composables/useAction"; // 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 { id: string; diff --git a/frontend/src/components/NoteEditor.vue b/frontend/src/components/NoteEditor.vue index 59f43f6..27cb357 100644 --- a/frontend/src/components/NoteEditor.vue +++ b/frontend/src/components/NoteEditor.vue @@ -47,9 +47,6 @@ function setBody(text: string): void { blocks.value = splitBlocks(text); } const labelList = ref(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 root = ref(null); // 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) { const input = e.target as HTMLInputElement; const file = input.files?.[0]; @@ -638,7 +629,10 @@ function revPreview(rev: NoteRevision): string { device until you remove it.

- +
- +
and pass `items` to /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. export function useNoteList( fetcher: () => Promise, diff --git a/src/inkwell/password_resets.py b/src/inkwell/password_resets.py index 03c9371..3f46219 100644 --- a/src/inkwell/password_resets.py +++ b/src/inkwell/password_resets.py @@ -1,7 +1,6 @@ """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 -(#2939 §2). This reuses what invites established: a random token, only its hash +Before this, a forgotten password needed a hand on the database (#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. Using the link sets a new password and signs the account out everywhere. Its web diff --git a/src/inkwell/serialize.py b/src/inkwell/serialize.py index 92857dd..622684b 100644 --- a/src/inkwell/serialize.py +++ b/src/inkwell/serialize.py @@ -2,7 +2,7 @@ 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 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 .common import iso