Add totalItemsLoading to EntityListContextProps so consumers can
distinguish a stale count (being refreshed) from a fresh one. Rename
the internal asyncTotalItems to totalItems.
Update CatalogTable to show a dimmed count while the count is loading,
and only show the full-table spinner on the very first load (when no
entities exist yet). Subsequent fetches keep stale rows visible with
a small spinner next to the title.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
* feat(skill): automatically onboard to openapi tooling
Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
* test skill against notifications backend
Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
* update URLs to point to main repo and describe multiple client types
Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
* address PR feedback
Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
* revert erroneous changes
Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
* add changeset
Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
* address review feedback: skill doc fixes and entityRef schema dedup
Disambiguate generated entityRef/orderField types and correct skill
guidance on operationId casing and OpenAPI version support.
Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
* note in skill that handler-side validation should be stripped
Reviewers may forget that manual InputError guards and primitive-type
checks become dead weight once the OpenAPI validator runs.
Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
---------
Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
A second call with mode='immediate' would incorrectly log "Unknown
strategy mode" because the deprecation flag was already set.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
INSERT return values differ across database engines (row IDs, row
counts, or empty arrays), making them unsuitable for detecting blocked
upserts. Use a post-write hash verification instead, which works
reliably on all engines.
Adds test coverage for stale ticket rejection across all supported
database engines (MySQL 8, PostgreSQL 14/18, SQLite 3).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Restore the 'does not re-fetch when backend filter params are
unchanged' test from #34324 that was accidentally dropped during
the rebase. Add a new test verifying that cursor navigation does
not re-run the count query (the core split-count behavior).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
On PostgreSQL and SQLite, the stitch ticket check is now part of the
upsert WHERE clause, eliminating the TOCTOU window between the check
and the write. MySQL does not support ON CONFLICT ... DO UPDATE ... WHERE,
so it retains the separate SELECT with a negligible race window.
SQLite misreports affected rows for blocked upserts, so a post-write
hash verification is used there instead of the row count.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
The initial SELECT entity_id FROM refresh_state check is redundant —
the processedResult query in the Promise.all already handles the
missing-entity case. This saves one database round trip per stitch.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Now that immediate mode is removed, the two-step pattern of inserting a
placeholder row and then updating it is unnecessary. Replace with a
single upsert that creates or updates the final_entities row in one
operation, removing a round-trip and simplifying the flow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
The conflict resolution replaced unicode escapes with literal control
character bytes, causing GitHub to render the file as binary.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Remove the immediate stitching strategy from the catalog-backend plugin.
All stitching now uses the deferred mode exclusively, which processes
entities asynchronously via a worker queue. This simplifies the stitching
subsystem by removing dead-weight code paths and the strategy parameter
threading, and fixes a bug where deleteWithEagerPruningOfChildren
hardcoded immediate-mode semantics regardless of configured mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Reapply the split-count concept on top of the refactored
useEntityListProvider (from #34324). The list fetch now uses
totalItems: 'exclude' to skip the expensive count, and a separate
useAsyncFn fetches the count only when filters change — page
navigation no longer re-runs the count query.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Cursor requests already carry the computed totalItems from page 1,
so the count query is skipped regardless of this value. Setting it
to 'exclude' reflects what actually happens, and the comment
explains why the value doesn't matter.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Layer the remaining concepts from the original PR on top of the
split-query foundation:
- totalItems parameter on REST API (GET and POST) and CatalogApi
- TotalItemsMode type replacing internal skipTotalItems boolean
- Sort field key lowercasing for search table comparison
- whereNotNull(search.value) on the list CTE to exclude truncated values
- Simplified ORDER BY (NULLS LAST removed since NULL values are
already excluded by whereNotNull)
- New tests for NULL sort field values and multi-valued sort field
totalItems accuracy
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
- Remove the path="*" fallback Route so mismatches between mountPath
and initialRouteEntries surface as test failures instead of silently
rendering without params
- Handle mountPath values that already end with /* to avoid double splat
- Extract repeated entity path string into a shared constant
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Address review feedback: mountedRoutes are for abstract route targets
the test subject links to, not for the subject itself. Add a dedicated
mountPath option that wraps the test element in a single Route with
the given path pattern, enabling useParams(). When mountPath is set
and initialRouteEntries is not, the initial entry defaults to mountPath.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Move the adjustedFilters useMemo above refresh and reuse it in both
the fetch callback and the frontend filtering memo.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
The lastFetchParamsRef starts as undefined, so the initial debounce
would have fetched with an empty filter (returning every entity in
the catalog). Guard against this by skipping the fetch when no filter
components have registered yet.
Also skip the URL sync effect until at least one filter has been set,
to avoid briefly clearing filter query params from the URL bar before
filter components initialize.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
The label is read by CatalogTable for the table title (e.g. "All
Components (42)"), so suppressing the label update would cause a
visible regression. The provider's ref-based fetch dedup already
prevents the redundant API call when only the label changes, so
the second updateFilters call is harmless.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Replace useAsyncFn + outputState comparison with ref-based fetch dedup
and generation counter. Split entity filtering into a synchronous
useMemo so frontend-only filter changes are instant.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
The list CTE's INNER JOIN on search already excludes entities whose
sort-field value is NULL (truncated long values stored as NULL by
buildEntitySearch). Add the same whereNotNull to the count query's
EXISTS so totalItems matches the reachable set. Matters for fields
like metadata.description where ~128K entities have NULL values.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
The list CTE and count query both need the same filter, query, and
full-text-search predicates. Extract them into a shared
applyPredicates closure so they can't drift apart. Move the count
query construction next to the CTE for readability.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Remove pr-33721, pr-34001, pr-34004 — all shipped in v1.51.0.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>