Merge branch 'kortix-ai:main' into feat/vnc_ui

This commit is contained in:
Krishav 2025-08-18 05:33:40 +05:30 committed by GitHub
commit a95cdb6382
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 138 additions and 47 deletions

View File

@ -20,7 +20,7 @@ import { ThreadContent } from '@/components/thread/content/ThreadContent';
import { ThreadSkeleton } from '@/components/thread/content/ThreadSkeleton';
import { useAddUserMessageMutation } from '@/hooks/react-query/threads/use-messages';
import { useStartAgentMutation, useStopAgentMutation } from '@/hooks/react-query/threads/use-agent-run';
import { useSubscription } from '@/hooks/react-query/subscriptions/use-subscriptions';
import { useSharedSubscription } from '@/contexts/SubscriptionContext';
import { SubscriptionStatus } from '@/components/thread/chat-input/_use-model-selection';
import { UnifiedMessage, ApiMessageType, ToolCallInput, Project } from '../_types';
@ -164,7 +164,7 @@ export default function ThreadPage({
}
}, [threadAgentData, agents, initializeFromAgents]);
const { data: subscriptionData } = useSubscription();
const { data: subscriptionData } = useSharedSubscription();
const subscriptionStatus: SubscriptionStatus = subscriptionData?.status === 'active'
? 'active'
: 'no_subscription';

View File

@ -7,7 +7,8 @@ import { isLocalMode } from '@/lib/config';
import { createPortalSession } from '@/lib/api';
import { useAuth } from '@/components/AuthProvider';
import { Skeleton } from '@/components/ui/skeleton';
import { useSubscription, useSubscriptionCommitment } from '@/hooks/react-query';
import { useSharedSubscription } from '@/contexts/SubscriptionContext';
import { useSubscriptionCommitment } from '@/hooks/react-query';
import Link from 'next/link';
import { OpenInNewWindowIcon } from '@radix-ui/react-icons';
import SubscriptionManagementModal from './subscription-management-modal';
@ -26,7 +27,7 @@ export default function AccountBillingStatus({ accountId, returnUrl }: Props) {
data: subscriptionData,
isLoading,
error: subscriptionQueryError,
} = useSubscription();
} = useSharedSubscription();
const {
data: commitmentInfo,

View File

@ -14,7 +14,7 @@ import { isLocalMode } from '@/lib/config';
import { createPortalSession } from '@/lib/api';
import { useAuth } from '@/components/AuthProvider';
import { Skeleton } from '@/components/ui/skeleton';
import { useSubscription } from '@/hooks/react-query';
import { useSharedSubscription } from '@/contexts/SubscriptionContext';
import Link from 'next/link';
import { CreditCard, Settings, HelpCircle } from 'lucide-react';
import { OpenInNewWindowIcon } from '@radix-ui/react-icons';
@ -44,7 +44,7 @@ export default function SubscriptionManagementModal({
data: subscriptionData,
isLoading,
error: subscriptionQueryError,
} = useSubscription();
} = useSharedSubscription();

View File

@ -20,6 +20,7 @@ import { useMaintenanceNoticeQuery } from '@/hooks/react-query/edge-flags';
import { useProjects, useThreads } from '@/hooks/react-query/sidebar/use-sidebar';
import { useIsMobile } from '@/hooks/use-mobile';
import { useAgents } from '@/hooks/react-query/agents/use-agents';
import { SubscriptionProvider } from '@/contexts/SubscriptionContext';
interface DashboardLayoutContentProps {
children: React.ReactNode;
@ -126,32 +127,34 @@ export default function DashboardLayoutContent({
return (
<DeleteOperationProvider>
<SidebarProvider>
<SidebarLeft />
<SidebarInset>
{mantenanceBanner}
<div className="bg-background">{children}</div>
</SidebarInset>
<SubscriptionProvider>
<SidebarProvider>
<SidebarLeft />
<SidebarInset>
{mantenanceBanner}
<div className="bg-background">{children}</div>
</SidebarInset>
{/* <PricingAlert
open={showPricingAlert}
onOpenChange={setShowPricingAlert}
closeable={false}
accountId={personalAccount?.account_id}
/> */}
{/* <PricingAlert
open={showPricingAlert}
onOpenChange={setShowPricingAlert}
closeable={false}
accountId={personalAccount?.account_id}
/> */}
<MaintenanceAlert
open={showMaintenanceAlert}
onOpenChange={setShowMaintenanceAlert}
closeable={true}
/>
<MaintenanceAlert
open={showMaintenanceAlert}
onOpenChange={setShowMaintenanceAlert}
closeable={true}
/>
{/* Status overlay for deletion operations */}
<StatusOverlay />
{/* Floating mobile menu button */}
<FloatingMobileMenuButton />
</SidebarProvider>
{/* Status overlay for deletion operations */}
<StatusOverlay />
{/* Floating mobile menu button */}
<FloatingMobileMenuButton />
</SidebarProvider>
</SubscriptionProvider>
</DeleteOperationProvider>
);
}

View File

@ -1,6 +1,6 @@
'use client';
import { useSubscription } from '@/hooks/react-query/subscriptions/use-subscriptions';
import { useSharedSubscription } from '@/contexts/SubscriptionContext';
import { useState, useEffect, useMemo } from 'react';
import { isLocalMode } from '@/lib/config';
import { useAvailableModels } from '@/hooks/react-query/subscriptions/use-model';
@ -170,7 +170,7 @@ export const useModelSelection = () => {
const [customModels, setCustomModels] = useState<CustomModel[]>([]);
const [hasInitialized, setHasInitialized] = useState(false);
const { data: subscriptionData } = useSubscription();
const { data: subscriptionData } = useSharedSubscription();
const { data: modelsData, isLoading: isLoadingModels } = useAvailableModels({
refetchOnMount: false,
});

View File

@ -25,7 +25,7 @@ import { Skeleton } from '@/components/ui/skeleton';
import { IntegrationsRegistry } from '@/components/agents/integrations-registry';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { useSubscriptionWithStreaming } from '@/hooks/react-query/subscriptions/use-subscriptions';
import { useSharedSubscription } from '@/contexts/SubscriptionContext';
import { isLocalMode } from '@/lib/config';
import { BillingModal } from '@/components/billing/billing-modal';
import { useRouter } from 'next/navigation';
@ -153,7 +153,7 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
refreshCustomModels,
} = useModelSelection();
const { data: subscriptionData } = useSubscriptionWithStreaming(isAgentRunning);
const { data: subscriptionData } = useSharedSubscription();
const deleteFileMutation = useFileDelete();
const queryClient = useQueryClient();

View File

@ -0,0 +1,71 @@
'use client';
import React, { createContext, useContext, ReactNode } from 'react';
import { useSubscription as useSubscriptionQuery } from '@/hooks/react-query/subscriptions/use-subscriptions';
import { SubscriptionStatus } from '@/lib/api';
interface SubscriptionContextType {
subscriptionData: SubscriptionStatus | null;
isLoading: boolean;
error: Error | null;
refetch: () => void;
}
const SubscriptionContext = createContext<SubscriptionContextType | null>(null);
interface SubscriptionProviderProps {
children: ReactNode;
}
export function SubscriptionProvider({ children }: SubscriptionProviderProps) {
const {
data: subscriptionData,
isLoading,
error,
refetch
} = useSubscriptionQuery();
const value: SubscriptionContextType = {
subscriptionData: subscriptionData || null,
isLoading,
error: error as Error | null,
refetch,
};
return (
<SubscriptionContext.Provider value={value}>
{children}
</SubscriptionContext.Provider>
);
}
export function useSubscriptionContext() {
const context = useContext(SubscriptionContext);
if (!context) {
throw new Error('useSubscriptionContext must be used within a SubscriptionProvider');
}
return context;
}
// Convenience hook that provides the same interface as the original useSubscription
// but uses the shared context data with fallback for components outside dashboard
export function useSharedSubscription() {
const context = useContext(SubscriptionContext);
if (!context) {
// Fallback to the original hook if context is not available
// This allows components outside the dashboard to still work
return useSubscriptionQuery();
}
const { subscriptionData, isLoading, error, refetch } = context;
return {
data: subscriptionData,
isLoading,
error,
refetch,
};
}

View File

@ -23,8 +23,11 @@ export const useBillingStatus = createQueryHook(
['billing', 'status'],
checkBillingStatus,
{
staleTime: 2 * 60 * 1000,
refetchOnWindowFocus: true,
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 10 * 60 * 1000, // 10 minutes cache time
refetchOnWindowFocus: false, // Don't refetch on window focus
refetchOnMount: false, // Don't refetch on mount if data exists
refetchOnReconnect: true, // Only refetch when network reconnects
}
);

View File

@ -16,8 +16,11 @@ export const useSubscription = createQueryHook(
subscriptionKeys.details(),
getSubscription,
{
staleTime: 1000 * 60 * 5,
refetchOnWindowFocus: true,
staleTime: 1000 * 60 * 10, // 10 minutes - subscription status doesn't change frequently
gcTime: 1000 * 60 * 15, // 15 minutes cache time
refetchOnWindowFocus: false, // Don't refetch on every window focus
refetchOnMount: false, // Don't refetch on every component mount if data exists
refetchOnReconnect: true, // Only refetch when network reconnects
},
);
@ -38,17 +41,20 @@ export const useSubscriptionWithStreaming = (isStreaming: boolean = false) => {
return useQuery({
queryKey: subscriptionKeys.details(),
queryFn: getSubscription,
staleTime: 1000 * 60 * 2, // 2 minutes
refetchOnWindowFocus: true,
staleTime: 1000 * 60 * 5, // 5 minutes - longer stale time
gcTime: 1000 * 60 * 15, // 15 minutes cache time
refetchOnWindowFocus: false, // Don't refetch on window focus
refetchOnMount: false, // Don't refetch on mount if data exists
refetchInterval: (data) => {
// No refresh if tab is hidden
if (!isVisible) return false;
// If actively streaming: refresh every 5s (costs are changing)
if (isStreaming) return 5 * 1000;
// If actively streaming: refresh every 2 minutes instead of 5 seconds
// Billing data doesn't need to be that real-time
if (isStreaming) return 2 * 60 * 1000;
// If visible but not streaming: refresh every 5min
return 5 * 60 * 1000;
// If visible but not streaming: refresh every 10 minutes
return 10 * 60 * 1000;
},
refetchIntervalInBackground: false, // Stop when tab backgrounded
});
@ -70,8 +76,11 @@ export const useSubscriptionCommitment = (subscriptionId?: string) => {
queryKey: subscriptionKeys.commitment(subscriptionId || ''),
queryFn: () => getSubscriptionCommitment(subscriptionId!),
enabled: !!subscriptionId,
staleTime: 1000 * 60 * 5, // 5 minutes
staleTime: 1000 * 60 * 15, // 15 minutes - commitment info changes very rarely
gcTime: 1000 * 60 * 30, // 30 minutes cache time
refetchOnWindowFocus: false,
refetchOnMount: false, // Don't refetch on mount if data exists
refetchOnReconnect: false, // Commitment data rarely changes
});
};

View File

@ -9,14 +9,15 @@ export const useBillingStatusQuery = (enabled = true) =>
{
enabled,
retry: 1,
staleTime: 1000 * 60 * 5,
gcTime: 1000 * 60 * 10,
staleTime: 1000 * 60 * 10, // 10 minutes - increased stale time
gcTime: 1000 * 60 * 15, // 15 minutes cache time
refetchOnWindowFocus: false,
refetchOnMount: false,
refetchOnReconnect: false,
refetchInterval: (query: any) => {
// Only refetch if billing is in a problematic state and at a slower rate
if (query.state.data && !query.state.data.can_run) {
return 1000 * 60;
return 1000 * 60 * 5; // 5 minutes instead of 1 minute
}
return false;
},

View File

@ -1878,6 +1878,9 @@ export const createPortalSession = async (
export const getSubscription = async (): Promise<SubscriptionStatus> => {
try {
// Log when subscription API is called for debugging
console.log('🔍 [BILLING] Making subscription API call:', new Date().toISOString());
const supabase = createClient();
const {
data: { session },