Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -88,6 +89,8 @@ export function DiskManagementForm() {
},
})

const { hasAccess, entitlementConfig } = useCheckEntitlements('instances.compute_update')

const [isDialogOpen, setIsDialogOpen] = useState<boolean>(false)
const [refetchInterval, setRefetchInterval] = useState<number | false>(false)
const [message, setMessageState] = useState<DiskManagementMessage | null>(null)
Expand Down Expand Up @@ -192,16 +195,15 @@ 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
const totalSize = formState.defaultValues?.totalSize || 0
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

Expand Down Expand Up @@ -316,7 +318,7 @@ export function DiskManagementForm() {
<ScaffoldContainer className="relative flex flex-col gap-10" bottomPadding>
<NoticeBar
type="default"
visible={isPlanUpgradeRequired}
visible={!hasAccess}
title="Compute and Disk configuration is not available on the Free Plan"
actions={<UpgradePlanButton source="diskManagementConfigure" plan="Pro" />}
description="You will need to upgrade to at least the Pro Plan to configure compute and disk"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<TableField>) => void
Expand All @@ -26,6 +27,7 @@ const SUCCESS_MESSAGE_DURATION_MS = 3000
export const QuickstartAIWidget = ({ onSelectTable, disabled }: QuickstartAIWidgetProps) => {
const [lastGeneratedPrompt, setLastGeneratedPrompt] = useState('')
const inputRef = useRef<HTMLInputElement>(null)
const track = useTrack()

const {
generateTables,
Expand Down Expand Up @@ -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 (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<TableField>) => void
Expand All @@ -21,22 +22,40 @@ export const QuickstartTemplatesWidget = ({
disabled,
}: QuickstartTemplatesWidgetProps) => {
const [activeCategory, setActiveCategory] = useState<string | null>(null)
const track = useTrack()

useEffect(() => {
if (activeCategory === null && CATEGORIES.length > 0) {
setActiveCategory(CATEGORIES[0])
}
}, [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] || [] : []
Expand All @@ -58,7 +77,7 @@ export const QuickstartTemplatesWidget = ({
{CATEGORIES.map((category) => (
<button
key={category}
onClick={() => setActiveCategory(category)}
onClick={() => handleCategorySelect(category)}
disabled={disabled}
role="tab"
aria-selected={activeCategory === category}
Expand Down
27 changes: 23 additions & 4 deletions apps/studio/components/layouts/Tabs/NewTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { partition } from 'lodash'
import { Table2 } from 'lucide-react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useMemo, useState } from 'react'
import { useEffect, useMemo, useRef, useState } from 'react'
import { toast } from 'sonner'

import { useParams } from 'common'
Expand All @@ -20,6 +20,7 @@ import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { usePHFlag } from 'hooks/ui/useFlag'
import { uuidv4 } from 'lib/helpers'
import { useProfile } from 'lib/profile'
import { useTrack } from 'lib/telemetry/track'
import { AssistantMessageType, useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2'
import { useTableEditorStateSnapshot } from 'state/table-editor'
Expand All @@ -28,12 +29,12 @@ import { createTabId, useTabsStateSnapshot } from 'state/tabs'
import {
AiIconAnimation,
Button,
cn,
SQL_ICON,
Tabs_Shadcn_,
TabsContent_Shadcn_,
TabsList_Shadcn_,
TabsTrigger_Shadcn_,
Tabs_Shadcn_,
cn,
} from 'ui'
import { useEditorType } from '../editors/EditorsLayout.hooks'
import { ActionCard } from './ActionCard'
Expand Down Expand Up @@ -65,8 +66,10 @@ export function NewTab() {
const [isCreatingChat, setIsCreatingChat] = useState(false)
const [templates] = partition(SQL_TEMPLATES, { type: 'template' })
const [quickstarts] = partition(SQL_TEMPLATES, { type: 'quickstart' })
const hasTrackedExposure = useRef(false)

const { mutate: sendEvent } = useSendEventMutation()
const track = useTrack()
const { can: canCreateSQLSnippet } = useAsyncCheckPermissions(
PermissionAction.CREATE,
'user_content',
Expand All @@ -78,7 +81,7 @@ export function NewTab() {

/**
* Returns:
* - `QuickstartVariant`: user variation (if bucketed into AI, Templates, or future variants)
* - `QuickstartVariant`: user variation (`ai`, `templates`, `assistant`)
* - `false`: user not yet bucketed or not targeted for experiment
* - `undefined`: PostHog still loading
*/
Expand All @@ -99,6 +102,15 @@ export function NewTab() {
? tableQuickstartVariant
: null

useEffect(() => {
if (activeQuickstartVariant && !hasTrackedExposure.current) {
hasTrackedExposure.current = true
track('table_quickstart_opened', {
variant: activeQuickstartVariant,
})
}
}, [activeQuickstartVariant, track])

const handleOpenAssistant = () => {
if (isCreatingChat) return

Expand All @@ -111,6 +123,9 @@ export function NewTab() {
})

if (!chatId) {
track('table_quickstart_assistant_opened', {
chatCreated: false,
})
throw new Error('Failed to create chat')
}

Expand All @@ -127,6 +142,10 @@ export function NewTab() {
}

aiSnap.saveMessage([userMessage, assistantMessage])

track('table_quickstart_assistant_opened', {
chatCreated: true,
})
} catch (error) {
console.error('Failed to open AI assistant:', error)
const message = error instanceof Error ? error.message : 'Unknown error'
Expand Down
2 changes: 1 addition & 1 deletion apps/studio/lib/api/self-hosted/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export const POSTGRES_PORT = process.env.POSTGRES_PORT || 5432
export const POSTGRES_HOST = process.env.POSTGRES_HOST || 'db'
export const POSTGRES_DATABASE = process.env.POSTGRES_DB || 'postgres'
export const POSTGRES_PASSWORD = process.env.POSTGRES_PASSWORD || 'postgres'
export const POSTGRES_USER_READ_WRITE = 'postgres'
export const POSTGRES_USER_READ_WRITE = 'supabase_admin'
export const POSTGRES_USER_READ_ONLY = 'supabase_read_only_user'
11 changes: 11 additions & 0 deletions apps/www/_events/2025-11-06__uleam-tech-fest-hackathon.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
title: 'Hackathon - Uleam Tech Fest'
type: 'hackathon'
onDemand: false
disable_page_build: true
link: { href: https://luma.com/iz19mnqn, target: '_blank' }
date: '2025-11-06T14:00:00.000-05:00'
timezone: 'America/Guayaquil'
categories:
- hackathon
---
12 changes: 12 additions & 0 deletions apps/www/_events/2025-11-13__aic-ha-11-13.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: '🧜‍♀️ The AI Collective HR • Vibecoding 101: Launch your idea today'
type: 'workshop'
onDemand: false
disable_page_build: true
link: { href: https://luma.com/aic-ha-11-13, target: '_blank' }
date: '2025-11-13T18:00:00.000-04:00'
timezone: 'America/Detroit'
duration: '2 hours'
categories:
- workshop
---
Loading
Loading