Skip to content

feat(view-options): add saved view options API - #665

Merged
craigcarlyle merged 3 commits into
mainfrom
ernesto/view-options
Aug 19, 2026
Merged

feat(view-options): add saved view options API#665
craigcarlyle merged 3 commits into
mainfrom
ernesto/view-options

Conversation

@gnapse

@gnapse gnapse commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Complete the saved view-options schemas, including valid singleton IDs, tombstones, and calendar settings.
  • Add typed get, set, and delete methods to TodoistApi.
  • Add reusable helpers for finding active view options.

Example

import { TodoistApi, findViewOptions } from "@doist/todoist-sdk"

const api = new TodoistApi(token)
const options = await api.getViewOptions()
const savedOptions = findViewOptions(options, {
    viewTypes: ["FILTER", "WORKSPACE_FILTER"],
    objectId: filterId,
})

await api.setViewOptions({
    viewType: "FILTER",
    objectId: filterId,
    sortedBy: "DUE_DATE",
    sortOrder: "ASC",
})

Validation

  • Used scripts against a live Todoist test account to create a project and round-trip saved options through the local SDK: set, get, lookup, delete, verify absence, and restore. The Todoist UI reflected the restored grouping and sorting.
  • Adapted todoist-cli#463 locally to use TodoistApi.setViewOptions() from a packed local SDK build. Its full test and check suites passed.
  • The SDK test suite (52 files, 667 tests), build, and package API checks passed.

Context

This is the first PR in the stack. It lets SDK consumers use saved view options without parsing raw Sync responses.

Related CLI work:

Stack created with GitHub Stacks CLIGive Feedback 💬

@doistbot doistbot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds a clean saved view-options API surface — a new sub-client, public TodoistApi methods (get/set/delete), expanded Zod schemas, and a findViewOptions helper — that follows the existing sub-client and Sync request conventions nicely.

Few things worth tightening:

  • ViewOptionsSetArgs types deadline and calendarSettings as non-null, but the response schema marks both as nullable and the sibling ProjectViewOptionsDefaultsSetArgs already accepts | null. This means callers can't send { deadline: null } or { calendarSettings: null } to clear an existing saved value — add | null to both fields.

I also included a few optional follow-up notes in the details below.

Optional follow-up notes (3)
  • P3 src/utils/view-options.ts:19: The "active view option" check (isDeleted !== true) is now duplicated in ViewOptionsClient.getViewOptions (src/clients/view-options-client.ts:14) and here in findViewOptions, both added in this PR. Extract a shared helper (e.g. isActiveViewOption) so the definition of "active" lives in one place and can't drift between the two.
  • P3 src/todoist-api.view-options.test.ts:133: findViewOptions is a utility in src/utils/view-options.ts, but its tests are embedded in the TodoistApi view-options test file. Every other utility in this repo has a matching src/utils/<name>.test.ts. Move this describe block into src/utils/view-options.test.ts to keep the test layout consistent and the utility testable independently of the API surface.
  • P3 src/todoist-api.ts:362: These three public methods only have one-line summaries, while every other method on TodoistApi documents @param and @returns. Add the matching JSDoc (e.g. @param args, @param requestId, @returns) so IDE hints and generated docs stay consistent for this public SDK surface.

Share FeedbackReview Logs

Comment thread src/types/sync/commands/view-options.ts Outdated
@gnapse gnapse self-assigned this Aug 18, 2026
craigcarlyle added a commit to Doist/todoist-cli that referenced this pull request Aug 18, 2026
`td filter view` printed tasks in whatever order the API returned. Todoist
doesn't sort server-side: every client applies the sorting saved on the view,
and falls back to a documented default hierarchy when the view has none, which
is what "Manual (default)" means in the app. The CLI read neither piece, so a
saved filter listed in an order no other Todoist client shows.

Reads the saved options with `api.getViewOptions()` and orders the results with
`sortTasks`, both from the SDK. What lives here is the part the SDK asks the
caller to supply: the vocabulary `--sort` speaks, the mapping from a saved view
to that vocabulary, the sidebar layout it wants as a lookup, and the guess at
whether a filter query is date-driven, which picks between the priority-first
and date-first hierarchies.

Adds `--sort default|priority|date|deadline|date-added|name|project|assignee|
workspace|none` and `--sort-order asc|desc`, resolved flag first, then saved
view, then Todoist default. `--sort none` returns the raw API order. Each
section of a comma-separated filter sorts on its own, and `--json` / `--ndjson`
come back in the same order as the pretty output.

BLOCKED: needs the SDK release carrying Doist/todoist-sdk-typescript#665 and
#666, plus the v14 bump in #477. `package.json` still pins 13.0.2, so this
branch does not build until both land and the pin moves.

Closes #473

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gnapse
gnapse force-pushed the ernesto/view-options branch from f55acd2 to 726dc1c Compare August 18, 2026 17:52
@gnapse
gnapse requested a review from doistbot August 18, 2026 18:25

@doistbot doistbot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds a clean saved view-options API surface — sub-client, public TodoistApi methods, expanded Zod schemas, and reusable helpers — that follows existing Sync conventions.

Few things worth tightening:

  • ViewOptionsSetArgs.viewMode is still typed as non-null ViewMode, but the response schema now allows null and the sibling ProjectViewOptionsDefaultsSetArgs.viewMode already accepts ViewMode | null. Add | null so callers can clear a saved view mode via { viewMode: null }, matching every other nullable field in the set args.

I also left one optional follow-up note in the details below.

Optional follow-up note (1)
  • P3 src/utils/view-options.test.ts:31: The test title claims objectId is matched both when null and when omitted, but only the omitted case is exercised. FindViewOptionsArgs.objectId explicitly accepts string | null, and findViewOptions normalizes both via ?? null — pass objectId: null in this assertion too (or narrow the title) so the null path is covered and the name matches what's actually tested.

Share FeedbackReview Logs

Comment thread src/types/sync/resources/view-options.ts
craigcarlyle added a commit to Doist/todoist-cli that referenced this pull request Aug 18, 2026
`td filter view` printed tasks in whatever order the API returned. Todoist
doesn't sort server-side: every client applies the sorting saved on the view,
and falls back to a documented default hierarchy when the view has none, which
is what "Manual (default)" means in the app. The CLI read neither piece, so a
saved filter listed in an order no other Todoist client shows.

Reads the saved options with `api.getViewOptions()` and orders the results with
`sortTasks`, both from the SDK. What lives here is the part the SDK asks the
caller to supply: the vocabulary `--sort` speaks, the mapping from a saved view
to that vocabulary, the sidebar layout it wants as a lookup, and the guess at
whether a filter query is date-driven, which picks between the priority-first
and date-first hierarchies.

Adds `--sort default|priority|date|deadline|date-added|name|project|assignee|
workspace|none` and `--sort-order asc|desc`, resolved flag first, then saved
view, then Todoist default. `--sort none` returns the raw API order. Each
section of a comma-separated filter sorts on its own, and `--json` / `--ndjson`
come back in the same order as the pretty output.

BLOCKED: needs the SDK release carrying Doist/todoist-sdk-typescript#665 and
#666, plus the v14 bump in #477. `package.json` still pins 13.0.2, so this
branch does not build until both land and the pin moves.

Closes #473

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gnapse
gnapse requested a review from craigcarlyle August 18, 2026 22:45

@craigcarlyle craigcarlyle left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/utils/view-options.ts Outdated
Every other exported shape in src/ is declared with export type. This was
the only export interface, so bring it in line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@craigcarlyle
craigcarlyle merged commit 4caaa68 into main Aug 19, 2026
5 checks passed
@craigcarlyle
craigcarlyle deleted the ernesto/view-options branch August 19, 2026 19:26
doist-release-bot Bot added a commit that referenced this pull request Aug 19, 2026
## [14.1.0](v14.0.2...v14.1.0) (2026-08-19)

### Features

* **tasks:** add reusable task sorting ([#666](#666)) ([a9464c1](a9464c1))
* **view-options:** add saved view options API ([#665](#665)) ([4caaa68](4caaa68))
@doist-release-bot

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 14.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

craigcarlyle added a commit to Doist/todoist-cli that referenced this pull request Aug 19, 2026
`td filter view` printed tasks in whatever order the API returned. Todoist
doesn't sort server-side: every client applies the sorting saved on the view,
and falls back to a documented default hierarchy when the view has none, which
is what "Manual (default)" means in the app. The CLI read neither piece, so a
saved filter listed in an order no other Todoist client shows.

Reads the saved options with `api.getViewOptions()` and orders the results with
`sortTasks`, both added to the SDK by @gnapse in
Doist/todoist-sdk-typescript#665 and #666. What lives here is the part the SDK
asks the caller to supply: the vocabulary `--sort` speaks, the mapping from a
saved view to that vocabulary, the sidebar layout it wants as a lookup, and the
guess at whether a filter query is date-driven, which picks between the
priority-first and date-first hierarchies.

Adds `--sort default|priority|date|deadline|date-added|name|project|assignee|
workspace|none` and `--sort-order asc|desc`, resolved flag first, then saved
view, then Todoist default. `--sort none` returns the raw API order. Each
section of a comma-separated filter sorts on its own, and `--json` / `--ndjson`
come back in the same order as the pretty output.

Closes #473

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
craigcarlyle added a commit to Doist/todoist-cli that referenced this pull request Aug 19, 2026
`td filter view` printed tasks in whatever order the API returned. Todoist
doesn't sort server-side: every client applies the sorting saved on the view,
and falls back to a documented default hierarchy when the view has none, which
is what "Manual (default)" means in the app. The CLI read neither piece, so a
saved filter listed in an order no other Todoist client shows.

Reads the saved options with `api.getViewOptions()` and orders the results with
`sortTasks`, both added to the SDK by @gnapse in
Doist/todoist-sdk-typescript#665 and #666. What lives here is the part the SDK
asks the caller to supply: the vocabulary `--sort` speaks, the mapping from a
saved view to that vocabulary, the sidebar layout it wants as a lookup, and the
guess at whether a filter query is date-driven, which picks between the
priority-first and date-first hierarchies.

Adds `--sort default|priority|date|deadline|date-added|name|project|assignee|
workspace|none` and `--sort-order asc|desc`, resolved flag first, then saved
view, then Todoist default. `--sort none` returns the raw API order. Each
section of a comma-separated filter sorts on its own, and `--json` / `--ndjson`
come back in the same order as the pretty output.

Closes #473

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
craigcarlyle added a commit to Doist/todoist-cli that referenced this pull request Aug 19, 2026
`td filter view` printed tasks in whatever order the API returned. Todoist
doesn't sort server-side: every client applies the sorting saved on the view,
and falls back to a documented default hierarchy when the view has none, which
is what "Manual (default)" means in the app. The CLI read neither piece, so a
saved filter listed in an order no other Todoist client shows.

Reads the saved options with `api.getViewOptions()` and orders the results with
`sortTasks`, both added to the SDK by @gnapse in
Doist/todoist-sdk-typescript#665 and #666. What lives here is the part the SDK
asks the caller to supply: the vocabulary `--sort` speaks, the mapping from a
saved view to that vocabulary, the sidebar layout it wants as a lookup, and the
guess at whether a filter query is date-driven, which picks between the
priority-first and date-first hierarchies.

Adds `--sort default|priority|date|deadline|date-added|name|project|assignee|
workspace|none` and `--sort-order asc|desc`, resolved flag first, then saved
view, then Todoist default. `--sort none` returns the raw API order. Each
section of a comma-separated filter sorts on its own, and `--json` / `--ndjson`
come back in the same order as the pretty output.

Closes #473

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants