Merge branch 'staging' into cursor/replace-select-with-dropdown-component-39ce

This commit is contained in:
Nate Kelley 2025-07-14 11:40:57 -06:00
commit 90801c89c4
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
16 changed files with 149 additions and 48 deletions

View File

@ -1,23 +1,23 @@
{
"folders": [
{ "path": "./apps/api" },
{ "path": "./apps/electric-server" },
{ "path": "./apps/server" },
{ "path": "./apps/trigger" },
{ "path": "./apps/web" },
{ "path": "./packages/access-controls" },
{ "path": "./packages/ai" },
{ "path": "./packages/data-source" },
{ "path": "./packages/database" },
{ "path": "./packages/rerank" },
{ "path": "./packages/server-shared" },
{ "path": "./packages/slack" },
{ "path": "./packages/stored-values" },
{ "path": "./packages/supabase" },
{ "path": "./packages/test-utils" },
{ "path": "./packages/typescript-config" },
{ "path": "./packages/vitest-config" },
{ "path": "./packages/web-tools" }
{ "path": "../apps/api" },
{ "path": "../apps/electric-server" },
{ "path": "../apps/server" },
{ "path": "../apps/trigger" },
{ "path": "../apps/web" },
{ "path": "../packages/access-controls" },
{ "path": "../packages/ai" },
{ "path": "../packages/data-source" },
{ "path": "../packages/database" },
{ "path": "../packages/rerank" },
{ "path": "../packages/server-shared" },
{ "path": "../packages/slack" },
{ "path": "../packages/stored-values" },
{ "path": "../packages/supabase" },
{ "path": "../packages/test-utils" },
{ "path": "../packages/typescript-config" },
{ "path": "../packages/vitest-config" },
{ "path": "../packages/web-tools" }
],
"settings": {
"editor.defaultFormatter": "biomejs.biome",

35
.vscode/settings.json vendored
View File

@ -9,6 +9,39 @@
"typescript.suggest.autoImports": true,
"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
"files.watcherExclude": {
"**/node_modules/**": true,
@ -16,6 +49,7 @@
"**/.git/subtree-cache/**": true,
"**/target/**": true,
"**/.turbo/**": true
// NOTE: We explicitly DO NOT exclude dist folders from watching
},
// Exclude dist folders from file explorer (but keep them in watcher)
@ -48,7 +82,6 @@
"typescript.check.npmIsInstalled": false,
"typescript.disableAutomaticTypeAcquisition": true,
// Default Biome formatting for all file types
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"

View File

@ -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 { requireAuth } from '../../../middleware/auth';
import { CURRENCIES_MAP } from './config';
@ -6,7 +6,7 @@ import { CURRENCIES_MAP } from './config';
const app = new Hono();
app.use('*', requireAuth).get('/', async (c) => {
return c.json<Currency[]>(CURRENCIES_MAP);
return c.json<CurrencyResponse>(CURRENCIES_MAP);
});
export default app;

View File

@ -7,6 +7,8 @@ declare global {
ENVIRONMENT: string;
NODE_ENV?: 'development' | 'production' | 'test';
BUSTER_URL: string;
BUSTER_ALERT_CHANNEL_TOKEN?: string;
BUSTER_ALERT_CHANNEL_ID?: string;
}
}
}

View File

@ -211,6 +211,24 @@ export async function sendSlackNotification(
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) {
logger.log('Successfully sent Slack notification', {
organizationId: params.organizationId,

View File

@ -4,7 +4,7 @@ import { useShape, useShapeStream } from '../instances';
import { useChatUpdate } from '@/context/Chats/useChatUpdate';
import { updateMessageShapeToIChatMessage } from './helpers';
import { useMemoizedFn } from '@/hooks';
import { useGetChatMemoized } from '@/api/buster_rest/chats';
import { prefetchGetListChats, useGetChatMemoized } from '@/api/buster_rest/chats';
import uniq from 'lodash/uniq';
export const useGetMessage = ({ chatId, messageId }: { chatId: string; messageId: string }) => {
@ -33,6 +33,7 @@ export const useTrackAndUpdateMessageChanges = (
) => {
const { onUpdateChatMessage, onUpdateChat } = useChatUpdate();
const getChatMemoized = useGetChatMemoized();
const shape = useMemo(
() => messageShape({ chatId: chatId || '', messageId }),
[chatId, messageId]
@ -58,6 +59,10 @@ export const useTrackAndUpdateMessageChanges = (
message_ids: allMessageIds
});
}
if (iChatMessage.is_completed) {
prefetchGetListChats()
}
}
callback?.(iChatMessage);
onUpdateChatMessage(iChatMessage);

View File

@ -38,7 +38,7 @@ export const useGetListChats = (
filters?: Omit<Parameters<typeof getListChats>[0], 'page_token' | 'page_size'>
) => {
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]
);

View File

@ -6,5 +6,5 @@ export const createNewChat = async (props: ChatCreateRequest) => {
};
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);
};

View File

@ -29,7 +29,7 @@ const chatsGetList = (
filters?: Omit<Parameters<typeof getListChats>[0], 'page_token' | 'page_size'>
) =>
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
initialData: [],
initialDataUpdatedAt: 0

View File

@ -1,6 +1,7 @@
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'],
initialData: [],
initialDataUpdatedAt: 0,

View File

@ -108,12 +108,9 @@ const SubmitButton: React.FC<{
onSubmitPreflight: () => void;
onStop?: () => void;
}> = React.memo(({ disabled, sendIcon, loading, loadingIcon, onSubmitPreflight, onStop }) => {
const memoizedPrefix = useMemo(() => {
return (
const prefix = (
<div
className={cn(
'relative h-4 w-4 transition-all duration-300 ease-out will-change-transform'
)}>
className={cn('relative h-4 w-4 transition-all duration-300 ease-out will-change-transform')}>
<div
className={`absolute inset-0 transition-all duration-300 ease-out ${loading ? 'scale-80 opacity-0' : 'scale-100 opacity-100'}`}>
{sendIcon}
@ -124,13 +121,12 @@ const SubmitButton: React.FC<{
</div>
</div>
);
}, [loading, sendIcon, loadingIcon]);
return (
<Button
rounding={'large'}
variant="black"
prefix={memoizedPrefix}
prefix={prefix}
onClick={loading && onStop ? onStop : onSubmitPreflight}
disabled={disabled}
className={cn(

View File

@ -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 { useMemoizedFn } from '@/hooks';
import { cn } from '@/lib/classMerge';
@ -17,8 +17,8 @@ export const ChatInput: React.FC = React.memo(() => {
const [inputValue, setInputValue] = useState('');
const disableSubmit = useMemo(() => {
return !inputHasText(inputValue);
}, [inputValue]);
return !inputHasText(inputValue) && !isStreamingMessage;
}, [inputValue, isStreamingMessage]);
const { onSubmitPreflight, onStopChat } = useChatInputFlow({
disableSubmit,
@ -32,6 +32,14 @@ export const ChatInput: React.FC = React.memo(() => {
setInputValue(e.target.value);
});
useEffect(() => {
if (hasChat) {
requestAnimationFrame(() => {
textAreaRef.current?.focus();
});
}
}, [hasChat, textAreaRef]);
return (
<div
className={cn(

View File

@ -135,8 +135,10 @@ export const useChatInputFlow = ({
const onStopChat = useMemoizedFn(() => {
if (!chatId) return;
onStopChatContext({ chatId, messageId: currentMessageId });
setTimeout(() => {
textAreaRef.current?.focus();
textAreaRef.current?.select();
}, 100);
});
return useMemo(

View File

@ -1 +1,2 @@
export * from './currency.types';
export * from './responses';

View File

@ -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>;

29
tsconfig.json Normal file
View File

@ -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" }
]
}