mirror of https://github.com/buster-so/buster.git
Merge branch 'staging' into cursor/replace-select-with-dropdown-component-39ce
This commit is contained in:
commit
90801c89c4
|
@ -1,23 +1,23 @@
|
||||||
{
|
{
|
||||||
"folders": [
|
"folders": [
|
||||||
{ "path": "./apps/api" },
|
{ "path": "../apps/api" },
|
||||||
{ "path": "./apps/electric-server" },
|
{ "path": "../apps/electric-server" },
|
||||||
{ "path": "./apps/server" },
|
{ "path": "../apps/server" },
|
||||||
{ "path": "./apps/trigger" },
|
{ "path": "../apps/trigger" },
|
||||||
{ "path": "./apps/web" },
|
{ "path": "../apps/web" },
|
||||||
{ "path": "./packages/access-controls" },
|
{ "path": "../packages/access-controls" },
|
||||||
{ "path": "./packages/ai" },
|
{ "path": "../packages/ai" },
|
||||||
{ "path": "./packages/data-source" },
|
{ "path": "../packages/data-source" },
|
||||||
{ "path": "./packages/database" },
|
{ "path": "../packages/database" },
|
||||||
{ "path": "./packages/rerank" },
|
{ "path": "../packages/rerank" },
|
||||||
{ "path": "./packages/server-shared" },
|
{ "path": "../packages/server-shared" },
|
||||||
{ "path": "./packages/slack" },
|
{ "path": "../packages/slack" },
|
||||||
{ "path": "./packages/stored-values" },
|
{ "path": "../packages/stored-values" },
|
||||||
{ "path": "./packages/supabase" },
|
{ "path": "../packages/supabase" },
|
||||||
{ "path": "./packages/test-utils" },
|
{ "path": "../packages/test-utils" },
|
||||||
{ "path": "./packages/typescript-config" },
|
{ "path": "../packages/typescript-config" },
|
||||||
{ "path": "./packages/vitest-config" },
|
{ "path": "../packages/vitest-config" },
|
||||||
{ "path": "./packages/web-tools" }
|
{ "path": "../packages/web-tools" }
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"editor.defaultFormatter": "biomejs.biome",
|
"editor.defaultFormatter": "biomejs.biome",
|
||||||
|
|
|
@ -9,6 +9,39 @@
|
||||||
"typescript.suggest.autoImports": true,
|
"typescript.suggest.autoImports": true,
|
||||||
"typescript.updateImportsOnFileMove.enabled": "always",
|
"typescript.updateImportsOnFileMove.enabled": "always",
|
||||||
|
|
||||||
|
// CRITICAL: Enable TypeScript build mode for project references
|
||||||
|
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
|
"typescript.preferences.preferTypeOnlyAutoImports": true,
|
||||||
|
|
||||||
|
// Force TypeScript to use project references
|
||||||
|
"typescript.tsserver.useSyntaxServer": "never",
|
||||||
|
"typescript.tsserver.experimental.enableProjectDiagnostics": true,
|
||||||
|
|
||||||
|
// MONOREPO CRITICAL: Force real-time checking
|
||||||
|
"typescript.tsserver.watchOptions": {
|
||||||
|
"watchFile": "priorityPollingInterval",
|
||||||
|
"watchDirectory": "dynamicPriorityPolling",
|
||||||
|
"fallbackPolling": "dynamicPriorityPolling",
|
||||||
|
"synchronousWatchDirectory": true,
|
||||||
|
"excludeDirectories": ["**/node_modules", "**/target", "**/.turbo"],
|
||||||
|
"excludeFiles": []
|
||||||
|
},
|
||||||
|
|
||||||
|
// Enable automatic TypeScript build
|
||||||
|
"typescript.tsc.autoDetect": "on",
|
||||||
|
|
||||||
|
// Force TypeScript to track all project references
|
||||||
|
"typescript.tsserver.includeCompletionsForModuleExports": true,
|
||||||
|
"typescript.tsserver.includePackageJsonAutoImports": "on",
|
||||||
|
// CRITICAL: Disable syntax-only mode to get full type checking
|
||||||
|
|
||||||
|
// Increase memory for large monorepo
|
||||||
|
"typescript.tsserver.maxTsServerMemory": 16384,
|
||||||
|
|
||||||
|
// Force restart on config changes
|
||||||
|
"typescript.tsserver.restartOnConfigChange": true,
|
||||||
|
|
||||||
// Ensure dist folders are NEVER excluded from file watching
|
// Ensure dist folders are NEVER excluded from file watching
|
||||||
"files.watcherExclude": {
|
"files.watcherExclude": {
|
||||||
"**/node_modules/**": true,
|
"**/node_modules/**": true,
|
||||||
|
@ -16,6 +49,7 @@
|
||||||
"**/.git/subtree-cache/**": true,
|
"**/.git/subtree-cache/**": true,
|
||||||
"**/target/**": true,
|
"**/target/**": true,
|
||||||
"**/.turbo/**": true
|
"**/.turbo/**": true
|
||||||
|
// NOTE: We explicitly DO NOT exclude dist folders from watching
|
||||||
},
|
},
|
||||||
|
|
||||||
// Exclude dist folders from file explorer (but keep them in watcher)
|
// Exclude dist folders from file explorer (but keep them in watcher)
|
||||||
|
@ -48,7 +82,6 @@
|
||||||
"typescript.check.npmIsInstalled": false,
|
"typescript.check.npmIsInstalled": false,
|
||||||
"typescript.disableAutomaticTypeAcquisition": true,
|
"typescript.disableAutomaticTypeAcquisition": true,
|
||||||
|
|
||||||
|
|
||||||
// Default Biome formatting for all file types
|
// Default Biome formatting for all file types
|
||||||
"[typescript]": {
|
"[typescript]": {
|
||||||
"editor.defaultFormatter": "biomejs.biome"
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Currency } from '@buster/server-shared/currency';
|
import type { Currency, CurrencyResponse } from '@buster/server-shared/currency';
|
||||||
import { Hono } from 'hono';
|
import { Hono } from 'hono';
|
||||||
import { requireAuth } from '../../../middleware/auth';
|
import { requireAuth } from '../../../middleware/auth';
|
||||||
import { CURRENCIES_MAP } from './config';
|
import { CURRENCIES_MAP } from './config';
|
||||||
|
@ -6,7 +6,7 @@ import { CURRENCIES_MAP } from './config';
|
||||||
const app = new Hono();
|
const app = new Hono();
|
||||||
|
|
||||||
app.use('*', requireAuth).get('/', async (c) => {
|
app.use('*', requireAuth).get('/', async (c) => {
|
||||||
return c.json<Currency[]>(CURRENCIES_MAP);
|
return c.json<CurrencyResponse>(CURRENCIES_MAP);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|
|
@ -7,6 +7,8 @@ declare global {
|
||||||
ENVIRONMENT: string;
|
ENVIRONMENT: string;
|
||||||
NODE_ENV?: 'development' | 'production' | 'test';
|
NODE_ENV?: 'development' | 'production' | 'test';
|
||||||
BUSTER_URL: string;
|
BUSTER_URL: string;
|
||||||
|
BUSTER_ALERT_CHANNEL_TOKEN?: string;
|
||||||
|
BUSTER_ALERT_CHANNEL_ID?: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,6 +211,24 @@ export async function sendSlackNotification(
|
||||||
slackMessage
|
slackMessage
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const busterChannelToken = process.env.BUSTER_ALERT_CHANNEL_TOKEN;
|
||||||
|
const busterChannelId = process.env.BUSTER_ALERT_CHANNEL_ID;
|
||||||
|
|
||||||
|
//Step 6: Send Alert To Buster Channel
|
||||||
|
if (busterChannelToken && busterChannelId) {
|
||||||
|
const busterResult = await sendSlackMessage(
|
||||||
|
busterChannelToken,
|
||||||
|
busterChannelId,
|
||||||
|
slackMessage
|
||||||
|
);
|
||||||
|
if (!busterResult.success) {
|
||||||
|
logger.warn('Failed to send alert to Buster channel', {
|
||||||
|
error: busterResult.error,
|
||||||
|
channelId: busterChannelId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
logger.log('Successfully sent Slack notification', {
|
logger.log('Successfully sent Slack notification', {
|
||||||
organizationId: params.organizationId,
|
organizationId: params.organizationId,
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { useShape, useShapeStream } from '../instances';
|
||||||
import { useChatUpdate } from '@/context/Chats/useChatUpdate';
|
import { useChatUpdate } from '@/context/Chats/useChatUpdate';
|
||||||
import { updateMessageShapeToIChatMessage } from './helpers';
|
import { updateMessageShapeToIChatMessage } from './helpers';
|
||||||
import { useMemoizedFn } from '@/hooks';
|
import { useMemoizedFn } from '@/hooks';
|
||||||
import { useGetChatMemoized } from '@/api/buster_rest/chats';
|
import { prefetchGetListChats, useGetChatMemoized } from '@/api/buster_rest/chats';
|
||||||
import uniq from 'lodash/uniq';
|
import uniq from 'lodash/uniq';
|
||||||
|
|
||||||
export const useGetMessage = ({ chatId, messageId }: { chatId: string; messageId: string }) => {
|
export const useGetMessage = ({ chatId, messageId }: { chatId: string; messageId: string }) => {
|
||||||
|
@ -33,6 +33,7 @@ export const useTrackAndUpdateMessageChanges = (
|
||||||
) => {
|
) => {
|
||||||
const { onUpdateChatMessage, onUpdateChat } = useChatUpdate();
|
const { onUpdateChatMessage, onUpdateChat } = useChatUpdate();
|
||||||
const getChatMemoized = useGetChatMemoized();
|
const getChatMemoized = useGetChatMemoized();
|
||||||
|
|
||||||
const shape = useMemo(
|
const shape = useMemo(
|
||||||
() => messageShape({ chatId: chatId || '', messageId }),
|
() => messageShape({ chatId: chatId || '', messageId }),
|
||||||
[chatId, messageId]
|
[chatId, messageId]
|
||||||
|
@ -58,6 +59,10 @@ export const useTrackAndUpdateMessageChanges = (
|
||||||
message_ids: allMessageIds
|
message_ids: allMessageIds
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iChatMessage.is_completed) {
|
||||||
|
prefetchGetListChats()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
callback?.(iChatMessage);
|
callback?.(iChatMessage);
|
||||||
onUpdateChatMessage(iChatMessage);
|
onUpdateChatMessage(iChatMessage);
|
||||||
|
|
|
@ -38,7 +38,7 @@ export const useGetListChats = (
|
||||||
filters?: Omit<Parameters<typeof getListChats>[0], 'page_token' | 'page_size'>
|
filters?: Omit<Parameters<typeof getListChats>[0], 'page_token' | 'page_size'>
|
||||||
) => {
|
) => {
|
||||||
const filtersCompiled: Parameters<typeof getListChats>[0] = useMemo(
|
const filtersCompiled: Parameters<typeof getListChats>[0] = useMemo(
|
||||||
() => ({ admin_view: false, page_token: 0, page_size: 3500, ...filters }),
|
() => ({ admin_view: false, page_token: 0, page_size: 5000, ...filters }),
|
||||||
[filters]
|
[filters]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -6,5 +6,5 @@ export const createNewChat = async (props: ChatCreateRequest) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const stopChat = async ({ chatId }: { chatId: string }) => {
|
export const stopChat = async ({ chatId }: { chatId: string }) => {
|
||||||
return mainApiV2.patch<unknown>(`/chats/${chatId}`, { stop: true }).then((res) => res.data);
|
return mainApiV2.delete<unknown>(`/chats/${chatId}/cancel`).then((res) => res.data);
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,7 +29,7 @@ const chatsGetList = (
|
||||||
filters?: Omit<Parameters<typeof getListChats>[0], 'page_token' | 'page_size'>
|
filters?: Omit<Parameters<typeof getListChats>[0], 'page_token' | 'page_size'>
|
||||||
) =>
|
) =>
|
||||||
queryOptions<ChatListItem[]>({
|
queryOptions<ChatListItem[]>({
|
||||||
queryKey: ['chats', 'list', filters || { page_token: 0, page_size: 3500 }] as const,
|
queryKey: ['chats', 'list', filters || { page_token: 0, page_size: 5000, admin_view: false }] as const,
|
||||||
staleTime: 60 * 1000, // 1 minute
|
staleTime: 60 * 1000, // 1 minute
|
||||||
initialData: [],
|
initialData: [],
|
||||||
initialDataUpdatedAt: 0
|
initialDataUpdatedAt: 0
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { queryOptions } from '@tanstack/react-query';
|
import { queryOptions } from '@tanstack/react-query';
|
||||||
|
import { CurrencyResponse } from '@buster/server-shared/currency';
|
||||||
|
|
||||||
export const getCurrencies = queryOptions<{ code: string; description: string; flag: string }[]>({
|
export const getCurrencies = queryOptions<CurrencyResponse>({
|
||||||
queryKey: ['nextjs', 'list', 'currencies'],
|
queryKey: ['nextjs', 'list', 'currencies'],
|
||||||
initialData: [],
|
initialData: [],
|
||||||
initialDataUpdatedAt: 0,
|
initialDataUpdatedAt: 0,
|
||||||
|
|
|
@ -108,29 +108,25 @@ const SubmitButton: React.FC<{
|
||||||
onSubmitPreflight: () => void;
|
onSubmitPreflight: () => void;
|
||||||
onStop?: () => void;
|
onStop?: () => void;
|
||||||
}> = React.memo(({ disabled, sendIcon, loading, loadingIcon, onSubmitPreflight, onStop }) => {
|
}> = React.memo(({ disabled, sendIcon, loading, loadingIcon, onSubmitPreflight, onStop }) => {
|
||||||
const memoizedPrefix = useMemo(() => {
|
const prefix = (
|
||||||
return (
|
<div
|
||||||
|
className={cn('relative h-4 w-4 transition-all duration-300 ease-out will-change-transform')}>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={`absolute inset-0 transition-all duration-300 ease-out ${loading ? 'scale-80 opacity-0' : 'scale-100 opacity-100'}`}>
|
||||||
'relative h-4 w-4 transition-all duration-300 ease-out will-change-transform'
|
{sendIcon}
|
||||||
)}>
|
|
||||||
<div
|
|
||||||
className={`absolute inset-0 transition-all duration-300 ease-out ${loading ? 'scale-80 opacity-0' : 'scale-100 opacity-100'}`}>
|
|
||||||
{sendIcon}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`absolute inset-0 flex items-center justify-center text-sm transition-all duration-300 ease-out ${loading ? 'scale-100 opacity-100' : 'scale-85 opacity-0'}`}>
|
|
||||||
{loadingIcon}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
<div
|
||||||
}, [loading, sendIcon, loadingIcon]);
|
className={`absolute inset-0 flex items-center justify-center text-sm transition-all duration-300 ease-out ${loading ? 'scale-100 opacity-100' : 'scale-85 opacity-0'}`}>
|
||||||
|
{loadingIcon}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
rounding={'large'}
|
rounding={'large'}
|
||||||
variant="black"
|
variant="black"
|
||||||
prefix={memoizedPrefix}
|
prefix={prefix}
|
||||||
onClick={loading && onStop ? onStop : onSubmitPreflight}
|
onClick={loading && onStop ? onStop : onSubmitPreflight}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { type ChangeEvent, useMemo, useRef, useState } from 'react';
|
import React, { type ChangeEvent, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { InputTextAreaButton } from '@/components/ui/inputs/InputTextAreaButton';
|
import { InputTextAreaButton } from '@/components/ui/inputs/InputTextAreaButton';
|
||||||
import { useMemoizedFn } from '@/hooks';
|
import { useMemoizedFn } from '@/hooks';
|
||||||
import { cn } from '@/lib/classMerge';
|
import { cn } from '@/lib/classMerge';
|
||||||
|
@ -17,8 +17,8 @@ export const ChatInput: React.FC = React.memo(() => {
|
||||||
const [inputValue, setInputValue] = useState('');
|
const [inputValue, setInputValue] = useState('');
|
||||||
|
|
||||||
const disableSubmit = useMemo(() => {
|
const disableSubmit = useMemo(() => {
|
||||||
return !inputHasText(inputValue);
|
return !inputHasText(inputValue) && !isStreamingMessage;
|
||||||
}, [inputValue]);
|
}, [inputValue, isStreamingMessage]);
|
||||||
|
|
||||||
const { onSubmitPreflight, onStopChat } = useChatInputFlow({
|
const { onSubmitPreflight, onStopChat } = useChatInputFlow({
|
||||||
disableSubmit,
|
disableSubmit,
|
||||||
|
@ -32,6 +32,14 @@ export const ChatInput: React.FC = React.memo(() => {
|
||||||
setInputValue(e.target.value);
|
setInputValue(e.target.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasChat) {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
textAreaRef.current?.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [hasChat, textAreaRef]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
|
@ -135,8 +135,10 @@ export const useChatInputFlow = ({
|
||||||
const onStopChat = useMemoizedFn(() => {
|
const onStopChat = useMemoizedFn(() => {
|
||||||
if (!chatId) return;
|
if (!chatId) return;
|
||||||
onStopChatContext({ chatId, messageId: currentMessageId });
|
onStopChatContext({ chatId, messageId: currentMessageId });
|
||||||
textAreaRef.current?.focus();
|
setTimeout(() => {
|
||||||
textAreaRef.current?.select();
|
textAreaRef.current?.focus();
|
||||||
|
textAreaRef.current?.select();
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
export * from './currency.types';
|
export * from './currency.types';
|
||||||
|
export * from './responses';
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { CurrencySchema } from './currency.types';
|
||||||
|
|
||||||
|
export const CurrencyResponseSchema = z.array(CurrencySchema);
|
||||||
|
|
||||||
|
export type CurrencyResponse = z.infer<typeof CurrencyResponseSchema>;
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
// Packages - Base configs first
|
||||||
|
{ "path": "./packages/typescript-config" },
|
||||||
|
{ "path": "./packages/vitest-config" },
|
||||||
|
|
||||||
|
// Core packages
|
||||||
|
{ "path": "./packages/database" },
|
||||||
|
{ "path": "./packages/supabase" },
|
||||||
|
{ "path": "./packages/server-shared" },
|
||||||
|
|
||||||
|
// Feature packages
|
||||||
|
{ "path": "./packages/access-controls" },
|
||||||
|
{ "path": "./packages/ai" },
|
||||||
|
{ "path": "./packages/data-source" },
|
||||||
|
{ "path": "./packages/rerank" },
|
||||||
|
{ "path": "./packages/slack" },
|
||||||
|
{ "path": "./packages/stored-values" },
|
||||||
|
{ "path": "./packages/test-utils" },
|
||||||
|
{ "path": "./packages/web-tools" },
|
||||||
|
|
||||||
|
// Apps
|
||||||
|
{ "path": "./apps/server" },
|
||||||
|
{ "path": "./apps/trigger" },
|
||||||
|
{ "path": "./apps/web" },
|
||||||
|
{ "path": "./apps/electric-server" }
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue