Commit Graph
165 Commits
Author SHA1 Message Date
Denis Vodopianov f2f9104534 chore: [front-end] convert provisioning feature toggle to config param (#129854)
replace provisioning feature toggle with config param
2026-08-03 15:58:26 +02:00
Denis Vodopianov 84681a7d80 Revert "chore: clean up provisioning feature toggle on fe side (#129077) (#129840)
Revert "chore: clean up provisioning feature toggle on fe side (#129077)"

This reverts commit 64c8b3d03a.
2026-07-31 14:51:21 +02:00
Andrej Ocenas 9a8212ab71 Folder API: Replace legacy access control logic with app platform API call (#125642)
* Replace legacy access control logic with app platform api

* Update virtual folders paths

* Better virtual folder handling

* Update for real access call for virtual folders

* Don't call parent API endpoint when virtual folder
2026-07-29 14:10:01 +02:00
Denis Vodopianov 64c8b3d03a chore: clean up provisioning feature toggle on fe side (#129077) 2026-07-24 19:06:43 +00:00
Roberto Jiménez SánchezandClaude Fable 5 1d86fc3a84 Provisioning: drop stale and duplicate watch events in the frontend list cache (#128766)
* Provisioning: drop stale and duplicate watch events in the list cache

The shared RTK Query watch handler upserted events by metadata.name
without comparing resourceVersion, so with multiple interleaved watch
streams (HA delivery, reconnect replays) a late older object could
overwrite newer cached state, and duplicate deliveries caused redundant
store updates and re-renders. Compare resourceVersions and skip events
that are not newer than the cached item, failing open when either
version is missing or non-numeric.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Provisioning: rewrite watch handler tests on the MSW harness

Drive the real useListJobQuery({watch: true}) flow through
setupProvisioningMswServer and MockGrafanaLiveSrv watch events instead
of mocking ScopedResourceClient directly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 13:13:54 +00:00
Alex Khomenko 75efa2af63 Navigation: Show starred folders in the Starred nav section (#127747)
* Navigation: Show starred folders in the Starred nav section

Folders join dashboards in the nav Starred list when starredFoldersEnabled()
(grafana.starredFolders + starsFromAPIServer + foldersAppPlatformAPI).
Per-kind icons (apps/folder) and dashboards-before-folders ordering make
same-named items distinguishable; both are gated on the feature so the nav
is byte-identical while it is off.

* Navigation: Keep starred nav order stable on rename, announce kind on starred icons

Review feedback: updateDashboardName sorted pure-alphabetically, re-interleaving
starred folders among dashboards until the next sync; a same-named folder/dashboard
pair read as two identical links to screen readers. A shared comparator and icon
titles fix both; new tests pin the rename ordering and the flag-off folder guard.

* Navigation: Fix stale starred nav on folder delete and failed star

Deleting a starred folder left its nav row behind, and a
server-rejected star mutation still updated the nav; with no
reconcile path the wrong state persisted until reload.

* Navigation: Only un-star folders the bulk delete actually removed

The un-star loop ran for every requested folder, clearing starred nav
entries even when the delete was skipped (provisioned folder) or failed.
Dispatch per folder on delete success instead.

* Navigation: Update starred folder label on rename

Browse-tree refetches don't touch the mounted Starred nav row, so a
renamed folder kept its old label until remount. Dispatch
updateDashboardName (as dashboard saves already do) from both folder
rename paths: legacy saveFolder and app-platform useUpdateFolder.

* Navigation: Keep starred nav sync scoped by kind

The sync search matches the starred uid union against both kinds, so
a starred dashboard rendered a bogus folder row when an unstarred
folder shared its uid, and a uid starred as both kinds rendered twice.
Filter hits against the per-kind star sets and dedupe the union.

Also from review: collapse setStarred's inline payload type into
StarredNavItem, and import the API group ids from @grafana/api-clients
instead of hardcoding them.

* Stars: Add kind-aware usage analytics

The legacy grafana_dashboards_star_dashboard event carried no kind, so
folder stars were indistinguishable from dashboard stars. Replace it
with typed grafana_stars_item_starred (defineFeatureEvents) and enrich
grafana_navigation_item_clicked with itemIsStarred/itemKind to measure
starred-folder click-through.
2026-07-09 11:08:06 -04:00
Haris Rozajac 70bea86e37 Global template variables: add rtk client (#127704)
* gnerate rtk client for global variables

* fix test

* i18n
2026-07-08 07:44:10 -06:00
Andrej Ocenas d1c52b2ee2 Chore: remove team folders toggle (#126551) 2026-07-02 15:58:15 +02:00
Georges Chaudy 2219c362b1 Folders: grant default permissions on app platform folder create (#127631)
When foldersAppPlatformAPI is enabled the UI creates folders via the K8s
folder API instead of POST /api/folders. Root-level creates must include
the ephemeral grafana.app/grant-permissions annotation so default RBAC
permissions are written under kubernetesAuthzResourcePermissionApis.

Fixes grafana/grafana#126964
2026-07-01 12:47:43 +02:00
Andrej Ocenas 1c2400f697 Browse Dashboards: Fix counts in tabs and for delete/move dialogs (#127266) 2026-06-30 14:30:37 +02:00
Tobias SkarhedandClaude Opus 4.7 e9f3f3ece1 Scopes: Add frontend API client for default scope endpoint (#126396)
* Scopes: Fix sync-from-enterprise.sh script bugs

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Scopes: Regenerate frontend API client for default scope endpoint

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-12 14:06:20 +00:00
Andrej Ocenas 102a474753 Browse Dashboards: Change messaging of delete/move modal and add counts to tabs in folder detail (#124299) 2026-06-12 14:52:36 +02:00
Ashley Harrisonandjoshhunt f0ac804eab Chore: knip grafana code (#126143)
* knip grafana code

* update translations

* some fixes

* remove more unused files

* knip more types

* knip exports

* more fixes and i18n extraction

* setup node in lint-knip to properly resolve webpack configs

* slightly tidier knip config

* knip ignore tmp e2e files

* remove more unused dependencies

---------

Co-authored-by: joshhunt <josh.hunt@grafana.com>
2026-06-11 15:16:20 +01:00
Ashley Harrison d3be522f89 Chore: Clean up exported types with knip (#126098)
* clean up some more unused files

* clean up exported types

* commit translation extractions

* clean up types

* restore some incorrectly removed types
2026-06-10 11:03:15 +01:00
Ashley Harrison ee828233fe Chore: Remove unused files with knip (#125994)
* remove unused files with knip

* fix CODEOWNERS

* commit translations

* adjust knip config to have api clients as entry points

* fix CODEOWNERS
2026-06-09 15:40:35 +01:00
Alex Khomenko 68c5da7d68 Provisioning: Add duplicate-path validation to ResourceEditFormSharedFields (#125415)
* feat(provisioning): add duplicate-path validation to ResourceEditFormSharedFields

- Add async validatePath that checks for existing files at the target path
- Add MSW handler for files/:path returning 404 for test coverage
- Migrate ResourceEditFormSharedFields tests to MSW

* chore(i18n): extract translation strings

* fix(provisioning): always-fresh path check + correct RHF deps direction

Address PR review feedback on ResourceEditFormSharedFields:

- Remove preferCacheValue=true on the pre-save existence check; cached
  404/200 results can be stale by the time the user submits.
- Swap the deps direction. RHF triggers a field's deps when *that field*
  changes, so 'deps: [ref]' on path meant 'when path changes, validate
  ref' (the opposite of intent). Move 'deps: [path]' onto the ref field
  so branch changes correctly re-run validatePath.

* fix(folders): guard against null display/keys in combineFolderResponses

The DisplayList type declares display and keys as required arrays,
but the IAM display mapping API can return null for either field.
Without optional chaining on these properties, indexing into null
throws TypeError: Cannot read properties of null (reading '0'),
crashing every folder page when foldersAppPlatformAPI is enabled.
2026-05-27 15:26:46 +03:00
Ryan McKinley 4cb84f2cf4 Folders: Add frontend helpers to resolve the "general" folder (#125318) 2026-05-26 12:22:21 +03:00
Victor MarinandClaude Opus 4.7 4219853d23 Annotations: Route manual annotation writes through annotation.grafana.app k8s API (#124104)
* wip

* fix(annotations): optional AnnotationTagList.items, tighten comments, add scope tests

- AnnotationTagList.items is now optional (defensive ?? [] implies it can be absent)
- Replace multi-line comment blocks with single-line inline comments per codebase style
- Add scope-forwarding tests to setDashboardPanelContext: verify scopes from
  sceneGraph.getScopes() are included in k8s create/update request spec

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(annotations): wire k8s app installer to FF, fix tags shape, fix ID normalisation

- Register annotation app installer when kubernetesAnnotations FF is on
  (previously only cfg.AnnotationAppPlatform.Enabled=true triggered it,
  leaving all routes as 404 when only the FF was set)
- Fix AnnotationTagList/AnnotationTagItem to match backend shape
  ({tags:[{tag,count}]} not {items:[{name,count}]}) and update the
  term mapping in K8sAnnotationServer.tags()
- Add toK8sName(id: string|number) to normalise legacy numeric IDs
  (e.g. 23 or "23") to the k8s "a-{id}" prefix required by parseAnnotationID;
  apply it to both update (GET fetch-then-merge) and remove (DELETE)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(annotations): route dashboard query through k8s /search sub-resource

When kubernetesAnnotations is on, dashboard annotation queries now hit
/apis/annotation.grafana.app/v0alpha1/namespaces/{ns}/search instead of
the legacy /api/annotations endpoint:

- Add annotationK8sClient.search() with param translation (matchAny → tagsMatchAny,
  panelId → panelID, tags[] → repeated tag) and AnnotationList → AnnotationEvent[] mapping
- Route K8sAnnotationServer.query through search; forAlert stays on legacy because
  ListOptions has no Type/AlertUID filter on the backend
- Strip the "a-" prefix on the way out so consumers see legacy-shaped ids
- Use loose Record<string, unknown> + typeof narrowing instead of type assertions
- Update setDashboardPanelContext.test to assert the a-{id} prefix the new path produces

AnnoListPanel still uses /api/annotations directly because it depends on
identity fields (login/email/avatarUrl) and a userId filter that the new
spec/endpoint don't expose; migrating it requires backend changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(annolist): migrate AnnoListPanel to k8s API with IAM identity hydration

When kubernetesAnnotations is on, the Annotations List panel now hits
/apis/annotation.grafana.app/v0alpha1/namespaces/{ns}/search and hydrates
identity fields (userId/login/email/avatarUrl) via the IAM /display endpoint:

- Expose createdBy ("user:<uid>") on AnnotationEventResource by reading
  metadata.annotations["grafana.app/createdBy"] in annotationToEvent
- Branch AnnoListPanel.doSearch on the FF: legacy /api/annotations stays for
  FF-off; FF-on routes through annotationK8sClient.search() then a single
  batch call to /apis/iam.grafana.app/v0alpha1/.../display to resolve
  displayName/avatarURL/internalId for every unique createdBy key
- queryUser carries the uid so subsequent searches filter via createdBy:user:{uid}
- displayName substitutes for both login (gates avatar) and email (tooltip text)
  since /display doesn't return email

No backend changes required.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(annolist): hydrate email via per-user IAM User resource fetch

The IAM /display batch endpoint deliberately omits email, so previously we
substituted displayName for email in the "Created by" tooltip. The User
resource (GET /apis/iam.grafana.app/v0alpha1/namespaces/{ns}/users/{uid})
exposes spec.email, so we now fetch it per unique createdBy uid in parallel
with the /display batch. On per-user fetch failure (e.g. viewer without
iam:users:get) we fall back to displayName so the tooltip still has a label.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(annotations): drop backend FF + installer wiring (moved to separate PR)

All kubernetesAnnotations feature toggle artifacts (Go registry +
generated Go/CSV/JSON + generated TS) and the pkg/registry/apps/apps.go
installer wiring live on branch mdv/annotations-k8s-feature-flag and ship
as a separate PR. Frontend and backend deploy at different cadences, so
they cannot share a PR.

This branch references config.featureToggles.kubernetesAnnotations, so
the backend PR must merge first before this one will typecheck on main.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* rename(annotations): kubernetesAnnotations FF → kubernetesAnnotationsClient

Mirrors the backend rename. Updates config.featureToggles checks, test
toggle assignments, and a few comment references.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* TEMP: force kubernetesAnnotationsClient FF on for local testing

Backend FF PR (mdv/annotations-k8s-feature-flag) is in review, so the FF
isn't yet defined on main. Hardcode both check sites (AnnoListPanel.tsx
and features/annotations/api.ts) to always take the new k8s path so the
client can be exercised without the FF.

Revert this commit once the backend lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(annotation client): drop test-only reset hatch

ScopedResourceClient construction is just a getAPINamespace() call plus
a string concat, so memoizing it wasn't earning much, and the cache
forced a resetAnnotationK8sClientForTests test-only export. Drop the
cache and construct on each call; the export and its lone caller in
resetAnnotationServerForTests go away.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* revert(annolist): drop per-user IAM fetch for email

Earlier we added a per-user GET /apis/iam.grafana.app/v0alpha1/namespaces/{ns}/users/{uid}
to read spec.email. In practice that 404s in the test environment (likely
a namespace/scope mismatch on the IAM apiserver), and even when it 403s
the failed request shows up in the browser console. The /display
batch already gives us displayName, so revert to using it for the email
substitute as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(annotations): switch FF gate to config.annotationAppPlatformEnabled

The backend now exposes [annotations.app_platform] enabled via the
bootstrap settings DTO (see mdv/annotations-k8s-feature-flag), so the
frontend reads config.annotationAppPlatformEnabled instead of a feature
toggle. Removes the TEMP force-on hack since the real config can be
flipped via grafana.ini.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(annotation server): drop test-only reset hatch

Both AnnotationServer implementations are stateless wrappers around
backend calls, so memoizing the chosen instance wasn't earning much,
and the cache forced a resetAnnotationServerForTests test-only export.
Drop the cache and construct on each call; the export and its callers
in api.test.ts and setDashboardPanelContext.test.ts go away. The empty
beforeEach blocks left behind in the dashboard test are removed too.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* cleanup

* feat(annotations): forward selected scopes on the search/query path

Read paths previously omitted scopes, so the backend returned every
annotation regardless of the dashboard's selected scope. Two call sites
now source scopes the same way the create/update path already does:

- GrafanaDatasource.getAnnotations: when options.dashboard is a
  SceneObject, mirror SceneQueryRunner via sceneGraph.getScopes(...).
  Gated on config.annotationAppPlatformEnabled so the legacy
  /api/annotations endpoint never sees the param.
- AnnoListPanel: read this.context?.state.value via ScopesContext (class
  contextType), forward to annotationK8sClient.search. Already only ran
  in the k8s branch, so legacy is unaffected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(annotations): forward request.scopes to getAnnotations on the panel path

The previous attempt sourced scopes from options.dashboard via
sceneGraph.getScopes, but on a scenes dashboard options.dashboard is the
legacy DashboardModel returned by getDashboardSrv().getCurrent(), so
isSceneObject(...) is false and scopes never get added.

The scenes AnnotationsDataLayer's standardAnnotationQuery already
populates request.scopes via sceneGraph.getScopes(layer) before calling
datasource.query(). Thread that through into getAnnotations so /search
sees the scope filter on the dashboard panel annotation path. The
options.dashboard sceneGraph path stays as a fallback for direct callers
that don't go through query().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(annolist): re-run search when ScopesContext value changes

ScopesContext exposes a stable Provider value, so static contextType +
React re-render didn't fire on scope changes (panels work via the
scenes-side imperative setContext/observable path). Subscribe to
stateObservable in componentDidMount and re-run doSearch when the joined
scope-name key differs from the last one we queried with. The replay-on-
subscribe initial emission is filtered out via the lastScopeKey written
during the first componentDidMount-driven doSearch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* cleanup

* fix

* flag it behind both new api being enabled and fe client ff

* fixes

* prettier + fix test

* typecheck

* keep alert anno legacy call since new API does not yet fetch those

* use PATCH + api discoverability

* fix

* fix ff

* refactor

* rename

* fix

* use PATCH for update

* reusable discoverability util

* fix

* fix

* policybot

* make gen toggles

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 11:03:39 +03:00
chansuke 06bcf09857 Folders: use MSW in v1beta1 update hook test (#123947)
* Folders: use MSW in v1beta1 update hook test

* Folders: address hook test review feedback
2026-05-04 08:49:33 +03:00
Andrej Ocenas 1f2ba9f13c Team folders: Refresh browse dashboard cache after changes to team folders (#123794)
* Force refetch for team folders folder in browse dashboards

* Always show team folders folder

* Move the refresh into the new API

* Hide behind feature flag

* Make sure team folder are only on the first page

* Fix circular dep

* fix import

* Break import cycle

* Add team msw handler
2026-04-30 17:28:54 +02:00
Alex Khomenko 98d4753546 Browse dashboards: prevent stale folder in restore dialog after deletion (#122008)
* Browse dashboards: validate restore folder selection on open

* Folders: invalidate deleted folder item caches

* Browse dashboards: track deleted folders in trash state

* Browse dashboards: restore delete flow comments

* Browse dashboards: clean up restore follow-ups

* test(browse-dashboards): migrate browseDashboardsAPI tests to MSW

Replace jest.mock('@grafana/runtime') getBackendSrv override with MSW
handlers via setupMockServer(). Tests now exercise the real backendSrv
fetch stack (URL construction, headers, error normalization).

- Remove mockFetch/mockGet/mockPut/mockPost and rxjs imports
- Add setBackendSrv(backendSrv) + setupMockServer() at module level
- Use folderAPIVersionResolver.set('v1beta1') to bypass HTTP discovery
- Use per-test server.use() with http.get/delete handlers and spy fns
- Keep jest.mock for getDashboardAPI (JS factory, not HTTP)

* Browse dashboards: clean up restore delete helpers

* Browse dashboards: tidy folder delete helpers

* Browse dashboards: split deleted folder state

* Browse dashboards: refresh after failed bulk delete

* Browse dashboards: keep bulk delete invalidations

* Browse dashboards: preserve restore target on 403

* Browse dashboards: invalidate quota on folder delete

* Fix picker font size

* test(browse-dashboards): use testWithFeatureToggles for feature toggle cleanup

Replace manual config.featureToggles.provisioning mutation in beforeEach
with testWithFeatureToggles({ disable: ['provisioning'] }) which handles
both setup and afterEach teardown.

* inline funcs

* Remove deletedFoldersState, simplify RestoreModal and deleteFolders mutation

Delete the session-scoped deletedFoldersState singleton and all its
consumers. The RestoreModal already validates the origin folder via
useGetFolderQuery with refetchOnMountOrArgChange, making the client-side
cache redundant — a 404 response clears the picker identically.

- Delete deletedFoldersState.ts and its test
- Remove markDeleted/isDeleted calls from folder v1beta1 API,
  browseDashboardsAPI (both deleteFolder and deleteFolders mutations)
- Simplify RestoreModal: replace null/undefined/string tri-state with
  a single useState<string | undefined>, remove useCallback wrapper,
  simplify getAutoTarget from 4 params to 3, pass setUserTarget
  directly to FolderPicker
- Simplify deleteFolders: remove DeleteFoldersResult type, return void
  instead of tracking per-folder success/failure for markDeleted
- Update all tests, remove tests whose sole purpose was verifying
  deletedFoldersState behavior

* comments

* update test
2026-04-13 18:16:27 +03:00
Kristina c1b159be7b Correlations: Add app notifications for create/delete actions (#119979)
* Add notifications for create/delete, organize notification translations

* test the notification was successfully constructed

* Use standard for error handling

* lint cleanup
2026-04-08 10:39:35 -05:00
Alex Khomenko b2e3a523bd Provisioning: Add polling fallback when WebSocket watch streams are unavailable (#121775)
* Provisioning: Add polling fallback when WebSocket watch streams are unavailable

* refactor: move connection failure handling to centrifuge service layer

Move connection timeout and liveEnabled detection from
ScopedResourceClient.watch() into CentrifugeService where the hang
originates:

- initChannel: Promise.race the connectionBlocker against a 10s timeout
  so channels that never connect get shutdownWithError instead of
  hanging forever.
- getChannel: when liveEnabled=false, immediately shutdownWithError
  without creating a subscription or waiting for the timeout.

This lets watch() use a clean pipe chain (map → filter → map →
catchError) instead of a 45-line Observable wrapper with manual timer
and subscription management.

Add centrifuge service tests for the two new behaviors.

* add comment to connection timeout Promise.race

* remove excessive comments from service test

* document known limitation: first poll can't detect deletions during race window
2026-04-02 20:20:01 +03:00
Alex Khomenko 2281978edd Folders: Fix double-slash URL for non-Latin folder titles (#121741) 2026-04-02 18:47:02 +03:00
Ashley Harrison b10025b40d Chore: Add lint rule for consistent type imports (#121336)
* add lint rule config

* whoops, we actually want inline...

* fixes for consistent type imports
2026-03-30 12:44:01 +01:00
Kristina 575f663cbd App Platform: Use util for error handling (#121148)
Change error handling to use utility
2026-03-26 08:49:14 -05:00
Andrej Ocenas 429a50a76c TeamFolders: Create folder during team creation (#118969)
* Separate creation of the folder with results in cards

* Put card into separate component

* Extract the card to separate file

* Change to alert component instead

* Clean up the card creation

* Pass showSuccessAlert in the createTeam

* Simplify the error handling

* Use request component pattern

* Revert "Use request component pattern"

This reverts commit 8a2acaa220.

* Decompose and refactor the api calls

* Rename api calls file

* Initial tests for the API calls

* Comments and small refactor

* Add icon to success link

* Better text messages

* translations

* showSuccessAlert handling

* Small improvements to state reporting

* Add default role handler and update tests

* Test fixes

* Catch the error in onQueryStarted

* Fix tests

* Put handlers into helper functions

* Move helper handlers to packages

* remove unused import

* Add translation

* Update lint workers

* simplify types

* remove unused imports

* Fix import

* generics again

* rollback ci changes

* Add reporting

* Address review comments

* Fix tests

* Fix owner ref creation bug

* Fix lint ci change
2026-03-25 15:40:08 +01:00
Eric Shields b4cf765901 Scopes: Add depth and rootScope parameters to scope navigation requests (#119551)
Adds `depth` and `rootScope` query parameters to `scope_navigations` and
`scope_dashboard_bindings` API requests, enabling the backend to return
contextual results for nested scope navigation.

**`depth`**: Nesting level in the rendered navigation tree. Omitted at
depth 0 (top-level request). Calculated as `path.length - 1` where path
includes the root `''` key — e.g. `['', folderA]` → depth 1.

**`rootScope`**: The top-level scope the navigation tree was built for
(`forScopeNames[0]`). Omitted on the root request; present on all
sub-scope expansion requests. Uses `forScopeNames` rather than
`navigationScope`, which is UI state only set when navigating to a
dashboard under a sub-scope.

Both params use truthy checks so depth 0 and empty rootScope are stripped
before the HTTP request is made.

Also removed stale 'name' field from the gen file.
2026-03-24 14:20:13 -07:00
Yunwen Zheng dfe1422718 extractErrorMessage: make extractErrorMessage optional with explicit fallbacks (#120875)
* extractErrorMessage: return undefined if no proper error
2026-03-24 13:10:10 -04:00
Tom Ratcliffe 4dc1b6bbcd API Clients: Scope legacy APIs under internal/ export path (#119622) 2026-03-13 13:40:31 +00:00
Eric ShieldsandClaude Opus 4.6 08025e8c94 Scopes: Remove unused name field from find endpoint generated types (#119566)
Remove the spurious `name` field from the generated scope find
endpoint arg types and the `name: ''` workarounds in ScopesApiClient.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:38:34 -07:00
Alex Khomenko b3225d9977 Provisioning: Fix watch stream permission error for anonymous users (#119191)
* Provisioning: Show watch error to user + fallback to polling

When Grafana Live watch streams fail (e.g., with anonymous auth enabled),
the branch dropdown in the Provisioning Wizard step 2 loads forever because
useRepositoryStatus waits for reconciliation via the broken watch stream.

This change:
- Widens the onError callback signature in createOnCacheEntryAdded to receive
  dispatch and arg, allowing handlers to react to watch failures
- Adds polling fallback (every 5s) to listRepository and listConnection
- Shows a warning notification only if polling itself fails, avoiding noise
  when the fallback mechanism works

The user still gets data updates (via polling instead of real-time watch), and
only sees an error message if both watch AND polling fail.

* Provisioning: Fix watch permission error for anonymous users

Allow anonymous users to subscribe to watch streams by assigning them
an 'anonymous' user ID instead of rejecting with a permission error.
Simplify the watch error handler to show a notification without
polling fallback, which was causing redundant requests.
2026-03-06 07:59:35 +02:00
Marc M. 2145c70a0a Folders: Fix dashboard load failure when user lacks folder access with foldersAppPlatformAPI enabled (#119302) 2026-03-02 16:43:55 +01:00
Alex Khomenko 25e762b86f Provisioning: Add fix folder IDs button (#119092)
* Provisioning: Add "Fix Folder IDs" button + isFetching→isLoading fix

- Fixed `useFolderMetadataStatus` to use `isLoading` instead of `isFetching` for better UX (prevents flash on background refetches)
- Extended `useFolderMetadataStatus` return type to include repository name (needed for fix job API calls)
- Created `useFixFolderMetadata` hook to trigger fix-folder-metadata jobs with loading state UI
- Added "Fix folder IDs" button to folder permissions drawer via `MissingFolderMetadataBanner`
- Added repo-level warning banner on Repository Overview page when folders lack metadata
- Created `useRepoHasMissingFolderMetadata` hook to detect missing metadata at repository level
- Added `hasMissingFolderMetadata` utility function to tree builder
- Added success/error notifications for fix-folder-metadata job actions
- Updated i18n strings and tests

* Remove fixFolderMetadata success toast, merge banner components

- Remove "Fix folder metadata job started" notification — button
  already shows loading state via job watching
- Merge MissingFolderMetadataBanner and RepoMissingFolderMetadataBanner
  into a single component with a `variant` prop ('folder' | 'repo')

* Fix useFolderMetadataStatus tests for object return type

Update assertions to use result.current.status instead of
result.current, and change isFetching mock to isLoading.

* Consolidate useRepoHasMissingFolderMetadata into useFolderMetadataStatus

Extend useFolderMetadataStatus with a repo-level overload that accepts
{ repositoryName } and checks the full files listing for missing
_folder.json metadata, replacing the separate useRepoHasMissingFolderMetadata
hook and hasMissingFolderMetadata tree utility.

* Split useFolderMetadataStatus into two focused hooks

Extract repo-level metadata check into useRepoMetadataStatus, restoring
useFolderMetadataStatus to its original single-folder purpose. Each hook
now has its own test file with no cross-mock overhead.

* Move fixFolderMetadata error handling into hook, simplify feature toggle check

* Fix false positives in repo-level metadata check, prevent duplicate job submissions

checkFilesForMissingMetadata now uses resource data to only check provisioned
folders (resource type 'folders') instead of inferring folders from file paths.
This eliminates false positives where root _folder.json was required even when
root wasn't a provisioned folder.

Also adds 'pending' state to job-running checks in useFixFolderMetadata and
SyncRepository to prevent duplicate job submissions between mutation completion
and job transition to 'working'.

Tests migrated from jest.mock to MSW per project conventions.

* Break circular dependency between folderMetadata and treeUtils

Check resources directly against file paths instead of using
mergeFilesAndResources, which imports from treeUtils (which itself
imports getFolderMetadataPath from folderMetadata).

* Add unit tests for checkFilesForMissingMetadata

* Add success notification when folder metadata fix job is submitted

Notifies the user that the fix has started and will continue in the
background, so they know it's safe to navigate away.
2026-02-27 14:27:13 +02:00
Alex Khomenko 63b7efb0fd Browse dashboards: Add quota limit banners for dashboards and folders (#118400)
* Generate quotas API client

* Browse: Add quota limit banners for dashboards and folders

Display warning/error banners on the Browse Dashboards page when users
approach or reach their dashboard/folder creation quotas. Gated behind
the kubernetesUnifiedStorageQuotas feature toggle.

- Extract quota fetching and state calculation into useQuotaLimits hook
- Warning banners are dismissable (persisted via localStorage); error banners are not
- Show "Request quota extension" button for paying users
- Add comprehensive test coverage (22 tests)

* Browse: Improve quota banners with cache invalidation and split alerts

- Wire up RTK Query cache invalidation so quota data refreshes on
  resource create/delete (dashboards, folders)
- Use granular tag invalidation for delete mutations to avoid 404s
- Show separate alerts for error (at_limit) and warning (nearing)
- Follow i18n best practices: Trans for JSX children, t() for props
- Use type guard instead of `as` assertion per lint rules

* Browse: Extract shared invalidateQuotaUsage helper and rewrite tests

- Export invalidateQuotaUsage(dispatch) from quotas API package
- Use shared helper in browseDashboardsAPI and folder hooks
- Rewrite QuotaLimitBanner tests with getByRole assertions,
  inline data, and organized by severity

* Browse: Use Alert buttonContent for extension button, position dismiss in top-right

- Use onRemove + buttonContent props to render extension button in
  Alert's native action slot
- Position dismiss IconButton absolutely in top-right corner
- Always show dismiss button regardless of tier
- Tighten tests: use within() for scoped getByRole queries

* Update tests

* comments

* Fix percentage rounding, remove unnecessary quota invalidation and wrapper style

Use Math.floor instead of Math.round so percentage only shows 100% when
usage equals the limit. Remove quota invalidation from saveDashboard since
it only edits existing dashboards. Drop redundant wrapper div with
position: relative since Alert already provides it.

* Only invalidate quota usage on new dashboard creation and simplify early return

Conditionally invalidate quota cache in saveDashboard only when
data.version === 1 (new dashboard). Simplify QuotaLimitBanner by
computing atLimit/nearing arrays directly and early-returning when
both are empty.

* Use generated GetUsageResponse type and remove manual type guard

The quotas API client now includes proper typed GetUsageResponse with
usage and limit fields, so the manual QuotaUsageResponse interface and
isQuotaUsageResponse type guard are no longer needed.

* Extract shared invalidateListOnSuccess and extensionProps to reduce duplication

* Use tuple iteration to build resource statuses in useQuotaLimits

* Address PR review: rewrite tests with MSW and use API_GROUP constants

- Rewrite QuotaLimitBanner tests to use MSW handlers instead of mocking hooks
- Add quotas.grafana.app MSW handler to grafana-test-utils
- Use testWithFeatureToggles utility for feature flag management
- Use user from render result instead of importing userEvent
- Use API_GROUP constants from API clients in useQuotaLimits

* Deduplicate QuotaLimitBanner test helpers and use shared constants

- Extract usageResponse() and expectNoAlert() helpers to reduce repetition
- Consolidate mockError() into mockErrorForResource() with optional params
- Use testWithFeatureToggles for the flag-off test instead of manual config override
- Use DASHBOARD_API_GROUP/FOLDER_API_GROUP constants instead of hardcoded strings
- Import QUOTAS_USAGE_URL from @grafana/test-utils/handlers instead of local constant

* Rename hasError to allQueriesFailed for clarity

The condition uses && (both queries must fail), so hasError was misleading
since it sounds like any single error would qualify.

* Revert handlers/index.ts re-export; use local QUOTAS_USAGE_URL constant

* Re-export QUOTAS_USAGE_URL from @grafana/test-utils/handlers

Follow the same pattern as PROVISIONING_API_BASE instead of
using a local constant in the test.

* Add quotas.grafana.app OpenAPI spec snapshot

* fix: prevent auto-sync race condition in provisioning quota tests

Use SkipSync to prevent controller auto-sync from racing with file
copy, matching the pattern in sync_quota_test.go. Without this, the
auto-sync could read partially-written files and pollute quota tracker
stats with the root folder before the explicit sync runs.

* chore: add overrides.yaml to gitignore and update OpenAPI specs

Ignore overrides.yaml and regenerate API clients to pick up
correlations and IAM spec changes from main merge.

* rtkq/quotas: gate quota invalidation behind feature toggle
2026-02-26 17:52:02 +02:00
Kristina 702f6d27ee Correlations: Enable create and edit using app platform (#117505)
* WIP

* Make transformations properties optional, create correct object for partial spec

* update the generated client type, fix logic for submission of transformations

* Update readme with what is needed for updating the client

* Move logic to utils, add test

* Add tests to increase coverage

* continue to build out test coverage

* Add tests

* Add create correlation

* WIP improve function coverage

* fix test

* wip add notification on edit

* Moving directories

* Move back as we are no longer rendering with a wrapper

* Run the generator
2026-02-26 07:39:26 -06:00
Laura Benz ea976d8240 TeamFolders: Block team deletion (#117880)
* feat: temporary modal

* feat: temporary modal

* feat: add delete modal

* Refactor: tweak delete button

* feat: add folder data to team data and adjust TeamDeleteModal

* feat: run make i18n-extract

* refactor: adjust button styling

* feat: add tracking events

* feat: add folder list handler for fixing TeamList test

* feat: add a test for TeamDeleteModal

* refactor: replace TestProvider

* refactor: improve test

* refactor: fix test

* refactor: fix test

* refactor: apply changes from review

* refactor: replace hook

* refactor: clean up

* refactor: replace hook

* refactor: extract i18n

* refactor: replace hook

* refactor: adjust query to only get necessary data

* refactor: apply changes after code review

* refactor: improve error handling

* feat: add abort()

* refactor: exclude abort error

* refactor: refactor abort error handling

* refactor: extract i18n
2026-02-23 16:13:28 +01:00
Alex Khomenko e10ff6b7cc APIServer: Surface watch errors in the UI (#117983)
* APIServer: Surface watch errors in the UI

When watch API calls fail (e.g., for non-admin users), errors are now propagated through the Observable pipeline and displayed as toast notifications, preventing the UI from appearing stuck during bulk operations.

* pass error status

* Set error status on job when watch fails instead of clearing items

When a WebSocket watch fails, set the job's status to error with the
error message instead of clearing cached items. This keeps the job
in cache so JobContent renders the error naturally via onStatusChange,
rather than falling through to FinishedJobStatus which shows a
misleading "No job found" error.

* Add back admin-only watch restriction for testing

Temporarily limit watch subscriptions to admin users while testing
provisioning repositories. This needs to be removed later.

* Use ErrorPermissionDenied and add clarifying comments

- Map SubscribeStreamStatusPermissionDenied to centrifuge.ErrorPermissionDenied
  (code 103) instead of ErrorUnauthorized for correct semantics
- Document why RxJS retry is not needed on the live channel path
- Document the listJob onError cache mutation logic

* Simplify createOnCacheEntryAdded error handling

Remove notification logic and dispatch from the error handler.
Consumers now own error handling entirely via the onError callback.

* Remove admin-only watch restriction

Remove the temporary admin-only gate on watch subscriptions that was
used for testing.
2026-02-16 14:23:11 +02:00
16c325d525 Provisioning: Remove domain restrictions for Git providers (#117850)
* Provisioning: Remove domain restrictions for GitHub, GitLab, and Bitbucket URLs

Allow self-hosted instances (GitHub Enterprise, self-managed GitLab, self-hosted
Bitbucket) to use provider-specific connectors instead of requiring the generic
git connector. Consolidate URL validation into shared config, apply generic
domain-stripping to all providers, and remove dead code.

* Provisioning: Move httpUtils to api/clients/provisioning/utils

Move the provisioning error helper to its new home alongside the other
provisioning API client utilities.

* Apply suggestion from @hugohaggmark

Co-authored-by: Hugo Häggmark <hugo.haggmark@gmail.com>

* Stricter i18n sorting

---------

Co-authored-by: Hugo Häggmark <hugo.haggmark@gmail.com>
Co-authored-by: Andrej Ocenas <mr.ocenas@gmail.com>
2026-02-11 12:04:41 +02:00
Stephanie HingtgenandAnna Urbiztondo c0dbeefee6 Playlists: Graduate to v1 apis (#117638)
* Playlists: Graduate to v1 apis

* fix codegen

* Update docs/sources/developer-resources/api-reference/http-api/playlist.md

Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>

* Update docs/sources/developer-resources/api-reference/http-api/playlist.md

Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>

* Update docs/sources/developer-resources/api-reference/http-api/playlist.md

Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>

* Update docs/sources/developer-resources/api-reference/http-api/playlist.md

Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>

* Update docs/sources/developer-resources/api-reference/http-api/playlist.md

Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>

* Update docs/sources/developer-resources/api-reference/http-api/playlist.md

Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>

* Update docs/sources/developer-resources/api-reference/http-api/playlist.md

Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>

* Update docs/sources/developer-resources/api-reference/http-api/playlist.md

Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>

* Update docs/sources/developer-resources/api-reference/http-api/playlist.md

Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>

---------

Co-authored-by: Anna Urbiztondo <anna.urbiztondo@grafana.com>
2026-02-09 09:36:26 +03:00
Yudintsev George (Egor) e124ee79f4 Chore: RBAC: Migrate role picker to rtkq (#116571)
What is this feature?

This PR introduce refactoring for role picker for teams and users. It uses RTK Query.
The related task: grafana/identity-access-team#1821

The previous PR with related logic: #113783

Why do we need this feature?

This refactoring is a cleaner way for handing refetching.
2026-02-03 13:46:41 +00:00
Tom Ratcliffe 7c618f8e28 Folders: Show owner references on folder details pages (#116843) 2026-02-02 14:36:07 +00:00
Tom Ratcliffe 206754901c Folders: Use update folder method rather than replace (#117188) 2026-02-02 13:14:33 +00:00
Alex Khomenko d601f04cb8 Provisioning: Do not disable "next" button on form errors (#117065)
* Provisioning: Do not disable "next" button on form errors

* Handle errors from dryRun

* Show field errors for app step in Wizard

* Cleanup

* Fixes

* use existing util

* Revert isNextDisabled changes

* memoize sorted items

* Do not disable on finish step

* Show all errors

* Separate fetching and loading

* Add revalidate mode

* Tighten the types
2026-01-29 18:44:05 +00:00
Tom Ratcliffe ab404dc398 Team Folders: Update hooks to allow creating folders with owner references (#116594) 2026-01-23 11:20:17 +00:00
Alex Khomenko 4959fbcc4e Provisioning: Add dryRun validation for Connection resources (#116693)
* Provisioning: Add dryRun validation for Connection resources

Validate connection configuration before saving by calling the create/replace endpoint with dryRun=true. This mirrors the repository test endpoint behavior and returns field-level validation errors that are displayed in the form.

Fixes #751

* Use dryRun All
2026-01-22 18:54:29 +02:00
Alex Khomenko 91f4e745f9 Provisioning: Use watch for connections (#116679) 2026-01-22 12:48:29 +00:00
Yunwen Zheng d8abb1365f BrowseDashboards: Fix nested folder's parent folder dropped after rename folder title (#116223)
updateFolderAppPlatform: include parentUid in update folder payload
2026-01-15 13:15:36 -05:00
Tobias Skarhed d1064da4cd Scopes: Add RTK Query API client for caching (#115494)
* Scopes API client

* Initial RTK query commit

* Copy API client from generated enterprise folder

* Mock ScopesApiClient for integration tests

* Update e2e tests

* Handle group expansion for dashboard navigation

* Extract integration test mocks

* Move mock to only be for integration tests

* Update path for enterprise sync script

* Re-export mockData

* Disregard caching for search

* Leave name parameters empty

* Disable subscriptions for client requests

* Add functionality to reset cache between mocked requests

* Use grafana-test-utils for scopes integration tests

* Rollback mock setup

* Remove store form window object

* Remove cache helper

* Restore scopenode search functionality

* Improve request erro handling

* Clean up subscription in case subscription: false lies

* Fix logging security risk

* Rewrite tests to cover RTK query usage and improve error catching

* Update USE_LIVE_DATA to be consistent

* Remove unused timout parameter

* Fix error handling

* Make dashboard-navigation test pass
2026-01-13 13:09:08 +01:00
Alex Khomenko 250ca7985f Provisioning: Add Connections page (#116060)
* Provisioning: Add connections page

* Provisioning: Add connections form

* Provisioning: Add connections form

* Update fields

* Fix generated name

* Update connection name

* Add edit page

* error handling

* Form validation

* Add Connections button

* Cleanup

* Extract ConnectionFormData type

* Add list test and separate empty states

* Add form test

* Update tests

* i18n

* Cleanup

* Use SecretTextArea from grafana-ui

* Fix breadcrumbs

* tweaks

* Add missing URL

* Switch to ShowConfirmModalEvent

* i18n

* redirect to list on success

* add timeout

* Fix tags invalidation
2026-01-13 08:25:40 +02:00