mirror of https://github.com/buster-so/buster.git
Merge remote-tracking branch 'origin/evals' into evals
This commit is contained in:
commit
5ffaf3fc74
|
@ -0,0 +1 @@
|
|||
export const MAX_NUMBER_OF_ITEMS_ON_DASHBOARD = 30;
|
|
@ -1,2 +1,3 @@
|
|||
export * from './dashboardConfigInterfaces';
|
||||
export * from './interfaces';
|
||||
export * from './config';
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
});
|
||||
};
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Reference in New Issue