import { css } from '@emotion/css'; import { FocusScope } from '@react-aria/focus'; import { KBarAnimator, KBarPortal, KBarPositioner, KBarResults, KBarSearch, useMatches, Action, VisualState, useRegisterActions, useKBar, } from 'kbar'; import React, { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import { GrafanaTheme2 } from '@grafana/data'; import { reportInteraction, locationService } from '@grafana/runtime'; import { useStyles2 } from '@grafana/ui'; import { StoreState } from 'app/types'; import { keybindingSrv } from '../../core/services/keybindingSrv'; import { ResultItem } from './ResultItem'; import getDashboardNavActions from './actions/dashboard.nav.actions'; import getGlobalActions from './actions/global.static.actions'; /** * Wrap all the components from KBar here. * @constructor */ export const CommandPalette = () => { const styles = useStyles2(getSearchStyles); const [actions, setActions] = useState([]); const { query, showing } = useKBar((state) => ({ showing: state.visualState === VisualState.showing, })); const isNotLogin = locationService.getLocation().pathname !== '/login'; const { navBarTree } = useSelector((state: StoreState) => { return { navBarTree: state.navBarTree, }; }); useEffect(() => { (async () => { if (isNotLogin) { const staticActions = getGlobalActions(navBarTree); const dashAct = await getDashboardNavActions('go/dashboard'); setActions([...staticActions, ...dashAct]); } })(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [isNotLogin]); useEffect(() => { if (showing) { reportInteraction('commandPalette_opened'); keybindingSrv.bindGlobal('esc', () => { query.setVisualState(VisualState.animatingOut); }); } return () => { keybindingSrv.bindGlobal('esc', () => { keybindingSrv.globalEsc(); }); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [showing]); useRegisterActions(actions, [actions]); return actions.length > 0 ? ( ) : null; }; const RenderResults = () => { const { results, rootActionId } = useMatches(); const styles = useStyles2(getSearchStyles); return (
typeof item === 'string' ? (
{item}
) : ( ) } />
); }; const getSearchStyles = (theme: GrafanaTheme2) => ({ positioner: css({ zIndex: theme.zIndex.portal, marginTop: '0px', '&::before': { content: '""', position: 'fixed', top: 0, right: 0, bottom: 0, left: 0, background: theme.components.overlay.background, backdropFilter: 'blur(1px)', }, }), animator: css({ maxWidth: theme.breakpoints.values.sm, // supposed to be 600... width: '100%', background: theme.colors.background.canvas, color: theme.colors.text.primary, borderRadius: theme.shape.borderRadius(4), overflow: 'hidden', boxShadow: theme.shadows.z3, }), search: css({ padding: theme.spacing(2, 3), fontSize: theme.typography.fontSize, width: '100%', boxSizing: 'border-box', outline: 'none', border: 'none', background: theme.colors.background.canvas, color: theme.colors.text.primary, borderBottom: `1px solid ${theme.colors.border.weak}`, }), sectionHeader: css({ padding: theme.spacing(1, 2), fontSize: theme.typography.h6.fontSize, fontWeight: theme.typography.body.fontWeight, color: theme.colors.text.secondary, }), resultsContainer: css({ padding: theme.spacing(2, 0), }), });