fix(provisioning): prevent button disable when expanding folders

- Use ref to access latest browseState without causing re-renders
- Memoize selected item UIDs to only re-run effect when selection changes
- Fixes issue where Export button was disabled when unfolding folders
This commit is contained in:
Roberto Jimenez Sanchez
2025-12-02 19:20:16 +01:00
parent f6839a6ab9
commit d179b98f7b
@@ -1,4 +1,4 @@
import { useState, useEffect, useCallback, useMemo } from 'react';
import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { config } from '@grafana/runtime';
import { ScopedResourceClient } from 'app/features/apiserver/client';
@@ -35,12 +35,27 @@ export function useSelectionUnmanagedStatus(
[]
);
// Memoize the selected item UIDs to avoid unnecessary re-runs when children are loaded
const selectedDashboardUIDs = useMemo(
() => Object.keys(selectedItems.dashboard || {}).filter((uid) => selectedItems.dashboard[uid]),
[selectedItems.dashboard]
);
const selectedFolderUIDs = useMemo(
() => Object.keys(selectedItems.folder || {}).filter((uid) => selectedItems.folder[uid]),
[selectedItems.folder]
);
// Use a ref to always access the latest browseState without causing re-renders
const browseStateRef = useRef(browseState);
browseStateRef.current = browseState;
const findItemInState = useCallback(
(uid: string) => {
const item = findItem(browseState.rootItems?.items || [], browseState.childrenByParentUID, uid);
const state = browseStateRef.current;
const item = findItem(state.rootItems?.items || [], state.childrenByParentUID, uid);
return item ? { parentUID: item.parentUID, managedBy: item.managedBy } : undefined;
},
[browseState]
[] // No dependencies - always uses latest state via ref
);
const getFolderMeta = useCallback(
@@ -116,20 +131,15 @@ export function useSelectionUnmanagedStatus(
const checkUnmanagedStatus = async () => {
setStatus({ hasUnmanaged: false, isLoading: true });
const selectedDashboards = Object.keys(selectedItems.dashboard || {}).filter(
(uid) => selectedItems.dashboard[uid]
);
const selectedFolders = Object.keys(selectedItems.folder || {}).filter((uid) => selectedItems.folder[uid]);
if (selectedDashboards.length === 0 && selectedFolders.length === 0) {
if (selectedDashboardUIDs.length === 0 && selectedFolderUIDs.length === 0) {
setStatus({ hasUnmanaged: false, isLoading: false });
return;
}
// Check all selected items
const checks = [
...selectedDashboards.map((uid) => checkItemUnmanaged(uid, false)),
...selectedFolders.map((uid) => checkItemUnmanaged(uid, true)),
...selectedDashboardUIDs.map((uid) => checkItemUnmanaged(uid, false)),
...selectedFolderUIDs.map((uid) => checkItemUnmanaged(uid, true)),
];
const results = await Promise.all(checks);
@@ -139,7 +149,7 @@ export function useSelectionUnmanagedStatus(
};
checkUnmanagedStatus();
}, [selectedItems, provisioningEnabled, checkItemUnmanaged]);
}, [selectedDashboardUIDs, selectedFolderUIDs, provisioningEnabled, checkItemUnmanaged]);
return status;
}