mirror of https://github.com/buster-so/buster.git
Merge branch 'staging' into big-nate-bus-1815-pulled-in-reports-treated-as-dashboards
This commit is contained in:
commit
e23fa1184c
|
@ -310,7 +310,7 @@ export const useAddAndRemoveAssetsFromCollection = () => {
|
|||
const addAndRemoveAssetsToCollection = async (variables: {
|
||||
collectionId: string;
|
||||
assets: {
|
||||
type: Exclude<ShareAssetType, 'collection'>;
|
||||
type: ShareAssetType;
|
||||
id: string;
|
||||
}[];
|
||||
}) => {
|
||||
|
|
|
@ -108,7 +108,7 @@ export const addAssetToCollection = async ({
|
|||
}: {
|
||||
id: string;
|
||||
assets: {
|
||||
type: Exclude<ShareAssetType, 'collection'>;
|
||||
type: ShareAssetType;
|
||||
id: string;
|
||||
}[];
|
||||
}) => {
|
||||
|
|
|
@ -18,6 +18,8 @@ import { useDebounce } from '@/hooks/useDebounce';
|
|||
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
|
||||
import { formatDate } from '@/lib/date';
|
||||
|
||||
type SelectedAsset = { id: string; type: ShareAssetType };
|
||||
|
||||
export const AddToCollectionModal: React.FC<{
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
|
@ -35,7 +37,10 @@ export const AddToCollectionModal: React.FC<{
|
|||
num_results: 100,
|
||||
});
|
||||
|
||||
const [selectedAssets, setSelectedAssets] = useState<string[]>([]);
|
||||
const [selectedAssets, setSelectedAssets] = useState<SelectedAsset[]>([]);
|
||||
const selectedAssetIds = useMemo(() => {
|
||||
return selectedAssets.map((asset) => asset.id);
|
||||
}, [selectedAssets]);
|
||||
|
||||
const columns = useMemo<InputSelectModalProps<BusterSearchResult>['columns']>(
|
||||
() => [
|
||||
|
@ -78,46 +83,48 @@ export const AddToCollectionModal: React.FC<{
|
|||
);
|
||||
}, [searchResults]);
|
||||
|
||||
const handleAddAndRemoveMetrics = useMemoizedFn(async () => {
|
||||
const keyedAssets = rows.reduce<
|
||||
Record<string, { type: Exclude<ShareAssetType, 'collection'>; id: string }>
|
||||
>((acc, asset) => {
|
||||
if (asset.data?.type && asset.data?.type !== 'collection') {
|
||||
acc[asset.id] = { type: asset.data?.type, id: asset.id };
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
const createKeySearchResultMap = useMemoizedFn(() => {
|
||||
const map = new Map<string, SelectedAsset>();
|
||||
rows.forEach((asset) => {
|
||||
if (asset.data?.type) map.set(asset.id, { type: asset.data?.type, id: asset.id });
|
||||
});
|
||||
return map;
|
||||
});
|
||||
|
||||
const assets = selectedAssets.map<{
|
||||
type: Exclude<ShareAssetType, 'collection'>;
|
||||
id: string;
|
||||
}>((asset) => ({
|
||||
id: asset,
|
||||
type: keyedAssets[asset].type,
|
||||
}));
|
||||
const handleAddAndRemoveMetrics = useMemoizedFn(async () => {
|
||||
await addAndRemoveAssetsFromCollection({
|
||||
collectionId,
|
||||
assets,
|
||||
assets: selectedAssets,
|
||||
});
|
||||
onClose();
|
||||
});
|
||||
|
||||
const handleSelectChange = useMemoizedFn((assets: string[]) => {
|
||||
const selectedAssets: SelectedAsset[] = [];
|
||||
const keySearchResultMap = createKeySearchResultMap();
|
||||
assets.forEach((assetId) => {
|
||||
const asset = keySearchResultMap.get(assetId);
|
||||
if (asset) selectedAssets.push({ id: assetId, type: asset.type });
|
||||
});
|
||||
setSelectedAssets(selectedAssets);
|
||||
});
|
||||
|
||||
const originalIds = useMemo(() => {
|
||||
return collection?.assets?.map((asset) => asset.id) || [];
|
||||
}, [collection?.assets]);
|
||||
|
||||
const isSelectedChanged = useMemo(() => {
|
||||
const newIds = selectedAssets;
|
||||
const newIds = selectedAssetIds;
|
||||
return originalIds.length !== newIds.length || originalIds.some((id) => !newIds.includes(id));
|
||||
}, [originalIds, selectedAssets]);
|
||||
}, [originalIds, selectedAssetIds]);
|
||||
|
||||
const removedAssetCount = useMemo(() => {
|
||||
return originalIds.filter((id) => !selectedAssets.includes(id)).length;
|
||||
}, [originalIds, selectedAssets]);
|
||||
return originalIds.filter((id) => !selectedAssetIds.includes(id)).length;
|
||||
}, [originalIds, selectedAssetIds]);
|
||||
|
||||
const addedAssetCount = useMemo(() => {
|
||||
return selectedAssets.filter((id) => !originalIds.includes(id)).length;
|
||||
}, [originalIds, selectedAssets]);
|
||||
return selectedAssetIds.filter((id) => !originalIds.includes(id)).length;
|
||||
}, [originalIds, selectedAssetIds]);
|
||||
|
||||
const primaryButtonText = useMemo(() => {
|
||||
if (!isFetchedCollection) {
|
||||
|
@ -202,8 +209,11 @@ export const AddToCollectionModal: React.FC<{
|
|||
|
||||
useLayoutEffect(() => {
|
||||
if (isFetchedCollection) {
|
||||
const assets = collection?.assets?.map((asset) => asset.id) || [];
|
||||
setSelectedAssets(assets);
|
||||
const assets = collection?.assets?.map((asset) => ({
|
||||
id: asset.id,
|
||||
type: asset.asset_type,
|
||||
}));
|
||||
setSelectedAssets(assets || []);
|
||||
}
|
||||
}, [isFetchedCollection, collection?.assets]);
|
||||
|
||||
|
@ -214,8 +224,8 @@ export const AddToCollectionModal: React.FC<{
|
|||
onClose={onClose}
|
||||
columns={columns}
|
||||
rows={rows}
|
||||
onSelectChange={setSelectedAssets}
|
||||
selectedRowKeys={selectedAssets}
|
||||
onSelectChange={handleSelectChange}
|
||||
selectedRowKeys={selectedAssetIds}
|
||||
footer={footer}
|
||||
emptyState={emptyState}
|
||||
searchText={searchTerm}
|
||||
|
|
|
@ -17,7 +17,7 @@ const useSupabaseContextInternal = ({ supabaseSession }: SupabaseContextType) =>
|
|||
const refreshTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
||||
const busterUser = useGetUserBasicInfo();
|
||||
const [supabaseUser, setSupabaseUser] = useState<null | User>(null);
|
||||
const [accessToken, setAccessToken] = useState(supabaseSession?.accessToken);
|
||||
const [accessToken, setAccessToken] = useState(supabaseSession?.accessToken || '');
|
||||
|
||||
const isAnonymousUser: boolean = !busterUser?.id || supabaseUser?.is_anonymous === true;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { ModelMessage } from 'ai';
|
||||
import { and, eq, isNull } from 'drizzle-orm';
|
||||
import { and, eq, isNull, lte } from 'drizzle-orm';
|
||||
import { z } from 'zod';
|
||||
import { db } from '../../connection';
|
||||
import { messages } from '../../schema';
|
||||
|
@ -244,13 +244,14 @@ function convertToolResultPart(part: unknown): unknown | unknown[] | null {
|
|||
return part;
|
||||
}
|
||||
|
||||
// Helper function to get chatId from messageId
|
||||
async function getChatIdFromMessage(messageId: string): Promise<string> {
|
||||
let messageResult: Array<{ chatId: string }>;
|
||||
// Helper function to get chatId and createdAt from messageId
|
||||
async function getMessageInfo(messageId: string): Promise<{ chatId: string; createdAt: string }> {
|
||||
let messageResult: Array<{ chatId: string; createdAt: string }>;
|
||||
try {
|
||||
messageResult = await db
|
||||
.select({
|
||||
chatId: messages.chatId,
|
||||
createdAt: messages.createdAt,
|
||||
})
|
||||
.from(messages)
|
||||
.where(and(eq(messages.id, messageId), isNull(messages.deletedAt)))
|
||||
|
@ -266,11 +267,14 @@ async function getChatIdFromMessage(messageId: string): Promise<string> {
|
|||
throw new Error('Message not found or has been deleted');
|
||||
}
|
||||
|
||||
return messageRow.chatId;
|
||||
return messageRow;
|
||||
}
|
||||
|
||||
// Helper function to get all messages for a chat
|
||||
async function getAllMessagesForChat(chatId: string): Promise<
|
||||
// Helper function to get messages for a chat up to a specific timestamp
|
||||
async function getMessagesUpToTimestamp(
|
||||
chatId: string,
|
||||
upToTimestamp: string
|
||||
): Promise<
|
||||
Array<{
|
||||
id: string;
|
||||
rawLlmMessages: unknown;
|
||||
|
@ -293,7 +297,13 @@ async function getAllMessagesForChat(chatId: string): Promise<
|
|||
isCompleted: messages.isCompleted,
|
||||
})
|
||||
.from(messages)
|
||||
.where(and(eq(messages.chatId, chatId), isNull(messages.deletedAt)))
|
||||
.where(
|
||||
and(
|
||||
eq(messages.chatId, chatId),
|
||||
isNull(messages.deletedAt),
|
||||
lte(messages.createdAt, upToTimestamp)
|
||||
)
|
||||
)
|
||||
.orderBy(messages.createdAt);
|
||||
} catch (dbError) {
|
||||
throw new Error(
|
||||
|
@ -315,9 +325,9 @@ export type ChatConversationHistoryInput = z.infer<typeof ChatConversationHistor
|
|||
export type ChatConversationHistoryOutput = z.infer<typeof ChatConversationHistoryOutputSchema>;
|
||||
|
||||
/**
|
||||
* Get complete conversation history for a chat from any message in that chat
|
||||
* Get conversation history for a chat up to and including a specific message
|
||||
* Finds the chat from the given messageId, then merges and deduplicates all rawLlmMessages
|
||||
* from all messages in the chat to create a complete conversation history
|
||||
* from messages up to and including the specified message to create the conversation history
|
||||
*/
|
||||
export async function getChatConversationHistory(
|
||||
input: ChatConversationHistoryInput
|
||||
|
@ -326,11 +336,11 @@ export async function getChatConversationHistory(
|
|||
// Validate input
|
||||
const validatedInput = ChatConversationHistoryInputSchema.parse(input);
|
||||
|
||||
// Get chatId from messageId
|
||||
const chatId = await getChatIdFromMessage(validatedInput.messageId);
|
||||
// Get chatId and timestamp from messageId
|
||||
const { chatId, createdAt } = await getMessageInfo(validatedInput.messageId);
|
||||
|
||||
// Get all messages for this chat
|
||||
const chatMessages = await getAllMessagesForChat(chatId);
|
||||
// Get all messages for this chat up to and including the current message
|
||||
const chatMessages = await getMessagesUpToTimestamp(chatId, createdAt);
|
||||
|
||||
// Collect all rawLlmMessages from all messages
|
||||
const allRawMessages: unknown[] = [];
|
||||
|
|
Loading…
Reference in New Issue