Skip to content

fix(github): name an unfiltered empty project view instead of blaming a filter - #20588

Merged
nwparker merged 3 commits into
mainfrom
nwparker/project-unfiltered-empty-state
Sep 14, 2026
Merged

nwparker merged 3 commits into
mainfrom
nwparker/project-unfiltered-empty-state

Conversation

@nwparker

@nwparker nwparker commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​46 $\color{#cf222e}{\Huge{\mathbf{−}}}$​3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​43
Prod 10 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​69 $\color{#cf222e}{\Huge{\mathbf{−}}}$​20 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​49

Replaces #13561 (external contribution by @bbingz), which targeted the same issue with a change that turns out to be a no-op.

Why #13561 could not work

#13561 removed the query: argument from ProjectV2.items(...) for unfiltered views, on the theory that omitting it skips GitHub's Projects search index. Live introspection says otherwise:

$ gh api graphql -f query='{__type(name:"ProjectV2"){fields{name args{name defaultValue type{kind name}}}}}'
{"defaultValue":"\"\"","name":"query","type":{"kind":"SCALAR","name":"String"}}

query is declared String = "". Per GraphQL spec §6.4.1 (CoerceArgumentValues), an omitted argument with a declared default contributes that default to the coerced argument map, so the resolver receives "" either way. Confirmed empirically against GitHub's own endpoint using __Type.fields(includeDeprecated: Boolean = false): omitted and explicit-default both return 14 fields, explicit non-default returns 19. GitHub applies declared defaults server-side.

Two further schema facts close the door on any client-side fix:

  • items is the only item enumeration on ProjectV2 — there is no non-search field to fall back to.
  • ProjectV2View has no items field at all, so there is no view-scoped connection traversal either.

No request shape Orca can emit avoids the index.

What this PR does instead

The real user-visible defect in #12648 is the message, not the request. A view with no filter rendered "No items match this view's filter" — factually wrong, and it reads as data loss when a freshly populated board momentarily comes back empty.

ProjectItemsEmptyState words the empty state from the view's own filter: the existing filter message only when filter.trim() is non-empty, otherwise "This view has no items yet." + "Recently added items can take a while to appear."

Also folds together the byte-identical empty-state blocks that ProjectViewList.tsx and ProjectRoadmap.tsx each carried (both reusing the same translate key), and corrects the GitHubProjectView.filter doc comment, which asserted a query-shape rationale that does not hold.

This does not make a lagging board show items — nothing client-side can. It stops Orca from misattributing the emptiness, which is what the issue reporter asked for as the fallback remedy.

Verification

  • pnpm tc — exit 0
  • pnpm test (github-project, i18n, main/github) — 1002 passed / 102 files
  • pnpm run check:code-quality:changed — 0 new findings across all five gates
  • oxlint — exit 0, sanity-checked against a seeded violation
  • i18n: 2 new keys added to all six catalogs (en/es/fr/ja/ko/zh) with real translations

References #12648 (already closed) rather than claiming to close it.

Testing

  • pnpm typecheck — exit 0
  • oxlint — exit 0 (sanity-checked against a seeded violation); pnpm run check:code-quality:changed — 0 new findings across all five gates
  • pnpm test — 1002 passed across 102 files
  • Full CI green — 18/18, including package (windows) and all 8 test shards
  • i18n: 2 new keys in all six catalogs (en/es/fr/ja/ko/zh) with real translations

Notes

  • Provider neutrality: ProjectItemsEmptyState / "view" / "filter" / "items" are provider-neutral names. Nothing GitHub-specific was introduced for a generic concept; the module itself is GitHub Projects v2, which has no GitLab counterpart in this codebase.
  • No wire or persisted-state surface. Renderer-only copy change plus a corrected type comment.
  • This does not make a lagging board show items — nothing client-side can, since items is the only enumeration on ProjectV2. It stops Orca from misattributing the emptiness, which is what the issue reporter asked for as the fallback remedy.

bbingz and others added 3 commits September 14, 2026 00:29
Empty query still used items(query:\$q), which routes through GitHub's
Projects search index and can return totalCount 0 while the board is full
during index lag. Omit the query argument when the view filter is empty.

Fixes #12648.
…ters

Unfiltered item fetches omit items(query:) so boards skip search-index
lag. The View.filter field is still '' when GitHub returns null.

Co-authored-by: Cursor <cursoragent@cursor.com>
… a filter

The search-index workaround in this branch was a no-op. Live introspection of
ProjectV2.items shows `query` is declared `String = ""`, so omitting the
argument and sending `$q = ""` coerce to the identical resolver input; GitHub
applies declared defaults for omitted args (verified against its own endpoint).
There is no non-search item field on ProjectV2 and ProjectV2View has no `items`
at all, so no request shape can dodge the index. Revert the branching query
construction and the module it added.

What the user actually reported in #12648 is the copy: a view with no filter
rendered "No items match this view's filter", which reads as data loss when a
freshly populated board momentarily comes back empty. Word the empty state from
the view's own filter — the filter message only when there is a filter, and an
honest "no items yet" plus a transience hint when there is not — and share the
one implementation between the table and roadmap surfaces.

Refs #12648.
@coderabbitai

coderabbitai Bot commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: 99921e5f-2ddd-4c58-8102-5657ed250940

📥 Commits

Reviewing files that changed from the base of the PR and between 539d4d1 and d866fa8.

📒 Files selected for processing (12)
  • src/renderer/src/components/github-project/ProjectRoadmap.test.tsx
  • src/renderer/src/components/github-project/ProjectRoadmap.tsx
  • src/renderer/src/components/github-project/ProjectViewList.tsx
  • src/renderer/src/components/github-project/ProjectViewStates.test.tsx
  • src/renderer/src/components/github-project/ProjectViewStates.tsx
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/fr.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/shared/github/project-types.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The change adds ProjectItemsEmptyState, which shows filter-specific text for nonblank filters and unfiltered empty-state text with a recent-items hint otherwise. ProjectRoadmap and ProjectViewList now use this component. English and five additional locales provide the new strings. Tests cover filter propagation and blank, whitespace, and filtered states. The GitHubProjectView.filter comment now documents the empty-string behavior.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to d866f

The updated empty-state messaging correctly distinguishes filtered and unfiltered project views, with no actionable merge risk identified.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 6 files. (6 skipped: 6… Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description provides detailed rationale, implementation scope, testing results, and issue references. However, it does not follow the required template and omits required sections, including ELI5,… Add the missing template sections. Include a valid linked issue using Fixes #..., attach before-and-after visual proof or write N/A with a reason, complete the testing and checklist items, and address the remaining required sections.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the primary change: correcting the empty-state message for unfiltered GitHub project views.
Full details: Docstring Coverage

Explanation

Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 6 files. (6 skipped: 6 unsupported.)

Full details: Description check

Explanation

The description provides detailed rationale, implementation scope, testing results, and issue references. However, it does not follow the required template and omits required sections, including ELI5, What Changed, Linked Issue with a Fixes # entry, Visual Proof or N/A, AI Disclosure, Review, Agent skill upstream boundary, and the required checklist items.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pullfrog pullfrog Bot 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.

Important

The new empty-state copy can still be false: it decides from the view's authored filter, not the query the rows were actually fetched with, so a no-result search override (or Orca's repo-selection filter) on an unfiltered view now reports "This view has no items yet."

Reviewed changes

  • Unfiltered empty state named from the filter — ProjectItemsEmptyState picks between the existing filter-miss copy and the new "no items yet" copy on filter.trim().
  • Duplicated empty blocks folded — ProjectViewList and ProjectRoadmap now render the shared component instead of byte-identical inline blocks.
  • Two i18n keys added to all six catalogs; extraction/catalog/coverage/runtime-catalog checks all pass.
  • Doc correction — the GitHubProjectView.filter comment now reflects that GitHub's declared String = "" default makes omitted and empty equivalent.
  • Tests — new ProjectViewStates.test.tsx plus an unfiltered roadmap case.

The filtered-branch key reuse and the two new hash IDs match the repo's existing extraction scheme (verified by running verify:localization-extraction), so nothing else here looks off.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment on lines +238 to +239
export function ProjectItemsEmptyState({ filter }: { filter: string }): React.JSX.Element {
if (filter.trim().length > 0) {

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.

filter is the view's authored filter, not the query the rows were fetched with. When the user types a no-result search in the toolbar's ProjectSearchInput, useProjectViewTable fetches with the override but table.selectedView.filter stays the authored value, so an unfiltered view renders "This view has no items yet. Recently added items can take a while to appear." for items that simply didn't match the search — the same misattribution as #12648, in the other direction.

Technical details
# Empty-state reason ignores the effective row filter

## Affected sites
- `src/renderer/src/components/github-project/ProjectViewStates.tsx:239` — predicate only inspects the authored `filter`.
- `src/main/github/project-view/project-view-table.ts:116-118` — `effectiveQuery = args.queryOverride ?? selectedView.filter`, but the returned `selectedView` (lines 114, 167) is never updated, so the override is invisible downstream.
- `src/renderer/src/components/github-project/ProjectViewToolbar.tsx:63-91` — `ProjectSearchInput` writes the ephemeral override through `setAppliedQueryByView`.
- `src/renderer/src/components/github-project/useProjectViewTable.ts:173-184` — `visibleTable` also drops rows not matching `selectedRepoIds` (`filterProjectTableRowsBySelectedRepos`), another way to reach `rows.length === 0` with `filter === ''`.

## Required outcome
- The "view has no items yet" copy should appear only when neither the view filter nor any ephemeral/local filter removed rows. A search-no-results state and a repo-selection-no-results state should read as such, not as a genuinely empty view.

## Suggested approach (optional)
- Thread the effective query (e.g. `currentAppliedOverride`) and/or a "rows dropped locally" signal from `ProjectViewWrapper`/`useProjectViewTable` into the empty state as a discriminated reason, rather than inferring it from `selectedView.filter` alone.

## Open questions for the human (optional)
- Is the repository-selection filter intended to be the reason for an empty project list, and if so does it warrant its own copy?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants