Skip to main content
Glama

mcp-google-sheets

ai-credit-usage.tsx10.8 kB
import { useQueryClient } from '@tanstack/react-query'; import { t } from 'i18next'; import { Sparkles, Info, Loader2 } from 'lucide-react'; import { useEffect, useState, useMemo, useCallback } from 'react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Progress } from '@/components/ui/progress'; import { Separator } from '@/components/ui/separator'; import { Switch } from '@/components/ui/switch'; import { Tooltip, TooltipTrigger, TooltipContent, } from '@/components/ui/tooltip'; import { ApSubscriptionStatus, PlanName } from '@activepieces/ee-shared'; import { AiOverageState, PlatformBillingInformation, } from '@activepieces/shared'; import { billingMutations } from '../lib/billing-hooks'; import { AiCreditsUsageTable } from './ai-credits-usage-table'; interface AiCreditUsageProps { platformSubscription: PlatformBillingInformation; } export function AICreditUsage({ platformSubscription }: AiCreditUsageProps) { const queryClient = useQueryClient(); const { plan, usage } = platformSubscription; const planIncludedCredits = plan.includedAiCredits; const overageLimit = plan.aiCreditsOverageLimit; const totalCreditsUsed = usage.aiCredits; const aiOverrageState = plan.aiCreditsOverageState ?? plan.aiCreditsOverageState ?? AiOverageState.NOT_ALLOWED; const isFreePlan = plan.plan === PlanName.FREE; const isTrial = plan.stripeSubscriptionStatus === ApSubscriptionStatus.TRIALING; const overageConfig = useMemo(() => { const isAllowed = aiOverrageState !== AiOverageState.NOT_ALLOWED; const isEnabled = aiOverrageState === AiOverageState.ALLOWED_AND_ON; return { allowed: isAllowed, enabled: isEnabled, canToggle: !isFreePlan && !isTrial && isAllowed, }; }, [aiOverrageState, isFreePlan, isTrial]); const [usageBasedEnabled, setUsageBasedEnabled] = useState( overageConfig.enabled, ); const [usageLimit, setUsageLimit] = useState<number>(overageLimit ?? 500); const { mutate: setAiCreditOverageLimit, isPending: settingAiCreditsOverageLimit, } = billingMutations.useSetAiCreditOverageLimit(queryClient); const { mutate: toggleAiCreditsOverageEnabled, isPending: togglingAiCreditsOverageEnabled, } = billingMutations.useToggleAiCreditOverageEnabled(queryClient); const creditMetrics = useMemo(() => { const creditsUsedFromPlan = Math.min(totalCreditsUsed, planIncludedCredits); const overageCreditsUsed = Math.max( 0, totalCreditsUsed - planIncludedCredits, ); const planUsagePercentage = Math.min( 100, Math.round((creditsUsedFromPlan / planIncludedCredits) * 100), ); const overageUsagePercentage = usageBasedEnabled && overageLimit ? Math.min(100, Math.round((overageCreditsUsed / overageLimit) * 100)) : 0; return { creditsUsedFromPlan, overageCreditsUsed, planUsagePercentage, overageUsagePercentage, isPlanLimitApproaching: planUsagePercentage > 80, isPlanLimitExceeded: totalCreditsUsed > planIncludedCredits, isOverageLimitApproaching: overageUsagePercentage > 80, }; }, [totalCreditsUsed, planIncludedCredits, usageBasedEnabled, overageLimit]); const handleSaveAiCreditUsageLimit = useCallback(() => { setAiCreditOverageLimit({ limit: usageLimit }); }, [setAiCreditOverageLimit, usageLimit]); const handleToggleAiCreditUsage = useCallback(() => { const newState = usageBasedEnabled ? AiOverageState.ALLOWED_BUT_OFF : AiOverageState.ALLOWED_AND_ON; toggleAiCreditsOverageEnabled( { state: newState }, { onSuccess: () => { setUsageBasedEnabled(!usageBasedEnabled); }, }, ); }, [usageBasedEnabled, toggleAiCreditsOverageEnabled]); useEffect(() => { setUsageBasedEnabled(overageConfig.enabled); }, [overageConfig.enabled]); useEffect(() => { setUsageLimit(overageLimit ?? 500); }, [overageLimit]); return ( <Card className="w-full"> <CardHeader className="border-b"> <div className="flex items-center justify-between"> <div className="flex items-center gap-3"> <div className="flex items-center justify-center w-10 h-10 rounded-lg border"> <Sparkles className="w-5 h-5" /> </div> <div> <h3 className="text-lg font-semibold">{t('AI Credits')}</h3> <p className="text-sm text-muted-foreground"> Manage your AI usage and limits </p> </div> </div> {overageConfig.canToggle && ( <div className="flex items-center gap-3 py-2"> <span className="text-sm font-medium"> {t('Usage Based Billing')} </span> <Switch checked={usageBasedEnabled} disabled={togglingAiCreditsOverageEnabled} onCheckedChange={handleToggleAiCreditUsage} /> </div> )} </div> </CardHeader> <CardContent className="p-6 space-y-10"> <div className="space-y-4"> <div className="flex items-center gap-2"> <h4 className="text-base font-medium">{t('Plan Credits Usage')}</h4> <Tooltip> <TooltipTrigger> <Info className="w-4 h-4 text-muted-foreground" /> </TooltipTrigger> <TooltipContent> Credits reset monthly with your billing cycle </TooltipContent> </Tooltip> </div> <div className="rounded-lg space-y-3"> <div className="flex justify-between items-center text-sm"> <span className="text-muted-foreground"> {Math.round(creditMetrics.creditsUsedFromPlan)} /{' '} {planIncludedCredits} </span> <span className="text-xs font-medium text-muted-foreground"> {t('Plan Included')} </span> </div> <Progress value={creditMetrics.planUsagePercentage} className="w-full" /> <div className="flex items-center justify-between text-sm"> <span className="text-muted-foreground"> {creditMetrics.planUsagePercentage}% of plan credits used </span> {creditMetrics.isPlanLimitApproaching && !creditMetrics.isPlanLimitExceeded && ( <span className="text-orange-600 font-medium"> Approaching limit </span> )} {creditMetrics.isPlanLimitExceeded && ( <span className="text-destructive font-medium"> Plan limit exceeded </span> )} </div> </div> </div> {usageBasedEnabled && overageConfig.canToggle && ( <> <Separator /> <div className="space-y-4"> <div className="flex items-center gap-2"> <h4 className="text-base font-medium"> {t('Additional Credits Usage')} </h4> <Tooltip> <TooltipTrigger> <Info className="w-4 h-4 text-muted-foreground" /> </TooltipTrigger> <TooltipContent> Credits used beyond your plan limit ($0.01 each) </TooltipContent> </Tooltip> </div> <div className="rounded-lg space-y-3"> <div className="flex justify-between items-center text-sm"> <span className="text-muted-foreground"> {creditMetrics.overageCreditsUsed} /{' '} {overageLimit ?? 'unknown'} </span> <span className="text-xs font-medium text-muted-foreground"> {t('Usage Limit')} </span> </div> <Progress value={creditMetrics.overageUsagePercentage} className="w-full" /> <div className="flex items-center justify-between text-sm"> <span className="text-muted-foreground"> {creditMetrics.overageUsagePercentage}% of usage limit used </span> {creditMetrics.isOverageLimitApproaching && ( <span className="text-destructive font-medium"> Approaching usage limit </span> )} </div> </div> </div> <Separator /> <div className="space-y-4"> <div> <h5 className="text-base font-medium mb-1"> {t('Set Usage Limit')} </h5> <p className="text-sm text-muted-foreground"> Set a maximum number of additional AI credits to prevent unexpected charges </p> </div> <div className="rounded-lg space-y-4"> <div className="flex items-end gap-3"> <div className="flex-1 max-w-xs space-y-2"> <Input type="number" placeholder="Enter limit" value={usageLimit} onChange={(e) => setUsageLimit(Number(e.target.value))} className="w-full" min="0" /> </div> <Button onClick={handleSaveAiCreditUsageLimit} disabled={settingAiCreditsOverageLimit} className="whitespace-nowrap" > {settingAiCreditsOverageLimit && ( <Loader2 className="w-4 h-4 animate-spin mr-2" /> )} {t('Save Limit')} </Button> </div> <p className="text-xs text-muted-foreground"> Recommended: Set 20-50% above your expected monthly overage usage </p> </div> </div> <div className="text-sm text-muted-foreground bg-muted/30 rounded-lg p-3"> {t('$1 per 1000 additional credits beyond plan limit')} </div> </> )} <Separator /> <AiCreditsUsageTable /> </CardContent> </Card> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/activepieces/activepieces'

If you have feedback or need assistance with the MCP directory API, please join our Discord server