@lotics/app-sdk 0.98.3 → 0.98.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/hooks.js
CHANGED
|
@@ -227,8 +227,9 @@ export function useInfiniteQuery(alias, params, opts) {
|
|
|
227
227
|
// Keyset (seek) pagination: each page seeks past the previous page's
|
|
228
228
|
// `next_cursor` instead of an increasing OFFSET, so deep scrolls stay O(page)
|
|
229
229
|
// and never skip/duplicate a row as the set shifts. The cursor is opaque; the
|
|
230
|
-
// server keysets a sortable key (
|
|
231
|
-
// transparently. `loadMore`/`rows` are
|
|
230
|
+
// server keysets a sortable key (the query's own order when `sort` is unset,
|
|
231
|
+
// else the id) and falls back to offset transparently. `loadMore`/`rows` are
|
|
232
|
+
// unchanged — the cursor is internal.
|
|
232
233
|
const getKey = (index, prev) => {
|
|
233
234
|
if (mockRows || !enabled)
|
|
234
235
|
return null;
|
package/docs/data_fetching.md
CHANGED
|
@@ -241,8 +241,9 @@ Reads paginate two different ways, and the difference is load-bearing:
|
|
|
241
241
|
opaque cursor instead of counting an offset, so a deep scroll stays O(page) and — the reason it
|
|
242
242
|
matters — **never skips or duplicates a row as the set shifts** under concurrent inserts/deletes.
|
|
243
243
|
The cursor is internal: the hook sends it and reads the next one back; you never see it. The
|
|
244
|
-
server keysets a single sortable key (the runtime `sort`,
|
|
245
|
-
back to offset transparently for a multi-key
|
|
244
|
+
server keysets a single sortable key (the runtime `sort`, else the template's own order on a
|
|
245
|
+
column it projects, else the record id) and falls back to offset transparently for a multi-key
|
|
246
|
+
sort it can't seek. So an infinite feed needs **no
|
|
246
247
|
dedupe** — key rows by `__source_record_id` for stable React keys, not to guard against repeats.
|
|
247
248
|
- **`useQuery`, `usePaginatedQuery`, and manual `rpc("query", { limit, offset })` use offset
|
|
248
249
|
pagination** — count `offset` rows, skip them, return the next page. Two consequences a keyset
|
|
@@ -265,7 +265,7 @@ client-side up front, and re-checked server-side.
|
|
|
265
265
|
- **The author is always the real signed-in member** — correct attribution, enforced server-side.
|
|
266
266
|
**Warning:** under "View as", comments still author as the real member (the admin), not the
|
|
267
267
|
view-as target — unlike `useViewer` and `is_current_member` scoping, which follow the target.
|
|
268
|
-
- **Edit and delete are author-only**, checked server-side against the viewer. `
|
|
268
|
+
- **Edit and delete are author-only**, checked server-side against the viewer. `Timeline`'s
|
|
269
269
|
`currentMemberId` prop drives the matching affordance client-side.
|
|
270
270
|
|
|
271
271
|
### Reading & writing
|
|
@@ -286,13 +286,13 @@ renders the panel. State: `{ comments, loading, error, available, createComment,
|
|
|
286
286
|
updateComment, deleteComment, refetch }`.
|
|
287
287
|
|
|
288
288
|
- `comments` — newest first on the wire (server order). Pass the array as-is to `@lotics/ui`'s
|
|
289
|
-
`
|
|
289
|
+
`Timeline`, which re-sorts oldest-first for display. Each `AppComment`: `{ id, record_id,
|
|
290
290
|
table_id, member_id, author, content, files, workspace_id, created_at, updated_at }`. Attachments
|
|
291
291
|
(`AppCommentFile`) carry `id` / `filename` / `mime_type` — a file's identity is its `id`, and
|
|
292
292
|
the server re-reads every attachment from storage by that id, so nothing else you hold about a
|
|
293
293
|
file can affect what is stored. The `url` / `thumbnail_url` / `preview_url` fields exist on the type
|
|
294
294
|
but the server does not populate them today — render attachments by name and type (what
|
|
295
|
-
`
|
|
295
|
+
`Timeline`'s default file row does), never by counting on a fetchable URL.
|
|
296
296
|
- `createComment({ content, file_ids? })` — posts as the viewing member. `file_ids` come from
|
|
297
297
|
`useFileUpload` / `useAttachments` (see [files](./files.md)). A comment must have content or at
|
|
298
298
|
least one file (empty input is a client no-op; the server enforces the same rule). Content max
|
|
@@ -308,7 +308,7 @@ updateComment, deleteComment, refetch }`.
|
|
|
308
308
|
app by someone the record references nowhere. So a thread that crosses a role boundary is legible without the app declaring member
|
|
309
309
|
access it does not otherwise need, and a per-viewer app never widens its reach for a display
|
|
310
310
|
string. `name` is `null` when the id no longer resolves in the org (a removed member) — render a
|
|
311
|
-
fallback (`
|
|
311
|
+
fallback (`Timeline` has an `unknownMember` label for exactly this). The one comment with no
|
|
312
312
|
`author` is the optimistic row `createComment` renders locally: the SDK knows the viewer's id and
|
|
313
313
|
not their name, and it will not invent one. The server's row replaces it when the refetch lands.
|
|
314
314
|
- **Freshness:** SWR-cached, revalidates on focus/reconnect, so another viewer's comment appears on
|
|
@@ -336,7 +336,7 @@ directly (full props: `node_modules/@lotics/ui/AGENTS.md` and its `docs/`):
|
|
|
336
336
|
| A select value (stored or picker option) | `Status` | A `useFieldOptions` option, or `byKey(readSelect(cell)[0]?.key)`; accepts a single option, an array (multi → one badge each), or null (renders nothing). Missing/unknown color → neutral. |
|
|
337
337
|
| A person, inline | `MemberChip` | `name` / `image` from a roster or a cell — both carry it; no image → initials |
|
|
338
338
|
| A member picker | `MemberSelect` | `members={useMembers().members}` — renders each option as a `MemberChip`; `MEMBER_UNASSIGNED` marks its optional "unassigned" option |
|
|
339
|
-
| A comment thread | `
|
|
339
|
+
| A comment thread | `Timeline` + `Composer` (`@lotics/ui/composer`) | `useComments` state; `resolveMember` reads each comment's own `author` (`{ name, image }`) — no roster needed |
|
|
340
340
|
|
|
341
341
|
The SDK never imports `@lotics/ui` — the app owns the (thin) data→UI adapter in each row above.
|
|
342
342
|
|