From 1830e2ce9d0baff9423a6e3816c421bd836e58b0 Mon Sep 17 00:00:00 2001 From: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:13:47 +0100 Subject: [PATCH] CommanPalette: Add Assistant integration for empty state (#112601) * CommanPalette: Add Assistant integration for empty state * Update assistant package and use new onClick pop * i18n * Update public/locales/en-US/grafana.json Co-authored-by: Sven Grossmann * Update public/app/features/commandPalette/CommandPalette.tsx Co-authored-by: Sven Grossmann * Update test --------- Co-authored-by: Sven Grossmann --- package.json | 2 +- packages/grafana-flamegraph/package.json | 2 +- .../commandPalette/CommandPalette.test.tsx | 60 +++++++++++++++++++ .../commandPalette/CommandPalette.tsx | 27 ++++++--- .../grafana-pyroscope-datasource/package.json | 2 +- public/locales/en-US/grafana.json | 1 + yarn.lock | 14 ++--- 7 files changed, 91 insertions(+), 17 deletions(-) create mode 100644 public/app/features/commandPalette/CommandPalette.test.tsx diff --git a/package.json b/package.json index 5d7dd234e25..9c03062a448 100644 --- a/package.json +++ b/package.json @@ -278,7 +278,7 @@ "@glideapps/glide-data-grid": "^6.0.0", "@grafana/alerting": "workspace:*", "@grafana/api-clients": "workspace:*", - "@grafana/assistant": "0.1.0", + "@grafana/assistant": "0.1.1", "@grafana/aws-sdk": "0.7.1", "@grafana/azure-sdk": "0.0.8", "@grafana/data": "workspace:*", diff --git a/packages/grafana-flamegraph/package.json b/packages/grafana-flamegraph/package.json index 98cb22e9fb2..14a3c5ab891 100644 --- a/packages/grafana-flamegraph/package.json +++ b/packages/grafana-flamegraph/package.json @@ -83,7 +83,7 @@ "typescript": "5.9.2" }, "peerDependencies": { - "@grafana/assistant": "^0.1.0", + "@grafana/assistant": "^0.1.1", "react": "^18.0.0", "react-dom": "^18.0.0" } diff --git a/public/app/features/commandPalette/CommandPalette.test.tsx b/public/app/features/commandPalette/CommandPalette.test.tsx new file mode 100644 index 00000000000..02cdd308229 --- /dev/null +++ b/public/app/features/commandPalette/CommandPalette.test.tsx @@ -0,0 +1,60 @@ +import { KBarProvider } from 'kbar'; +import { render, screen } from 'test/test-utils'; + +import { useAssistant } from '@grafana/assistant'; +import { setPluginLinksHook } from '@grafana/runtime'; +import { setGetObservablePluginLinks } from '@grafana/runtime/internal'; + +import { getObservablePluginLinks } from '../plugins/extensions/getPluginExtensions'; + +import { CommandPalette } from './CommandPalette'; + +setPluginLinksHook(() => ({ + links: [], + isLoading: false, +})); +setGetObservablePluginLinks(getObservablePluginLinks); + +jest.mock('@grafana/assistant', () => ({ + ...jest.requireActual('@grafana/assistant'), + useAssistant: jest.fn(), + OpenAssistantButton: jest.fn().mockImplementation(({ title }) => ), +})); + +jest.mock('kbar', () => ({ + ...jest.requireActual('kbar'), + KBarPortal: jest.fn().mockImplementation(({ children }) =>
{children}
), + KBarAnimator: jest.fn().mockImplementation(({ children }) =>
{children}
), +})); + +const setup = () => { + return render( + + + + ); +}; + +describe('CommandPalette', () => { + it('should render empty state with AI Assistant button when no results and assistant is available', async () => { + // Mock assistant being available + (useAssistant as jest.Mock).mockReturnValue({ isAvailable: true }); + setup(); + + // Check if empty state message is rendered + expect(await screen.findByText('No results found')).toBeInTheDocument(); + // Check if AI Assistant button is rendered with correct props + expect(screen.getByRole('button', { name: 'Try searching with Grafana Assistant' })).toBeInTheDocument(); + }); + + it('should render empty state without AI Assistant button when assistant is not available', async () => { + // Mock assistant being unavailable + (useAssistant as jest.Mock).mockReturnValue({ isAvailable: false }); + setup(); + + // Check if empty state message is rendered + expect(await screen.findByText('No results found')).toBeInTheDocument(); + // Check that AI Assistant button is not rendered + expect(screen.queryByRole('button', { name: 'Try searching with Grafana Assistant' })).not.toBeInTheDocument(); + }); +}); diff --git a/public/app/features/commandPalette/CommandPalette.tsx b/public/app/features/commandPalette/CommandPalette.tsx index 1bd1634546c..d51b238a569 100644 --- a/public/app/features/commandPalette/CommandPalette.tsx +++ b/public/app/features/commandPalette/CommandPalette.tsx @@ -5,6 +5,7 @@ import { useOverlay } from '@react-aria/overlays'; import { KBarAnimator, KBarPortal, KBarPositioner, VisualState, useKBar, ActionImpl } from 'kbar'; import React, { useCallback, useEffect, useMemo, useRef } from 'react'; +import { OpenAssistantButton, useAssistant } from '@grafana/assistant'; import { GrafanaTheme2 } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { t } from '@grafana/i18n'; @@ -88,7 +89,11 @@ function CommandPaletteContents() { {scopesRow ?
{scopesRow}
: null}
- +
@@ -131,10 +136,13 @@ function AncestorBreadcrumbs() { interface RenderResultsProps { isFetchingSearchResults: boolean; searchResults: CommandPaletteAction[]; + searchQuery: string; } -const RenderResults = ({ isFetchingSearchResults, searchResults }: RenderResultsProps) => { +const RenderResults = ({ isFetchingSearchResults, searchResults, searchQuery }: RenderResultsProps) => { const { results: kbarResults, rootActionId } = useMatches(); + const { query } = useKBar(); + const { isAvailable: isAssistantAvailable } = useAssistant(); const lateralSpace = getCommandPalettePosition(); const styles = useStyles2(getSearchStyles, lateralSpace); @@ -176,11 +184,16 @@ const RenderResults = ({ isFetchingSearchResults, searchResults }: RenderResults }, [showEmptyState]); return showEmptyState ? ( - + + {isAssistantAvailable && ( + + )} + ) : ( =12.1.0" "@grafana/runtime": ">=12.1.0" @@ -3027,7 +3027,7 @@ __metadata: "@grafana/ui": ">=12.1.0" react: ">=18.0.0" rxjs: ">=7.0.0" - checksum: 10/90cfee9860bc128190ec1357e554685892b3ddd080d914457da311f1d45294dfcc15a427be36c381463eefe39268b5abbc39e6b541ad402e78264cc6d038c23f + checksum: 10/33e5b3f59b3b7a747a736f36183c77014214fa6e8048faac7a680dbba64833b1827dd7ef2e8c1ddf566a31829347449579ef6255811586b39914ca0510bb34a5 languageName: node linkType: hard @@ -3248,7 +3248,7 @@ __metadata: tslib: "npm:2.8.1" typescript: "npm:5.9.2" peerDependencies: - "@grafana/assistant": ^0.1.0 + "@grafana/assistant": ^0.1.1 react: ^18.0.0 react-dom: ^18.0.0 languageName: unknown @@ -18844,7 +18844,7 @@ __metadata: "@glideapps/glide-data-grid": "npm:^6.0.0" "@grafana/alerting": "workspace:*" "@grafana/api-clients": "workspace:*" - "@grafana/assistant": "npm:0.1.0" + "@grafana/assistant": "npm:0.1.1" "@grafana/aws-sdk": "npm:0.7.1" "@grafana/azure-sdk": "npm:0.0.8" "@grafana/data": "workspace:*"