Merge remote-tracking branch 'origin/evals' into evals

This commit is contained in:
dal 2025-04-09 13:17:15 -06:00
commit 5ffaf3fc74
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
7 changed files with 108 additions and 20 deletions

View File

@ -0,0 +1 @@
export const MAX_NUMBER_OF_ITEMS_ON_DASHBOARD = 30;

View File

@ -1,2 +1,3 @@
export * from './dashboardConfigInterfaces';
export * from './interfaces';
export * from './config';

View File

@ -10,7 +10,11 @@ import {
unshareDashboard
} from './requests';
import { dashboardQueryKeys } from '@/api/query_keys/dashboard';
import { BusterDashboard, BusterDashboardResponse } from '@/api/asset_interfaces/dashboard';
import {
BusterDashboard,
BusterDashboardResponse,
MAX_NUMBER_OF_ITEMS_ON_DASHBOARD
} from '@/api/asset_interfaces/dashboard';
import { useMemo } from 'react';
import { useMemoizedFn } from '@/hooks';
import { useBusterNotifications } from '@/context/BusterNotifications';
@ -407,10 +411,23 @@ export const useAddAndRemoveMetricsFromDashboard = () => {
const { openErrorMessage } = useBusterNotifications();
const ensureDashboardConfig = useEnsureDashboardConfig();
const addMetricToDashboard = useMemoizedFn(
const addAndRemoveMetrics = useMemoizedFn(
async ({ metricIds, dashboardId }: { metricIds: string[]; dashboardId: string }) => {
const dashboardResponse = await ensureDashboardConfig(dashboardId);
const numberOfItemsOnDashboard: number =
dashboardResponse?.dashboard.config.rows?.reduce(
(acc, row) => acc + (row.items?.length || 0),
0
) || 0;
if (numberOfItemsOnDashboard > MAX_NUMBER_OF_ITEMS_ON_DASHBOARD) {
openErrorMessage(
`Dashboard is full, please remove some metrics before adding more. You can only have ${MAX_NUMBER_OF_ITEMS_ON_DASHBOARD} metrics on a dashboard`
);
return;
}
if (dashboardResponse) {
const newConfig = addAndRemoveMetricsToDashboard(
metricIds,
@ -427,7 +444,7 @@ export const useAddAndRemoveMetricsFromDashboard = () => {
);
return useMutation({
mutationFn: addMetricToDashboard,
mutationFn: addAndRemoveMetrics,
onSuccess: (data, variables) => {
if (data) {
queryClient.setQueryData(

View File

@ -1,11 +1,15 @@
import { useQuery, keepPreviousData } from '@tanstack/react-query';
import { useQuery, keepPreviousData, UseQueryOptions } from '@tanstack/react-query';
import { searchQueryKeys } from '@/api/query_keys/search';
import { search } from './requests';
export const useSearch = (params: Parameters<typeof search>[0]) => {
export const useSearch = (
params: Parameters<typeof search>[0],
options?: Omit<UseQueryOptions<Awaited<ReturnType<typeof search>>>, 'queryKey' | 'queryFn'>
) => {
return useQuery({
...searchQueryKeys.getSearchResult(params),
queryFn: () => search(params),
placeholderData: keepPreviousData
placeholderData: keepPreviousData,
...options
});
};

View File

@ -5,7 +5,7 @@ import { search } from '../buster_rest/search';
export const getSearchResult = (params: Parameters<typeof search>[0]) =>
queryOptions<BusterSearchResult[]>({
queryKey: ['search', 'results', params] as const,
staleTime: 1000 * 10 // 10 seconds,
staleTime: 1000 * 30 // 30 seconds,
});
export const searchQueryKeys = {

View File

@ -26,7 +26,7 @@ export const ResetPasswordForm: React.FC<{
const [password, setPassword] = useState('');
const [password2, setPassword2] = useState('');
const [goodPassword, setGoodPassword] = useState(false);
const { openErrorNotification, openSuccessMessage } = useBusterNotifications();
const { openErrorMessage, openSuccessMessage } = useBusterNotifications();
const [countdown, setCountdown] = useState(5);
const disabled = !goodPassword || loading || !password || !password2 || password !== password2;
@ -60,7 +60,7 @@ export const ResetPasswordForm: React.FC<{
startCountdown();
}
} catch (error) {
openErrorNotification(error);
openErrorMessage(error as string);
}
});

View File

@ -17,11 +17,15 @@ export const AddToDashboardModal: React.FC<{
const [searchTerm, setSearchTerm] = useState('');
const [selectedMetrics, setSelectedMetrics] = useState<string[]>([]);
const debouncedSearchTerm = useDebounce(searchTerm, { wait: 150 });
const { data: searchResults } = useSearch({
query: debouncedSearchTerm,
asset_types: ['metric'],
num_results: 100
});
const { data: searchResults } = useSearch(
{
query: debouncedSearchTerm,
asset_types: ['metric'],
num_results: 100
},
{ enabled: open }
);
const columns = useMemo<InputSelectModalProps['columns']>(
() => [
@ -81,6 +85,63 @@ export const AddToDashboardModal: React.FC<{
return undefined;
}, [isFetchedDashboard, rows]);
const addedMetricCount = useMemo(() => {
return selectedMetrics.filter((id) => !Object.keys(dashboard?.metrics || {}).includes(id))
.length;
}, [dashboard?.metrics, selectedMetrics]);
const removedMetricCount = useMemo(() => {
return Object.keys(dashboard?.metrics || {}).filter((id) => !selectedMetrics.includes(id))
.length;
}, [dashboard?.metrics, selectedMetrics]);
const primaryButtonText = useMemo(() => {
if (!isFetchedDashboard) {
return 'Loading metrics...';
}
const hasRemovedItems = removedMetricCount > 0;
const hasAddedItems = addedMetricCount > 0;
if (hasRemovedItems && hasAddedItems) {
return `Update dashboard`;
}
if (hasRemovedItems) {
return `Remove metrics`;
}
if (hasAddedItems) {
return `Add metrics`;
}
return `Update dashboard`;
}, [isFetchedDashboard, removedMetricCount, addedMetricCount]);
const primaryButtonTooltipText = useMemo(() => {
if (!isFetchedDashboard) {
return '';
}
const hasRemovedItems = removedMetricCount > 0;
const hasAddedItems = addedMetricCount > 0;
const returnText: string[] = [];
if (!hasRemovedItems && !hasAddedItems) {
return 'No changes to update';
}
if (hasRemovedItems) {
returnText.push(`Removing ${removedMetricCount}`);
}
if (hasAddedItems) {
returnText.push(`Adding ${addedMetricCount}`);
}
return returnText.join(', ');
}, [isFetchedDashboard, addedMetricCount, removedMetricCount]);
const footer: NonNullable<InputSelectModalProps['footer']> = useMemo(() => {
return {
left:
@ -94,15 +155,19 @@ export const AddToDashboardModal: React.FC<{
onClick: onClose
},
primaryButton: {
text: `Update metrics`,
text: primaryButtonText,
onClick: handleAddAndRemoveMetrics,
disabled: !isSelectedChanged,
tooltip: isSelectedChanged
? `Adding ${selectedMetrics.length} metrics`
: 'No changes to update'
tooltip: primaryButtonTooltipText
}
};
}, [selectedMetrics.length, isSelectedChanged, handleAddAndRemoveMetrics]);
}, [
selectedMetrics.length,
primaryButtonTooltipText,
primaryButtonText,
isSelectedChanged,
handleAddAndRemoveMetrics
]);
useLayoutEffect(() => {
if (isFetchedDashboard) {
@ -113,7 +178,7 @@ export const AddToDashboardModal: React.FC<{
return (
<InputSelectModal
width={665}
width={675}
open={open}
onClose={onClose}
columns={columns}