mirror of
https://github.com/cline/cline.git
synced 2026-09-17 17:45:33 +08:00
feat: Fixing payment stuff
This commit is contained in:
@@ -26,10 +26,19 @@ export async function getUserCredits(controller: Controller, request: EmptyReque
|
||||
throw new Error("Failed to fetch user credits data")
|
||||
}
|
||||
|
||||
const packedPaymentTransactions = (paymentTransactions || []).map((tx) => {
|
||||
return {
|
||||
paidAt: JSON.stringify(tx),
|
||||
creatorId: tx.id,
|
||||
amountCents: tx.amountCents,
|
||||
credits: tx.credits,
|
||||
}
|
||||
})
|
||||
|
||||
return UserCreditsData.create({
|
||||
balance: balance ? { currentBalance: balance.balance / 100 } : { currentBalance: 0 },
|
||||
usageTransactions: usageTransactions,
|
||||
paymentTransactions: paymentTransactions,
|
||||
paymentTransactions: packedPaymentTransactions,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch user credits data: ${error}`)
|
||||
|
||||
@@ -78,7 +78,7 @@ export async function refreshGroqModels(controller: Controller, request: EmptyRe
|
||||
inputPrice: staticModelInfo?.inputPrice || 0,
|
||||
outputPrice: staticModelInfo?.outputPrice || 0,
|
||||
cacheWritesPrice: (staticModelInfo as any)?.cacheWritesPrice || 0,
|
||||
cacheReadsPrice: (staticModelInfo as any).cacheReadsPrice || 0,
|
||||
cacheReadsPrice: (staticModelInfo as any)?.cacheReadsPrice || 0,
|
||||
description: generateModelDescription(rawModel, staticModelInfo),
|
||||
}
|
||||
|
||||
|
||||
@@ -129,10 +129,8 @@ export class ClineAccountService {
|
||||
console.error("Failed to fetch user ID for usage transactions")
|
||||
return undefined
|
||||
}
|
||||
const data = await this.authenticatedRequest<{ paymentTransactions: PaymentTransaction[] }>(
|
||||
`/api/v1/users/${me.id}/payments`,
|
||||
)
|
||||
return data.paymentTransactions
|
||||
const data = await this.authenticatedRequest<{ items: PaymentTransaction[] }>(`/api/v1/users/${me.id}/payments`)
|
||||
return data.items
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch payment transactions (RPC):", error)
|
||||
return undefined
|
||||
|
||||
@@ -43,10 +43,24 @@ export interface UsageTransaction {
|
||||
}
|
||||
|
||||
export interface PaymentTransaction {
|
||||
paidAt: string
|
||||
creatorId: string
|
||||
id: string
|
||||
transactionId: string
|
||||
userId: string
|
||||
amountCents: number
|
||||
credits: number
|
||||
type: string
|
||||
status: string
|
||||
providerReference: string
|
||||
metadata: {
|
||||
customer_id: string
|
||||
event_id: string
|
||||
payment_id: string
|
||||
provider: string
|
||||
subscription_id: string
|
||||
}
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
completedAt: string
|
||||
}
|
||||
|
||||
export interface OrganizationBalanceResponse {
|
||||
|
||||
@@ -11,7 +11,7 @@ import VSCodeButtonLink from "../common/VSCodeButtonLink"
|
||||
import { AccountWelcomeView } from "./AccountWelcomeView"
|
||||
import { CreditBalance } from "./CreditBalance"
|
||||
import CreditsHistoryTable from "./CreditsHistoryTable"
|
||||
import { convertProtoUsageTransactions, getClineUris, getMainRole } from "./helpers"
|
||||
import { convertProtoPaymentTransactions, convertProtoUsageTransactions, getClineUris, getMainRole } from "./helpers"
|
||||
|
||||
type AccountViewProps = {
|
||||
clineUser: ClineUser | null
|
||||
@@ -112,7 +112,7 @@ export const ClineAccountView = ({ clineUser, userOrganizations, activeOrganizat
|
||||
setBalance(newBalance ?? null)
|
||||
const newUsage = convertProtoUsageTransactions(response.usageTransactions)
|
||||
setUsageData((prev) => (deepEqual(newUsage, prev) ? prev : newUsage))
|
||||
const newPaymentsData = response.paymentTransactions
|
||||
const newPaymentsData = convertProtoPaymentTransactions(response.paymentTransactions)
|
||||
setPaymentsData((prev) => (deepEqual(newPaymentsData, prev) ? prev : newPaymentsData))
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch user credit:", error)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PaymentTransaction, UsageTransaction } from "@shared/ClineAccount"
|
||||
import type { PaymentTransaction as ClinePaymentTransaction, UsageTransaction } from "@shared/ClineAccount"
|
||||
import { VSCodeDataGrid, VSCodeDataGridCell, VSCodeDataGridRow } from "@vscode/webview-ui-toolkit/react"
|
||||
import { useState } from "react"
|
||||
import { formatDollars, formatTimestamp } from "@/utils/format"
|
||||
@@ -7,7 +7,7 @@ import { TabButton } from "../mcp/configuration/McpConfigurationView"
|
||||
interface CreditsHistoryTableProps {
|
||||
isLoading: boolean
|
||||
usageData: UsageTransaction[]
|
||||
paymentsData: PaymentTransaction[]
|
||||
paymentsData: ClinePaymentTransaction[]
|
||||
showPayments?: boolean
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ const CreditsHistoryTable = ({ isLoading, usageData, paymentsData, showPayments
|
||||
{paymentsData.map((row, index) => (
|
||||
<VSCodeDataGridRow key={index}>
|
||||
<VSCodeDataGridCell grid-column="1">
|
||||
{formatTimestamp(row.paidAt)}
|
||||
{formatTimestamp(row.completedAt)}
|
||||
</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell grid-column="2">{`$${formatDollars(row.amountCents)}`}</VSCodeDataGridCell>
|
||||
<VSCodeDataGridCell grid-column="3">{`${row.credits}`}</VSCodeDataGridCell>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import type { UsageTransaction as ClineAccountUsageTransaction } from "@shared/ClineAccount"
|
||||
import type { UsageTransaction as ProtoUsageTransaction } from "@shared/proto/cline/account"
|
||||
import type {
|
||||
PaymentTransaction as ClineAccountPaymentTransaction,
|
||||
UsageTransaction as ClineAccountUsageTransaction,
|
||||
} from "@shared/ClineAccount"
|
||||
import type {
|
||||
PaymentTransaction as ProtoPaymentTransaction,
|
||||
UsageTransaction as ProtoUsageTransaction,
|
||||
} from "@shared/proto/cline/account"
|
||||
|
||||
export const getMainRole = (roles?: string[]) => {
|
||||
if (!roles) return undefined
|
||||
@@ -45,3 +51,38 @@ export function convertProtoUsageTransaction(protoTransaction: ProtoUsageTransac
|
||||
export function convertProtoUsageTransactions(protoTransactions: ProtoUsageTransaction[]): ClineAccountUsageTransaction[] {
|
||||
return protoTransactions.map(convertProtoUsageTransaction)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a protobuf PaymentTransaction to a ClineAccount PaymentTransaction
|
||||
* This is a temporary workaround for the fact that the protobuf definition is out of sync with the API response.
|
||||
*/
|
||||
export function convertProtoPaymentTransaction(protoTransaction: ProtoPaymentTransaction): ClineAccountPaymentTransaction {
|
||||
try {
|
||||
const unpackedData = JSON.parse(protoTransaction.paidAt)
|
||||
return unpackedData as ClineAccountPaymentTransaction
|
||||
} catch (error) {
|
||||
console.error("Failed to parse packed payment transaction:", error)
|
||||
// Return a default/empty object that won't crash the UI
|
||||
return {
|
||||
id: "",
|
||||
transactionId: "",
|
||||
userId: "",
|
||||
amountCents: 0,
|
||||
credits: 0,
|
||||
type: "",
|
||||
status: "",
|
||||
providerReference: "",
|
||||
metadata: {},
|
||||
createdAt: "",
|
||||
updatedAt: "",
|
||||
completedAt: "",
|
||||
} as unknown as ClineAccountPaymentTransaction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of protobuf PaymentTransactions to ClineAccount PaymentTransactions
|
||||
*/
|
||||
export function convertProtoPaymentTransactions(protoTransactions: ProtoPaymentTransaction[]): ClineAccountPaymentTransaction[] {
|
||||
return protoTransactions.map(convertProtoPaymentTransaction)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useEffect } from "react"
|
||||
import { ClineMessage, ClineSayTool } from "@shared/ExtensionMessage"
|
||||
import { ChatState } from "../types/chatTypes"
|
||||
import { useDeepCompareEffect } from "react-use"
|
||||
|
||||
/**
|
||||
* Custom hook for managing button state based on messages
|
||||
@@ -19,7 +18,7 @@ export function useButtonState(messages: ClineMessage[], chatState: ChatState) {
|
||||
} = chatState
|
||||
|
||||
// Update button state based on last message
|
||||
useDeepCompareEffect(() => {
|
||||
useEffect(() => {
|
||||
if (lastMessage) {
|
||||
switch (lastMessage.type) {
|
||||
case "ask":
|
||||
@@ -146,7 +145,20 @@ export function useButtonState(messages: ClineMessage[], chatState: ChatState) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}, [lastMessage, secondLastMessage])
|
||||
}, [
|
||||
lastMessage?.type,
|
||||
lastMessage?.partial,
|
||||
lastMessage?.ask,
|
||||
lastMessage?.text,
|
||||
lastMessage?.say,
|
||||
secondLastMessage?.ask,
|
||||
setSendingDisabled,
|
||||
setEnableButtons,
|
||||
setPrimaryButtonText,
|
||||
setSecondaryButtonText,
|
||||
setDidClickCancel,
|
||||
chatState,
|
||||
])
|
||||
|
||||
// Reset button state when no messages
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user