mirror of https://github.com/buster-so/buster.git
add linking
This commit is contained in:
parent
08d7014725
commit
46f812d823
|
@ -65,16 +65,19 @@ export const prefetchGetReportsList = async (
|
||||||
/**
|
/**
|
||||||
* Hook to get an individual report by ID
|
* Hook to get an individual report by ID
|
||||||
*/
|
*/
|
||||||
export const useGetReport = (
|
export const useGetReport = <T = GetReportIndividualResponse>(
|
||||||
reportId: string | undefined,
|
reportId: string | undefined,
|
||||||
options?: Omit<UseQueryOptions<GetReportIndividualResponse, RustApiError>, 'queryKey' | 'queryFn'>
|
options?: Omit<
|
||||||
|
UseQueryOptions<GetReportIndividualResponse, RustApiError, T>,
|
||||||
|
'queryKey' | 'queryFn'
|
||||||
|
>
|
||||||
) => {
|
) => {
|
||||||
const queryFn = useMemoizedFn(() => {
|
const queryFn = useMemoizedFn(() => {
|
||||||
return getReportById(reportId!);
|
return getReportById(reportId!);
|
||||||
});
|
});
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
...queryKeys.reportsGetById(reportId!),
|
...queryKeys.reportsGetReport(reportId!),
|
||||||
queryFn,
|
queryFn,
|
||||||
enabled: !!reportId,
|
enabled: !!reportId,
|
||||||
select: options?.select,
|
select: options?.select,
|
||||||
|
@ -89,7 +92,7 @@ export const prefetchGetReportById = async (reportId: string, queryClientProp?:
|
||||||
const queryClient = queryClientProp || new QueryClient();
|
const queryClient = queryClientProp || new QueryClient();
|
||||||
|
|
||||||
await queryClient.prefetchQuery({
|
await queryClient.prefetchQuery({
|
||||||
...queryKeys.reportsGetById(reportId),
|
...queryKeys.reportsGetReport(reportId),
|
||||||
queryFn: () => getReportById_server(reportId)
|
queryFn: () => getReportById_server(reportId)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -112,18 +115,18 @@ export const useUpdateReport = () => {
|
||||||
onMutate: async ({ reportId, data }) => {
|
onMutate: async ({ reportId, data }) => {
|
||||||
// Cancel any outgoing refetches
|
// Cancel any outgoing refetches
|
||||||
await queryClient.cancelQueries({
|
await queryClient.cancelQueries({
|
||||||
queryKey: queryKeys.reportsGetById(reportId).queryKey
|
queryKey: queryKeys.reportsGetReport(reportId).queryKey
|
||||||
});
|
});
|
||||||
|
|
||||||
// Snapshot the previous value
|
// Snapshot the previous value
|
||||||
const previousReport = queryClient.getQueryData<GetReportIndividualResponse>(
|
const previousReport = queryClient.getQueryData<GetReportIndividualResponse>(
|
||||||
queryKeys.reportsGetById(reportId).queryKey
|
queryKeys.reportsGetReport(reportId).queryKey
|
||||||
);
|
);
|
||||||
|
|
||||||
// Optimistically update the individual report
|
// Optimistically update the individual report
|
||||||
if (previousReport) {
|
if (previousReport) {
|
||||||
queryClient.setQueryData(
|
queryClient.setQueryData(
|
||||||
queryKeys.reportsGetById(reportId).queryKey,
|
queryKeys.reportsGetReport(reportId).queryKey,
|
||||||
create(previousReport, (draft) => {
|
create(previousReport, (draft) => {
|
||||||
if (data.name !== undefined) draft.name = data.name;
|
if (data.name !== undefined) draft.name = data.name;
|
||||||
if (data.description !== undefined) draft.description = data.description;
|
if (data.description !== undefined) draft.description = data.description;
|
||||||
|
@ -141,14 +144,14 @@ export const useUpdateReport = () => {
|
||||||
// If the mutation fails, use the context to roll back
|
// If the mutation fails, use the context to roll back
|
||||||
if (context?.previousReport) {
|
if (context?.previousReport) {
|
||||||
queryClient.setQueryData(
|
queryClient.setQueryData(
|
||||||
queryKeys.reportsGetById(reportId).queryKey,
|
queryKeys.reportsGetReport(reportId).queryKey,
|
||||||
context.previousReport
|
context.previousReport
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSuccess: (data, { reportId, data: updateData }) => {
|
onSuccess: (data, { reportId, data: updateData }) => {
|
||||||
// Update the individual report cache with server response
|
// Update the individual report cache with server response
|
||||||
queryClient.setQueryData(queryKeys.reportsGetById(reportId).queryKey, data);
|
queryClient.setQueryData(queryKeys.reportsGetReport(reportId).queryKey, data);
|
||||||
|
|
||||||
const nameChanged = updateData.name !== undefined && updateData.name !== data.name;
|
const nameChanged = updateData.name !== undefined && updateData.name !== data.name;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ const reportsGetList = (filters?: GetReportsListRequest) =>
|
||||||
initialDataUpdatedAt: 0
|
initialDataUpdatedAt: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
const reportsGetById = (reportId: string) =>
|
const reportsGetReport = (reportId: string) =>
|
||||||
queryOptions<GetReportIndividualResponse>({
|
queryOptions<GetReportIndividualResponse>({
|
||||||
queryKey: ['reports', 'get', reportId] as const,
|
queryKey: ['reports', 'get', reportId] as const,
|
||||||
staleTime: 60 * 1000 // 60 seconds
|
staleTime: 60 * 1000 // 60 seconds
|
||||||
|
@ -21,5 +21,5 @@ const reportsGetById = (reportId: string) =>
|
||||||
|
|
||||||
export const reportsQueryKeys = {
|
export const reportsQueryKeys = {
|
||||||
reportsGetList,
|
reportsGetList,
|
||||||
reportsGetById
|
reportsGetReport
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import type { ContextMenuProps } from '../../context-menu/ContextMenu';
|
import type { ContextMenuProps } from '../../context-menu/ContextMenu';
|
||||||
import { BusterList } from './index';
|
import { BusterList } from './index';
|
||||||
import type { BusterListRow } from './interfaces';
|
import type { BusterListColumn, BusterListRow } from './interfaces';
|
||||||
|
|
||||||
const meta: Meta<typeof BusterList> = {
|
const meta: Meta<typeof BusterList> = {
|
||||||
title: 'UI/List/BusterList',
|
title: 'UI/List/BusterList',
|
||||||
|
@ -33,10 +33,19 @@ const meta: Meta<typeof BusterList> = {
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
|
|
||||||
type Story = StoryObj<typeof BusterList>;
|
// Define the data type for our rows
|
||||||
|
type SampleData = {
|
||||||
|
name: string;
|
||||||
|
age: number;
|
||||||
|
address?: string;
|
||||||
|
email?: string;
|
||||||
|
actions?: any; // For the actions column
|
||||||
|
};
|
||||||
|
|
||||||
|
type Story = StoryObj<typeof BusterList<SampleData>>;
|
||||||
|
|
||||||
// Sample data for the stories
|
// Sample data for the stories
|
||||||
const sampleColumns = [
|
const sampleColumns: BusterListColumn<SampleData>[] = [
|
||||||
{
|
{
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
title: 'Name',
|
title: 'Name',
|
||||||
|
@ -51,7 +60,9 @@ const sampleColumns = [
|
||||||
dataIndex: 'actions',
|
dataIndex: 'actions',
|
||||||
title: 'Actions',
|
title: 'Actions',
|
||||||
width: 100,
|
width: 100,
|
||||||
render: (_: any, record: any) => <button className="text-blue-500 hover:underline">View</button>
|
render: (_: any, record: SampleData) => (
|
||||||
|
<button className="text-blue-500 hover:underline">View</button>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,11 @@ const useBusterAssets = () => {
|
||||||
queryKey: queryKeys.chatsGetChat(assetId).queryKey,
|
queryKey: queryKeys.chatsGetChat(assetId).queryKey,
|
||||||
refetchType: 'all'
|
refetchType: 'all'
|
||||||
});
|
});
|
||||||
|
} else if (type === 'report') {
|
||||||
|
await queryClient.invalidateQueries({
|
||||||
|
queryKey: queryKeys.reportsGetReport(assetId).queryKey,
|
||||||
|
refetchType: 'all'
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
const exhaustiveCheck: never = type;
|
const exhaustiveCheck: never = type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,6 +167,9 @@ export const useGetAsset = (
|
||||||
isError: reportIsError,
|
isError: reportIsError,
|
||||||
showLoader: !reportIsFetched && !reportIsError
|
showLoader: !reportIsFetched && !reportIsError
|
||||||
};
|
};
|
||||||
|
case 'chat':
|
||||||
|
// Chat type is not supported in this hook
|
||||||
|
return { isFetched: true, error: null, isError: false, showLoader: false };
|
||||||
default: {
|
default: {
|
||||||
const exhaustiveCheck: never = props.type;
|
const exhaustiveCheck: never = props.type;
|
||||||
return { isFetched: false, error: null, isError: false, showLoader: false };
|
return { isFetched: false, error: null, isError: false, showLoader: false };
|
||||||
|
@ -182,15 +185,28 @@ export const useGetAsset = (
|
||||||
dashboardIsError,
|
dashboardIsError,
|
||||||
collectionIsFetched,
|
collectionIsFetched,
|
||||||
collectionError,
|
collectionError,
|
||||||
collectionIsError
|
collectionIsError,
|
||||||
|
reportIsFetched,
|
||||||
|
reportError,
|
||||||
|
reportIsError
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const title = useMemo(() => {
|
const title = useMemo(() => {
|
||||||
if (isMetric) return metricTitle;
|
if (isMetric) return metricTitle;
|
||||||
if (isDashboard) return dashboardTitle;
|
if (isDashboard) return dashboardTitle;
|
||||||
if (isCollection) return collectionTitle;
|
if (isCollection) return collectionTitle;
|
||||||
|
if (isReport) return reportTitle;
|
||||||
return undefined;
|
return undefined;
|
||||||
}, [isMetric, isDashboard, isCollection, metricTitle, dashboardTitle, collectionTitle]);
|
}, [
|
||||||
|
isMetric,
|
||||||
|
isDashboard,
|
||||||
|
isCollection,
|
||||||
|
isReport,
|
||||||
|
metricTitle,
|
||||||
|
dashboardTitle,
|
||||||
|
collectionTitle,
|
||||||
|
reportTitle
|
||||||
|
]);
|
||||||
|
|
||||||
const { hasAccess, passwordRequired, isPublic } = getAssetAccess(currentQuery.error);
|
const { hasAccess, passwordRequired, isPublic } = getAssetAccess(currentQuery.error);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,12 @@ export const CreateChatButton = React.memo(
|
||||||
dashboardId: assetId,
|
dashboardId: assetId,
|
||||||
chatId: result.id
|
chatId: result.id
|
||||||
});
|
});
|
||||||
|
} else if (assetType === 'report') {
|
||||||
|
await onChangePage({
|
||||||
|
route: BusterRoutes.APP_CHAT_ID_REPORT_ID,
|
||||||
|
reportId: assetId,
|
||||||
|
chatId: result.id
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
const _exhaustiveCheck: never = assetType;
|
const _exhaustiveCheck: never = assetType;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { createMetricRoute, type MetricRouteParams } from './createMetricRoute';
|
||||||
import { createDashboardRoute, type DashboardRouteParams } from './createDashboardRoute';
|
import { createDashboardRoute, type DashboardRouteParams } from './createDashboardRoute';
|
||||||
import { createReasoningRoute } from './createReasoningRoute';
|
import { createReasoningRoute } from './createReasoningRoute';
|
||||||
import { createDatasetRoute } from './createDatasetRoute';
|
import { createDatasetRoute } from './createDatasetRoute';
|
||||||
|
import { createReportRoute } from './createReportRoute';
|
||||||
|
|
||||||
type UnionOfFileTypes = FileType | ReasoningFileType | ReasoingMessage_ThoughtFileType;
|
type UnionOfFileTypes = FileType | ReasoningFileType | ReasoingMessage_ThoughtFileType;
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ type OtherRouteParams = {
|
||||||
dashboardVersionNumber?: number; //if this is provided, it will be used instead of versionNumber
|
dashboardVersionNumber?: number; //if this is provided, it will be used instead of versionNumber
|
||||||
page?: undefined;
|
page?: undefined;
|
||||||
secondaryView?: undefined | null | string;
|
secondaryView?: undefined | null | string;
|
||||||
type: Exclude<UnionOfFileTypes, 'metric' | 'dashboard'>;
|
type: UnionOfFileTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
type BaseParams = MetricRouteParams | DashboardRouteParams | OtherRouteParams;
|
type BaseParams = MetricRouteParams | DashboardRouteParams | OtherRouteParams;
|
||||||
|
@ -73,6 +74,13 @@ export const assetParamsToRoute = ({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === 'report') {
|
||||||
|
return createReportRoute({
|
||||||
|
assetId,
|
||||||
|
chatId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (type === 'reasoning') {
|
if (type === 'reasoning') {
|
||||||
return createReasoningRoute({
|
return createReasoningRoute({
|
||||||
assetId,
|
assetId,
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { BusterRoutes, createBusterRoute } from '@/routes/busterRoutes';
|
||||||
|
|
||||||
|
export type ReportRouteParams = {
|
||||||
|
assetId: string;
|
||||||
|
chatId?: string;
|
||||||
|
type: 'report';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createReportRoute = ({
|
||||||
|
assetId: reportId,
|
||||||
|
chatId
|
||||||
|
}: Omit<ReportRouteParams, 'type'>) => {
|
||||||
|
// Report routes within a chat context
|
||||||
|
if (chatId) {
|
||||||
|
return createBusterRoute({
|
||||||
|
route: BusterRoutes.APP_CHAT_ID_REPORT_ID,
|
||||||
|
chatId,
|
||||||
|
reportId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standalone report route
|
||||||
|
return createBusterRoute({
|
||||||
|
route: BusterRoutes.APP_REPORTS_ID,
|
||||||
|
reportId
|
||||||
|
});
|
||||||
|
};
|
|
@ -29,7 +29,7 @@ const ResponseMessage_FileMetadataSchema = z.object({
|
||||||
timestamp: z.number().optional(),
|
timestamp: z.number().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const ResponseMessageFileTypeSchema = z.enum(['metric', 'dashboard', 'reasoning']);
|
const ResponseMessageFileTypeSchema = z.enum(['metric', 'dashboard', 'reasoning', 'report']);
|
||||||
|
|
||||||
const ResponseMessage_FileSchema = z.object({
|
const ResponseMessage_FileSchema = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
|
@ -59,6 +59,7 @@ const ReasoningMessage_TextSchema = z.object({
|
||||||
const ReasoningFileTypeSchema = z.enum([
|
const ReasoningFileTypeSchema = z.enum([
|
||||||
'metric',
|
'metric',
|
||||||
'dashboard',
|
'dashboard',
|
||||||
|
'report',
|
||||||
'reasoning',
|
'reasoning',
|
||||||
'agent-action',
|
'agent-action',
|
||||||
'todo',
|
'todo',
|
||||||
|
|
Loading…
Reference in New Issue