Deduplicate the plugin/module feature flag registration loops and
distinguish the error source (Plugin vs Module). Treat
FEATURE_FLAG_INVALID as a warning in frontend-defaults.
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Made-with: Cursor
Wrap each feature flag registration in a try/catch so that a single
invalid flag name (e.g. containing a slash) is reported through the
error collector instead of crashing the entire app at bootstrap.
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Made-with: Cursor
The following patches were included in the v1.50.2 patch release and
no longer need to be tracked:
- pr-33908 (TechDocs sidebar positioning)
- pr-33952 (zod v4 bump)
- pr-33975 (React Aria dependency clamping)
- pr-33984 (tab indicator opacity fix)
Signed-off-by: Fredrik Adelöw <freben@spotify.com>
Made-with: Cursor
Add `isPending` prop to Alert, Button, ButtonIcon, Table, and
TableRoot, aligning with React Aria naming conventions. The
`loading` prop is deprecated but remains functional as an alias.
CSS selectors now target `data-ispending` instead of `data-loading`
for pending state styling. The `data-loading` attribute is still
emitted for backward compatibility.
Internal Table hooks (`PaginationResult`, `UsePageCacheResult`)
renamed `loading` to `isPending`. The `useTable` hook returns both
`isPending` and `loading` on `tableProps` to preserve backward
compatibility.
Updated docs-ui documentation and stories accordingly.
Signed-off-by: Johan Persson <johanopersson@gmail.com>
The NOT IN guard against null final_entity rows was preventing the
query planner from using parallel workers and (with a future covering
index) index-only scans. Without the covering index it caused a 2.6x
regression on the no-filter path (7s -> 18.4s).
The filtered path already excludes unstitched entities via the
whereNotNull('final_entities.final_entity') in the inner
entityIdSubquery, so no guard is needed there.
The no-filter path now matches 1.49.x behavior. A followup migration
adding a covering index can re-introduce the guard efficiently.
Signed-off-by: Fredrik Adelöw <freben@spotify.com>
Made-with: Cursor
When the app was served under a non-root base path, BUI link
components rewrote absolute `href` values as in-app paths — e.g.
`https://example.com` became `/basename/https:/example.com` —
because every href was passed through react-router's `useHref`,
which treats all strings as relative paths.
External URLs (`http://`, `https://`, `//`, `mailto:`, `tel:`)
now bypass href resolution. Internal hrefs are normalized to
their canonical pre-basename form in `useDefinition`, so
downstream resolution by react-router's `useHref` (for
rendering) and `navigate` (for click-navigation) adds the
basename exactly once.
Signed-off-by: Johan Persson <johanopersson@gmail.com>
Remove `export` from five internal helper functions that are not part of
the published API and are only used within their own files. The `sleep`
function in GitLabIntegration is kept exported for test access but marked
as `@internal`.
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Made-with: Cursor
The `otherGraph` variable in `listChangedPackages` was incorrectly
created from `thisLockfile` instead of `otherLockfile`, making the
merged dependency graph a duplicate of the current one. This meant
that dependencies only present in the old lockfile were never added
to the graph, so transitive removals could not be detected.
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Made-with: Cursor
Instead of checking IS NOT NULL against ~520k rows (which adds a
2.6x regression on the no-filter path), exclude the tiny set of
entities where final_entity IS NULL (~3,700 rows). The anti-join
is nearly free and allows the guard to be applied unconditionally,
so facets results consistently exclude not-yet-stitched (or future
tombstoned) entities regardless of whether filters are present.
Also addresses review feedback:
- Add regression test for unstitched entity exclusion
- Extract setupFacetsCatalog helper to reduce test boilerplate
- Tighten assertions: use exact arrays instead of arrayContaining
Signed-off-by: Fredrik Adelöw <freben@spotify.com>
Made-with: Cursor
Benchmarking on a production-like database shows that always applying
the final_entities subquery (even without filters) causes a 2.6x
regression on the no-filter path (5.2s -> 13.5s) due to ~530k
memoized index lookups against final_entities. The FK cascade from
search -> final_entities already guarantees search rows only exist
for entities with a final_entities row, so the constraint is only
needed when filters route through final_entities.
Signed-off-by: Fredrik Adelöw <freben@spotify.com>
Made-with: Cursor
The whereNotNull('final_entities.final_entity') was copied from other
code paths that select the final_entity column, but the facets subquery
only needs entity_id. Removing it preserves exact v1.49 semantics
(search rows only exist for stitched entities anyway, due to the FK
cascade from search -> final_entities) and avoids an inconsistency
where the no-filter path did not exclude unstitched entities while the
with-filter path did.
Signed-off-by: Fredrik Adelöw <freben@spotify.com>
Made-with: Cursor
Adds standalone test coverage for the facets method in
DefaultEntitiesCatalog to ensure it works correctly with:
- Predicate query filtering (simple key match)
- Predicate query filtering using $in operator
- Compound allOf filters
- Compound anyOf filters
- Both filter and query combined
Signed-off-by: Fredrik Adelöw <freben@spotify.com>
Made-with: Cursor
Route the EXISTS-based filters through final_entities (one row per
entity) instead of correlating against the search table directly.
This avoids the pathological case where correlated subqueries scan
the much larger search table for every row in the outer facets query.
Signed-off-by: Fredrik Adelöw <freben@spotify.com>
Made-with: Cursor
- Add aria-label="Open calendar" and aria-hidden on icon for the calendar trigger button
- Add aria-hidden on nav button icons (React Aria provides built-in labels for prev/next slots)
- Update React Aria docs link to react-aria.adobe.com format
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
Made-with: Cursor
- Fixed size: 1.5rem (small), 2rem (medium) in rem units
- No padding, flex-centered icon
- Inset focus ring using 1px box-shadow with --bui-ring token
- Border radius bumped to radius-2
- Medium size padding-inline-end reduced to space-1
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
Made-with: Cursor