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:
@@ -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";
|
||||||
|
|||||||
@@ -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 }),
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,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,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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user