mirror of https://github.com/buster-so/buster.git
prefetch list if a name change
This commit is contained in:
parent
87b0f55157
commit
e70d68d9ea
|
@ -11,7 +11,7 @@ import { queryKeys } from '@/api/query_keys';
|
|||
import type { RustApiError } from '../errors';
|
||||
import type {
|
||||
GetReportIndividualResponse,
|
||||
UpdateReportRequest,
|
||||
GetReportsListResponse,
|
||||
UpdateReportResponse
|
||||
} from '@buster/server-shared/reports';
|
||||
import {
|
||||
|
@ -21,6 +21,7 @@ import {
|
|||
getReportById_server,
|
||||
updateReport
|
||||
} from './requests';
|
||||
import { useDebounceFn } from '@/hooks/useDebounce';
|
||||
|
||||
/**
|
||||
* Hook to get a list of reports
|
||||
|
@ -61,6 +62,20 @@ export const prefetchGetReportsList = async (
|
|||
return queryClient;
|
||||
};
|
||||
|
||||
export const prefetchGetReportsListClient = async (
|
||||
params?: Parameters<typeof getReportsList>[0],
|
||||
queryClientProp?: QueryClient
|
||||
) => {
|
||||
const queryClient = queryClientProp || new QueryClient();
|
||||
|
||||
await queryClient.prefetchQuery({
|
||||
...queryKeys.reportsGetList(params),
|
||||
queryFn: () => getReportsList(params)
|
||||
});
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to get an individual report by ID
|
||||
*/
|
||||
|
@ -107,11 +122,11 @@ export const useUpdateReport = () => {
|
|||
return useMutation<
|
||||
UpdateReportResponse,
|
||||
RustApiError,
|
||||
{ reportId: string; data: UpdateReportRequest },
|
||||
Parameters<typeof updateReport>[0],
|
||||
{ previousReport?: GetReportIndividualResponse }
|
||||
>({
|
||||
mutationFn: ({ reportId, data }) => updateReport(reportId, data),
|
||||
onMutate: async ({ reportId, data }) => {
|
||||
mutationFn: updateReport,
|
||||
onMutate: async ({ reportId, ...data }) => {
|
||||
// Cancel any outgoing refetches
|
||||
await queryClient.cancelQueries({
|
||||
queryKey: queryKeys.reportsGetReport(reportId).queryKey
|
||||
|
@ -145,18 +160,32 @@ export const useUpdateReport = () => {
|
|||
);
|
||||
}
|
||||
},
|
||||
onSuccess: (data, { reportId, data: updateData }) => {
|
||||
onSuccess: (data, { reportId, ...updateData }, ctx) => {
|
||||
// Update the individual report cache with server response
|
||||
queryClient.setQueryData(queryKeys.reportsGetReport(reportId).queryKey, data);
|
||||
|
||||
const nameChanged = updateData.name !== undefined && updateData.name !== data.name;
|
||||
const nameChanged =
|
||||
updateData.name !== undefined &&
|
||||
ctx?.previousReport?.name !== undefined &&
|
||||
updateData.name !== ctx?.previousReport?.name;
|
||||
|
||||
// Invalidate the list cache to ensure it's fresh
|
||||
if (nameChanged) {
|
||||
const listQueryKey = queryKeys.reportsGetList().queryKey;
|
||||
const hasActiveQuery = queryClient.getQueryCache().find({
|
||||
queryKey: listQueryKey,
|
||||
exact: true,
|
||||
type: 'active'
|
||||
});
|
||||
|
||||
if (hasActiveQuery) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.reportsGetList().queryKey,
|
||||
queryKey: listQueryKey,
|
||||
refetchType: 'all'
|
||||
});
|
||||
} else {
|
||||
prefetchGetReportsListClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -50,6 +50,9 @@ export const getReportById_server = async (reportId: string) => {
|
|||
/**
|
||||
* Update a report
|
||||
*/
|
||||
export const updateReport = async (reportId: string, data: UpdateReportRequest) => {
|
||||
export const updateReport = async ({
|
||||
reportId,
|
||||
...data
|
||||
}: UpdateReportRequest & { reportId: string }) => {
|
||||
return mainApiV2.put<UpdateReportResponse>(`/reports/${reportId}`, data).then((res) => res.data);
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//import { ReportsListController } from '@/controllers/ReportsListController';
|
||||
import { ReportPageController } from '@/controllers/ReportPageControllers/ReportPageController';
|
||||
|
||||
export default async function Page(props: { params: Promise<{ reportId: string }> }) {
|
||||
const params = await props.params;
|
||||
|
||||
const { reportId } = params;
|
||||
|
||||
return <div>Report with an id of {reportId}</div>;
|
||||
return <ReportPageController reportId={reportId} />;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
'use client';
|
||||
|
||||
import {
|
||||
prefetchGetReportsListClient,
|
||||
useGetReport,
|
||||
useGetReportsList,
|
||||
useUpdateReport
|
||||
} from '@/api/buster_rest/reports';
|
||||
import { cn } from '@/lib/utils';
|
||||
import React from 'react';
|
||||
import { ReportPageHeader } from './ReportPageHeader';
|
||||
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
|
||||
import { useDebounceFn } from '@/hooks/useDebounce';
|
||||
|
||||
export const ReportPageController: React.FC<{
|
||||
reportId: string;
|
||||
readOnly?: boolean;
|
||||
className?: string;
|
||||
}> = ({ reportId, readOnly = false, className = '' }) => {
|
||||
const { data: report } = useGetReport({ reportId, versionNumber: undefined });
|
||||
|
||||
const { mutate: updateReport } = useUpdateReport();
|
||||
|
||||
const onChangeName = useMemoizedFn((name: string) => {
|
||||
updateReport({ reportId, name });
|
||||
});
|
||||
|
||||
const { run: debouncedUpdateReport } = useDebounceFn(updateReport, { wait: 300 });
|
||||
|
||||
return (
|
||||
<div className={cn('space-y-1.5 pt-9 pb-6 sm:px-[max(64px,calc(50%-350px))]', className)}>
|
||||
<ReportPageHeader
|
||||
name={report?.name}
|
||||
updatedAt={report?.updated_at}
|
||||
onChangeName={onChangeName}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { formatDate } from '@/lib/date';
|
||||
import { EditableTitle } from '@/components/ui/typography/EditableTitle';
|
||||
import { Paragraph } from '@/components/ui/typography/Paragraph';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const DEFAULT_CREATED_BY = 'Created by Buster';
|
||||
|
||||
export const ReportPageHeader = React.forwardRef<
|
||||
HTMLInputElement,
|
||||
{
|
||||
className?: string;
|
||||
name?: string;
|
||||
updatedAt?: string;
|
||||
onChangeName: (name: string) => void;
|
||||
}
|
||||
>(({ name = '', updatedAt = '', className = '', onChangeName }, ref) => {
|
||||
const updatedAtFormatted = useMemo(() => {
|
||||
if (!updatedAt) return '';
|
||||
return formatDate({ date: updatedAt, format: 'll' });
|
||||
}, [updatedAt]);
|
||||
|
||||
return (
|
||||
<div className={cn('flex flex-col space-y-1.5', className)}>
|
||||
<EditableTitle className="h-9" level={1} ref={ref} onChange={onChangeName}>
|
||||
{name}
|
||||
</EditableTitle>
|
||||
<Paragraph size={'base'} variant={'tertiary'}>
|
||||
{updatedAtFormatted} • {DEFAULT_CREATED_BY}
|
||||
</Paragraph>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
ReportPageHeader.displayName = 'ReportPageHeader';
|
|
@ -0,0 +1 @@
|
|||
export * from './ReportPageController';
|
Loading…
Reference in New Issue