Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b02ad91
fix(studio): stop unified logs bar chart animation replay on click FE…
jordienr Jul 15, 2026
1b1b1ea
chore: remove dead telemetry code (#47950)
pamelachia Jul 15, 2026
d23f860
feat(www): Partner Catalog update (#46757)
fsansalvadore Jul 15, 2026
00f75b6
fix(studio): bottom padding projects list (#47959)
kemaldotearth Jul 15, 2026
92b8ba7
fix(studio): give unified logs filter 'Only' button a solid backgroun…
jordienr Jul 15, 2026
320604d
feat(studio): ship both upgrade CTA placements, remove A/B experiment…
myerekapan Jul 15, 2026
a23f80d
feat(studio): identify unified logs analytics queries (#47963)
jordienr Jul 15, 2026
e218b24
fix(studio): disable unified logs on self-hosted (#47727)
jordienr Jul 15, 2026
3f20913
fix(billing): exit survey does not fire after downgrade via cancellat…
juleswritescode Jul 15, 2026
f0d2ae8
docs: clarify Vault/pgsodium root key lifecycle and portability (#47876)
aantti Jul 15, 2026
7cffbcc
docs(cli): add local-dev workflow guide and restructure CLI docs (#47…
aantti Jul 15, 2026
93e1631
fix: class name for text on infoicon (#47933)
kemaldotearth Jul 15, 2026
13330e6
fix(ui): expandable video preview image (#47964)
fsansalvadore Jul 15, 2026
c1bd941
docs: clarify edge function deployment size limits (5MB server-side v…
claude[bot] Jul 15, 2026
069051b
test(studio): cover Supabase API key formats in project client tests …
mandarini Jul 15, 2026
932b5dc
Remove skills page from ui library (#47947)
SaxonF Jul 15, 2026
cfd6af4
fix(studio): autoscaling marker positioning (#47958)
kemaldotearth Jul 15, 2026
805aee2
fix(studio): color regressions after theme update (#47794)
dnywh Jul 15, 2026
df69219
fix(ui): restore success and warning badge contrast (#47828)
dnywh Jul 15, 2026
8a37784
docs: add plugins package quick install for AI coding agent plugin (#…
Rodriguespn Jul 15, 2026
72d623f
Joshen/fe 3775 create a larger assistant workspace for observability …
joshenlim Jul 15, 2026
564185e
fix(studio): soften unified logs success grey (#47972)
dnywh Jul 15, 2026
5d0043f
Apply max width for ai assistant panel when maximized (#47974)
joshenlim Jul 15, 2026
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
33 changes: 33 additions & 0 deletions apps/design-system/__registry__/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1677,6 +1677,39 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: []
},
"success-check-demo": {
name: "success-check-demo",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/success-check-demo")),
source: "",
files: ["registry/default/example/success-check-demo.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"success-check-selected": {
name: "success-check-selected",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/success-check-selected")),
source: "",
files: ["registry/default/example/success-check-selected.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"success-check-progress": {
name: "success-check-progress",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/success-check-progress")),
source: "",
files: ["registry/default/example/success-check-progress.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"switch-demo": {
name: "switch-demo",
type: "components:example",
Expand Down
5 changes: 5 additions & 0 deletions apps/design-system/config/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,11 @@ export const docsConfig: DocsConfig = {
href: '/docs/components/sonner',
items: [],
},
{
title: 'Success Check',
href: '/docs/components/success-check',
items: [],
},
{
title: 'Switch',
href: '/docs/components/switch',
Expand Down
33 changes: 33 additions & 0 deletions apps/design-system/content/docs/components/success-check.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
title: Success Check
description: A brand-coloured success indicator with a check mark.
component: true
---

Use `SuccessCheck` when you need a compact, consistent mark for:

- **Selected state:** e.g. the chosen organisation in a list of cards
- **Completion progress:** e.g. finished steps in an upgrade or setup flow

<ComponentPreview name="success-check-demo" peekCode />

## Usage

```tsx
import { SuccessCheck } from 'ui'
;<SuccessCheck />
```

## Examples

### Selected state

Show which option is currently selected. Position the check absolutely in the trailing corner of the selectable item.

<ComponentPreview name="success-check-selected" peekCode />

### Completion progress

Mark finished steps in a linear progress list. Incomplete steps use a plain circle instead.

<ComponentPreview name="success-check-progress" peekCode />
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { SuccessCheck } from 'ui'

export default function SuccessCheckDemo() {
return <SuccessCheck />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { SuccessCheck } from 'ui'

const STEPS = ['Preparing', 'Upgrading', 'Finalising']

export default function SuccessCheckProgress() {
const completedThrough = 1

return (
<div className="flex flex-col gap-3">
{STEPS.map((step, index) => {
const isCompleted = index < completedThrough
const isCurrent = index === completedThrough

return (
<div key={step} className="flex items-center gap-3">
{isCompleted ? (
<SuccessCheck />
) : (
<span
className={`flex size-5 shrink-0 items-center justify-center rounded-full border ${
isCurrent ? 'border-foreground' : 'border-muted bg-overlay-hover'
}`}
/>
)}
<span
className={`text-sm ${
isCurrent
? 'text-foreground'
: isCompleted
? 'text-foreground-light'
: 'text-foreground-lighter'
}`}
>
{isCurrent ? `${step}…` : isCompleted ? `${step} complete` : step}
</span>
</div>
)
})}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use client'

import { useState } from 'react'
import { cn, SuccessCheck } from 'ui'

const OPTIONS = ['Production', 'Staging', 'Development']

export default function SuccessCheckSelected() {
const [selected, setSelected] = useState(OPTIONS[0])

return (
<div className="flex w-full max-w-sm flex-col gap-2">
{OPTIONS.map((option) => {
const isSelected = selected === option

return (
<button
key={option}
type="button"
aria-pressed={isSelected}
onClick={() => setSelected(option)}
className={cn(
'relative flex w-full items-center rounded-md border px-4 py-3 text-left text-sm transition-colors',
isSelected
? 'border-brand bg-brand-200/20 pr-10 dark:bg-brand-300'
: 'hover:border-default hover:bg-surface-200'
)}
>
{option}
{isSelected && (
<SuccessCheck className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2" />
)}
</button>
)
})}
</div>
)
}
15 changes: 15 additions & 0 deletions apps/design-system/registry/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,21 @@ export const examples: Registry = [
registryDependencies: ['sonner'],
files: ['example/sonner-upload.tsx'],
},
{
name: 'success-check-demo',
type: 'components:example',
files: ['example/success-check-demo.tsx'],
},
{
name: 'success-check-selected',
type: 'components:example',
files: ['example/success-check-selected.tsx'],
},
{
name: 'success-check-progress',
type: 'components:example',
files: ['example/success-check-progress.tsx'],
},
{
name: 'switch-demo',
type: 'components:example',
Expand Down
12 changes: 8 additions & 4 deletions apps/docs/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@ NEXT_PUBLIC_BASE_PATH="/docs"

# Whether to enable features available only on Supabase's own hosted services
# Setting this to true requires certain secret keys
NEXT_PUBLIC_IS_PLATFORM="false"
NEXT_PUBLIC_IS_PLATFORM="true"

# Base URL for the hosted MCP server. Overrides the DEFAULT_MCP_URL_PLATFORM
# fallback in @ui-patterns/McpUrlBuilder.
NEXT_PUBLIC_MCP_URL="http://localhost:8080/mcp"

# Supabase project containing integration information
# Supabase project containing integration information (legacy)
NEXT_PUBLIC_MISC_URL="https://obuldanrptloktxcffvn.supabase.co"
NEXT_PUBLIC_MISC_ANON_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im9idWxkYW5ycHRsb2t0eGNmZnZuIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTg2MTQ2ODUsImV4cCI6MjAzNDE5MDY4NX0.NFt49g6DFkc1X5khCzN5p01iAVo2TMxlx88cY1V0E2M"

# Supabase project backing the Partner Catalog / Dashboard Integrations Marketplace
NEXT_PUBLIC_MARKETPLACE_API_URL="https://fgxbxpvumhvzrhqngsyu.supabase.co"
NEXT_PUBLIC_MARKETPLACE_PUBLISHABLE_KEY="sb_publishable_VuF5ZvGqj6ODhZgN1J_vMw_YbiEs1R6"

# Supabase project containing docs content information
NEXT_PUBLIC_SUPABASE_URL="https://xguihxuzqibwxjnimxev.supabase.co"
NEXT_PUBLIC_SUPABASE_ANON_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InhndWloeHV6cWlid3hqbmlteGV2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTgzNzc1MTgsImV4cCI6MjAzMzk1MzUxOH0.aIqjQ9V7djMxYit-DT1fYNV_VWMHSqldh_18XfX2_BE"
NEXT_PUBLIC_MARKETPLACE_API_URL="https://otqhrpbxhxkrhrnjqbba.supabase.co/"
NEXT_PUBLIC_MARKETPLACE_PUBLISHABLE_KEY="sb_publishable_ZVVKKu1s88KsSBWVYlou-g_phb2OJVQ"
93 changes: 77 additions & 16 deletions apps/docs/app/guides/integrations/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { IS_PLATFORM } from 'common'
import { unstable_cache } from 'next/cache'
import { type NavMenuSection } from '~/components/Navigation/Navigation.types'
import { REVALIDATION_TAGS } from '~/features/helpers.fetch'
import Layout from '~/layouts/guides'
import { supabaseMisc } from '~/lib/supabaseMisc'
import { IS_PLATFORM } from 'common'
import {
createMarketplaceClient,
SUPABASE_LISTING_OVERRIDES,
SUPABASE_PARTNER_SLUG,
type CatalogListing,
} from 'common/marketplace-client'
import { unstable_cache } from 'next/cache'

export default async function IntegrationsLayout({ children }: { children: React.ReactNode }) {
const additionalNavItems = { integrations: await getPartners() }
Expand All @@ -16,26 +21,82 @@ export default async function IntegrationsLayout({ children }: { children: React
const getPartners = unstable_cache(getPartnersImpl, [], {
tags: [REVALIDATION_TAGS.PARTNERS],
})

async function getPartnersImpl() {
if (!IS_PLATFORM) return []

const { data, error } = await supabaseMisc()
.from('partners')
.select('slug, title')
.eq('approved', true)
.eq('type', 'technology')
.order('title')
const marketplaceClient = createMarketplaceClient()

const [{ data: partners, error }, { data: listings }] = await Promise.all([
marketplaceClient.from('partners').select('slug, name, type'),
marketplaceClient.from('catalog_listings').select('*'),
])
if (error) {
console.error(new Error('Error fetching partners', { cause: error }))
}

const partnerNavItems = (data ?? []).map(
(partner) =>
({
name: partner.title,
url: `https://supabase.com/partners/integrations/${partner.slug}` as `https://${string}`,
}) as Partial<NavMenuSection>
)
// Only "technology" partners belong in this list, not agencies/experts.
const technologyPartnerSlugs = new Set<string>()
const partnerNameBySlug = new Map<string, string>()
for (const partner of partners ?? []) {
if (!partner.slug) continue
partnerNameBySlug.set(partner.slug, partner.name ?? partner.slug)
if (partner.type === 'technology') technologyPartnerSlugs.add(partner.slug)
}

// Supabase-owned listings still get their own nav item, at their clean catalog page slug.
const supabaseOwnedNavItems: Partial<NavMenuSection>[] = []
const listingsByPartnerSlug = new Map<string, CatalogListing[]>()

for (const listing of listings ?? []) {
if (!listing.slug) continue

const override = SUPABASE_LISTING_OVERRIDES[listing.slug]
if (override) {
supabaseOwnedNavItems.push({
name: listing.title || override.name,
url: `https://supabase.com/partners/catalog/${override.slug}` as `https://${string}`,
})
continue
}

const partnerSlug = listing.partner_slug
if (
!partnerSlug ||
partnerSlug === SUPABASE_PARTNER_SLUG ||
!technologyPartnerSlugs.has(partnerSlug)
) {
continue
}

const partnerListings = listingsByPartnerSlug.get(partnerSlug) ?? []
partnerListings.push(listing)
listingsByPartnerSlug.set(partnerSlug, partnerListings)
}

// One nav item per listing (a partner with multiple listings — e.g. an FDW plus a
// Dashboard Integration — gets one entry per listing), linking straight to the tab
// that listing occupies on its Partner Catalog page.
const partnerNavItems: Partial<NavMenuSection>[] = [
...Array.from(listingsByPartnerSlug.entries()).flatMap(([partnerSlug, partnerListings]) => {
const partnerName = partnerNameBySlug.get(partnerSlug) ?? partnerSlug
const catalogUrl = `https://supabase.com/partners/catalog/${partnerSlug}`

// Show only listing name if partner has one listing
if (partnerListings.length === 1) {
const listingName = partnerListings[0].title || partnerName
return [{ name: listingName, url: catalogUrl as `https://${string}` }]
}

// otherwise show listing name (or slug if no title) plus partner name.
return partnerListings.map((listing) => ({
name: `${listing.title || listing.slug} (${partnerName})`,
url: `${catalogUrl}?tab=${listing.slug}` as `https://${string}`,
}))
}),
...supabaseOwnedNavItems,
]
partnerNavItems.sort((a, b) => (a.name ?? '').localeCompare(b.name ?? ''))

return partnerNavItems
}
4 changes: 2 additions & 2 deletions apps/docs/components/Navigation/Navigation.commands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ const navCommands = [
},
{
id: 'nav-integrations',
name: 'Go to Integrations',
route: 'https://supabase.com/partners/integrations',
name: 'Go to Partner Catalog',
route: 'https://supabase.com/partners/catalog',
icon: () => <ArrowRight />,
enabled: isFeatureEnabled('integrations:partners'),
},
Expand Down
Loading
Loading