Default the Plan issue dialog to Forgejo issue, with an open-issue picker #247

Merged
lucas merged 1 commit from agent/issue-246-plan-issue-picker into main 2026-11-10 22:18:25 +01:00
Collaborator

Closes: #246

The Plan issue dialog now opens on "Forgejo issue" (the leading radio) with
the caret already in the issue field, and that field became a combobox over the
repository's open issues.

What changed

  • Protocol — ForgejoIssueSummary / ListForgejoIssuesResponse.
  • DispatchApi.searchOpenIssues — open issues of owner/repo, newest-updated
    first, pull requests excluded. type=issues already excludes PRs server-side;
    the local pull_request == null filter keeps the contract true regardless.
    Ordering is done locally rather than through an unverified sort parameter.
  • GET /api/forgejo/issues — workspaceId (+ optional q), resolving
    workspace → config → repository with the same sequence and the same two 422
    messages as /forgejo/plan-issue, so a workspace that cannot plan an issue
    cannot list issues either. A client failure maps to 502.
  • apps/web/src/lib/issue-suggest.ts — local matcher, mirroring
    inbox-suggest.ts (that one is typed on InboxItem and scores over
    title/body/id, so it cannot be reused). All-digit queries match on the number,
    prefix matches first.
  • PlanIssueModal — the issue input and the inbox input now share one
    combobox implementation (query, activeIndex, AnchoredPortal, key
    handling). The dialog prefetches the open issues on open; a prose query hits
    the instance after a 140 ms debounce; a number never costs a request, because
    Forgejo's q= searches prose and a number is already a valid seed. Switching
    sources clears the shared field.

Degradation

Typing a number works independently of the list. When the prefetch or a search
fails, the dialog shows Could not load issues: … — type an issue number to plan it in muted text, not the red error box: it is a degraded list, not a failed
action. A number with no match in the loaded list renders nothing — submit
already answers with #N is closed, #N is a pull request, not an issue or
issue #N not found.

Verification

  • bun run typecheck — clean across all workspaces.
  • bun test — 1608 pass / 0 fail.
  • bun run build in apps/web — clean.
  • New: apps/web/src/lib/issue-suggest.test.ts (empty query → 10 newest, number
    query narrows by number with prefix first and ignores titles, multi-word
    ranking, no match → []) and describe("GET /forgejo/issues") in
    apps/server/src/routes-forgejo.test.ts (400 / 404 / 422, the happy path with
    the q argument asserted as null and as the trimmed string, and 502 on a
    client failure). The route tests seed a config row and give the workspace a
    real git origin on the configured instance, the way
    forgejo/workspace-index.test.ts does.
  • Not exercised: the manual end-to-end pass through a running dev server against
    a live instance (no browser in this session). The combobox plumbing is the
    existing inbox one, and the route/matcher sides are covered by the tests above.
Closes: #246 The **Plan issue** dialog now opens on "Forgejo issue" (the leading radio) with the caret already in the issue field, and that field became a combobox over the repository's open issues. ## What changed - **Protocol** — `ForgejoIssueSummary` / `ListForgejoIssuesResponse`. - **`DispatchApi.searchOpenIssues`** — open issues of `owner/repo`, newest-updated first, pull requests excluded. `type=issues` already excludes PRs server-side; the local `pull_request == null` filter keeps the contract true regardless. Ordering is done locally rather than through an unverified `sort` parameter. - **`GET /api/forgejo/issues`** — `workspaceId` (+ optional `q`), resolving workspace → config → repository with the same sequence and the same two 422 messages as `/forgejo/plan-issue`, so a workspace that cannot plan an issue cannot list issues either. A client failure maps to 502. - **`apps/web/src/lib/issue-suggest.ts`** — local matcher, mirroring `inbox-suggest.ts` (that one is typed on `InboxItem` and scores over title/body/id, so it cannot be reused). All-digit queries match on the number, prefix matches first. - **`PlanIssueModal`** — the issue input and the inbox input now share one combobox implementation (`query`, `activeIndex`, `AnchoredPortal`, key handling). The dialog prefetches the open issues on open; a prose query hits the instance after a 140 ms debounce; a number never costs a request, because Forgejo's `q=` searches prose and a number is already a valid seed. Switching sources clears the shared field. ## Degradation Typing a number works independently of the list. When the prefetch or a search fails, the dialog shows `Could not load issues: … — type an issue number to plan it` in muted text, not the red error box: it is a degraded list, not a failed action. A number with no match in the loaded list renders nothing — submit already answers with `#N is closed`, `#N is a pull request, not an issue` or `issue #N not found`. ## Verification - `bun run typecheck` — clean across all workspaces. - `bun test` — 1608 pass / 0 fail. - `bun run build` in `apps/web` — clean. - New: `apps/web/src/lib/issue-suggest.test.ts` (empty query → 10 newest, number query narrows by number with prefix first and ignores titles, multi-word ranking, no match → `[]`) and `describe("GET /forgejo/issues")` in `apps/server/src/routes-forgejo.test.ts` (400 / 404 / 422, the happy path with the `q` argument asserted as `null` and as the trimmed string, and 502 on a client failure). The route tests seed a config row and give the workspace a real git `origin` on the configured instance, the way `forgejo/workspace-index.test.ts` does. - Not exercised: the manual end-to-end pass through a running dev server against a live instance (no browser in this session). The combobox plumbing is the existing inbox one, and the route/matcher sides are covered by the tests above.
The Plan issue dialog now opens on the Forgejo issue source with the
caret in its field, and that field is a combobox over the repository's
open issues instead of a bare number input: the dialog prefetches the
open issues when it opens and searches titles on the instance while
typing, so an issue can be picked without remembering its number.

Typing a number stays independent of the list — it costs no request and
keeps working when the instance is slow or unreachable, which the dialog
reports as a degraded list rather than a failed action. Only open issues
are offered, since closed issues and pull requests are rejected as
plan-issue seeds anyway.

Feeding the picker needs a data-returning open-issue search, which
Forgejo exposure in the deck did not have: `DispatchApi` gains
`searchOpenIssues` and `/api/forgejo/issues` exposes it, resolving the
workspace, config and repository exactly as the plan-issue route does.

Co-Authored-By: Claude Opus 5 via omp-deck
lucas merged commit bf70839b81 into main 2026-11-10 22:18:25 +01:00
lucas deleted branch agent/issue-246-plan-issue-picker 2026-11-10 22:18:26 +01:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
lucas/omp-deck!247
No description provided.