mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 01:21:50 +08:00

* update eslint, tsconfig + esbuild to handle new jsx transform * remove thing that breaks the new jsx transform * remove react imports * adjust grafana-icons build * is this the correct syntax? * try this * well this was much easier than expected... * change grafana-plugin-configs webpack config * fixes * fix lockfile * fix 2 more violations * use path.resolve instead of require.resolve * remove react import * fix react imports * more fixes * remove React import * remove import React from docs * remove another react import
98 lines
2.7 KiB
TypeScript
98 lines
2.7 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react';
|
|
import * as React from 'react';
|
|
|
|
import { config } from '@grafana/runtime';
|
|
import { DashboardsTreeItem } from 'app/features/browse-dashboards/types';
|
|
import { DashboardViewItem } from 'app/features/search/types';
|
|
|
|
import { getDOMId } from './NestedFolderList';
|
|
|
|
interface TreeInteractionProps {
|
|
tree: DashboardsTreeItem[];
|
|
handleCloseOverlay: () => void;
|
|
handleFolderSelect: (item: DashboardViewItem) => void;
|
|
handleFolderExpand: (uid: string, newOpenState: boolean) => Promise<void>;
|
|
idPrefix: string;
|
|
search: string;
|
|
visible: boolean;
|
|
}
|
|
|
|
export function useTreeInteractions({
|
|
tree,
|
|
handleCloseOverlay,
|
|
handleFolderSelect,
|
|
handleFolderExpand,
|
|
idPrefix,
|
|
search,
|
|
visible,
|
|
}: TreeInteractionProps) {
|
|
const [focusedItemIndex, setFocusedItemIndex] = useState(-1);
|
|
const nestedFoldersEnabled = Boolean(config.featureToggles.nestedFolders);
|
|
|
|
useEffect(() => {
|
|
if (visible) {
|
|
setFocusedItemIndex(-1);
|
|
}
|
|
}, [visible]);
|
|
|
|
useEffect(() => {
|
|
setFocusedItemIndex(0);
|
|
}, [search]);
|
|
|
|
useEffect(() => {
|
|
document
|
|
.getElementById(getDOMId(idPrefix, tree[focusedItemIndex]?.item.uid))
|
|
?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
}, [focusedItemIndex, idPrefix, tree]);
|
|
|
|
const handleKeyDown = useCallback(
|
|
(ev: React.KeyboardEvent<HTMLInputElement>) => {
|
|
const foldersAreOpenable = nestedFoldersEnabled && !search;
|
|
switch (ev.key) {
|
|
// Expand/collapse folder on right/left arrow keys
|
|
case 'ArrowRight':
|
|
case 'ArrowLeft':
|
|
if (foldersAreOpenable) {
|
|
ev.preventDefault();
|
|
handleFolderExpand(tree[focusedItemIndex].item.uid, ev.key === 'ArrowRight');
|
|
}
|
|
break;
|
|
case 'ArrowUp':
|
|
if (focusedItemIndex > 0) {
|
|
ev.preventDefault();
|
|
setFocusedItemIndex(focusedItemIndex - 1);
|
|
}
|
|
break;
|
|
case 'ArrowDown':
|
|
if (focusedItemIndex < tree.length - 1) {
|
|
ev.preventDefault();
|
|
setFocusedItemIndex(focusedItemIndex + 1);
|
|
}
|
|
break;
|
|
case 'Enter':
|
|
ev.preventDefault();
|
|
const item = tree[focusedItemIndex].item;
|
|
if (item.kind === 'folder') {
|
|
handleFolderSelect(item);
|
|
}
|
|
break;
|
|
case 'Tab':
|
|
ev.stopPropagation();
|
|
handleCloseOverlay();
|
|
break;
|
|
case 'Escape':
|
|
ev.stopPropagation();
|
|
ev.preventDefault();
|
|
handleCloseOverlay();
|
|
break;
|
|
}
|
|
},
|
|
[focusedItemIndex, handleCloseOverlay, handleFolderExpand, handleFolderSelect, nestedFoldersEnabled, search, tree]
|
|
);
|
|
|
|
return {
|
|
focusedItemIndex,
|
|
handleKeyDown,
|
|
};
|
|
}
|