From 3668d0265044686d16347708c5cbc6c7fcdd9847 Mon Sep 17 00:00:00 2001 From: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> Date: Tue, 30 Sep 2025 11:49:22 +0200 Subject: [PATCH] Scopes: Resolve selector path on initial load (#111624) * Recusively load nodes, and insert into tree * Remove console.logs * Simply functions * Always show recent scopes category * Fix issues with parent node remaining in URL * Always display recent scopes * Make sure chdilren are loaded when collapsing * Add test cases for expanded items and imrpove a11y markup * Remove recent scopes always showing and update tests * Fix linting issue * Move insertPathNodesIntoTree to treeUtils * Add test for insertPathNodesIntoTree * Remove comment --- public/app/features/scopes/ScopesService.ts | 28 +++--- .../features/scopes/selector/RecentScopes.tsx | 4 +- .../scopes/selector/ScopesSelectorService.ts | 89 ++++++++++++++----- .../scopes/selector/ScopesTreeItem.tsx | 6 +- .../scopes/selector/scopesTreeUtils.test.ts | 35 ++++++++ .../scopes/selector/scopesTreeUtils.ts | 30 +++++++ .../features/scopes/tests/selector.test.ts | 30 +++++++ public/app/features/scopes/tests/tree.test.ts | 12 +++ .../features/scopes/tests/utils/actions.ts | 12 ++- .../features/scopes/tests/utils/selectors.ts | 4 + public/locales/en-US/grafana.json | 4 +- 11 files changed, 215 insertions(+), 39 deletions(-) diff --git a/public/app/features/scopes/ScopesService.ts b/public/app/features/scopes/ScopesService.ts index 5c5d4b33147..0e6f3500839 100644 --- a/public/app/features/scopes/ScopesService.ts +++ b/public/app/features/scopes/ScopesService.ts @@ -76,8 +76,8 @@ export class ScopesService implements ScopesContextValue { // Pre-load parent node, to prevent UI flickering if (parentNodeId) { - this.selectorService.getScopeNode(parentNodeId).catch((error) => { - console.error('Failed to pre-load parent node', error); + this.selectorService.resolvePathToRoot(parentNodeId, this.selectorService.state.tree!).catch((error) => { + console.error('Failed to pre-load parent node path', error); }); } @@ -94,7 +94,9 @@ export class ScopesService implements ScopesContextValue { const parentNode = queryParams.get('scope_parent'); const scopes = queryParams.getAll('scopes'); - if (scopes.length) { + // Check if new scopes are different from the old scopes + const currentScopes = this.selectorService.state.appliedScopes.map((scope) => scope.scopeId); + if (scopes.length && !isEqual(scopes, currentScopes)) { // We only update scopes but never delete them. This is to keep the scopes in memory if user navigates to // page that does not use scopes (like from dashboard to dashboard list back to dashboard). If user // changes the URL directly, it would trigger a reload so scopes would still be reset. @@ -105,17 +107,21 @@ export class ScopesService implements ScopesContextValue { // Update the URL based on change in the scopes state this.subscriptions.push( - selectorService.subscribeToState((state, prev) => { - const oldParentNode = prev.appliedScopes[0]?.parentNodeId; + selectorService.subscribeToState((state, prevState) => { + const oldParentNode = prevState.appliedScopes[0]?.parentNodeId; const newParentNode = state.appliedScopes[0]?.parentNodeId; - if (oldParentNode !== newParentNode && newParentNode) { - this.locationService.partial({ scope_parent: newParentNode }, true); - } - const oldScopeNames = prev.appliedScopes.map((scope) => scope.scopeId); + const parentNodeChanged = oldParentNode !== newParentNode; + + const oldScopeNames = prevState.appliedScopes.map((scope) => scope.scopeId); const newScopeNames = state.appliedScopes.map((scope) => scope.scopeId); - if (!isEqual(oldScopeNames, newScopeNames)) { - this.locationService.partial({ scopes: newScopeNames }, true); + + const scopesChanged = !isEqual(oldScopeNames, newScopeNames); + if (scopesChanged) { + this.locationService.partial( + { scopes: newScopeNames, scope_parent: parentNodeChanged ? newParentNode || null : oldParentNode }, + true + ); } }) ); diff --git a/public/app/features/scopes/selector/RecentScopes.tsx b/public/app/features/scopes/selector/RecentScopes.tsx index efd190f7ec3..66771f635fb 100644 --- a/public/app/features/scopes/selector/RecentScopes.tsx +++ b/public/app/features/scopes/selector/RecentScopes.tsx @@ -39,7 +39,9 @@ export const RecentScopes = ({ recentScopes, onSelect }: RecentScopesProps) => { recentScopes.map((recentScopeSet) => (