things-api 0.7.0 → 0.9.0
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/README.md +6 -3
- package/dist/cli/commands/area.d.ts +23 -0
- package/dist/cli/commands/area.js +164 -33
- package/dist/cli/commands/area.js.map +1 -1
- package/dist/cli/commands/project.d.ts +19 -0
- package/dist/cli/commands/project.js +142 -29
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/reads.d.ts +10 -51
- package/dist/cli/commands/reads.js +454 -268
- package/dist/cli/commands/reads.js.map +1 -1
- package/dist/cli/commands/show.d.ts +9 -0
- package/dist/cli/commands/show.js +169 -0
- package/dist/cli/commands/show.js.map +1 -0
- package/dist/cli/commands/snapshot.js +1 -1
- package/dist/cli/commands/snapshot.js.map +1 -1
- package/dist/cli/commands/todo.d.ts +9 -0
- package/dist/cli/commands/todo.js +101 -16
- package/dist/cli/commands/todo.js.map +1 -1
- package/dist/cli/commands/writes.js +55 -1
- package/dist/cli/commands/writes.js.map +1 -1
- package/dist/cli/did-you-mean.d.ts +29 -0
- package/dist/cli/did-you-mean.js +53 -0
- package/dist/cli/did-you-mean.js.map +1 -0
- package/dist/cli/glyphs.d.ts +95 -0
- package/dist/cli/glyphs.js +282 -0
- package/dist/cli/glyphs.js.map +1 -0
- package/dist/cli/main.js +11 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/period.d.ts +32 -0
- package/dist/cli/period.js +129 -0
- package/dist/cli/period.js.map +1 -0
- package/dist/cli/read-driver.d.ts +76 -0
- package/dist/cli/read-driver.js +181 -0
- package/dist/cli/read-driver.js.map +1 -0
- package/dist/cli/render.d.ts +182 -0
- package/dist/cli/render.js +585 -0
- package/dist/cli/render.js.map +1 -0
- package/dist/cli/resolve-invocation.d.ts +78 -0
- package/dist/cli/resolve-invocation.js +178 -0
- package/dist/cli/resolve-invocation.js.map +1 -0
- package/dist/cli/shell-quote.d.ts +9 -0
- package/dist/cli/shell-quote.js +12 -0
- package/dist/cli/shell-quote.js.map +1 -0
- package/dist/cli/style.d.ts +5 -0
- package/dist/cli/style.js +5 -0
- package/dist/cli/style.js.map +1 -1
- package/dist/client.d.ts +45 -39
- package/dist/client.js +11 -74
- package/dist/client.js.map +1 -1
- package/dist/contracts.d.ts +66 -1
- package/dist/contracts.js +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/db/baselines/db-v26.js +7 -5
- package/dist/db/baselines/db-v26.js.map +1 -1
- package/dist/db/schema.d.ts +1 -1
- package/dist/db/schema.js +7 -1
- package/dist/db/schema.js.map +1 -1
- package/dist/mcp/server.js +227 -44
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/entities.d.ts +21 -0
- package/dist/model/entities.js.map +1 -1
- package/dist/model/mappers.js +17 -1
- package/dist/model/mappers.js.map +1 -1
- package/dist/model/occurrences.d.ts +6 -1
- package/dist/model/occurrences.js +9 -2
- package/dist/model/occurrences.js.map +1 -1
- package/dist/model/recurrence.d.ts +30 -2
- package/dist/model/recurrence.js +20 -0
- package/dist/model/recurrence.js.map +1 -1
- package/dist/read/area-view.js +21 -5
- package/dist/read/area-view.js.map +1 -1
- package/dist/read/caps.d.ts +14 -0
- package/dist/read/caps.js +21 -0
- package/dist/read/caps.js.map +1 -0
- package/dist/read/detail.js +12 -2
- package/dist/read/detail.js.map +1 -1
- package/dist/read/log-boundary.d.ts +29 -0
- package/dist/read/log-boundary.js +38 -0
- package/dist/read/log-boundary.js.map +1 -0
- package/dist/read/pagination.d.ts +104 -0
- package/dist/read/pagination.js +208 -0
- package/dist/read/pagination.js.map +1 -0
- package/dist/read/predicates.d.ts +31 -0
- package/dist/read/predicates.js +48 -0
- package/dist/read/predicates.js.map +1 -0
- package/dist/read/project-view.js +28 -3
- package/dist/read/project-view.js.map +1 -1
- package/dist/read/queries.d.ts +21 -3
- package/dist/read/queries.js +35 -8
- package/dist/read/queries.js.map +1 -1
- package/dist/read/search-rank.d.ts +36 -0
- package/dist/read/search-rank.js +31 -0
- package/dist/read/search-rank.js.map +1 -0
- package/dist/read/show-target.d.ts +25 -0
- package/dist/read/show-target.js +41 -0
- package/dist/read/show-target.js.map +1 -0
- package/dist/read/sidebar-order.d.ts +19 -0
- package/dist/read/sidebar-order.js +92 -0
- package/dist/read/sidebar-order.js.map +1 -0
- package/dist/read/snapshot.js +2 -0
- package/dist/read/snapshot.js.map +1 -1
- package/dist/read/views.d.ts +64 -8
- package/dist/read/views.js +290 -155
- package/dist/read/views.js.map +1 -1
- package/dist/surface-copy.d.ts +23 -0
- package/dist/surface-copy.js +23 -0
- package/dist/surface-copy.js.map +1 -1
- package/dist/write/automation-probe.js +14 -6
- package/dist/write/automation-probe.js.map +1 -1
- package/dist/write/capabilities.d.ts +3 -0
- package/dist/write/capabilities.js +3 -0
- package/dist/write/capabilities.js.map +1 -1
- package/dist/write/checklist.d.ts +50 -0
- package/dist/write/checklist.js +61 -0
- package/dist/write/checklist.js.map +1 -0
- package/dist/write/clear-reminder.d.ts +3 -0
- package/dist/write/clear-reminder.js +205 -0
- package/dist/write/clear-reminder.js.map +1 -0
- package/dist/write/commands.js +122 -8
- package/dist/write/commands.js.map +1 -1
- package/dist/write/edit-checklist.d.ts +3 -0
- package/dist/write/edit-checklist.js +184 -0
- package/dist/write/edit-checklist.js.map +1 -0
- package/dist/write/failure-hints.d.ts +7 -0
- package/dist/write/failure-hints.js +25 -2
- package/dist/write/failure-hints.js.map +1 -1
- package/dist/write/guards.d.ts +1 -1
- package/dist/write/guards.js +16 -0
- package/dist/write/guards.js.map +1 -1
- package/dist/write/operations.d.ts +32 -1
- package/dist/write/operations.js +3 -0
- package/dist/write/operations.js.map +1 -1
- package/dist/write/pipeline.d.ts +3 -0
- package/dist/write/pipeline.js +23 -1
- package/dist/write/pipeline.js.map +1 -1
- package/dist/write/reversibility.d.ts +46 -0
- package/dist/write/reversibility.js +164 -0
- package/dist/write/reversibility.js.map +1 -0
- package/dist/write/undo.d.ts +29 -2
- package/dist/write/undo.js +357 -9
- package/dist/write/undo.js.map +1 -1
- package/dist/write/vectors/registry.js +2 -1
- package/dist/write/vectors/registry.js.map +1 -1
- package/dist/write/vectors/shortcuts.d.ts +9 -0
- package/dist/write/vectors/shortcuts.js +90 -0
- package/dist/write/vectors/shortcuts.js.map +1 -0
- package/dist/write/vectors/types.d.ts +11 -3
- package/dist/write/vectors/url-scheme.js +16 -0
- package/dist/write/vectors/url-scheme.js.map +1 -1
- package/dist/write/verify/delta.d.ts +1 -1
- package/dist/write/verify/delta.js +1 -1
- package/dist/write/verify/delta.js.map +1 -1
- package/package.json +1 -1
- package/shortcuts/things-proxy-find-items.shortcut +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one shared decision behind every surface's `--limit`/`--all` (CLI) and
|
|
3
|
+
* `limit`/`all` (MCP) cap resolution: given an explicit value, the `all`
|
|
4
|
+
* flag, and a default, decide the effective row cap. Each surface keeps its
|
|
5
|
+
* own input parsing and error emission (the CLI validates the string and
|
|
6
|
+
* writes a usage error; MCP validates via zod and returns a tool error) —
|
|
7
|
+
* only this pure conflict/default logic is shared.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Resolve one cap against `all` into a row cap: `null` = every row,
|
|
11
|
+
* `"conflict"` when an explicit value combines with `all: true`, otherwise
|
|
12
|
+
* the explicit value or the default.
|
|
13
|
+
*/
|
|
14
|
+
export function resolveCap(value, all, defaultLimit) {
|
|
15
|
+
if (all === true && value !== undefined)
|
|
16
|
+
return "conflict";
|
|
17
|
+
if (all === true)
|
|
18
|
+
return null;
|
|
19
|
+
return value ?? defaultLimit;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=caps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caps.js","sourceRoot":"","sources":["../../src/read/caps.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACxB,KAAyB,EACzB,GAAwB,EACxB,YAAoB;IAEpB,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC;IAC3D,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO,KAAK,IAAI,YAAY,CAAC;AAC/B,CAAC"}
|
package/dist/read/detail.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mapChecklistItem, mapHeading, mapProject, mapTodo, } from "../model/mappers.js";
|
|
2
2
|
import { decodeRecurrenceRule } from "../model/recurrence.js";
|
|
3
|
-
import { fetchChecklistRows, fetchTagsForTasks, fetchTaskByUuid, makeRefResolver, } from "./queries.js";
|
|
3
|
+
import { fetchChecklistRows, fetchTagsForTasks, fetchTaskByUuid, makeHeadingProjectResolver, makeRefResolver, } from "./queries.js";
|
|
4
|
+
import { logBoundary, markLogged } from "./log-boundary.js";
|
|
4
5
|
import { inheritedTagsFor } from "./tags.js";
|
|
5
6
|
export function byUuid(db, uuid) {
|
|
6
7
|
const row = fetchTaskByUuid(db, uuid);
|
|
@@ -14,9 +15,18 @@ function materializeOne(db, row) {
|
|
|
14
15
|
return mapHeading(row, refs);
|
|
15
16
|
const tags = fetchTagsForTasks(db, [row.uuid]).get(row.uuid) ?? [];
|
|
16
17
|
const entity = row.type === 1 ? mapProject(row, refs, tags) : mapTodo(row, refs, tags);
|
|
18
|
+
markLogged([entity], logBoundary(db));
|
|
17
19
|
entity.inheritedTags = inheritedTagsFor(db, row);
|
|
18
|
-
if (entity.type === "to-do")
|
|
20
|
+
if (entity.type === "to-do") {
|
|
19
21
|
entity.checklist = checklistFor(db, row.uuid);
|
|
22
|
+
// Container parity with list views: resolve the owning project through
|
|
23
|
+
// the heading (project itself stays null — DB truth).
|
|
24
|
+
if (entity.heading !== null) {
|
|
25
|
+
const p = makeHeadingProjectResolver(db)(entity.heading.uuid);
|
|
26
|
+
if (p !== null)
|
|
27
|
+
entity.headingProject = p;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
20
30
|
if (entity.repeating.isTemplate && row.rt1_recurrenceRule !== null) {
|
|
21
31
|
try {
|
|
22
32
|
entity.repeating.rule = decodeRecurrenceRule(row.rt1_recurrenceRule);
|
package/dist/read/detail.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detail.js","sourceRoot":"","sources":["../../src/read/detail.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,OAAO,GAER,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,UAAU,MAAM,CAAC,EAAgB,EAAE,IAAY;IACnD,MAAM,GAAG,GAAG,eAAe,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACtC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,cAAc,CAAC,EAAgB,EAAE,GAAY;IACpD,MAAM,IAAI,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;IACjC,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,iBAAiB,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACnE,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACvF,MAAM,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACjD,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;
|
|
1
|
+
{"version":3,"file":"detail.js","sourceRoot":"","sources":["../../src/read/detail.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,OAAO,GAER,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,0BAA0B,EAC1B,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,UAAU,MAAM,CAAC,EAAgB,EAAE,IAAY;IACnD,MAAM,GAAG,GAAG,eAAe,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACtC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,cAAc,CAAC,EAAgB,EAAE,GAAY;IACpD,MAAM,IAAI,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;IACjC,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,iBAAiB,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACnE,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACvF,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;IACtC,MAAM,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACjD,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC5B,MAAM,CAAC,SAAS,GAAG,YAAY,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9C,uEAAuE;QACvE,sDAAsD;QACtD,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAC5B,MAAM,CAAC,GAAG,0BAA0B,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC9D,IAAI,CAAC,KAAK,IAAI;gBAAE,MAAM,CAAC,cAAc,GAAG,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IACD,IAAI,MAAM,CAAC,SAAS,CAAC,UAAU,IAAI,GAAG,CAAC,kBAAkB,KAAK,IAAI,EAAE,CAAC;QACnE,IAAI,CAAC;YACH,MAAM,CAAC,SAAS,CAAC,IAAI,GAAG,oBAAoB,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACvE,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;YACnE,6DAA6D;QAC/D,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAAgB,EAAE,QAAgB;IAC7D,OAAO,kBAAkB,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The GUI's log-move boundary — completion and LOGGED are two separate
|
|
3
|
+
* states. A closed item enters the Logbook only when the app's periodic
|
|
4
|
+
* "Move completed items to Logbook" sweep passes it; until then it stays
|
|
5
|
+
* checked in its original list. No per-row column records this: membership
|
|
6
|
+
* is computed against `TMSettings.logInterval` + `manualLogDate`
|
|
7
|
+
* (probe: live prod diff 2026-07-10 — fresh completions absent from the
|
|
8
|
+
* GUI Logbook share every TMTask column shape with logged history; only
|
|
9
|
+
* the stopDate-vs-boundary relation differs).
|
|
10
|
+
*
|
|
11
|
+
* logInterval semantics (GUI enum VERIFIED live in a clone, 2026-07-12,
|
|
12
|
+
* s-campaign-results.md round 3): 0 = immediately, 1 = daily, 4 = manual
|
|
13
|
+
* ("When I choose"). Things 3.22.11's "Move completed items to Logbook"
|
|
14
|
+
* dropdown offers ONLY these three — there is NO weekly or monthly option,
|
|
15
|
+
* so the `case 2`/`case 3` branches below are UNREACHABLE with the current
|
|
16
|
+
* app (kept as defensive analogues in case a future build adds them; the
|
|
17
|
+
* real manual value 4 falls to `default`, which is correct). manualLogDate
|
|
18
|
+
* is the user's last explicit "log now" (an AppleScript `log completed now`
|
|
19
|
+
* advances it to the current time — VERIFIED); it can only move the boundary
|
|
20
|
+
* FORWARD past the interval's own edge.
|
|
21
|
+
*/
|
|
22
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
23
|
+
export declare function logBoundary(db: DatabaseSync, now?: Date): Date;
|
|
24
|
+
/** Stamp `logged` on mapped entities (closed AND at/before the boundary). */
|
|
25
|
+
export declare function markLogged<T extends {
|
|
26
|
+
status: string;
|
|
27
|
+
stopped: Date | null;
|
|
28
|
+
logged: boolean;
|
|
29
|
+
}>(items: T[], boundary: Date): T[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export function logBoundary(db, now = new Date()) {
|
|
2
|
+
const row = db.prepare("SELECT logInterval, manualLogDate FROM TMSettings").get();
|
|
3
|
+
const manual = row?.manualLogDate != null ? new Date(row.manualLogDate * 1000) : null;
|
|
4
|
+
const startOfDay = new Date(now);
|
|
5
|
+
startOfDay.setHours(0, 0, 0, 0);
|
|
6
|
+
let auto;
|
|
7
|
+
switch (row?.logInterval ?? 0) {
|
|
8
|
+
case 0:
|
|
9
|
+
auto = now;
|
|
10
|
+
break;
|
|
11
|
+
case 1:
|
|
12
|
+
auto = startOfDay;
|
|
13
|
+
break;
|
|
14
|
+
case 2: {
|
|
15
|
+
const d = new Date(startOfDay);
|
|
16
|
+
d.setDate(d.getDate() - d.getDay());
|
|
17
|
+
auto = d;
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
case 3: {
|
|
21
|
+
const d = new Date(startOfDay);
|
|
22
|
+
d.setDate(1);
|
|
23
|
+
auto = d;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
default:
|
|
27
|
+
auto = manual ?? now;
|
|
28
|
+
}
|
|
29
|
+
return manual !== null && manual > auto ? manual : auto;
|
|
30
|
+
}
|
|
31
|
+
/** Stamp `logged` on mapped entities (closed AND at/before the boundary). */
|
|
32
|
+
export function markLogged(items, boundary) {
|
|
33
|
+
for (const item of items) {
|
|
34
|
+
item.logged = item.status !== "open" && item.stopped !== null && item.stopped <= boundary;
|
|
35
|
+
}
|
|
36
|
+
return items;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=log-boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-boundary.js","sourceRoot":"","sources":["../../src/read/log-boundary.ts"],"names":[],"mappings":"AAuBA,MAAM,UAAU,WAAW,CAAC,EAAgB,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE;IAC5D,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC,GAAG,EAElE,CAAC;IACd,MAAM,MAAM,GAAG,GAAG,EAAE,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtF,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IACjC,UAAU,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAChC,IAAI,IAAU,CAAC;IACf,QAAQ,GAAG,EAAE,WAAW,IAAI,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC;YACJ,IAAI,GAAG,GAAG,CAAC;YACX,MAAM;QACR,KAAK,CAAC;YACJ,IAAI,GAAG,UAAU,CAAC;YAClB,MAAM;QACR,KAAK,CAAC,CAAC,CAAC,CAAC;YACP,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YACpC,IAAI,GAAG,CAAC,CAAC;YACT,MAAM;QACR,CAAC;QACD,KAAK,CAAC,CAAC,CAAC,CAAC;YACP,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACb,IAAI,GAAG,CAAC,CAAC;YACT,MAAM;QACR,CAAC;QACD;YACE,IAAI,GAAG,MAAM,IAAI,GAAG,CAAC;IACzB,CAAC;IACD,OAAO,MAAM,KAAK,IAAI,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1D,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,UAAU,CACxB,KAAU,EACV,QAAc;IAEd,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,IAAI,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC;IAC5F,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared list-view truncation: turn a full, filtered result into the rows a
|
|
3
|
+
* surface actually shows (default 50) plus the exact {@link Pagination}
|
|
4
|
+
* metadata every surface reports so nothing is ever silently dropped. The
|
|
5
|
+
* limit counts ITEMS in render order and truncates mid-group; grouped shapes
|
|
6
|
+
* (the Today split, sidebar sections) drop the trailing groups that fall
|
|
7
|
+
* entirely past the cut so no empty header survives. `limit === null` means
|
|
8
|
+
* "all rows" (the caller passed --all / all: true).
|
|
9
|
+
*/
|
|
10
|
+
import type { GroupedPagination, Pagination } from "../contracts.ts";
|
|
11
|
+
import type { Ref } from "../model/entities.ts";
|
|
12
|
+
import type { AreaView } from "./area-view.ts";
|
|
13
|
+
import { AREA_PREVIEW_LIMIT, DEFAULT_LIST_LIMIT, PROJECT_PREVIEW_LIMIT } from "../surface-copy.ts";
|
|
14
|
+
import type { ListItem, SidebarSection, TodayView } from "./views.ts";
|
|
15
|
+
export { AREA_PREVIEW_LIMIT, DEFAULT_LIST_LIMIT, PROJECT_PREVIEW_LIMIT };
|
|
16
|
+
/**
|
|
17
|
+
* Per-block caps for the grouped catalogues: `area` bounds each area-direct
|
|
18
|
+
* block (and the leading loose block), `project` each project's to-do list.
|
|
19
|
+
* `null` = uncapped (the caller passed --all / all: true, or — for someday's
|
|
20
|
+
* active-projects section — asked for every item).
|
|
21
|
+
*/
|
|
22
|
+
export interface GroupedLimits {
|
|
23
|
+
area: number | null;
|
|
24
|
+
project: number | null;
|
|
25
|
+
}
|
|
26
|
+
/** Flat list: slice to the limit; total is the full filtered length. */
|
|
27
|
+
export declare function paginateList<T>(items: T[], limit: number | null): {
|
|
28
|
+
data: T[];
|
|
29
|
+
pagination: Pagination;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Today split: the cut runs across Today then This Evening in render order,
|
|
33
|
+
* so a limit smaller than the Today block trims Evening to nothing. The badge
|
|
34
|
+
* (a whole-view count summary) is preserved unchanged.
|
|
35
|
+
*/
|
|
36
|
+
export declare function paginateToday(view: TodayView, limit: number | null): {
|
|
37
|
+
data: TodayView;
|
|
38
|
+
pagination: Pagination;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Split one sidebar section into its innermost item blocks: the direct
|
|
42
|
+
* to-dos that precede any project row, then one block per project (the
|
|
43
|
+
* project row plus the to-dos that follow it until the next project).
|
|
44
|
+
*/
|
|
45
|
+
export interface SectionBlocks {
|
|
46
|
+
direct: ListItem[];
|
|
47
|
+
projects: Array<{
|
|
48
|
+
project: ListItem;
|
|
49
|
+
items: ListItem[];
|
|
50
|
+
}>;
|
|
51
|
+
}
|
|
52
|
+
export declare function splitSectionBlocks(section: SidebarSection): SectionBlocks;
|
|
53
|
+
/**
|
|
54
|
+
* Anytime: the block skeleton is ALWAYS complete — every area header and
|
|
55
|
+
* every project row survives — and the caps apply INDEPENDENTLY to each
|
|
56
|
+
* innermost item list: `limits.area` to the loose block and each area's
|
|
57
|
+
* direct to-dos, `limits.project` to each project's to-dos. Returns the
|
|
58
|
+
* per-block-truncated sections (project rows retained) plus the per-block
|
|
59
|
+
* counts and a top-level `truncated` flag.
|
|
60
|
+
*/
|
|
61
|
+
export declare function previewSections(sections: SidebarSection[], limits: GroupedLimits): {
|
|
62
|
+
data: SidebarSection[];
|
|
63
|
+
grouped: GroupedPagination;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Someday sections split differently from anytime: PROJECT rows there are
|
|
67
|
+
* plain ITEMS (a someday project stands for itself — its children are never
|
|
68
|
+
* inline), so a section's "own" block is its project rows + container-less
|
|
69
|
+
* to-dos together, and the to-dos that DO carry a project reference (the
|
|
70
|
+
* activeProjectItems toggle) form separate per-project child groups.
|
|
71
|
+
*/
|
|
72
|
+
export interface SomedayPartition {
|
|
73
|
+
/** Project rows + direct to-dos, in section order. */
|
|
74
|
+
own: ListItem[];
|
|
75
|
+
/** Someday to-dos inside active projects, clustered per project. */
|
|
76
|
+
children: Array<{
|
|
77
|
+
project: Ref;
|
|
78
|
+
items: ListItem[];
|
|
79
|
+
}>;
|
|
80
|
+
}
|
|
81
|
+
export declare function partitionSomedaySection(section: SidebarSection): SomedayPartition;
|
|
82
|
+
/**
|
|
83
|
+
* Someday preview: every group survives; `limits.area` (null = no cap)
|
|
84
|
+
* applies independently to each section's own block (project rows + direct
|
|
85
|
+
* to-dos are items alike there), `limits.project` to each active project's
|
|
86
|
+
* child group (the show-active-project-items toggle). Sections keep their
|
|
87
|
+
* capped children after the own block, still clustered per project.
|
|
88
|
+
*/
|
|
89
|
+
export declare function previewSomedaySections(sections: SidebarSection[], limits: GroupedLimits): {
|
|
90
|
+
data: SidebarSection[];
|
|
91
|
+
grouped: GroupedPagination;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Sectioned cap for the `area show` detail view: its sections are containers,
|
|
95
|
+
* so there is no strict total limit — instead `limits.project` bounds the
|
|
96
|
+
* project-ROWS section and `limits.area` the direct-to-dos section (null =
|
|
97
|
+
* uncapped). The toggled later/logged lists and the trashed bucket pass
|
|
98
|
+
* through untouched. Counts ride the same grouped-block shape the sidebar
|
|
99
|
+
* catalogues emit (kind "projects" = the project-rows section).
|
|
100
|
+
*/
|
|
101
|
+
export declare function capAreaSections(view: AreaView, limits: GroupedLimits): {
|
|
102
|
+
data: AreaView;
|
|
103
|
+
grouped: GroupedPagination;
|
|
104
|
+
};
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { AREA_PREVIEW_LIMIT, DEFAULT_LIST_LIMIT, PROJECT_PREVIEW_LIMIT } from "../surface-copy.js";
|
|
2
|
+
export { AREA_PREVIEW_LIMIT, DEFAULT_LIST_LIMIT, PROJECT_PREVIEW_LIMIT };
|
|
3
|
+
const whole = (total, limit) => ({
|
|
4
|
+
shown: total,
|
|
5
|
+
total,
|
|
6
|
+
limit,
|
|
7
|
+
truncated: false,
|
|
8
|
+
});
|
|
9
|
+
/** Flat list: slice to the limit; total is the full filtered length. */
|
|
10
|
+
export function paginateList(items, limit) {
|
|
11
|
+
const total = items.length;
|
|
12
|
+
if (limit === null || total <= limit)
|
|
13
|
+
return { data: items, pagination: whole(total, limit) };
|
|
14
|
+
return {
|
|
15
|
+
data: items.slice(0, limit),
|
|
16
|
+
pagination: { shown: limit, total, limit, truncated: true },
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Today split: the cut runs across Today then This Evening in render order,
|
|
21
|
+
* so a limit smaller than the Today block trims Evening to nothing. The badge
|
|
22
|
+
* (a whole-view count summary) is preserved unchanged.
|
|
23
|
+
*/
|
|
24
|
+
export function paginateToday(view, limit) {
|
|
25
|
+
const total = view.today.length + view.evening.length;
|
|
26
|
+
if (limit === null || total <= limit)
|
|
27
|
+
return { data: view, pagination: whole(total, limit) };
|
|
28
|
+
const today = view.today.slice(0, limit);
|
|
29
|
+
const evening = view.evening.slice(0, Math.max(0, limit - today.length));
|
|
30
|
+
const shown = today.length + evening.length;
|
|
31
|
+
return {
|
|
32
|
+
data: { today, evening, badge: view.badge },
|
|
33
|
+
pagination: { shown, total, limit, truncated: true },
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function splitSectionBlocks(section) {
|
|
37
|
+
const direct = [];
|
|
38
|
+
const projects = [];
|
|
39
|
+
let cur = null;
|
|
40
|
+
for (const item of section.items) {
|
|
41
|
+
if (item.type === "project") {
|
|
42
|
+
cur = { project: item, items: [] };
|
|
43
|
+
projects.push(cur);
|
|
44
|
+
}
|
|
45
|
+
else if (cur === null) {
|
|
46
|
+
direct.push(item);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
cur.items.push(item);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { direct, projects };
|
|
53
|
+
}
|
|
54
|
+
const takeUpTo = (items, limit) => limit === null ? items : items.slice(0, limit);
|
|
55
|
+
/**
|
|
56
|
+
* Anytime: the block skeleton is ALWAYS complete — every area header and
|
|
57
|
+
* every project row survives — and the caps apply INDEPENDENTLY to each
|
|
58
|
+
* innermost item list: `limits.area` to the loose block and each area's
|
|
59
|
+
* direct to-dos, `limits.project` to each project's to-dos. Returns the
|
|
60
|
+
* per-block-truncated sections (project rows retained) plus the per-block
|
|
61
|
+
* counts and a top-level `truncated` flag.
|
|
62
|
+
*/
|
|
63
|
+
export function previewSections(sections, limits) {
|
|
64
|
+
const outSections = [];
|
|
65
|
+
const blocks = [];
|
|
66
|
+
let truncated = false;
|
|
67
|
+
for (const section of sections) {
|
|
68
|
+
const { direct, projects } = splitSectionBlocks(section);
|
|
69
|
+
const shownDirect = takeUpTo(direct, limits.area);
|
|
70
|
+
if (direct.length > 0) {
|
|
71
|
+
if (direct.length > shownDirect.length)
|
|
72
|
+
truncated = true;
|
|
73
|
+
blocks.push({
|
|
74
|
+
kind: section.area === null ? "loose" : "area",
|
|
75
|
+
uuid: section.area?.uuid ?? null,
|
|
76
|
+
title: section.area?.title ?? null,
|
|
77
|
+
shown: shownDirect.length,
|
|
78
|
+
total: direct.length,
|
|
79
|
+
limit: limits.area,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const items = [...shownDirect];
|
|
83
|
+
for (const { project, items: children } of projects) {
|
|
84
|
+
const shownChildren = takeUpTo(children, limits.project);
|
|
85
|
+
if (children.length > 0) {
|
|
86
|
+
if (children.length > shownChildren.length)
|
|
87
|
+
truncated = true;
|
|
88
|
+
blocks.push({
|
|
89
|
+
kind: "project",
|
|
90
|
+
uuid: project.uuid,
|
|
91
|
+
title: project.title,
|
|
92
|
+
shown: shownChildren.length,
|
|
93
|
+
total: children.length,
|
|
94
|
+
limit: limits.project,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
items.push(project, ...shownChildren);
|
|
98
|
+
}
|
|
99
|
+
outSections.push({ area: section.area, items });
|
|
100
|
+
}
|
|
101
|
+
return { data: outSections, grouped: { truncated, blocks } };
|
|
102
|
+
}
|
|
103
|
+
export function partitionSomedaySection(section) {
|
|
104
|
+
const own = [];
|
|
105
|
+
const byProject = new Map();
|
|
106
|
+
for (const item of section.items) {
|
|
107
|
+
const container = item.type === "to-do" ? (item.project ?? item.headingProject ?? null) : null;
|
|
108
|
+
if (container === null) {
|
|
109
|
+
own.push(item);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
let group = byProject.get(container.uuid);
|
|
113
|
+
if (group === undefined) {
|
|
114
|
+
group = { project: container, items: [] };
|
|
115
|
+
byProject.set(container.uuid, group);
|
|
116
|
+
}
|
|
117
|
+
group.items.push(item);
|
|
118
|
+
}
|
|
119
|
+
return { own, children: [...byProject.values()] };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Someday preview: every group survives; `limits.area` (null = no cap)
|
|
123
|
+
* applies independently to each section's own block (project rows + direct
|
|
124
|
+
* to-dos are items alike there), `limits.project` to each active project's
|
|
125
|
+
* child group (the show-active-project-items toggle). Sections keep their
|
|
126
|
+
* capped children after the own block, still clustered per project.
|
|
127
|
+
*/
|
|
128
|
+
export function previewSomedaySections(sections, limits) {
|
|
129
|
+
const outSections = [];
|
|
130
|
+
const blocks = [];
|
|
131
|
+
let truncated = false;
|
|
132
|
+
for (const section of sections) {
|
|
133
|
+
const { own, children } = partitionSomedaySection(section);
|
|
134
|
+
const shownOwn = takeUpTo(own, limits.area);
|
|
135
|
+
if (own.length > 0) {
|
|
136
|
+
if (own.length > shownOwn.length)
|
|
137
|
+
truncated = true;
|
|
138
|
+
const totalProjects = own.filter((i) => i.type === "project").length;
|
|
139
|
+
blocks.push({
|
|
140
|
+
kind: section.area === null ? "loose" : "area",
|
|
141
|
+
uuid: section.area?.uuid ?? null,
|
|
142
|
+
title: section.area?.title ?? null,
|
|
143
|
+
shown: shownOwn.length,
|
|
144
|
+
total: own.length,
|
|
145
|
+
limit: limits.area,
|
|
146
|
+
totalProjects,
|
|
147
|
+
totalTodos: own.length - totalProjects,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
const items = [...shownOwn];
|
|
151
|
+
for (const group of children) {
|
|
152
|
+
const shown = takeUpTo(group.items, limits.project);
|
|
153
|
+
if (group.items.length > shown.length)
|
|
154
|
+
truncated = true;
|
|
155
|
+
blocks.push({
|
|
156
|
+
kind: "project",
|
|
157
|
+
uuid: group.project.uuid,
|
|
158
|
+
title: group.project.title,
|
|
159
|
+
shown: shown.length,
|
|
160
|
+
total: group.items.length,
|
|
161
|
+
limit: limits.project,
|
|
162
|
+
});
|
|
163
|
+
items.push(...shown);
|
|
164
|
+
}
|
|
165
|
+
outSections.push({ area: section.area, items });
|
|
166
|
+
}
|
|
167
|
+
return { data: outSections, grouped: { truncated, blocks } };
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Sectioned cap for the `area show` detail view: its sections are containers,
|
|
171
|
+
* so there is no strict total limit — instead `limits.project` bounds the
|
|
172
|
+
* project-ROWS section and `limits.area` the direct-to-dos section (null =
|
|
173
|
+
* uncapped). The toggled later/logged lists and the trashed bucket pass
|
|
174
|
+
* through untouched. Counts ride the same grouped-block shape the sidebar
|
|
175
|
+
* catalogues emit (kind "projects" = the project-rows section).
|
|
176
|
+
*/
|
|
177
|
+
export function capAreaSections(view, limits) {
|
|
178
|
+
const blocks = [];
|
|
179
|
+
let truncated = false;
|
|
180
|
+
const projects = limits.project === null ? view.projects : view.projects.slice(0, limits.project);
|
|
181
|
+
if (view.projects.length > 0) {
|
|
182
|
+
if (projects.length < view.projects.length)
|
|
183
|
+
truncated = true;
|
|
184
|
+
blocks.push({
|
|
185
|
+
kind: "projects",
|
|
186
|
+
uuid: view.area.uuid,
|
|
187
|
+
title: view.area.title,
|
|
188
|
+
shown: projects.length,
|
|
189
|
+
total: view.projects.length,
|
|
190
|
+
limit: limits.project,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
const active = limits.area === null ? view.active : view.active.slice(0, limits.area);
|
|
194
|
+
if (view.active.length > 0) {
|
|
195
|
+
if (active.length < view.active.length)
|
|
196
|
+
truncated = true;
|
|
197
|
+
blocks.push({
|
|
198
|
+
kind: "area",
|
|
199
|
+
uuid: view.area.uuid,
|
|
200
|
+
title: view.area.title,
|
|
201
|
+
shown: active.length,
|
|
202
|
+
total: view.active.length,
|
|
203
|
+
limit: limits.area,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return { data: { ...view, projects, active }, grouped: { truncated, blocks } };
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/read/pagination.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAGnG,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,CAAC;AAazE,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,KAAoB,EAAc,EAAE,CAAC,CAAC;IAClE,KAAK,EAAE,KAAK;IACZ,KAAK;IACL,KAAK;IACL,SAAS,EAAE,KAAK;CACjB,CAAC,CAAC;AAEH,wEAAwE;AACxE,MAAM,UAAU,YAAY,CAC1B,KAAU,EACV,KAAoB;IAEpB,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;IAC3B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;IAC9F,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;QAC3B,UAAU,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE;KAC5D,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAe,EACf,KAAoB;IAEpB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IACtD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;IAC7F,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC5C,OAAO;QACL,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE;QAC3C,UAAU,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE;KACrD,CAAC;AACJ,CAAC;AAYD,MAAM,UAAU,kBAAkB,CAAC,OAAuB;IACxD,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAoD,EAAE,CAAC;IACrE,IAAI,GAAG,GAAoD,IAAI,CAAC;IAChE,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5B,GAAG,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;YACnC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;aAAM,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,QAAQ,GAAG,CAAI,KAAU,EAAE,KAAoB,EAAO,EAAE,CAC5D,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,QAA0B,EAC1B,MAAqB;IAErB,MAAM,WAAW,GAAqB,EAAE,CAAC;IACzC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACzD,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,IAAI,MAAM,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM;gBAAE,SAAS,GAAG,IAAI,CAAC;YACzD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;gBAC9C,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI;gBAChC,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,IAAI,IAAI;gBAClC,KAAK,EAAE,WAAW,CAAC,MAAM;gBACzB,KAAK,EAAE,MAAM,CAAC,MAAM;gBACpB,KAAK,EAAE,MAAM,CAAC,IAAI;aACnB,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,GAAe,CAAC,GAAG,WAAW,CAAC,CAAC;QAC3C,KAAK,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,QAAQ,EAAE,CAAC;YACpD,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YACzD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,IAAI,QAAQ,CAAC,MAAM,GAAG,aAAa,CAAC,MAAM;oBAAE,SAAS,GAAG,IAAI,CAAC;gBAC7D,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,KAAK,EAAE,aAAa,CAAC,MAAM;oBAC3B,KAAK,EAAE,QAAQ,CAAC,MAAM;oBACtB,KAAK,EAAE,MAAM,CAAC,OAAO;iBACtB,CAAC,CAAC;YACL,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,aAAa,CAAC,CAAC;QACxC,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;AAC/D,CAAC;AAgBD,MAAM,UAAU,uBAAuB,CAAC,OAAuB;IAC7D,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAG,IAAI,GAAG,EAA+C,CAAC;IACzE,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/F,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACvB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACf,SAAS;QACX,CAAC;QACD,IAAI,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;YAC1C,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvC,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;AACpD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAA0B,EAC1B,MAAqB;IAErB,MAAM,WAAW,GAAqB,EAAE,CAAC;IACzC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnB,IAAI,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM;gBAAE,SAAS,GAAG,IAAI,CAAC;YACnD,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;YACrE,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;gBAC9C,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI;gBAChC,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,IAAI,IAAI;gBAClC,KAAK,EAAE,QAAQ,CAAC,MAAM;gBACtB,KAAK,EAAE,GAAG,CAAC,MAAM;gBACjB,KAAK,EAAE,MAAM,CAAC,IAAI;gBAClB,aAAa;gBACb,UAAU,EAAE,GAAG,CAAC,MAAM,GAAG,aAAa;aACvC,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,GAAe,CAAC,GAAG,QAAQ,CAAC,CAAC;QACxC,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YACpD,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM;gBAAE,SAAS,GAAG,IAAI,CAAC;YACxD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI;gBACxB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK;gBAC1B,KAAK,EAAE,KAAK,CAAC,MAAM;gBACnB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM;gBACzB,KAAK,EAAE,MAAM,CAAC,OAAO;aACtB,CAAC,CAAC;YACH,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QACvB,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;AAC/D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAc,EACd,MAAqB;IAErB,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAClG,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE,SAAS,GAAG,IAAI,CAAC;QAC7D,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI;YACpB,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK;YACtB,KAAK,EAAE,QAAQ,CAAC,MAAM;YACtB,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM;YAC3B,KAAK,EAAE,MAAM,CAAC,OAAO;SACtB,CAAC,CAAC;IACL,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IACtF,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,IAAI,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,SAAS,GAAG,IAAI,CAAC;QACzD,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI;YACpB,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK;YACtB,KAAK,EAAE,MAAM,CAAC,MAAM;YACpB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YACzB,KAAK,EAAE,MAAM,CAAC,IAAI;SACnB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Real to-dos/projects (type IN 0,1), untrashed, excluding repeating templates. */
|
|
2
|
+
export declare const LIVE = "t.type IN (0, 1) AND t.trashed = 0 AND (t.rt1_recurrenceRule IS NULL AND t.repeater IS NULL)";
|
|
3
|
+
/** {@link LIVE} restricted to open (status = 0) rows. */
|
|
4
|
+
export declare const OPEN = "t.type IN (0, 1) AND t.trashed = 0 AND (t.rt1_recurrenceRule IS NULL AND t.repeater IS NULL) AND t.status = 0";
|
|
5
|
+
/** An item's own anytime membership: unscheduled-active, or dated <= today. */
|
|
6
|
+
export declare const ANYTIME_SELF: (col: string) => string;
|
|
7
|
+
/**
|
|
8
|
+
* The item's effective project: its own link, or its heading's project for
|
|
9
|
+
* headed children (heading rows carry the project link).
|
|
10
|
+
*/
|
|
11
|
+
export declare const EFF_PROJECT = "COALESCE(t.project, (SELECT h.project FROM TMTask h WHERE h.uuid = t.heading))";
|
|
12
|
+
/**
|
|
13
|
+
* Container cascade (live-verified against the UI, 2026-07-09): a to-do
|
|
14
|
+
* inside a project that is NOT itself anytime-visible (someday or
|
|
15
|
+
* future-scheduled, logged, or trashed) is absent from Anytime regardless of
|
|
16
|
+
* the to-do's own start state — the project row alone represents it.
|
|
17
|
+
* Projects and container-less to-dos pass through. Two binds (packedToday ×2).
|
|
18
|
+
*/
|
|
19
|
+
export declare const PROJECT_ANYTIME_ACTIVE: string;
|
|
20
|
+
/**
|
|
21
|
+
* DERIVED-trash exclusion: project deletion is SHALLOW (A24B — only the
|
|
22
|
+
* project row flips trashed=1; children keep trashed=0 and their links, so
|
|
23
|
+
* their Trash membership is derived through the container chain). Every live
|
|
24
|
+
* view must therefore check the chain, not just the row's own flag: the
|
|
25
|
+
* heading (if any) and the effective project (direct or via heading) must
|
|
26
|
+
* both be untrashed. Areas cannot be trashed (they delete permanently), so
|
|
27
|
+
* the chain is at most heading → project. Trash-adjacent surfaces stay
|
|
28
|
+
* exempt on purpose: `things trash` lists directly-flagged rows, and a
|
|
29
|
+
* trashed project's OWN view shows its would-be-recovered children.
|
|
30
|
+
*/
|
|
31
|
+
export declare const CONTAINER_UNTRASHED = "(t.heading IS NULL OR EXISTS (\n SELECT 1 FROM TMTask hh WHERE hh.uuid = t.heading AND hh.trashed = 0))\n AND (COALESCE(t.project, (SELECT h.project FROM TMTask h WHERE h.uuid = t.heading)) IS NULL OR EXISTS (\n SELECT 1 FROM TMTask cc WHERE cc.uuid = COALESCE(t.project, (SELECT h.project FROM TMTask h WHERE h.uuid = t.heading)) AND cc.trashed = 0))";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared SQL predicate fragments for the list views (src/read/views.ts).
|
|
3
|
+
* Every live view composes these so the membership rules — untrashed, open,
|
|
4
|
+
* anytime-self, the effective-project resolution, and the derived-trash
|
|
5
|
+
* container checks — are written once and cannot drift between views.
|
|
6
|
+
*
|
|
7
|
+
* Derivation and live-probe provenance are documented at each view's call
|
|
8
|
+
* site in views.ts and in docs/atlas/schema-v26.md.
|
|
9
|
+
*/
|
|
10
|
+
import { NOT_TEMPLATE } from "./queries.js";
|
|
11
|
+
/** Real to-dos/projects (type IN 0,1), untrashed, excluding repeating templates. */
|
|
12
|
+
export const LIVE = `t.type IN (0, 1) AND t.trashed = 0 AND ${NOT_TEMPLATE}`;
|
|
13
|
+
/** {@link LIVE} restricted to open (status = 0) rows. */
|
|
14
|
+
export const OPEN = `${LIVE} AND t.status = 0`;
|
|
15
|
+
/** An item's own anytime membership: unscheduled-active, or dated <= today. */
|
|
16
|
+
export const ANYTIME_SELF = (col) => `((${col}.start = 1 AND (${col}.startDate IS NULL OR ${col}.startDate <= ?))
|
|
17
|
+
OR (${col}.start = 2 AND ${col}.startDate IS NOT NULL AND ${col}.startDate <= ?))`;
|
|
18
|
+
/**
|
|
19
|
+
* The item's effective project: its own link, or its heading's project for
|
|
20
|
+
* headed children (heading rows carry the project link).
|
|
21
|
+
*/
|
|
22
|
+
export const EFF_PROJECT = `COALESCE(t.project, (SELECT h.project FROM TMTask h WHERE h.uuid = t.heading))`;
|
|
23
|
+
/**
|
|
24
|
+
* Container cascade (live-verified against the UI, 2026-07-09): a to-do
|
|
25
|
+
* inside a project that is NOT itself anytime-visible (someday or
|
|
26
|
+
* future-scheduled, logged, or trashed) is absent from Anytime regardless of
|
|
27
|
+
* the to-do's own start state — the project row alone represents it.
|
|
28
|
+
* Projects and container-less to-dos pass through. Two binds (packedToday ×2).
|
|
29
|
+
*/
|
|
30
|
+
export const PROJECT_ANYTIME_ACTIVE = `(${EFF_PROJECT} IS NULL OR EXISTS (
|
|
31
|
+
SELECT 1 FROM TMTask p WHERE p.uuid = ${EFF_PROJECT}
|
|
32
|
+
AND p.trashed = 0 AND p.status = 0 AND ${ANYTIME_SELF("p")}))`;
|
|
33
|
+
/**
|
|
34
|
+
* DERIVED-trash exclusion: project deletion is SHALLOW (A24B — only the
|
|
35
|
+
* project row flips trashed=1; children keep trashed=0 and their links, so
|
|
36
|
+
* their Trash membership is derived through the container chain). Every live
|
|
37
|
+
* view must therefore check the chain, not just the row's own flag: the
|
|
38
|
+
* heading (if any) and the effective project (direct or via heading) must
|
|
39
|
+
* both be untrashed. Areas cannot be trashed (they delete permanently), so
|
|
40
|
+
* the chain is at most heading → project. Trash-adjacent surfaces stay
|
|
41
|
+
* exempt on purpose: `things trash` lists directly-flagged rows, and a
|
|
42
|
+
* trashed project's OWN view shows its would-be-recovered children.
|
|
43
|
+
*/
|
|
44
|
+
export const CONTAINER_UNTRASHED = `(t.heading IS NULL OR EXISTS (
|
|
45
|
+
SELECT 1 FROM TMTask hh WHERE hh.uuid = t.heading AND hh.trashed = 0))
|
|
46
|
+
AND (${EFF_PROJECT} IS NULL OR EXISTS (
|
|
47
|
+
SELECT 1 FROM TMTask cc WHERE cc.uuid = ${EFF_PROJECT} AND cc.trashed = 0))`;
|
|
48
|
+
//# sourceMappingURL=predicates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predicates.js","sourceRoot":"","sources":["../../src/read/predicates.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,oFAAoF;AACpF,MAAM,CAAC,MAAM,IAAI,GAAG,0CAA0C,YAAY,EAAE,CAAC;AAE7E,yDAAyD;AACzD,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,IAAI,mBAAmB,CAAC;AAE/C,+EAA+E;AAC/E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAW,EAAU,EAAE,CAClD,KAAK,GAAG,mBAAmB,GAAG,yBAAyB,GAAG;UAClD,GAAG,kBAAkB,GAAG,8BAA8B,GAAG,mBAAmB,CAAC;AAEvF;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,gFAAgF,CAAC;AAE5G;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,WAAW;6CACR,WAAW;8CACV,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAEpE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;;QAE3B,WAAW;+CAC4B,WAAW,uBAAuB,CAAC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { encodePackedDate, localToday, decodePackedDate } from "../model/dates.js";
|
|
2
2
|
import { mapHeading, mapProject, mapTodo } from "../model/mappers.js";
|
|
3
3
|
import { fetchTagsForTasks, fetchTaskByUuid, fetchTaskRows, makeRefResolver } from "./queries.js";
|
|
4
|
+
import { logBoundary, markLogged } from "./log-boundary.js";
|
|
5
|
+
import { inheritedTagsFor } from "./tags.js";
|
|
4
6
|
export class ProjectNotFoundError extends Error {
|
|
5
7
|
constructor(uuid) {
|
|
6
8
|
super(`no project with uuid ${uuid}`);
|
|
@@ -15,6 +17,8 @@ export function projectView(db, uuid, now) {
|
|
|
15
17
|
const tagsOf = (rows) => fetchTagsForTasks(db, rows.map((r) => r.uuid));
|
|
16
18
|
const projectTags = tagsOf([projectRow]);
|
|
17
19
|
const project = mapProject(projectRow, refs, projectTags.get(projectRow.uuid) ?? []);
|
|
20
|
+
// The card view surfaces area-inherited tags (the UI's tag filter honors them).
|
|
21
|
+
project.inheritedTags = inheritedTagsFor(db, projectRow);
|
|
18
22
|
const headingRows = fetchTaskRows(db, `t.type = 2 AND t.project = ? AND t.trashed = 0 ORDER BY t."index" ASC`, [uuid]);
|
|
19
23
|
const headings = headingRows.map((h) => mapHeading(h, refs));
|
|
20
24
|
const childRows = fetchTaskRows(db, `t.type = 0 AND (t.project = ? OR t.heading IN (
|
|
@@ -22,10 +26,12 @@ export function projectView(db, uuid, now) {
|
|
|
22
26
|
))
|
|
23
27
|
ORDER BY t."index" ASC`, [uuid, uuid]);
|
|
24
28
|
const childTags = tagsOf(childRows);
|
|
29
|
+
const boundary = logBoundary(db, now);
|
|
25
30
|
const todos = childRows.map((r) => ({
|
|
26
31
|
row: r,
|
|
27
32
|
todo: mapTodo(r, refs, childTags.get(r.uuid) ?? []),
|
|
28
33
|
}));
|
|
34
|
+
markLogged([project, ...todos.map((t) => t.todo)], boundary);
|
|
29
35
|
const packedToday = encodePackedDate(localToday(now));
|
|
30
36
|
const active = [];
|
|
31
37
|
const byHeading = new Map();
|
|
@@ -44,7 +50,21 @@ export function projectView(db, uuid, now) {
|
|
|
44
50
|
continue;
|
|
45
51
|
}
|
|
46
52
|
if (row.status !== 0) {
|
|
47
|
-
logged
|
|
53
|
+
// Completion ≠ logged: closed items the log-move sweep has not
|
|
54
|
+
// passed stay checked IN PLACE (their heading / the active block),
|
|
55
|
+
// exactly like the GUI — only logged ones join the Logbook bucket.
|
|
56
|
+
if (todo.logged) {
|
|
57
|
+
logged.push(todo);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (row.heading) {
|
|
61
|
+
const list = byHeading.get(row.heading) ?? [];
|
|
62
|
+
list.push(todo);
|
|
63
|
+
byHeading.set(row.heading, list);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
active.push(todo);
|
|
67
|
+
}
|
|
48
68
|
continue;
|
|
49
69
|
}
|
|
50
70
|
if (row.start === 2 && row.startDate === null) {
|
|
@@ -52,7 +72,11 @@ export function projectView(db, uuid, now) {
|
|
|
52
72
|
continue;
|
|
53
73
|
}
|
|
54
74
|
if (row.startDate !== null && row.startDate > packedToday) {
|
|
55
|
-
scheduledRows.push({
|
|
75
|
+
scheduledRows.push({
|
|
76
|
+
date: decodePackedDate(row.startDate) ?? "",
|
|
77
|
+
ti: row.todayIndex ?? 0,
|
|
78
|
+
todo,
|
|
79
|
+
});
|
|
56
80
|
continue;
|
|
57
81
|
}
|
|
58
82
|
if (row.heading) {
|
|
@@ -65,7 +89,8 @@ export function projectView(db, uuid, now) {
|
|
|
65
89
|
}
|
|
66
90
|
logged.sort((a, b) => (b.stopped?.getTime() ?? 0) - (a.stopped?.getTime() ?? 0));
|
|
67
91
|
const scheduled = [];
|
|
68
|
-
|
|
92
|
+
// Within a day the UI sorts by todayIndex ASC (Upcoming drag order).
|
|
93
|
+
for (const { date, todo } of scheduledRows.sort((a, b) => a.date.localeCompare(b.date) || a.ti - b.ti)) {
|
|
69
94
|
const last = scheduled[scheduled.length - 1];
|
|
70
95
|
if (last && last.date === date)
|
|
71
96
|
last.items.push(todo);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-view.js","sourceRoot":"","sources":["../../src/read/project-view.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEnF,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAgB,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"project-view.js","sourceRoot":"","sources":["../../src/read/project-view.ts"],"names":[],"mappings":"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"}
|