Skip to content

Commit cfd6d74

Browse files
drankouclaude
andauthored
fix: render builds status filter dashes correctly in Safari (#459)
Fixes [ENG-4333](https://linear.app/e2b/issue/ENG-4333). The builds Status filter drew its dashed status rings with a CSS `border-dashed` on rounded elements, which Safari renders with uneven, sparse dashes (Chrome was fine). - Render the rings via the registry `StatusIcon` SVG instead of a CSS dashed border, keeping a `bg-bg` backdrop so the front ring masks the one behind it in the overlap. - Sync `StatusIcon` from the e2b registry to pick up `pathLength`, which evenly distributes the dash pattern around the circle. | Before | After | | ------- | ------- | | <img width="200" alt="CleanShot 2026-06-25 at 09 41 38" src="https://github.com/user-attachments/assets/76e68ef2-5b61-47d0-9e03-be13f9341d6e" /> | <img width="200" alt="CleanShot 2026-06-25 at 09 42 32" src="https://github.com/user-attachments/assets/c86023fa-4e81-4bcc-a410-1e0c8636af2c" /> | | Before | After | | ------- | ------- | | <img width="368" height="116" alt="CleanShot 2026-06-25 at 09 40 20@2x" src="https://github.com/user-attachments/assets/eed646a8-9d9b-446e-a743-43e01253d1ca" /> | <img width="364" height="118" alt="CleanShot 2026-06-25 at 09 40 06@2x" src="https://github.com/user-attachments/assets/b5871d8e-02bc-47d2-9029-20708ae2c647" /> | 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent ce6ef5c commit cfd6d74

3 files changed

Lines changed: 34 additions & 28 deletions

File tree

src/features/dashboard/common/log-level-filter.tsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
DropdownMenuRadioItem,
99
DropdownMenuTrigger,
1010
} from '@/ui/primitives/dropdown-menu'
11+
import { StatusIcon } from '@/ui/primitives/icons'
1112
import type { LogLevelValue } from './log-cells'
1213

1314
const DEFAULT_OPTIONS: Array<{ value: LogLevelValue; label: string }> = [
@@ -63,16 +64,13 @@ export function LogLevelFilter({
6364

6465
function LevelIndicator({ level }: { level: LogLevelValue }) {
6566
return (
66-
<div
67-
className={cn(
68-
'size-3.5 rounded-full bg-bg border-[1.5px] border-dashed',
69-
{
70-
'border-fg-tertiary': level === 'debug',
71-
'border-accent-info-highlight': level === 'info',
72-
'border-accent-warning-highlight': level === 'warn',
73-
'border-accent-error-highlight': level === 'error',
74-
}
75-
)}
67+
<StatusIcon
68+
className={cn({
69+
'text-fg-tertiary!': level === 'debug',
70+
'text-accent-info-highlight!': level === 'info',
71+
'text-accent-warning-highlight!': level === 'warn',
72+
'text-accent-error-highlight!': level === 'error',
73+
})}
7674
/>
7775
)
7876
}

src/features/dashboard/templates/builds/status-filter.tsx

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
DropdownMenuSeparator,
1111
DropdownMenuTrigger,
1212
} from '@/ui/primitives/dropdown-menu'
13+
import { StatusIcon } from '@/ui/primitives/icons'
1314
import { Status } from './table-cells'
1415

1516
const STATUS_OPTIONS: Array<{ value: BuildStatus; label: string }> = [
@@ -83,14 +84,15 @@ interface StatusIconsProps {
8384
}
8485

8586
function StatusIcons({ selectedStatuses }: StatusIconsProps) {
86-
const sortedStatuses = STATUS_DISPLAY_ORDER.filter((s) =>
87-
selectedStatuses.includes(s)
88-
)
89-
9087
return (
91-
<div className="flex -space-x-1.5">
92-
{sortedStatuses.map((status, i) => (
93-
<DashedStatusCircleIcon key={status} status={status} index={i} />
88+
<div className="flex -space-x-2">
89+
{STATUS_DISPLAY_ORDER.map((status, i) => (
90+
<DashedStatusCircleIcon
91+
key={status}
92+
status={status}
93+
index={i}
94+
selected={selectedStatuses.includes(status)}
95+
/>
9496
))}
9597
</div>
9698
)
@@ -99,23 +101,28 @@ function StatusIcons({ selectedStatuses }: StatusIconsProps) {
99101
interface DashedStatusCircleIconProps {
100102
status: BuildStatus
101103
index: number
104+
selected: boolean
102105
}
103106

104107
function DashedStatusCircleIcon({
105108
status,
106109
index,
110+
selected,
107111
}: DashedStatusCircleIconProps) {
108112
return (
109-
<div
110-
className={cn(
111-
'size-3.5 rounded-full bg-bg border-[1.5px] border-dashed',
112-
{
113-
'border-fg-tertiary': status === 'building',
114-
'border-accent-positive-highlight': status === 'success',
115-
'border-accent-error-highlight': status === 'failed',
116-
}
117-
)}
113+
<span
114+
className="relative grid shrink-0 place-items-center"
118115
style={{ rotate: `${index * 50}deg`, zIndex: index + 1 }}
119-
/>
116+
>
117+
<span className="col-start-1 row-start-1 size-3.5 rounded-full bg-bg" />
118+
<StatusIcon
119+
className={cn('col-start-1 row-start-1', {
120+
'text-fill!': !selected,
121+
'text-fg-tertiary!': selected && status === 'building',
122+
'text-accent-positive-highlight!': selected && status === 'success',
123+
'text-accent-error-highlight!': selected && status === 'failed',
124+
})}
125+
/>
126+
</span>
120127
)
121128
}

src/ui/primitives/icons/status-icon.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Icon, type IconProps } from './icon'
22

33
/**
4-
* ![StatusIcon](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTQuMTY2IDhDMTQuMTY2IDExLjMxMzcgMTEuNDc5NyAxNCA4LjE2NjAyIDE0QzQuODUyMzEgMTQgMi4xNjYwMiAxMS4zMTM3IDIuMTY2MDIgOEMyLjE2NjAyIDQuNjg2MjkgNC44NTIzMSAyIDguMTY2MDIgMkMxMS40Nzk3IDIgMTQuMTY2IDQuNjg2MjkgMTQuMTY2IDhaIiBzdHJva2U9IiM4ODg4ODgiIHN0cm9rZS13aWR0aD0iMS4zMzMzMyIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWRhc2hhcnJheT0iMS4zMyAyLjY3Ii8+PC9zdmc+)
4+
* ![StatusIcon](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTQuMTY2IDhDMTQuMTY2IDExLjMxMzcgMTEuNDc5NyAxNCA4LjE2NjAyIDE0QzQuODUyMzEgMTQgMi4xNjYwMiAxMS4zMTM3IDIuMTY2MDIgOEMyLjE2NjAyIDQuNjg2MjkgNC44NTIzMSAyIDguMTY2MDIgMkMxMS40Nzk3IDIgMTQuMTY2IDQuNjg2MjkgMTQuMTY2IDhaIiBzdHJva2U9IiM4ODg4ODgiIHN0cm9rZS13aWR0aD0iMS4zMzMzMyIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWRhc2hhcnJheT0iMS4zMyAyLjY3IiBwYXRoTGVuZ3RoPSIzMiIvPjwvc3ZnPg==)
55
*
66
* Synced from Figma `Icon/16px/Status`.
77
*/
@@ -14,6 +14,7 @@ export const StatusIcon = (props: IconProps) => (
1414
strokeLinejoin="round"
1515
strokeWidth="1.33333"
1616
strokeDasharray="1.33 2.67"
17+
pathLength={32}
1718
/>
1819
</Icon>
1920
)

0 commit comments

Comments
 (0)