feat(studio): rebuild Workers empty state on EmptyStatePresentational

The previous empty state used a bespoke two-column Card with steps and a
right-rail — inconsistent with the design system and carrying wrong info
(listed Bun/Python as supported runtimes, referenced US West without noting
the alpha lock).

Rewrite on ui-patterns/EmptyStatePresentational: BoxPlus icon, active-language
title ("Deploy your first worker"), a short description aligned with the
Private Alpha requirements (Dockerfile/Node.js/Deno supported, US West
(Oregon), Bun and Python coming soon), and the primary Deploy worker /
Deploy with CLI actions from the previous version.

Below the actions, a tabbed snippet block using WorkerSnippetTabs seeded with
EXAMPLE_WORKER exposes AI prompt, CLI, and cURL variants — copy-ready, so a
user landing here can go straight to a template without leaving the page.

Also fix a drive-by: the config.toml snippet's region comment said us-west-1
while WORKERS_REGION is us-west-2. Corrected to match.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XQ5b58nwfCGsifA7PCheQb
This commit is contained in:
Claude committed 2026-08-20 09:30:21 +00:00
1 parent 0ae221455d
commit dd491f78b2
2 files changed
+37 -92

No files matched your search

@@ -1,110 +1,55 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { Plus, Sparkles, Terminal } from 'lucide-react'
import { Button, Card } from 'ui'
import { BoxPlus } from 'icons'
import { Plus, Terminal } from 'lucide-react'
import { Button } from 'ui'
import { EmptyStatePresentational } from 'ui-patterns/EmptyStatePresentational'
import { EXAMPLE_WORKER } from './workerSnippets'
import { WorkerSnippetTabs } from './WorkerSnippetTabs'
import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
import CopyButton from '@/components/ui/CopyButton'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
import { WORKERS_CLI_DEPLOY, WORKERS_SKILL_MARKDOWN } from '@/lib/constants/workers'
interface WorkersEmptyStateProps {
onDeploy: () => void
onCreate: () => void
}
const STEPS = [
{
title: 'Detects your stack',
description:
'The CLI inspects your project and picks the right runtime — Node, Deno, Bun, Python, or your Dockerfile.',
},
{
title: 'Builds & schedules',
description:
'Your worker is built and scheduled onto a microVM in US West, right next to your database.',
},
{
title: 'Streams back here',
description: 'Lifecycle events and logs stream to Logflare and show up on this page.',
},
]
export const WorkersEmptyState = ({ onDeploy, onCreate }: WorkersEmptyStateProps) => {
const { can: canDeployWorkers } = useAsyncCheckPermissions(PermissionAction.FUNCTIONS_WRITE, '*')
return (
<Card className="grid grid-cols-1 divide-y divide-default lg:grid-cols-[1.6fr_1fr] lg:divide-x lg:divide-y-0">
<div className="flex flex-col gap-6 p-8">
<div className="space-y-2">
<h3 className="text-lg text-foreground">Deploy a worker</h3>
<p className="max-w-md text-sm text-foreground-light">
No workers yet. Run managed compute in microVMs next to your database. Deploy from the
dashboard, or push your own code with the Supabase CLI.
</p>
</div>
<div className="flex items-center gap-2">
<ButtonTooltip
variant="primary"
icon={<Plus />}
disabled={!canDeployWorkers}
onClick={onCreate}
tooltip={{
content: {
side: 'bottom',
text: canDeployWorkers
? undefined
: 'You need additional permissions to deploy workers',
},
}}
>
New worker
</ButtonTooltip>
<Button variant="default" icon={<Terminal />} onClick={onDeploy}>
Deploy with CLI
</Button>
</div>
<ol className="space-y-5">
{STEPS.map((step, index) => (
<li key={step.title} className="flex gap-3">
<span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full border border-strong text-xs text-foreground-light">
{index + 1}
</span>
<div className="space-y-0.5">
<p className="text-sm text-foreground">{step.title}</p>
<p className="max-w-md text-sm text-foreground-lighter">{step.description}</p>
</div>
</li>
))}
</ol>
<EmptyStatePresentational
icon={BoxPlus}
title="Deploy your first worker"
description="Run backend workers in microVMs next to your database. Dockerfile, Node.js and Deno supported at Private Alpha, in US West (Oregon)."
className="gap-y-6 py-8"
>
<div className="flex items-center gap-2">
<ButtonTooltip
variant="primary"
size="tiny"
icon={<Plus size={14} />}
disabled={!canDeployWorkers}
onClick={onCreate}
tooltip={{
content: {
side: 'bottom',
text: canDeployWorkers
? undefined
: 'You need additional permissions to deploy workers',
},
}}
>
Deploy worker
</ButtonTooltip>
<Button variant="default" size="tiny" icon={<Terminal size={14} />} onClick={onDeploy}>
Deploy with CLI
</Button>
</div>
<div className="flex flex-col gap-4 p-8">
<p className="text-xs font-mono uppercase tracking-wider text-foreground-lighter">
Prefer the CLI?
</p>
<div className="rounded-md border border-default bg-surface-100 px-3 py-2 font-mono text-sm text-foreground-light">
{WORKERS_CLI_DEPLOY}
</div>
<div className="space-y-2 rounded-md border border-default p-4">
<div className="flex items-center gap-2">
<span className="text-sm text-foreground">SKILL.md</span>
<span className="inline-flex items-center gap-1 rounded-full border border-strong px-1.5 py-0.5 text-[10px] uppercase tracking-wide text-foreground-lighter">
<Sparkles size={10} /> For agents
</span>
</div>
<p className="text-sm text-foreground-lighter">
Drop a skill file into your agent so it can deploy and manage workers for you.
</p>
<div className="flex items-center gap-3 pt-1">
<CopyButton text={WORKERS_SKILL_MARKDOWN} variant="default" size="tiny">
Copy SKILL.md
</CopyButton>
</div>
</div>
<div className="w-full max-w-[640px] pt-2">
<WorkerSnippetTabs input={EXAMPLE_WORKER} tabs={['ai', 'cli', 'curl']} />
</div>
</Card>
</EmptyStatePresentational>
)
}
@@ -52,7 +52,7 @@ export function buildWorkerSnippets(input: WorkerSnippetInput): WorkerSnippets {
`size = "${input.size}" # ${formatSize(input.size)}`,
`access = "${input.access}"`,
`instances = ${input.instances}`,
`# region is locked to us-west-1 at alpha`,
`# region is locked to us-west-2 at alpha`,
].join('\n')
const authHeader =