mirror of https://github.com/buster-so/buster.git
better keyboard shortcutrs
This commit is contained in:
parent
d31859b316
commit
b029c909d7
|
@ -122,22 +122,29 @@ const useCheckIfWeHaveAFollowupDashboard = (messageId: string) => {
|
|||
for (const file of allFiles) {
|
||||
const fileType = (file as ChatMessageResponseMessage_File).file_type;
|
||||
if (fileType === 'dashboard') {
|
||||
const queryKey = dashboardQueryKeys
|
||||
.dashboardGetDashboard(file.id, file.version_number)
|
||||
.queryKey.slice(0, 3);
|
||||
queryClient.invalidateQueries({
|
||||
...dashboardQueryKeys.dashboardGetDashboard(file.id, file.version_number),
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
...dashboardQueryKeys.dashboardGetDashboard(file.id, 'LATEST'),
|
||||
exact: false,
|
||||
queryKey,
|
||||
});
|
||||
} else if (fileType === 'metric') {
|
||||
const queryKey = metricsQueryKeys
|
||||
.metricsGetMetric(file.id, file.version_number)
|
||||
.queryKey.slice(0, 3);
|
||||
queryClient.invalidateQueries({
|
||||
...metricsQueryKeys.metricsGetMetric(file.id, file.version_number),
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
...metricsQueryKeys.metricsGetMetric(file.id, 'LATEST'),
|
||||
exact: false,
|
||||
queryKey,
|
||||
});
|
||||
} else if (fileType === 'report') {
|
||||
const { queryKey } = reportsQueryKeys.reportsGetReport(file.id, file.version_number);
|
||||
queryClient.invalidateQueries({ queryKey });
|
||||
const queryKey = reportsQueryKeys
|
||||
.reportsGetReport(file.id, file.version_number)
|
||||
.queryKey.slice(0, 3);
|
||||
queryClient.invalidateQueries({
|
||||
exact: false,
|
||||
queryKey,
|
||||
});
|
||||
} else {
|
||||
const _exhaustiveCheck: 'reasoning' = fileType;
|
||||
}
|
||||
|
|
|
@ -28,8 +28,7 @@ export const useEnsureDashboardConfig = (params?: { prefetchData?: boolean }) =>
|
|||
});
|
||||
if (res) {
|
||||
queryClient.setQueryData(
|
||||
dashboardQueryKeys.dashboardGetDashboard(res.dashboard.id, res.dashboard.version_number)
|
||||
.queryKey,
|
||||
dashboardQueryKeys.dashboardGetDashboard(res.dashboard.id, 'LATEST').queryKey,
|
||||
res
|
||||
);
|
||||
dashboardResponse = res;
|
||||
|
@ -112,6 +111,10 @@ export const getDashboardAndInitializeMetrics = async ({
|
|||
|
||||
if (isLatestVersion) {
|
||||
setOriginalDashboardFn?.(data.dashboard);
|
||||
queryClient.setQueryData(
|
||||
dashboardQueryKeys.dashboardGetDashboard(data.dashboard.id, 'LATEST').queryKey,
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
if (data.dashboard.version_number) {
|
||||
|
|
|
@ -104,8 +104,7 @@ export const useAddAndRemoveMetricsFromDashboard = () => {
|
|||
onSuccess: (data) => {
|
||||
if (data) {
|
||||
queryClient.setQueryData(
|
||||
dashboardQueryKeys.dashboardGetDashboard(data.dashboard.id, data.dashboard.version_number)
|
||||
.queryKey,
|
||||
dashboardQueryKeys.dashboardGetDashboard(data.dashboard.id, 'LATEST').queryKey,
|
||||
data
|
||||
);
|
||||
setOriginalDashboard(data.dashboard);
|
||||
|
@ -175,8 +174,7 @@ export const useAddMetricsToDashboard = () => {
|
|||
onSuccess: (data) => {
|
||||
if (data) {
|
||||
queryClient.setQueryData(
|
||||
dashboardQueryKeys.dashboardGetDashboard(data.dashboard.id, data.dashboard.version_number)
|
||||
.queryKey,
|
||||
dashboardQueryKeys.dashboardGetDashboard(data.dashboard.id, 'LATEST').queryKey,
|
||||
data
|
||||
);
|
||||
for (const metric of Object.values(data.metrics)) {
|
||||
|
@ -207,7 +205,6 @@ export const useRemoveMetricsFromDashboard = () => {
|
|||
const { openConfirmModal, openErrorMessage } = useBusterNotifications();
|
||||
const queryClient = useQueryClient();
|
||||
const ensureDashboardConfig = useEnsureDashboardConfig({ prefetchData: false });
|
||||
const getLatestMetricVersion = useGetLatestMetricVersionMemoized();
|
||||
|
||||
const removeMetricFromDashboard = async ({
|
||||
metricIds,
|
||||
|
@ -234,7 +231,7 @@ export const useRemoveMetricsFromDashboard = () => {
|
|||
if (dashboardResponse) {
|
||||
const versionedOptions = dashboardQueryKeys.dashboardGetDashboard(
|
||||
dashboardResponse.dashboard.id,
|
||||
dashboardResponse.dashboard.version_number
|
||||
'LATEST'
|
||||
);
|
||||
|
||||
const newConfig = removeMetricFromDashboardConfig(
|
||||
|
@ -252,8 +249,7 @@ export const useRemoveMetricsFromDashboard = () => {
|
|||
const data = await dashboardsUpdateDashboard({ id: dashboardId, config: newConfig });
|
||||
|
||||
queryClient.setQueryData(
|
||||
dashboardQueryKeys.dashboardGetDashboard(data.dashboard.id, data.dashboard.version_number)
|
||||
.queryKey,
|
||||
dashboardQueryKeys.dashboardGetDashboard(data.dashboard.id, 'LATEST').queryKey,
|
||||
data
|
||||
);
|
||||
|
||||
|
@ -281,8 +277,9 @@ export const useRemoveMetricsFromDashboard = () => {
|
|||
mutationFn: removeMetricFromDashboard,
|
||||
onSuccess: (_, variables) => {
|
||||
variables.metricIds.forEach((id) => {
|
||||
const queryKey = metricsQueryKeys.metricsGetMetric(id, 'LATEST').queryKey.slice(0, 3);
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: metricsQueryKeys.metricsGetMetric(id, 'LATEST').queryKey.slice(0, 3),
|
||||
queryKey,
|
||||
refetchType: 'all',
|
||||
exact: false,
|
||||
});
|
||||
|
|
|
@ -16,13 +16,13 @@ export const useSaveDashboard = (params?: { updateOnSave?: boolean }) => {
|
|||
onSuccess: (data, variables) => {
|
||||
if (updateOnSave && data) {
|
||||
queryClient.setQueryData(
|
||||
dashboardQueryKeys.dashboardGetDashboard(data.dashboard.id, data.dashboard.version_number)
|
||||
.queryKey,
|
||||
dashboardQueryKeys.dashboardGetDashboard(data.dashboard.id, 'LATEST').queryKey,
|
||||
data
|
||||
);
|
||||
setOriginalDashboard(data.dashboard);
|
||||
|
||||
if (variables.restore_to_version) {
|
||||
console.warn('TODO check if this is correct');
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: dashboardQueryKeys.dashboardGetDashboard(data.dashboard.id, 'LATEST')
|
||||
.queryKey,
|
||||
|
|
|
@ -9,12 +9,11 @@ import { shareDashboard, unshareDashboard, updateDashboardShare } from '../reque
|
|||
*/
|
||||
export const useShareDashboard = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const getLatestDashboardVersion = useGetLatestDashboardVersionMemoized();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: shareDashboard,
|
||||
onMutate: ({ id, params }) => {
|
||||
const latestVersionNumber = getLatestDashboardVersion(id) ?? 'LATEST';
|
||||
const queryKey = dashboardQueryKeys.dashboardGetDashboard(id, latestVersionNumber).queryKey;
|
||||
const queryKey = dashboardQueryKeys.dashboardGetDashboard(id, 'LATEST').queryKey;
|
||||
|
||||
queryClient.setQueryData(queryKey, (previousData) => {
|
||||
if (!previousData) return previousData;
|
||||
|
@ -47,15 +46,10 @@ export const useShareDashboard = () => {
|
|||
*/
|
||||
export const useUnshareDashboard = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const getLatestDashboardVersion = useGetLatestDashboardVersionMemoized();
|
||||
return useMutation({
|
||||
mutationFn: unshareDashboard,
|
||||
onMutate: (variables) => {
|
||||
const latestVersionNumber = getLatestDashboardVersion(variables.id) ?? 'LATEST';
|
||||
const queryKey = dashboardQueryKeys.dashboardGetDashboard(
|
||||
variables.id,
|
||||
latestVersionNumber
|
||||
).queryKey;
|
||||
const queryKey = dashboardQueryKeys.dashboardGetDashboard(variables.id, 'LATEST').queryKey;
|
||||
queryClient.setQueryData(queryKey, (previousData) => {
|
||||
if (!previousData) return previousData;
|
||||
return create(previousData, (draft) => {
|
||||
|
@ -73,12 +67,11 @@ export const useUnshareDashboard = () => {
|
|||
*/
|
||||
export const useUpdateDashboardShare = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const getLatestDashboardVersion = useGetLatestDashboardVersionMemoized();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: updateDashboardShare,
|
||||
onMutate: ({ id, params }) => {
|
||||
const latestVersionNumber = getLatestDashboardVersion(id) ?? 'LATEST';
|
||||
const queryKey = dashboardQueryKeys.dashboardGetDashboard(id, latestVersionNumber).queryKey;
|
||||
const queryKey = dashboardQueryKeys.dashboardGetDashboard(id, 'LATEST').queryKey;
|
||||
queryClient.setQueryData(queryKey, (previousData) => {
|
||||
if (!previousData) return previousData;
|
||||
return create(previousData, (draft) => {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { create } from 'mutative';
|
|||
import { dashboardQueryKeys } from '@/api/query_keys/dashboard';
|
||||
import { getOriginalDashboard } from '@/context/Dashboards/useOriginalDashboardStore';
|
||||
import { useGetLatestDashboardVersionMemoized } from '../dashboardVersionNumber';
|
||||
import type { dashboardsUpdateDashboard } from '../requests';
|
||||
import { useSaveDashboard } from './useSaveDashboard';
|
||||
|
||||
/**
|
||||
|
@ -19,9 +20,7 @@ export const useUpdateDashboard = (params?: {
|
|||
const { mutateAsync: saveDashboard } = useSaveDashboard({ updateOnSave });
|
||||
const getLatestDashboardVersion = useGetLatestDashboardVersionMemoized();
|
||||
|
||||
const mutationFn = async (
|
||||
variables: Parameters<typeof import('../requests').dashboardsUpdateDashboard>[0]
|
||||
) => {
|
||||
const mutationFn = async (variables: Parameters<typeof dashboardsUpdateDashboard>[0]) => {
|
||||
if (saveToServer) {
|
||||
return await saveDashboard({
|
||||
...variables,
|
||||
|
@ -33,16 +32,12 @@ export const useUpdateDashboard = (params?: {
|
|||
return useMutation({
|
||||
mutationFn,
|
||||
onMutate: (variables) => {
|
||||
const latestVersionNumber = getLatestDashboardVersion(variables.id) ?? 'LATEST';
|
||||
const originalDashboard = getOriginalDashboard(variables.id);
|
||||
if (!originalDashboard) return;
|
||||
const updatedDashboard = create(originalDashboard, (draft) => {
|
||||
Object.assign(draft, variables);
|
||||
});
|
||||
const queryKey = dashboardQueryKeys.dashboardGetDashboard(
|
||||
variables.id,
|
||||
latestVersionNumber
|
||||
).queryKey;
|
||||
const queryKey = dashboardQueryKeys.dashboardGetDashboard(variables.id, 'LATEST').queryKey;
|
||||
|
||||
queryClient.setQueryData(queryKey, (previousData) => {
|
||||
if (!previousData) return previousData;
|
||||
|
|
|
@ -22,8 +22,7 @@ export const useUpdateDashboardConfig = () => {
|
|||
}: Partial<BusterDashboard['config']> & {
|
||||
dashboardId: string;
|
||||
}) => {
|
||||
const latestVersionNumber = getLatestDashboardVersion(dashboardId) ?? 'LATEST';
|
||||
const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId, latestVersionNumber);
|
||||
const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId, 'LATEST');
|
||||
const previousDashboard = queryClient.getQueryData(options.queryKey);
|
||||
const previousConfig = previousDashboard?.dashboard?.config;
|
||||
if (previousConfig) {
|
||||
|
|
|
@ -149,15 +149,14 @@ export const prefetchGetDashboard = async (
|
|||
queryClient: QueryClient
|
||||
) => {
|
||||
const chosenVersionNumber = version_number || 'LATEST';
|
||||
const queryFn = async () => {
|
||||
return getDashboardAndInitializeMetrics({
|
||||
const queryFn = async () =>
|
||||
getDashboardAndInitializeMetrics({
|
||||
id,
|
||||
version_number: chosenVersionNumber,
|
||||
queryClient,
|
||||
prefetchMetricsData: false,
|
||||
shouldInitializeMetrics: true,
|
||||
});
|
||||
};
|
||||
|
||||
const queryKey = dashboardQueryKeys.dashboardGetDashboard(id, chosenVersionNumber)?.queryKey;
|
||||
const existingData = queryClient.getQueryData(queryKey);
|
||||
|
|
|
@ -363,14 +363,15 @@ const DropdownItem = <
|
|||
index: number;
|
||||
showIndex: boolean;
|
||||
}) => {
|
||||
const onClickItem = useMemoizedFn((e: React.MouseEvent<HTMLDivElement>) => {
|
||||
const onClickItem = useMemoizedFn((e: React.MouseEvent<HTMLDivElement> | KeyboardEvent) => {
|
||||
if (disabled) return;
|
||||
if (onClick) onClick(e);
|
||||
if (onSelect) onSelect(value as T);
|
||||
});
|
||||
const enabledHotKeys = showIndex && !disabled && !!onSelectItem;
|
||||
|
||||
// Add hotkey support when showIndex is true
|
||||
useHotkeys(showIndex ? `${index}` : '', (_e) => onSelectItem(index), {
|
||||
useHotkeys(`${index}`, onClickItem, {
|
||||
enabled: enabledHotKeys,
|
||||
});
|
||||
|
||||
|
@ -391,7 +392,7 @@ const DropdownItem = <
|
|||
{shortcut && <DropdownMenuShortcut>{shortcut}</DropdownMenuShortcut>}
|
||||
{link && (
|
||||
<DropdownMenuLink<TRouter, TOptions, TFrom>
|
||||
className="-mr-1 ml-auto opacity-0 group-hover:opacity-50 hover:opacity-100"
|
||||
className="ml-auto opacity-0 group-hover:opacity-50 hover:opacity-100"
|
||||
link={isSelectable ? link : null}
|
||||
linkIcon={linkIcon}
|
||||
/>
|
||||
|
|
|
@ -308,7 +308,7 @@ const DropdownMenuLink = <
|
|||
|
||||
return (
|
||||
<div
|
||||
className={cn('swag', className)}
|
||||
className={className}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { useEffect, useRef } from 'react';
|
||||
import { cn } from '@/lib/classMerge';
|
||||
import { Magnifier } from '../icons';
|
||||
import { Input } from '../inputs';
|
||||
|
@ -22,19 +23,38 @@ export const DropdownMenuHeaderSearch = <T,>({
|
|||
placeholder,
|
||||
className = '',
|
||||
}: DropdownMenuHeaderSearchProps<T>) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const { onChange: onChangePreflight, onKeyDown: onKeyDownPreflight } = useRadixDropdownSearch({
|
||||
showIndex,
|
||||
onSelectItem,
|
||||
onChange,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
// Use requestAnimationFrame to ensure DOM is ready after animations
|
||||
const focusInput = () => {
|
||||
if (inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
};
|
||||
|
||||
// Try immediate focus first
|
||||
focusInput();
|
||||
|
||||
// If that doesn't work, try after the next frame
|
||||
requestAnimationFrame(() => {
|
||||
focusInput();
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={cn('flex items-center gap-x-0', className)}>
|
||||
<span className="text-icon-color ml-2 flex">
|
||||
<Magnifier />
|
||||
</span>
|
||||
<Input
|
||||
autoFocus
|
||||
ref={inputRef}
|
||||
autoFocus={true}
|
||||
variant={'ghost'}
|
||||
className="pl-1.5!"
|
||||
size={'small'}
|
||||
|
|
|
@ -14,7 +14,7 @@ export interface IDropdownItem<
|
|||
secondaryLabel?: string;
|
||||
value: T;
|
||||
shortcut?: string;
|
||||
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
||||
onClick?: (e: React.MouseEvent<HTMLDivElement> | KeyboardEvent) => void;
|
||||
closeOnSelect?: boolean; //default is true
|
||||
icon?: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
|
|
|
@ -11,7 +11,7 @@ import { canEdit } from '@/lib/share';
|
|||
import { useGetOriginalDashboard } from './useOriginalDashboardStore';
|
||||
|
||||
export const useIsDashboardChanged = ({
|
||||
dashboardId,
|
||||
dashboardId = '',
|
||||
enabled = true,
|
||||
}: {
|
||||
dashboardId: string | undefined;
|
||||
|
@ -40,7 +40,7 @@ export const useIsDashboardChanged = ({
|
|||
}, [currentDashboard]);
|
||||
|
||||
const onResetToOriginal = useMemoizedFn(() => {
|
||||
const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId || '', 'LATEST');
|
||||
const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId, 'LATEST');
|
||||
const currentDashboard = queryClient.getQueryData<BusterDashboardResponse>(options.queryKey);
|
||||
if (originalDashboard && currentDashboard) {
|
||||
const resetDashboard = create(currentDashboard, (draft) => {
|
||||
|
|
Loading…
Reference in New Issue