diff --git a/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx b/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx index 34b228bc60ef2..19ab6c1881f0a 100644 --- a/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx +++ b/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx @@ -64,6 +64,7 @@ import { } from './ui/DiskManagement.constants' import { NoticeBar } from './ui/NoticeBar' import { SpendCapDisabledSection } from './ui/SpendCapDisabledSection' +import { useCheckEntitlements } from 'hooks/misc/useCheckEntitlements' export function DiskManagementForm() { const { ref: projectRef } = useParams() @@ -88,6 +89,8 @@ export function DiskManagementForm() { }, }) + const { hasAccess, entitlementConfig } = useCheckEntitlements('instances.compute_update') + const [isDialogOpen, setIsDialogOpen] = useState(false) const [refetchInterval, setRefetchInterval] = useState(false) const [message, setMessageState] = useState(null) @@ -192,7 +195,7 @@ export function DiskManagementForm() { const isRequestingChanges = data?.requested_modification !== undefined const readReplicas = (databases ?? []).filter((db) => db.identifier !== projectRef) - const isPlanUpgradeRequired = org?.plan.id === 'free' + const isPlanUpgradeRequired = !hasAccess const { formState } = form const usedSize = Math.round(((diskUtil?.metrics.fs_used_bytes ?? 0) / GB) * 100) / 100 @@ -200,8 +203,7 @@ export function DiskManagementForm() { const usedPercentage = (usedSize / totalSize) * 100 const disableIopsThroughputConfig = - RESTRICTED_COMPUTE_FOR_THROUGHPUT_ON_GP3.includes(form.watch('computeSize')) && - org?.plan.id !== 'free' + RESTRICTED_COMPUTE_FOR_THROUGHPUT_ON_GP3.includes(form.watch('computeSize')) && !hasAccess const isBranch = project?.parent_project_ref !== undefined @@ -316,7 +318,7 @@ export function DiskManagementForm() { } description="You will need to upgrade to at least the Pro Plan to configure compute and disk" diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/QuickstartAIWidget.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/QuickstartAIWidget.tsx index 3127d0086d3c0..d9c5ba1af34ab 100644 --- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/QuickstartAIWidget.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/QuickstartAIWidget.tsx @@ -15,6 +15,7 @@ import { AI_QUICK_IDEAS } from './constants' import type { TableSuggestion } from './types' import { useAITableGeneration } from './useAITableGeneration' import { convertTableSuggestionToTableField } from './utils' +import { useTrack } from 'lib/telemetry/track' interface QuickstartAIWidgetProps { onSelectTable: (tableData: Partial) => void @@ -26,6 +27,7 @@ const SUCCESS_MESSAGE_DURATION_MS = 3000 export const QuickstartAIWidget = ({ onSelectTable, disabled }: QuickstartAIWidgetProps) => { const [lastGeneratedPrompt, setLastGeneratedPrompt] = useState('') const inputRef = useRef(null) + const track = useTrack() const { generateTables, @@ -53,32 +55,66 @@ export const QuickstartAIWidget = ({ onSelectTable, disabled }: QuickstartAIWidg const handleSelectTemplate = useCallback( (template: TableSuggestion) => { + track('table_quickstart_template_clicked', { + tableName: template.tableName, + columnCount: template.fields.length, + source: 'ai', + }) + const tableField = convertTableSuggestionToTableField(template) onSelectTable(tableField) toast.success(`Applied ${template.tableName} template. You can customize the fields below.`, { duration: SUCCESS_MESSAGE_DURATION_MS, }) }, - [onSelectTable] + [onSelectTable, track] ) const handleGenerateTables = useCallback( - async (promptOverride?: string) => { + async ({ + promptOverride, + wasQuickIdea = false, + }: { promptOverride?: string; wasQuickIdea?: boolean } = {}) => { const promptToUse = promptOverride ?? aiPrompt if (!promptToUse.trim() || isGenerating) return - await generateTables(promptToUse) - setLastGeneratedPrompt(promptToUse) + track('table_quickstart_ai_prompt_submitted', { + promptLength: promptToUse.length, + wasQuickIdea, + }) + + try { + const tables = await generateTables(promptToUse) + + track('table_quickstart_ai_generation_completed', { + success: tables.length > 0, + tablesGenerated: tables.length, + promptLength: promptToUse.length, + }) + + setLastGeneratedPrompt(promptToUse) + } catch (error) { + track('table_quickstart_ai_generation_completed', { + success: false, + tablesGenerated: 0, + promptLength: promptToUse.length, + errorMessage: error instanceof Error ? error.message : 'Unknown error', + }) + } }, - [aiPrompt, generateTables, isGenerating] + [aiPrompt, generateTables, isGenerating, track] ) const handleQuickIdea = useCallback( (idea: string) => { + track('table_quickstart_quick_idea_clicked', { + ideaText: idea, + }) + setAiPrompt(idea) - handleGenerateTables(idea) + handleGenerateTables({ promptOverride: idea, wasQuickIdea: true }) }, - [handleGenerateTables, setAiPrompt] + [handleGenerateTables, setAiPrompt, track] ) return ( diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/QuickstartTemplatesWidget.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/QuickstartTemplatesWidget.tsx index 14d2336a7755d..897a2f67f88d9 100644 --- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/QuickstartTemplatesWidget.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/QuickstartTemplatesWidget.tsx @@ -7,6 +7,7 @@ import type { TableField } from '../TableEditor.types' import { tableTemplates } from './templates' import type { TableSuggestion } from './types' import { convertTableSuggestionToTableField } from './utils' +import { useTrack } from 'lib/telemetry/track' interface QuickstartTemplatesWidgetProps { onSelectTemplate: (tableData: Partial) => void @@ -21,6 +22,7 @@ export const QuickstartTemplatesWidget = ({ disabled, }: QuickstartTemplatesWidgetProps) => { const [activeCategory, setActiveCategory] = useState(null) + const track = useTrack() useEffect(() => { if (activeCategory === null && CATEGORIES.length > 0) { @@ -28,15 +30,32 @@ export const QuickstartTemplatesWidget = ({ } }, [activeCategory]) + const handleCategorySelect = useCallback( + (category: string) => { + setActiveCategory(category) + track('table_quickstart_category_clicked', { + categoryName: category, + }) + }, + [track] + ) + const handleSelectTemplate = useCallback( (template: TableSuggestion) => { + track('table_quickstart_template_clicked', { + tableName: template.tableName, + columnCount: template.fields.length, + source: 'templates', + categoryName: activeCategory ?? 'Unknown', + }) + const tableField = convertTableSuggestionToTableField(template) onSelectTemplate(tableField) toast.success(`Applied ${template.tableName} template. You can customize the fields below.`, { duration: SUCCESS_MESSAGE_DURATION_MS, }) }, - [onSelectTemplate] + [onSelectTemplate, track, activeCategory] ) const displayedTemplates = activeCategory ? tableTemplates[activeCategory] || [] : [] @@ -58,7 +77,7 @@ export const QuickstartTemplatesWidget = ({ {CATEGORIES.map((category) => (