mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-09 15:07:55 -05:00
v0.5.25: minor ui improvements, copilot billing fix
This commit is contained in:
@@ -3,7 +3,6 @@ import { userStats } from '@sim/db/schema'
|
||||
import { eq, sql } from 'drizzle-orm'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { deductFromCredits } from '@/lib/billing/credits/balance'
|
||||
import { checkAndBillOverageThreshold } from '@/lib/billing/threshold-billing'
|
||||
import { checkInternalApiKey } from '@/lib/copilot/utils'
|
||||
import { isBillingEnabled } from '@/lib/core/config/environment'
|
||||
@@ -92,17 +91,11 @@ export async function POST(req: NextRequest) {
|
||||
return NextResponse.json({ error: 'User stats record not found' }, { status: 500 })
|
||||
}
|
||||
|
||||
const { creditsUsed, overflow } = await deductFromCredits(userId, cost)
|
||||
if (creditsUsed > 0) {
|
||||
logger.info(`[${requestId}] Deducted cost from credits`, { userId, creditsUsed, overflow })
|
||||
}
|
||||
const costToStore = overflow
|
||||
|
||||
const updateFields = {
|
||||
totalCost: sql`total_cost + ${costToStore}`,
|
||||
currentPeriodCost: sql`current_period_cost + ${costToStore}`,
|
||||
totalCopilotCost: sql`total_copilot_cost + ${costToStore}`,
|
||||
currentPeriodCopilotCost: sql`current_period_copilot_cost + ${costToStore}`,
|
||||
totalCost: sql`total_cost + ${cost}`,
|
||||
currentPeriodCost: sql`current_period_cost + ${cost}`,
|
||||
totalCopilotCost: sql`total_copilot_cost + ${cost}`,
|
||||
currentPeriodCopilotCost: sql`current_period_copilot_cost + ${cost}`,
|
||||
totalCopilotCalls: sql`total_copilot_calls + 1`,
|
||||
lastActive: new Date(),
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ function WorkflowsListSkeleton({ rowCount = 5 }: { rowCount?: number }) {
|
||||
*/
|
||||
function DashboardSkeleton() {
|
||||
return (
|
||||
<div className='mt-[24px] flex min-h-0 flex-1 flex-col'>
|
||||
<div className='mt-[24px] flex min-h-0 flex-1 flex-col pb-[24px]'>
|
||||
{/* Graphs Section */}
|
||||
<div className='mb-[16px] flex-shrink-0'>
|
||||
<div className='grid grid-cols-1 gap-[16px] md:grid-cols-3'>
|
||||
@@ -774,7 +774,7 @@ export default function Dashboard({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='mt-[24px] flex min-h-0 flex-1 flex-col'>
|
||||
<div className='mt-[24px] flex min-h-0 flex-1 flex-col pb-[24px]'>
|
||||
{/* Graphs Section */}
|
||||
<div className='mb-[16px] flex-shrink-0'>
|
||||
<div className='grid grid-cols-1 gap-[16px] md:grid-cols-3'>
|
||||
|
||||
@@ -161,9 +161,9 @@ export function LogDetails({
|
||||
<ScrollArea className='mt-[20px] h-full w-full overflow-y-auto' ref={scrollAreaRef}>
|
||||
<div className='flex flex-col gap-[10px] pb-[16px]'>
|
||||
{/* Timestamp & Workflow Row */}
|
||||
<div className='flex items-center gap-[16px] px-[1px]'>
|
||||
<div className='flex min-w-0 items-center gap-[16px] px-[1px]'>
|
||||
{/* Timestamp Card */}
|
||||
<div className='flex w-[140px] flex-col gap-[8px]'>
|
||||
<div className='flex w-[140px] flex-shrink-0 flex-col gap-[8px]'>
|
||||
<div className='font-medium text-[12px] text-[var(--text-tertiary)]'>
|
||||
Timestamp
|
||||
</div>
|
||||
@@ -179,16 +179,16 @@ export function LogDetails({
|
||||
|
||||
{/* Workflow Card */}
|
||||
{log.workflow && (
|
||||
<div className='flex flex-col gap-[8px]'>
|
||||
<div className='flex w-0 min-w-0 flex-1 flex-col gap-[8px]'>
|
||||
<div className='font-medium text-[12px] text-[var(--text-tertiary)]'>
|
||||
Workflow
|
||||
</div>
|
||||
<div className='flex items-center gap-[8px]'>
|
||||
<div className='flex min-w-0 items-center gap-[8px]'>
|
||||
<div
|
||||
className='h-[10px] w-[10px] flex-shrink-0 rounded-[3px]'
|
||||
style={{ backgroundColor: log.workflow?.color }}
|
||||
/>
|
||||
<span className='font-medium text-[14px] text-[var(--text-secondary)]'>
|
||||
<span className='min-w-0 flex-1 truncate font-medium text-[14px] text-[var(--text-secondary)]'>
|
||||
{log.workflow.name}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -410,14 +410,14 @@ export default function Logs() {
|
||||
|
||||
{/* Dashboard view */}
|
||||
{isDashboardView && (
|
||||
<div className='pr-[24px] pb-[24px]'>
|
||||
<div className='flex min-h-0 flex-1 flex-col pr-[24px]'>
|
||||
<Dashboard isLive={isLive} refreshTrigger={dashboardRefreshTrigger} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Main content area with table - only show in logs view */}
|
||||
{!isDashboardView && (
|
||||
<div className='relative mt-[24px] flex min-h-0 flex-1 overflow-hidden rounded-[6px]'>
|
||||
<div className='relative mt-[24px] flex min-h-0 flex-1 flex-col overflow-hidden rounded-[6px]'>
|
||||
{/* Table container */}
|
||||
<div className='relative flex min-h-0 flex-1 flex-col overflow-hidden rounded-[6px] bg-[var(--surface-1)]'>
|
||||
{/* Table header */}
|
||||
|
||||
@@ -398,8 +398,8 @@ export const Copilot = forwardRef<CopilotRef, CopilotProps>(({ panelWidth }, ref
|
||||
className='flex h-full flex-col overflow-hidden'
|
||||
>
|
||||
{/* Header */}
|
||||
<div className='flex flex-shrink-0 items-center justify-between rounded-[4px] bg-[var(--surface-5)] px-[12px] py-[8px]'>
|
||||
<h2 className='font-medium text-[14px] text-[var(--text-primary)]'>
|
||||
<div className='flex flex-shrink-0 items-center justify-between gap-[8px] rounded-[4px] bg-[var(--surface-5)] px-[12px] py-[8px]'>
|
||||
<h2 className='min-w-0 flex-1 truncate font-medium text-[14px] text-[var(--text-primary)]'>
|
||||
{currentChat?.title || 'New Chat'}
|
||||
</h2>
|
||||
<div className='flex items-center gap-[8px]'>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { memo, useCallback } from 'react'
|
||||
import { ArrowLeftRight, ArrowUpDown, Circle, CircleOff, LogOut } from 'lucide-react'
|
||||
import { Button, Duplicate, Tooltip, Trash2 } from '@/components/emcn'
|
||||
import { Button, Copy, Tooltip, Trash2 } from '@/components/emcn'
|
||||
import { cn } from '@/lib/core/utils/cn'
|
||||
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
|
||||
import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow'
|
||||
@@ -119,7 +119,7 @@ export const ActionBar = memo(
|
||||
className='hover:!text-[var(--text-inverse)] h-[23px] w-[23px] rounded-[8px] bg-[var(--surface-9)] p-0 text-[#868686] hover:bg-[var(--brand-secondary)]'
|
||||
disabled={disabled}
|
||||
>
|
||||
<Duplicate className='h-[11px] w-[11px]' />
|
||||
<Copy className='h-[11px] w-[11px]' />
|
||||
</Button>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content side='top'>{getTooltipMessage('Duplicate Block')}</Tooltip.Content>
|
||||
|
||||
@@ -703,12 +703,12 @@ export const WorkflowBlock = memo(function WorkflowBlock({
|
||||
const colorClasses = isError ? '!bg-red-400 dark:!bg-red-500' : '!bg-[var(--surface-12)]'
|
||||
|
||||
const positionClasses = {
|
||||
left: '!left-[-7px] !h-5 !w-[7px] !rounded-l-[2px] !rounded-r-none hover:!left-[-10px] hover:!w-[10px] hover:!rounded-l-full',
|
||||
left: '!left-[-8px] !h-5 !w-[7px] !rounded-l-[2px] !rounded-r-none hover:!left-[-11px] hover:!w-[10px] hover:!rounded-l-full',
|
||||
right:
|
||||
'!right-[-7px] !h-5 !w-[7px] !rounded-r-[2px] !rounded-l-none hover:!right-[-10px] hover:!w-[10px] hover:!rounded-r-full',
|
||||
top: '!top-[-7px] !h-[7px] !w-5 !rounded-t-[2px] !rounded-b-none hover:!top-[-10px] hover:!h-[10px] hover:!rounded-t-full',
|
||||
'!right-[-8px] !h-5 !w-[7px] !rounded-r-[2px] !rounded-l-none hover:!right-[-11px] hover:!w-[10px] hover:!rounded-r-full',
|
||||
top: '!top-[-8px] !h-[7px] !w-5 !rounded-t-[2px] !rounded-b-none hover:!top-[-11px] hover:!h-[10px] hover:!rounded-t-full',
|
||||
bottom:
|
||||
'!bottom-[-7px] !h-[7px] !w-5 !rounded-b-[2px] !rounded-t-none hover:!bottom-[-10px] hover:!h-[10px] hover:!rounded-b-full',
|
||||
'!bottom-[-8px] !h-[7px] !w-5 !rounded-b-[2px] !rounded-t-none hover:!bottom-[-11px] hover:!h-[10px] hover:!rounded-b-full',
|
||||
}
|
||||
|
||||
return cn(baseClasses, colorClasses, positionClasses[position])
|
||||
|
||||
@@ -57,9 +57,10 @@ import { cn } from '@/lib/core/utils/cn'
|
||||
/**
|
||||
* Shared base styles for all popover interactive items.
|
||||
* Ensures consistent height and styling across items, folders, and back button.
|
||||
* Uses fast transitions (duration-75) to prevent hover state "jumping" during rapid mouse movement.
|
||||
*/
|
||||
const POPOVER_ITEM_BASE_CLASSES =
|
||||
'flex h-[25px] min-w-0 cursor-pointer items-center gap-[8px] rounded-[6px] px-[6px] font-base text-[var(--text-primary)] text-[12px] transition-colors dark:text-[var(--text-primary)] [&_svg]:transition-colors disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed'
|
||||
'flex h-[25px] min-w-0 cursor-pointer items-center gap-[8px] rounded-[6px] px-[6px] font-base text-[var(--text-primary)] text-[12px] transition-colors duration-75 dark:text-[var(--text-primary)] [&_svg]:transition-colors [&_svg]:duration-75 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed'
|
||||
|
||||
/**
|
||||
* Variant-specific active state styles for popover items.
|
||||
|
||||
@@ -42,9 +42,7 @@ export function openCopilotWithMessage(message: string): void {
|
||||
return
|
||||
}
|
||||
|
||||
const messageWithInstructions = `${trimmedMessage}\n\nPlease fix this.`
|
||||
|
||||
void copilotStore.sendMessage(messageWithInstructions, { stream: true }).catch((error) => {
|
||||
void copilotStore.sendMessage(trimmedMessage, { stream: true }).catch((error) => {
|
||||
logger.error('Failed to send message to copilot', { error })
|
||||
})
|
||||
|
||||
|
||||
@@ -110,6 +110,10 @@ export const useTerminalConsoleStore = create<ConsoleStore>()(
|
||||
if (isErrorNotificationsEnabled) {
|
||||
try {
|
||||
const errorMessage = String(newEntry.error)
|
||||
const blockName = newEntry.blockName || 'Unknown Block'
|
||||
|
||||
// Copilot message includes block name for better debugging context
|
||||
const copilotMessage = `${errorMessage}\n\nError in ${blockName}.\n\nPlease fix this.`
|
||||
|
||||
useNotificationStore.getState().addNotification({
|
||||
level: 'error',
|
||||
@@ -117,7 +121,7 @@ export const useTerminalConsoleStore = create<ConsoleStore>()(
|
||||
workflowId: entry.workflowId,
|
||||
action: {
|
||||
type: 'copilot',
|
||||
message: errorMessage,
|
||||
message: copilotMessage,
|
||||
},
|
||||
})
|
||||
} catch (notificationError) {
|
||||
|
||||
Reference in New Issue
Block a user