mirror of https://github.com/buster-so/buster.git
start moving to hook based updates
This commit is contained in:
parent
545ad32f50
commit
77ece34d25
|
@ -41,4 +41,6 @@ export type UpdateMetricParams = {
|
|||
feedback?: 'negative';
|
||||
/** Admin only: verification status update */
|
||||
status?: VerificationStatus;
|
||||
/** file in yaml format to update */
|
||||
file?: string;
|
||||
} & ShareRequest;
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
listMetrics_server,
|
||||
updateMetric
|
||||
} from './requests';
|
||||
import type { GetMetricParams, ListMetricsParams } from './interfaces';
|
||||
import type { GetMetricParams, ListMetricsParams, UpdateMetricParams } from './interfaces';
|
||||
import { upgradeMetricToIMetric } from '@/lib/chat';
|
||||
import { queryKeys } from '@/api/query_keys';
|
||||
import { useMemo } from 'react';
|
||||
|
@ -19,6 +19,8 @@ import { resolveEmptyMetric } from '@/lib/metrics/resolve';
|
|||
import { useGetUserFavorites } from '../users';
|
||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||
import type { IBusterMetric } from '@/api/asset_interfaces/metric';
|
||||
import { create } from 'mutative';
|
||||
import { prepareMetricUpdateMetric } from '@/lib/metrics/saveToServerHelpers';
|
||||
|
||||
export const useGetMetric = <TData = IBusterMetric>(
|
||||
id: string | undefined,
|
||||
|
@ -119,11 +121,15 @@ export const prefetchGetMetricDataClient = async (
|
|||
});
|
||||
};
|
||||
|
||||
export const useUpdateMetric = () => {
|
||||
/**
|
||||
* This is a mutation that saves a metric to the server.
|
||||
* It will simply use the params passed in and not do any special logic.
|
||||
*/
|
||||
export const useSaveMetric = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: updateMetric,
|
||||
onSuccess: (data, variables, context) => {
|
||||
onSuccess: (data) => {
|
||||
const hasDraftSessionId = data.draft_session_id;
|
||||
const metricId = data.id;
|
||||
const options = queryKeys.metricsGetMetric(metricId);
|
||||
|
@ -138,6 +144,38 @@ export const useUpdateMetric = () => {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a mutation that updates a metric.
|
||||
* It will create a new metric with the new values combined with the old values and save it to the server.
|
||||
* It will also strip out any values that are not changed from the DEFAULT_CHART_CONFIG.
|
||||
* It will also update the draft_session_id if it exists.
|
||||
*/
|
||||
export const useUpdateMetric = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { mutateAsync: saveMetric } = useSaveMetric();
|
||||
const mutationFn = useMemoizedFn(
|
||||
async (newMetricPartial: Partial<IBusterMetric> & { id: string }) => {
|
||||
const metricId = newMetricPartial.id;
|
||||
const options = queryKeys.metricsGetMetric(metricId);
|
||||
const prevMetric = queryClient.getQueryData(options.queryKey);
|
||||
const newMetric = create(prevMetric, (draft) => {
|
||||
Object.assign(draft || {}, newMetricPartial);
|
||||
});
|
||||
|
||||
if (prevMetric && newMetric) {
|
||||
const changedValues = prepareMetricUpdateMetric(newMetric, prevMetric);
|
||||
if (changedValues) {
|
||||
return saveMetric(changedValues);
|
||||
}
|
||||
}
|
||||
return Promise.resolve(newMetric!);
|
||||
}
|
||||
);
|
||||
return useMutation({
|
||||
mutationFn
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteMetric = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
|
@ -202,8 +240,8 @@ export const useMetricIndividual = ({ metricId }: { metricId: string }) => {
|
|||
};
|
||||
|
||||
export const useSaveMetricToCollection = () => {
|
||||
const { mutateAsync: updateMetricMutation } = useUpdateMetric();
|
||||
const { data: userFavorites, refetch: refreshFavoritesList } = useGetUserFavorites();
|
||||
const { mutateAsync: saveMetric } = useSaveMetric();
|
||||
|
||||
const saveMetricToCollection = useMemoizedFn(
|
||||
async ({ metricId, collectionIds }: { metricId: string; collectionIds: string[] }) => {
|
||||
|
@ -212,7 +250,7 @@ export const useSaveMetricToCollection = () => {
|
|||
return collectionIds.includes(searchId);
|
||||
});
|
||||
|
||||
await updateMetricMutation({
|
||||
await saveMetric({
|
||||
id: metricId,
|
||||
add_to_collections: collectionIds
|
||||
});
|
||||
|
@ -230,8 +268,8 @@ export const useSaveMetricToCollection = () => {
|
|||
};
|
||||
|
||||
export const useRemoveMetricFromCollection = () => {
|
||||
const { mutateAsync: updateMetricMutation } = useUpdateMetric();
|
||||
const { data: userFavorites, refetch: refreshFavoritesList } = useGetUserFavorites();
|
||||
const { mutateAsync: saveMetric } = useSaveMetric();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const removeMetricFromCollection = useMemoizedFn(
|
||||
|
@ -244,7 +282,7 @@ export const useRemoveMetricFromCollection = () => {
|
|||
return currentMetric.collections.some((c) => c.id === searchId);
|
||||
});
|
||||
|
||||
await updateMetricMutation({
|
||||
await saveMetric({
|
||||
id: metricId,
|
||||
remove_from_collections: [collectionId]
|
||||
});
|
||||
|
@ -262,11 +300,11 @@ export const useRemoveMetricFromCollection = () => {
|
|||
|
||||
export const useSaveMetricToDashboard = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { mutateAsync: updateMetricMutation } = useUpdateMetric();
|
||||
const { mutateAsync: saveMetric } = useSaveMetric();
|
||||
|
||||
const saveMetricToDashboard = useMemoizedFn(
|
||||
async ({ metricId, dashboardIds }: { metricId: string; dashboardIds: string[] }) => {
|
||||
await updateMetricMutation({
|
||||
await saveMetric({
|
||||
id: metricId,
|
||||
save_to_dashboard: dashboardIds
|
||||
});
|
||||
|
@ -275,7 +313,7 @@ export const useSaveMetricToDashboard = () => {
|
|||
|
||||
return useMutation({
|
||||
mutationFn: saveMetricToDashboard,
|
||||
onSuccess: (data, variables, context) => {
|
||||
onSuccess: (data, variables) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: variables.dashboardIds.map((id) => queryKeys.dashboardGetDashboard(id).queryKey)
|
||||
});
|
||||
|
@ -284,10 +322,8 @@ export const useSaveMetricToDashboard = () => {
|
|||
};
|
||||
|
||||
export const useRemoveMetricFromDashboard = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { openConfirmModal } = useBusterNotifications();
|
||||
const { mutateAsync: updateMetricMutation } = useUpdateMetric();
|
||||
|
||||
const { mutateAsync: saveMetric } = useSaveMetric();
|
||||
const removeMetricFromDashboard = useMemoizedFn(
|
||||
async ({
|
||||
metricId,
|
||||
|
@ -299,7 +335,7 @@ export const useRemoveMetricFromDashboard = () => {
|
|||
useConfirmModal?: boolean;
|
||||
}) => {
|
||||
const method = async () => {
|
||||
await updateMetricMutation({
|
||||
await saveMetric({
|
||||
id: metricId,
|
||||
remove_from_dashboard: [dashboardId]
|
||||
});
|
||||
|
|
|
@ -17,7 +17,7 @@ import { UserGroup, ChevronRight } from '@/components/ui/icons';
|
|||
import { cn } from '@/lib/classMerge';
|
||||
import type { ShareRequest } from '@/api/asset_interfaces/shared_interfaces';
|
||||
import { useUpdateCollection } from '@/api/buster_rest/collections';
|
||||
import { useUpdateMetric } from '@/api/buster_rest/metrics';
|
||||
import { useSaveMetric, useUpdateMetric } from '@/api/buster_rest/metrics';
|
||||
import { useUpdateDashboard } from '@/api/buster_rest/dashboards';
|
||||
|
||||
export const ShareMenuContentBody: React.FC<{
|
||||
|
@ -77,7 +77,7 @@ const ShareMenuContentShare: React.FC<{
|
|||
}> = React.memo(({ setOpenShareWithGroupAndTeam, assetType, individual_permissions, assetId }) => {
|
||||
const userTeams = useUserConfigContextSelector((state) => state.userTeams);
|
||||
const { mutateAsync: onShareDashboard } = useUpdateDashboard();
|
||||
const { mutateAsync: onShareMetric } = useUpdateMetric();
|
||||
const { mutateAsync: onShareMetric } = useSaveMetric();
|
||||
const { mutateAsync: onShareCollection } = useUpdateCollection();
|
||||
const [inputValue, setInputValue] = React.useState<string>('');
|
||||
const [isInviting, setIsInviting] = React.useState<boolean>(false);
|
||||
|
|
|
@ -10,7 +10,7 @@ import { UserGroup } from '@/components/ui/icons';
|
|||
import { ShareAssetType } from '@/api/asset_interfaces';
|
||||
import type { ShareRequest } from '@/api/asset_interfaces/shared_interfaces';
|
||||
import { useGetCollection, useUpdateCollection } from '@/api/buster_rest/collections';
|
||||
import { useGetMetric, useUpdateMetric } from '@/api/buster_rest/metrics';
|
||||
import { useGetMetric, useSaveMetric } from '@/api/buster_rest/metrics';
|
||||
import { useGetDashboard, useUpdateDashboard } from '@/api/buster_rest/dashboards';
|
||||
|
||||
export const ShareWithGroupAndTeam: React.FC<{
|
||||
|
@ -21,7 +21,7 @@ export const ShareWithGroupAndTeam: React.FC<{
|
|||
}> = ({ assetType, assetId, goBack, onCopyLink }) => {
|
||||
const userTeams = useUserConfigContextSelector((state) => state.userTeams);
|
||||
const { mutateAsync: onShareDashboard } = useUpdateDashboard();
|
||||
const { mutateAsync: onShareMetric } = useUpdateMetric();
|
||||
const { mutateAsync: onShareMetric } = useSaveMetric();
|
||||
const { mutateAsync: onShareCollection } = useUpdateCollection();
|
||||
const { data: dashboardResponse } = useGetDashboard(
|
||||
assetType === ShareAssetType.DASHBOARD ? assetId : undefined
|
||||
|
|
|
@ -22,12 +22,12 @@ const BusterTableChartBase: React.FC<BusterTableChartProps> = ({
|
|||
columnLabelFormats = DEFAULT_CHART_CONFIG.columnLabelFormats,
|
||||
tableColumnWidths = DEFAULT_CHART_CONFIG.tableColumnWidths,
|
||||
editable = true,
|
||||
onInitialAnimationEnd,
|
||||
//TODO
|
||||
tableHeaderBackgroundColor,
|
||||
tableHeaderFontColor,
|
||||
isDarkMode,
|
||||
animate,
|
||||
onInitialAnimationEnd,
|
||||
tableColumnFontColor
|
||||
}) => {
|
||||
const onUpdateMetricChartConfig = useBusterMetricsContextSelector(
|
||||
|
|
|
@ -6,7 +6,7 @@ import { BusterReactQueryProvider } from './BusterReactQuery/BusterReactQueryAnd
|
|||
import { AppLayoutProvider } from './BusterAppLayout';
|
||||
import { BusterUserConfigProvider } from './Users/UserConfigProvider';
|
||||
import { BusterAssetsProvider } from './Assets/BusterAssetsProvider';
|
||||
import { BusterPosthogProvider } from './Posthog/usePosthog';
|
||||
import { BusterPosthogProvider } from './Posthog';
|
||||
import { BusterChatProvider } from './Chats';
|
||||
import { RoutePrefetcher } from './RoutePrefetcher';
|
||||
import { BusterMetricsProvider } from './Metrics';
|
||||
|
|
|
@ -3,10 +3,9 @@
|
|||
import React, { PropsWithChildren, useTransition } from 'react';
|
||||
import { createContext, useContextSelector } from 'use-context-selector';
|
||||
import {
|
||||
BusterMetric,
|
||||
ColumnSettings,
|
||||
DEFAULT_CHART_CONFIG,
|
||||
IColumnLabelFormat,
|
||||
type IColumnLabelFormat,
|
||||
type IBusterMetric,
|
||||
type IBusterMetricChartConfig
|
||||
} from '@/api/asset_interfaces/metric';
|
||||
|
@ -14,13 +13,9 @@ import { useParams } from 'next/navigation';
|
|||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { queryKeys } from '@/api/query_keys';
|
||||
import { useDebounceFn, useMemoizedFn } from '@/hooks';
|
||||
import {
|
||||
prepareMetricUpdateMetric,
|
||||
resolveEmptyMetric,
|
||||
upgradeMetricToIMetric
|
||||
} from '@/lib/metrics';
|
||||
import { prepareMetricUpdateMetric, resolveEmptyMetric } from '@/lib/metrics';
|
||||
import { create } from 'mutative';
|
||||
import { ShareRole, VerificationStatus } from '@/api/asset_interfaces/share';
|
||||
import { ShareRole } from '@/api/asset_interfaces/share';
|
||||
import { useUpdateMetric } from '@/api/buster_rest/metrics';
|
||||
|
||||
const useBusterMetrics = () => {
|
||||
|
@ -44,7 +39,7 @@ const useBusterMetrics = () => {
|
|||
|
||||
// STATE UPDATERS
|
||||
|
||||
const setMetricToState = useMemoizedFn((metric: IBusterMetric) => {
|
||||
const _setMetricToState = useMemoizedFn((metric: IBusterMetric) => {
|
||||
const metricId = getMetricId(metric.id);
|
||||
const options = queryKeys.metricsGetMetric(metricId);
|
||||
queryClient.setQueryData(options.queryKey, metric);
|
||||
|
@ -57,7 +52,7 @@ const useBusterMetrics = () => {
|
|||
const newMetric = create(currentMetric, (draft) => {
|
||||
Object.assign(draft, newMetricPartial);
|
||||
});
|
||||
setMetricToState(newMetric);
|
||||
_setMetricToState(newMetric);
|
||||
//This will trigger a rerender and push prepareMetricUpdateMetric off UI metric
|
||||
startTransition(() => {
|
||||
const isReadyOnly = currentMetric.permission === ShareRole.VIEWER;
|
||||
|
@ -73,7 +68,7 @@ const useBusterMetrics = () => {
|
|||
useMemoizedFn((newMetric: IBusterMetric, oldMetric: IBusterMetric) => {
|
||||
const changedValues = prepareMetricUpdateMetric(newMetric, oldMetric);
|
||||
if (changedValues) {
|
||||
updateMetricMutation(changedValues);
|
||||
// updateMetricMutation(changedValues);
|
||||
}
|
||||
}),
|
||||
{ wait: 750 }
|
||||
|
@ -173,32 +168,12 @@ const useBusterMetrics = () => {
|
|||
}
|
||||
);
|
||||
|
||||
const onSaveMetricChanges = useMemoizedFn(
|
||||
async (params: { metricId: string; save_draft: boolean; save_as_metric_state?: string }) => {
|
||||
return updateMetricMutation({
|
||||
id: params.metricId,
|
||||
...params
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const onVerifiedMetric = useMemoizedFn(
|
||||
async ({ metricId, status }: { metricId: string; status: VerificationStatus }) => {
|
||||
return await onUpdateMetric({
|
||||
id: metricId,
|
||||
status
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
getMetricMemoized,
|
||||
onUpdateMetric,
|
||||
onUpdateMetricChartConfig,
|
||||
onUpdateColumnLabelFormat,
|
||||
onUpdateColumnSetting,
|
||||
onSaveMetricChanges,
|
||||
onVerifiedMetric
|
||||
onUpdateColumnSetting
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './BusterPosthogProvider';
|
|
@ -1,8 +1,7 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { MetricViewChartContent } from './MetricViewChartContent';
|
||||
import { MetricViewChartHeader } from './MetricViewChartHeader';
|
||||
import { useMetricIndividual } from '@/api/buster_rest/metrics';
|
||||
import { useBusterMetricsContextSelector } from '@/context/Metrics';
|
||||
import { useMetricIndividual, useUpdateMetric } from '@/api/buster_rest/metrics';
|
||||
import { useMemoizedFn } from '@/hooks';
|
||||
import { inputHasText } from '@/lib/text';
|
||||
import { MetricChartEvaluation } from './MetricChartEvaluation';
|
||||
|
@ -11,7 +10,7 @@ import { AnimatePresence, motion } from 'framer-motion';
|
|||
import { cn } from '@/lib/classMerge';
|
||||
|
||||
export const MetricViewChart: React.FC<{ metricId: string }> = React.memo(({ metricId }) => {
|
||||
const onUpdateMetric = useBusterMetricsContextSelector((x) => x.onUpdateMetric);
|
||||
const { mutateAsync: updateMetric } = useUpdateMetric();
|
||||
const { metric, metricData, metricDataError, isFetchedMetricData } = useMetricIndividual({
|
||||
metricId
|
||||
});
|
||||
|
@ -24,7 +23,8 @@ export const MetricViewChart: React.FC<{ metricId: string }> = React.memo(({ met
|
|||
|
||||
const onSetTitle = useMemoizedFn((title: string) => {
|
||||
if (inputHasText(title)) {
|
||||
onUpdateMetric({
|
||||
updateMetric({
|
||||
id: metricId,
|
||||
title
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import type { MetricViewProps } from '../config';
|
||||
import { CodeCard } from '@/components/ui/card';
|
||||
import { useBusterMetricsContextSelector } from '@/context/Metrics';
|
||||
import { useMemoizedFn } from '@/hooks';
|
||||
import { SaveResetFilePopup } from '@/components/features/popups/SaveResetFilePopup';
|
||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||
import { useMetricIndividual } from '@/api/buster_rest/metrics';
|
||||
import { useMetricIndividual, useUpdateMetric } from '@/api/buster_rest/metrics';
|
||||
|
||||
export const MetricViewFile: React.FC<MetricViewProps> = React.memo(({ metricId }) => {
|
||||
const { metric } = useMetricIndividual({ metricId });
|
||||
const { openSuccessMessage } = useBusterNotifications();
|
||||
const onUpdateMetric = useBusterMetricsContextSelector((x) => x.onUpdateMetric);
|
||||
const { mutateAsync: updateMetric } = useUpdateMetric();
|
||||
|
||||
const { file: fileProp, file_name } = metric;
|
||||
|
||||
|
@ -23,8 +22,9 @@ export const MetricViewFile: React.FC<MetricViewProps> = React.memo(({ metricId
|
|||
});
|
||||
|
||||
const onSaveFile = useMemoizedFn(async () => {
|
||||
await onUpdateMetric({
|
||||
file
|
||||
await updateMetric({
|
||||
file,
|
||||
id: metricId
|
||||
});
|
||||
openSuccessMessage(`${file_name} saved`);
|
||||
});
|
||||
|
|
|
@ -8,14 +8,13 @@ import { useQueryClient } from '@tanstack/react-query';
|
|||
import { useRef, useState } from 'react';
|
||||
import { didColumnDataChange, simplifyChatConfigForSQLChange } from './helpers';
|
||||
import { useRunSQL as useRunSQLQuery } from '@/api/buster_rest';
|
||||
import { useUpdateMetric } from '@/api/buster_rest/metrics';
|
||||
import { useSaveMetric, useUpdateMetric } from '@/api/buster_rest/metrics';
|
||||
|
||||
export const useMetricRunSQL = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const onUpdateMetric = useBusterMetricsContextSelector((x) => x.onUpdateMetric);
|
||||
const getMetricMemoized = useBusterMetricsContextSelector((x) => x.getMetricMemoized);
|
||||
const onSaveMetricChanges = useBusterMetricsContextSelector((x) => x.onSaveMetricChanges);
|
||||
const { mutateAsync: updateMetricMutation } = useUpdateMetric();
|
||||
const { mutateAsync: saveMetric } = useSaveMetric();
|
||||
const { mutateAsync: runSQLMutation } = useRunSQLQuery();
|
||||
const { openSuccessNotification } = useBusterNotifications();
|
||||
|
||||
|
@ -88,7 +87,7 @@ export const useMetricRunSQL = () => {
|
|||
data_metadata,
|
||||
code: sql
|
||||
});
|
||||
onUpdateMetric({
|
||||
updateMetricMutation({
|
||||
id: metricId,
|
||||
chart_config: totallyDefaultChartConfig
|
||||
});
|
||||
|
@ -121,7 +120,7 @@ export const useMetricRunSQL = () => {
|
|||
setWarnBeforeNavigating(false);
|
||||
if (!originalConfigs.current) return;
|
||||
const oldConfig = originalConfigs.current?.chartConfig;
|
||||
onUpdateMetric({
|
||||
updateMetricMutation({
|
||||
id: metricId,
|
||||
chart_config: oldConfig
|
||||
});
|
||||
|
@ -161,14 +160,10 @@ export const useMetricRunSQL = () => {
|
|||
}
|
||||
}
|
||||
|
||||
await updateMetricMutation({
|
||||
await saveMetric({
|
||||
id: metricId,
|
||||
sql: sql
|
||||
});
|
||||
await onSaveMetricChanges({
|
||||
metricId,
|
||||
save_draft: true,
|
||||
save_as_metric_state: metricId
|
||||
sql: sql,
|
||||
save_draft: true
|
||||
});
|
||||
|
||||
setWarnBeforeNavigating(false);
|
||||
|
|
|
@ -14,7 +14,8 @@ import { Dots, Star, Trash, Xmark } from '@/components/ui/icons';
|
|||
import {
|
||||
useDeleteMetric,
|
||||
useRemoveMetricFromCollection,
|
||||
useSaveMetricToCollection
|
||||
useSaveMetricToCollection,
|
||||
useUpdateMetric
|
||||
} from '@/api/buster_rest/metrics';
|
||||
import {
|
||||
useAddUserFavorite,
|
||||
|
@ -130,11 +131,18 @@ const StatusButton: React.FC<{
|
|||
selectedRowKeys: string[];
|
||||
onSelectChange: (selectedRowKeys: string[]) => void;
|
||||
}> = ({ selectedRowKeys, onSelectChange }) => {
|
||||
const onVerifiedMetric = useBusterMetricsContextSelector((state) => state.onVerifiedMetric);
|
||||
const { mutateAsync: updateMetric } = useUpdateMetric();
|
||||
const isAdmin = useUserConfigContextSelector((state) => state.isAdmin);
|
||||
|
||||
const onVerify = useMemoizedFn(async (d: { id: string; status: VerificationStatus }[]) => {
|
||||
// await onVerifiedMetric(d);
|
||||
await Promise.all(
|
||||
d.map(({ id, status }) => {
|
||||
return updateMetric({
|
||||
id,
|
||||
status
|
||||
});
|
||||
})
|
||||
);
|
||||
onSelectChange([]);
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue