mirror of
https://github.com/supabase/supabase.git
synced 2026-10-14 13:49:09 +03:00
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:
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 =
|
||||
|
||||
Reference in new issue
Block a user