From cef4449f14b2c9ebb92614d6ee32013cc08d08ff Mon Sep 17 00:00:00 2001 From: Tom Ratcliffe Date: Wed, 26 Nov 2025 11:16:47 +0000 Subject: [PATCH] Folders: Send permissions query param with app platform for folder picker (#114158) --- .../rtkq/dashboard/v0alpha1/endpoints.gen.ts | 4 +-- pkg/registry/apis/dashboard/search.go | 4 +-- pkg/tests/apis/dashboard/search_test.go | 28 +++++++++---------- .../dashboard.grafana.app-v0alpha1.json | 8 +++--- .../NestedFolderPicker/useFoldersQuery.ts | 8 +++++- .../useFoldersQueryAppPlatform.ts | 8 +++--- 6 files changed, 33 insertions(+), 27 deletions(-) diff --git a/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts index 264ac389e42..d2cc21d31e6 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts @@ -612,8 +612,8 @@ export type GetSearchApiArg = { tags?: string[]; /** find dashboards that reference a given libraryPanel */ libraryPanel?: string; - /** permission needed for the resource (View, Edit, Admin) */ - permission?: 'View' | 'Edit' | 'Admin'; + /** permission needed for the resource (view, edit, admin) */ + permission?: 'view' | 'edit' | 'admin'; /** sortable field */ sort?: string; /** number of results to return */ diff --git a/pkg/registry/apis/dashboard/search.go b/pkg/registry/apis/dashboard/search.go index 6d85a66b344..19e5b71e0d9 100644 --- a/pkg/registry/apis/dashboard/search.go +++ b/pkg/registry/apis/dashboard/search.go @@ -136,9 +136,9 @@ func (s *SearchHandler) GetAPIRoutes(defs map[string]common.OpenAPIDefinition) * ParameterProps: spec3.ParameterProps{ Name: "permission", In: "query", - Description: "permission needed for the resource (View, Edit, Admin)", + Description: "permission needed for the resource (view, edit, admin)", Required: false, - Schema: spec.StringProperty().WithEnum("View", "Edit", "Admin"), + Schema: spec.StringProperty().WithEnum("view", "edit", "admin"), }, }, { diff --git a/pkg/tests/apis/dashboard/search_test.go b/pkg/tests/apis/dashboard/search_test.go index 129a44aee21..09d23398c3f 100644 --- a/pkg/tests/apis/dashboard/search_test.go +++ b/pkg/tests/apis/dashboard/search_test.go @@ -126,7 +126,7 @@ func runSearchPermissionTest(t *testing.T, mode rest.DualWriterMode) { // 2. Viewer searching with permission=View should find it { - res := callSearch(helper.Org1.Viewer, "permission=View") + res := callSearch(helper.Org1.Viewer, "permission=view") found := false for _, h := range res.Hits { if h.Name == folderUID { // Verify it's our folder @@ -134,12 +134,12 @@ func runSearchPermissionTest(t *testing.T, mode rest.DualWriterMode) { break } } - require.True(t, found, "Viewer should find folder with permission=View") + require.True(t, found, "Viewer should find folder with permission=view") } // 3. Viewer searching with permission=Edit should NOT find it { - res := callSearch(helper.Org1.Viewer, "permission=Edit") + res := callSearch(helper.Org1.Viewer, "permission=edit") found := false for _, h := range res.Hits { if h.Name == folderUID { // Verify it's our folder @@ -147,12 +147,12 @@ func runSearchPermissionTest(t *testing.T, mode rest.DualWriterMode) { break } } - require.False(t, found, "Viewer should NOT find folder with permission=Edit") + require.False(t, found, "Viewer should NOT find folder with permission=edit") } // 4. Editor searching with permission=Edit should find it { - res := callSearch(helper.Org1.Editor, "permission=Edit") + res := callSearch(helper.Org1.Editor, "permission=edit") found := false for _, h := range res.Hits { if h.Name == folderUID { // Verify it's our folder @@ -160,12 +160,12 @@ func runSearchPermissionTest(t *testing.T, mode rest.DualWriterMode) { break } } - require.True(t, found, "Editor should find folder with permission=Edit") + require.True(t, found, "Editor should find folder with permission=edit") } // 5. Editor searching with permission=View should find it (Edit permission includes View) { - res := callSearch(helper.Org1.Editor, "permission=View") + res := callSearch(helper.Org1.Editor, "permission=view") found := false for _, h := range res.Hits { if h.Name == folderUID { // Verify it's our folder @@ -173,7 +173,7 @@ func runSearchPermissionTest(t *testing.T, mode rest.DualWriterMode) { break } } - require.True(t, found, "Editor should find folder with permission=View (Edit includes View)") + require.True(t, found, "Editor should find folder with permission=view (Edit includes View)") } // 6. Editor searching without permission parameter should find it (has Edit access) @@ -191,7 +191,7 @@ func runSearchPermissionTest(t *testing.T, mode rest.DualWriterMode) { // 7. Admin searching with permission=View should find it (Admin has full access) { - res := callSearch(helper.Org1.Admin, "permission=View") + res := callSearch(helper.Org1.Admin, "permission=view") found := false for _, h := range res.Hits { if h.Name == folderUID { // Verify it's our folder @@ -199,12 +199,12 @@ func runSearchPermissionTest(t *testing.T, mode rest.DualWriterMode) { break } } - require.True(t, found, "Admin should find folder with permission=View") + require.True(t, found, "Admin should find folder with permission=view") } // 8. Admin searching with permission=Edit should find it (Admin has full access) { - res := callSearch(helper.Org1.Admin, "permission=Edit") + res := callSearch(helper.Org1.Admin, "permission=edit") found := false for _, h := range res.Hits { if h.Name == folderUID { // Verify it's our folder @@ -212,12 +212,12 @@ func runSearchPermissionTest(t *testing.T, mode rest.DualWriterMode) { break } } - require.True(t, found, "Admin should find folder with permission=Edit") + require.True(t, found, "Admin should find folder with permission=edit") } // 9. Admin searching with permission=Admin should find it (Admin has full access) { - res := callSearch(helper.Org1.Admin, "permission=Admin") + res := callSearch(helper.Org1.Admin, "permission=admin") found := false for _, h := range res.Hits { if h.Name == folderUID { // Verify it's our folder @@ -225,7 +225,7 @@ func runSearchPermissionTest(t *testing.T, mode rest.DualWriterMode) { break } } - require.True(t, found, "Admin should find folder with permission=Admin") + require.True(t, found, "Admin should find folder with permission=admin") } // 10. Admin searching without permission parameter should find it (has Admin access) diff --git a/pkg/tests/apis/openapi_snapshots/dashboard.grafana.app-v0alpha1.json b/pkg/tests/apis/openapi_snapshots/dashboard.grafana.app-v0alpha1.json index 06bad0ba004..238db87aff4 100644 --- a/pkg/tests/apis/openapi_snapshots/dashboard.grafana.app-v0alpha1.json +++ b/pkg/tests/apis/openapi_snapshots/dashboard.grafana.app-v0alpha1.json @@ -1823,13 +1823,13 @@ { "name": "permission", "in": "query", - "description": "permission needed for the resource (View, Edit, Admin)", + "description": "permission needed for the resource (view, edit, admin)", "schema": { "type": "string", "enum": [ - "View", - "Edit", - "Admin" + "view", + "edit", + "admin" ] } }, diff --git a/public/app/core/components/NestedFolderPicker/useFoldersQuery.ts b/public/app/core/components/NestedFolderPicker/useFoldersQuery.ts index d852d9c241f..19ceab28b77 100644 --- a/public/app/core/components/NestedFolderPicker/useFoldersQuery.ts +++ b/public/app/core/components/NestedFolderPicker/useFoldersQuery.ts @@ -22,7 +22,13 @@ export function useFoldersQuery({ rootFolderItem, }: UseFoldersQueryProps) { const resultLegacy = useFoldersQueryLegacy({ isBrowsing, openFolders, permission, rootFolderUID, rootFolderItem }); - const resultAppPlatform = useFoldersQueryAppPlatform({ isBrowsing, openFolders, rootFolderUID, rootFolderItem }); + const resultAppPlatform = useFoldersQueryAppPlatform({ + isBrowsing, + openFolders, + permission, + rootFolderUID, + rootFolderItem, + }); // Running the hooks themselves don't have any side effects, so we can just conditionally use one or the other // requestNextPage function from the result diff --git a/public/app/core/components/NestedFolderPicker/useFoldersQueryAppPlatform.ts b/public/app/core/components/NestedFolderPicker/useFoldersQueryAppPlatform.ts index 34d068589c9..ae6c8574adb 100644 --- a/public/app/core/components/NestedFolderPicker/useFoldersQueryAppPlatform.ts +++ b/public/app/core/components/NestedFolderPicker/useFoldersQueryAppPlatform.ts @@ -27,14 +27,14 @@ const collator = new Intl.Collator(); * does not have pagination at the moment. */ -type Props = Omit; export function useFoldersQueryAppPlatform({ isBrowsing, openFolders, /* rootFolderUID: configure which folder to start browsing from */ rootFolderUID, rootFolderItem, -}: Props) { + permission, +}: UseFoldersQueryProps) { const dispatch = useDispatch(); // Keep a list of all request subscriptions so we can unsubscribe from them when the component is unmounted @@ -89,7 +89,7 @@ export function useFoldersQueryAppPlatform({ return; } - const args = { folder: finalParentUid, type: 'folder' } as const; + const args = { folder: finalParentUid, type: 'folder', permission } as const; // Make a request const subscription = dispatch(dashboardAPIv0alpha1.endpoints.getSearch.initiate(args)); @@ -101,7 +101,7 @@ export function useFoldersQueryAppPlatform({ // the subscriptions are saved in a ref so they can be unsubscribed on unmount requestsRef.current = requestsRef.current.concat([subscription]); }, - [state, dispatch] + [state, dispatch, permission] ); // Unsubscribe from all requests when the component is unmounted