Commit Graph

73369 Commits

Author SHA1 Message Date
pillaris fbc2c76d39 fix: update alpha API report to match API Extractor output
The manually-written empty report-alpha.api.md didn't match what API
Extractor generates for an empty alpha entry point. Use the correct
generated output to pass the CI api-reports check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-28 10:14:28 +05:30
pillaris ff199fef07 fix: address Andre's review comments
- Update copyright year from 2024 to 2026 across all new source files
- Clear alpha entry point (no alpha exports needed for a net-new package)
  and regenerate report-alpha.api.md accordingly
- Delete CHANGELOG.md (auto-generated by the release process)
- Change changeset bump from patch to minor so the first release is 0.1.0,
  and remove the redundant "New package:" title line
- Reset package version to 0.0.0 (release process sets the real version)
- Add incremental ingestion section to docs/integrations/azure/org.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-28 09:54:40 +05:30
pillaris 1b5e83401f fix: wrap child group transformer in try/catch to keep burst resilient
A throwing custom groupTransformer on a child group member would fail
the entire groups-phase burst. Apply the same try/catch + debug/warn
logging pattern already used for user member transformation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-27 15:43:33 +05:30
pillaris 69cf79ea00 chore: fix prettier formatting in provider test file
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-27 15:28:39 +05:30
pillaris e1714a861c fix: guard user.id before photo fetch, warn on groupIncludeSubGroups, skip dangling child refs
- Guard getUserPhotoGated with user.id presence to prevent requesting
  users/undefined/photo when Graph omits the id field
- Log a warning when groupIncludeSubGroups is configured, matching the
  existing warning for unsupported userGroupMember* options
- Skip spec.children population when groupFilter/groupSearch is active,
  since child groups may not pass the filter and would create dangling
  references in the catalog

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-27 15:10:25 +05:30
pillaris 9e9eca49c7 docs: fix page-size docs and note groupIncludeSubGroups unsupported
Update all references to "up to 999 items" to accurately reflect that
users are fetched in pages of 999 while groups use a smaller page of
100. Also document groupIncludeSubGroups as unsupported in the JSDoc
@remarks, README, and comparison table.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-27 14:44:07 +05:30
pillaris 0f36fcd879 chore: remove incremental ingestion modules from example backend
These modules are not needed by all Backstage users, so registering them
unconditionally in the example backend adds unnecessary routes, services,
and runtime dependencies. The backend.add(...) lines are documented in
the plugin README instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-27 14:37:30 +05:30
pillaris ac04bb696d fix: pass $select when fetching group members to prevent sparse objects
Without $select, Microsoft Graph returns only id and @odata.type for
group members, which causes defaultUserTransformer/defaultGroupTransformer
to return undefined and silently drop membership refs. Requesting the
minimum fields needed by both transformers ensures member objects always
have enough data to produce stable entity refs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-27 14:29:41 +05:30
pillaris 6fa66e7907 fix: remove unnecessary direct msgraph dep from example backend
@backstage/plugin-catalog-backend-module-msgraph is only used
transitively via msgraph-incremental; no direct import exists in
packages/backend/src/index.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-27 14:26:52 +05:30
pillaris 99ddcc3957 fix: address third round of Copilot review comments
- Wrap userTransformer call for group members in try/catch so a sparse
  object that causes the transformer to throw logs a warning and skips
  that member rather than failing the entire groups page
- Split PAGE_SIZE into USER_PAGE_SIZE (999) and GROUP_PAGE_SIZE (100)
  so each burst stays within its time budget despite per-group member
  fetching in the groups phase
- Always send $count=true in advanced mode even when no query object is
  provided (use empty object spread instead of short-circuit on query)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-27 12:44:50 +05:30
pillaris 159a862ec3 fix: address second round of Copilot review comments
- getUserPhotoGated now throws for non-404 errors (401/403/5xx) so
  callers can distinguish a missing photo from a real API failure
- Log a debug message when photo loading fails instead of swallowing
  the error silently
- Merge transformer-pre-populated spec.members/spec.children with
  fetched Graph membership rather than overwriting them
- deriveRestLength now also excludes manual-trigger schedule objects
  (not just cron expressions) from being cast as HumanDuration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-27 12:15:34 +05:30
pillaris e1cb610c7b fix: update alpha API report for MSGraphCursor.nextLink type change
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-27 10:55:37 +05:30
pillaris 758bfaa356 fix: address Copilot review comments on msgraph-incremental provider
- Use undefined instead of null for MSGraphCursor.nextLink (repo style)
- Avoid mutating caller-provided query object in requestOnePage
- Improve error handling for non-JSON Graph API error responses
- Build entity spec immutably instead of mutating entity.spec directly
- Log debug message when a sparse group member cannot be transformed
- Warn when schedule.frequency is a cron expression (restLength falls back to 8h)
- Use proper MSGraphContext generic instead of unknown in addProvider

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-25 12:40:42 +05:30
pillaris 02859a1db9 fix(catalog): fix lint and type errors in msgraph-incremental plugin
- Use node:crypto import protocol
- Add @backstage/backend-test-utils to devDependencies
- Use template literal instead of string concatenation
- Add non-null assertions on result.entities in tests
- Remove unused rootGroup variable
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-25 10:13:23 +05:30
pillaris 5126adb17a chore: update yarn.lock for msgraph-incremental workspace entry
Add workspace:^ alias for the new plugin so the lockfile is consistent
with the packages/backend dependency reference. Remove stale pg@^8.11.0
range no longer referenced by any workspace package.
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-25 09:56:42 +05:30
pillaris 70adee104e fix(catalog): always pair \$count=true with ConsistencyLevel: eventual in advanced mode
Microsoft Graph requires \$count=true whenever the ConsistencyLevel: eventual
header is present, including plain listing requests with no \$filter or \$search.
The previous condition only added \$count when a filter or search was present,
causing the /groups endpoint to silently return an empty value array when
queryMode is set to advanced without a group filter.
Signed-off-by: pillaris <pillaris@adobe.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 12:21:00 +05:30
pillaris f1279ea2d6 feat(catalog): add catalog-backend-module-msgraph-incremental plugin
Introduces a new Backstage backend module that incrementally ingests
users and groups from Microsoft Graph one page at a time, using the
incremental ingestion framework.
Unlike MicrosoftGraphOrgEntityProvider, this module never holds the
full dataset in memory. Each burst processes a single page (up to 999
items), making it suitable for large Azure AD tenants where the
full-scan provider causes memory pressure or OOM failures.
The @odata.nextLink cursor is persisted in the incremental ingestion
marks table, so a pod restart during ingestion resumes from the last
completed page rather than starting over.
Signed-off-by: pillaris <pillaris@adobe.com>
2026-04-23 15:56:43 +05:30
Fredrik Adelöw e2fdc2b61f Merge pull request #33911 from backstage/changeset-release/master
Version Packages (next)
2026-04-21 18:05:23 +02:00
github-actions[bot] 1cc86bee1c Version Packages (next) 2026-04-21 15:07:43 +00:00
Charles de Dreuille 50a66a9183 Merge pull request #33909 from backstage/cursor/add-date-range-picker
feat(ui): add DateRangePicker component
2026-04-21 15:54:38 +01:00
Patrik Oldsberg 957be583cd Merge pull request #34017 from drodil/home_fix_patch
chore: add patch file for #33721
2026-04-21 11:56:07 +02:00
Hellgren Heikki 81f8d5f7de chore: add patch file for #33721
Signed-off-by: Hellgren Heikki <heikki.hellgren@op.fi>
2026-04-21 12:42:00 +03:00
Fredrik Adelöw e5e7700c7b Merge pull request #34001 from backstage/freben/facets-perf
catalog-backend: fix facets endpoint performance regression
2026-04-21 09:59:56 +02:00
Patrik Oldsberg 94e941867b Merge pull request #34011 from backstage/rugvip/remove-unused-integration-exports
integration: remove unnecessary exports from internal helpers
2026-04-20 19:59:42 +02:00
Patrik Oldsberg 05eca714b6 Merge pull request #34008 from backstage/rugvip/remove-unused-addunprocessedentitiesresult
catalog-backend: 🧹
2026-04-20 19:59:20 +02:00
Andre Wanlin 391ef097e9 Merge pull request #34002 from awanlin/blog/bc-kc-amsterdam-2026
Backstage in Amsterdam: Highlights from BackstageCon and KubeCon + CloudNativeCon Europe 2026
2026-04-20 10:59:53 -05:00
Andre Wanlin 54b58d0fed Prettier
Signed-off-by: Andre Wanlin <awanlin@spotify.com>
2026-04-20 10:47:47 -05:00
Johan Persson e8a1a35714 feat(ui): add isPending prop and deprecate loading
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>
2026-04-20 17:36:21 +02:00
Fredrik Adelöw 0ecb700add Remove NOT IN unstitched guard from facets no-filter path
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
2026-04-20 17:31:00 +02:00
Patrik Oldsberg 191b41a0b3 integration: remove unnecessary exports from internal helpers
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
2026-04-20 16:49:21 +02:00
Patrik Oldsberg 6316dc66d3 catalog-backend: remove unused AddUnprocessedEntitiesResult type
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Made-with: Cursor
2026-04-20 16:40:38 +02:00
Fredrik Adelöw f32d334034 Exclude unstitched entities from facets via NOT IN null set
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
2026-04-20 16:14:03 +02:00
Fredrik Adelöw 88409600ba Revert to conditional final_entities constraint for facets
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
2026-04-20 15:46:37 +02:00
Fredrik Adelöw d7c6ad8e14 Remove unnecessary whereNotNull guard from facets subquery
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
2026-04-20 14:43:22 +02:00
Fredrik Adelöw 9ae08d07e2 Add thorough facets tests for predicate queries and compound filters
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
2026-04-20 14:21:57 +02:00
Andre Wanlin 0d14cb6acf Clean up
Signed-off-by: Andre Wanlin <awanlin@spotify.com>
2026-04-20 07:03:42 -05:00
Fredrik Adelöw 673587dd4f Add patch release file for PR #34001
Signed-off-by: Fredrik Adelöw <freben@spotify.com>
Made-with: Cursor
2026-04-20 14:03:19 +02:00
Fredrik Adelöw cf195de72c catalog-backend: fix facets endpoint performance regression
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
2026-04-20 14:02:02 +02:00
MT Lewis 7192e84cad Merge pull request #33948 from backstage/flex-item-props
ui: add support for flex-item props to generic layout components
2026-04-20 09:54:14 +01:00
Fredrik Adelöw e6f30e028a Merge pull request #33993 from backstage/freben/fix-scheduler-sleep
fix(scheduler): handle setTimeout overflow for long sleep durations
2026-04-20 09:47:11 +02:00
Fredrik Adelöw 1688bdc19d Merge pull request #33996 from backstage/freben/owner-column-cleanup
Simplify OwnerEntityColumn to use EntityRefLink directly
2026-04-20 09:46:34 +02:00
Andre Wanlin 60d785e5c9 Edits
Signed-off-by: Andre Wanlin <awanlin@spotify.com>
2026-04-19 15:25:15 -05:00
Charles de Dreuille 3e9f20340a fix(ui): improve DateRangePicker accessibility and fix docs link
- 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
2026-04-19 07:36:48 +02:00
Charles de Dreuille dc17c01a53 Update page.mdx
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
2026-04-19 07:33:10 +02:00
Charles de Dreuille d676565abb fix(ui): refine DateRangePicker calendar button styling
- 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
2026-04-19 06:59:06 +02:00
Charles de Dreuille b6d52bdb7d chore: dedupe yarn.lock
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
Made-with: Cursor
2026-04-19 06:45:32 +02:00
Charles de Dreuille f221068ab9 fix(ui): use BUI Popover and add unavailable dates story in DateRangePicker
- Switch DateRangePicker to use the BUI Popover component (with hideArrow)
  instead of the raw react-aria-components Popover
- Add WithUnavailableDates story showing isDateUnavailable with weekends
  blocked and non-contiguous ranges disallowed (default behaviour)

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
Made-with: Cursor
2026-04-19 06:38:47 +02:00
Charles de Dreuille ff68a57b14 Update report.api.md
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
2026-04-19 06:38:21 +02:00
Charles de Dreuille 20a5de0605 Fix styles
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
2026-04-19 06:38:21 +02:00
Charles de Dreuille 401916d55b feat(ui): add DateRangePicker component
Adds a new DateRangePicker component to @backstage/ui built on React Aria,
featuring a custom field group with two DateInput fields and a calendar
trigger, a RangeCalendar popover with proper range selection visuals
(solid circles for start/end, transparent solid fill for in-range cells
with row-boundary rounding), and full BUI token usage including bg
consumer auto-increment. Includes Storybook stories and a docs-ui page.

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
Made-with: Cursor
2026-04-19 06:38:19 +02:00