Files
supabase/apps/studio/components/interfaces/Database/Replication/DestinationLogo.tsx
T
Danny White ffc76c1e36 feat(studio): give replication destinations a brand mark (#50251)
## What kind of change does this PR introduce?

Studio UI polish. This is the first PR in the Pipelines review stack and
targets `master`. Resolves DEPR-674.

## What is the current behaviour?

Replication destinations use generic line icons across the destination
picker, pipelines list, and replication diagram. The existing shared
ClickHouse and Snowflake assets also use older artwork.

## What is the new behaviour?

Adds a reusable `DestinationLogo` treatment and uses it consistently
across Replication surfaces. BigQuery, ClickHouse, DuckLake, and
Snowflake now use their colour brand marks, while destinations without a
dedicated asset retain their existing line icon in the same frame.

The refreshed ClickHouse and Snowflake artwork replaces the canonical
shared assets, so existing consumers such as the Wrappers catalogue
receive the updated marks too.

| Light | Dark |
| --- | --- |
| <img width="572" height="804" alt="CleanShot 2026-09-11 at 16 48
42@2x"
src="https://github.com/user-attachments/assets/5c2eaef3-8714-4c0a-8bcc-7c8618abd677"
/> | <img width="552" height="788" alt="CleanShot 2026-09-11 at 16 47
30@2x"
src="https://github.com/user-attachments/assets/2aff8775-cdc1-4d6b-9f78-7b40d42e102a"
/> |

| Add Pipeline form |
| --- |
| <img width="1252" height="730" alt="CleanShot 2026-09-11 at 16 48
57@2x"
src="https://github.com/user-attachments/assets/025a158c-57ee-495e-8356-00ed1717d09d"
/> |

## To test

1. Open `/project/<ref>/database/replication` and start adding a
pipeline.
2. Confirm the BigQuery, ClickHouse, DuckLake, and Snowflake marks
appear consistently in the destination picker, pipelines list, and
replication diagram.
3. Open the ClickHouse and Snowflake entries in the Wrappers catalogue
and confirm they use the refreshed artwork.
4. Confirm Analytics Bucket retains its existing fallback icon within
the same frame.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Visual Updates**
* Destination logos now display dedicated brand marks for ClickHouse,
DuckLake, Snowflake, and BigQuery.
* Updated replication destination selectors, rows, and diagrams to use
consistent destination logos.
  * Adjusted the destination type column width for improved layout.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-14 09:31:27 +10:00

62 lines
2.1 KiB
TypeScript

import { cn, StatusIcon } from 'ui'
import { DestinationIcon } from './DestinationIcon'
import type { DestinationType } from './DestinationPanel/DestinationPanel.types'
import { BASE_PATH } from '@/lib/constants'
// Destinations with a brand mark. Anything absent falls back to the line icon in the same frame,
// so a new destination type never renders an empty square.
const BRAND_MARK_BY_TYPE: Partial<Record<DestinationType, string>> = {
BigQuery: `${BASE_PATH}/img/icons/bigquery-icon.svg`,
ClickHouse: `${BASE_PATH}/img/icons/clickhouse-icon.svg`,
DuckLake: `${BASE_PATH}/img/icons/ducklake-icon.svg`,
Snowflake: `${BASE_PATH}/img/icons/snowflake-icon.svg`,
}
const SIZE_CLASS_NAME = {
small: { frame: 'h-8 w-8 rounded-md', mark: 'h-4 w-4', icon: 16 },
large: { frame: 'h-14 w-14 rounded-lg', mark: 'h-6 w-6', icon: 24 },
} as const
interface DestinationLogoProps {
type: DestinationType
size?: keyof typeof SIZE_CLASS_NAME
className?: string
/** Destructive badge on the bottom-right corner (e.g. table replication errors). */
hasErrors?: boolean
}
/**
* A destination's brand mark in a square app-icon frame, used wherever a destination is the
* subject: the list rows, the pipeline header, and the replication diagram.
*/
export const DestinationLogo = ({
type,
size = 'small',
className,
hasErrors = false,
}: DestinationLogoProps) => {
const sizing = SIZE_CLASS_NAME[size]
const brandMark = BRAND_MARK_BY_TYPE[type]
return (
<span className={cn('relative inline-flex shrink-0', className)}>
<span className={cn('flex items-center justify-center border bg-surface-100', sizing.frame)}>
{brandMark === undefined ? (
<DestinationIcon type={type} size={sizing.icon} className="text-foreground-light" />
) : (
<img src={brandMark} alt="" aria-hidden className={sizing.mark} />
)}
</span>
{hasErrors && (
<span
className="absolute -bottom-1 -right-1 rounded-sm bg-background outline outline-2 outline-background"
aria-hidden
>
<StatusIcon variant="destructive" />
</span>
)}
</span>
)
}