Skip to content

Commit 4ba37e5

Browse files
Remove Bootstrap Icons (#1480)
This PR removes bootstrap-icons entirely from the app. It also adds an eslint plugin to detect uses and throw an error, this will help in the immediate short term with PRs in flight and merging downstream. Fixes HDX-3050
1 parent 58e78ab commit 4ba37e5

File tree

69 files changed

+685
-2470
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+685
-2470
lines changed

.changeset/hungry-cups-applaud.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hyperdx/app": patch
3+
---
4+
5+
Swap out bootstrap icons for tabler icons across app

agent_docs/tech_stack.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- **Charts/Visualization**: Recharts, uPlot
99
- **Code Editor**: CodeMirror (for SQL/JSON editing)
1010
- **Styling**: Mantine's built-in system, SCSS modules when needed
11+
- **Icons**: Use `@tabler/icons-react`
1112

1213
**UI Component Priority**: Mantine components first → Custom components on Mantine primitives → Custom SCSS modules as last resort
1314

packages/app/.storybook/preview-head.html

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
<link
2-
rel="stylesheet"
3-
href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css"
4-
/>
51
<link
62
rel="preconnect"
73
href="https://fonts.gstatic.com"

packages/app/eslint.config.mjs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,15 @@ export default [
6868
],
6969
},
7070
],
71+
// Temporary rule to enforce use of @tabler/icons-react instead of bi bi-icons
72+
// Will remove after we've updated all icons and let some PRs merge.
73+
'no-restricted-syntax': [
74+
'error',
75+
{
76+
selector: 'Literal[value=/\\bbi-\\b/i]',
77+
message: 'Please update to use @tabler/icons-react instead',
78+
},
79+
],
7180
'react-hooks/exhaustive-deps': 'error',
7281
'no-console': ['error', { allow: ['warn', 'error'] }],
7382
},

packages/app/pages/_document.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ export default function Document() {
1717
<script src="/__ENV.js" />
1818
{/* eslint-disable-next-line @next/next/no-sync-scripts */}
1919
<script src="https://cdn.jsdelivr.net/pyodide/v0.27.2/full/pyodide.js"></script>
20-
<link
21-
rel="stylesheet"
22-
href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css"
23-
/>
2420
</Head>
2521
<body>
2622
<Main />

packages/app/src/AlertsPage.tsx

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,17 @@ import {
2020
Tooltip,
2121
} from '@mantine/core';
2222
import { notifications } from '@mantine/notifications';
23-
import { IconBell } from '@tabler/icons-react';
23+
import {
24+
IconAlertTriangle,
25+
IconBell,
26+
IconBrandSlack,
27+
IconChartLine,
28+
IconCheck,
29+
IconChevronRight,
30+
IconHelpCircle,
31+
IconInfoCircleFilled,
32+
IconTableRow,
33+
} from '@tabler/icons-react';
2434
import { useQueryClient } from '@tanstack/react-query';
2535

2636
import { ErrorBoundary } from '@/components/ErrorBoundary';
@@ -312,7 +322,7 @@ function AlertDetails({ alert }: { alert: AlertsPageItem }) {
312322
{alert.dashboard?.name}
313323
{tileName ? (
314324
<>
315-
<i className="bi bi-chevron-right fs-8 mx-1 " />
325+
<IconChevronRight size={14} className="mx-1" />
316326
{tileName}
317327
</>
318328
) : null}
@@ -338,11 +348,11 @@ function AlertDetails({ alert }: { alert: AlertsPageItem }) {
338348
const alertIcon = (() => {
339349
switch (alert.source) {
340350
case AlertSource.TILE:
341-
return 'bi-graph-up';
351+
return <IconChartLine size={14} />;
342352
case AlertSource.SAVED_SEARCH:
343-
return 'bi-layout-text-sidebar-reverse';
353+
return <IconTableRow size={14} />;
344354
default:
345-
return 'bi-question';
355+
return <IconHelpCircle size={14} />;
346356
}
347357
})();
348358

@@ -359,9 +369,9 @@ function AlertDetails({ alert }: { alert: AlertsPageItem }) {
359369
const notificationMethod = React.useMemo(() => {
360370
if (alert.channel.type === 'webhook') {
361371
return (
362-
<span>
363-
Notify via <i className="bi bi-slack"></i> Webhook
364-
</span>
372+
<Group gap={2}>
373+
Notify via <IconBrandSlack size={16} /> Webhook
374+
</Group>
365375
);
366376
}
367377
}, [alert]);
@@ -400,8 +410,10 @@ function AlertDetails({ alert }: { alert: AlertsPageItem }) {
400410
className={styles.alertLink}
401411
title={linkTitle}
402412
>
403-
<i className={`bi ${alertIcon} me-2 fs-8`} />
404-
{alertName}
413+
<Group gap={2}>
414+
{alertIcon}
415+
{alertName}
416+
</Group>
405417
</Link>
406418
</div>
407419
<div className="fs-8 d-flex gap-2">
@@ -435,18 +447,18 @@ function AlertCardList({ alerts }: { alerts: AlertsPageItem[] }) {
435447
<div className="d-flex flex-column gap-4">
436448
{alarmAlerts.length > 0 && (
437449
<div>
438-
<div className={styles.sectionHeader}>
439-
<i className="bi bi-exclamation-triangle"></i> Triggered
440-
</div>
450+
<Group className={styles.sectionHeader}>
451+
<IconAlertTriangle size={14} /> Triggered
452+
</Group>
441453
{alarmAlerts.map((alert, index) => (
442454
<AlertDetails key={index} alert={alert} />
443455
))}
444456
</div>
445457
)}
446458
<div>
447-
<div className={styles.sectionHeader}>
448-
<i className="bi bi-check-lg"></i> OK
449-
</div>
459+
<Group className={styles.sectionHeader}>
460+
<IconCheck size={14} /> OK
461+
</Group>
450462
{okData.length === 0 && (
451463
<div className="text-center my-4 fs-8">No alerts</div>
452464
)}
@@ -472,7 +484,7 @@ export default function AlertsPage() {
472484
<div className="my-4">
473485
<Container maw={1500}>
474486
<Alert
475-
icon={<i className="bi bi-info-circle-fill " />}
487+
icon={<IconInfoCircleFilled size={16} />}
476488
color="gray"
477489
py="xs"
478490
mt="md"

packages/app/src/AppNav.components.tsx

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,19 @@ import {
1414
UnstyledButton,
1515
} from '@mantine/core';
1616
import { useDisclosure } from '@mantine/hooks';
17+
import {
18+
IconBook,
19+
IconBrandDiscord,
20+
IconBulb,
21+
IconChevronDown,
22+
IconChevronRight,
23+
IconChevronUp,
24+
IconHelp,
25+
IconLogout,
26+
IconSettings,
27+
IconUserCog,
28+
} from '@tabler/icons-react';
1729

18-
import { Icon } from '@/components/Icon';
1930
import InstallInstructionModal from '@/InstallInstructionsModal';
2031
import { useSources } from '@/source';
2132

@@ -132,7 +143,7 @@ export const AppNavUserMenu = ({
132143
</Text>
133144
</div>
134145
</Tooltip>
135-
<Icon name="chevron-right" className="fs-8 " />
146+
<IconChevronRight size={14} />
136147
</>
137148
)}
138149
</Group>
@@ -146,14 +157,14 @@ export const AppNavUserMenu = ({
146157
data-testid="team-settings-menu-item"
147158
href="/team"
148159
component={Link}
149-
leftSection={<Icon name="gear" />}
160+
leftSection={<IconSettings size={16} />}
150161
>
151162
Team Settings
152163
</Menu.Item>
153164
)}
154165
<Menu.Item
155166
data-testid="user-preferences-menu-item"
156-
leftSection={<Icon name="person-gear" />}
167+
leftSection={<IconUserCog size={16} />}
157168
onClick={onClickUserPreferences}
158169
>
159170
User Preferences
@@ -164,7 +175,7 @@ export const AppNavUserMenu = ({
164175
<Menu.Item
165176
data-testid="logout-menu-item"
166177
color="red"
167-
leftSection={<Icon name="box-arrow-left" />}
178+
leftSection={<IconLogout size={16} />}
168179
component={Link}
169180
href={logoutUrl}
170181
>
@@ -221,7 +232,7 @@ export const AppNavHelpMenu = ({
221232
<Menu.Target>
222233
<UnstyledButton data-testid="help-menu-trigger" w="100%">
223234
<Group align="center" justify="center" h={28}>
224-
<Icon name="question-lg" />
235+
<IconHelp size={16} />
225236
</Group>
226237
</UnstyledButton>
227238
</Menu.Target>
@@ -239,13 +250,13 @@ export const AppNavHelpMenu = ({
239250
data-testid="documentation-menu-item"
240251
href="https://clickhouse.com/docs/use-cases/observability/clickstack"
241252
component="a"
242-
leftSection={<Icon name="book" />}
253+
leftSection={<IconBook size={16} />}
243254
>
244255
Documentation
245256
</Menu.Item>
246257
<Menu.Item
247258
data-testid="discord-menu-item"
248-
leftSection={<Icon name="discord" />}
259+
leftSection={<IconBrandDiscord size={16} />}
249260
component="a"
250261
href="https://hyperdx.io/discord"
251262
target="_blank"
@@ -254,7 +265,7 @@ export const AppNavHelpMenu = ({
254265
</Menu.Item>
255266
<Menu.Item
256267
data-testid="setup-instructions-menu-item"
257-
leftSection={<Icon name="lightbulb" />}
268+
leftSection={<IconBulb size={16} />}
258269
onClick={onAddDataClick}
259270
>
260271
Setup Instructions
@@ -321,11 +332,11 @@ export const AppNavLink = ({
321332
size="sm"
322333
onClick={onToggle}
323334
>
324-
<i
325-
className={`fs-8 bi bi-chevron-${
326-
isExpanded ? 'up' : 'down'
327-
} text-muted-hover`}
328-
/>
335+
{isExpanded ? (
336+
<IconChevronUp size={14} className="text-muted-hover" />
337+
) : (
338+
<IconChevronDown size={14} className="text-muted-hover" />
339+
)}
329340
</ActionIcon>
330341
)}
331342
</Group>

packages/app/src/AppNav.tsx

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,15 @@ import {
2727
import { useDisclosure, useLocalStorage } from '@mantine/hooks';
2828
import {
2929
IconBell,
30+
IconBellFilled,
3031
IconChartDots,
32+
IconChevronDown,
33+
IconChevronRight,
34+
IconCommand,
3135
IconDeviceLaptop,
3236
IconLayoutGrid,
3337
IconLayoutSidebarLeftCollapse,
38+
IconSearch,
3439
IconSettings,
3540
IconSitemap,
3641
IconTable,
@@ -135,7 +140,7 @@ function SearchInput({
135140
return (
136141
<div className={styles.kbd}>
137142
{window.navigator.platform?.toUpperCase().includes('MAC') ? (
138-
<i className="bi bi-command" />
143+
<IconCommand size={8} />
139144
) : (
140145
<span style={{ letterSpacing: -2 }}>Ctrl</span>
141146
)}
@@ -161,7 +166,7 @@ function SearchInput({
161166
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
162167
onChange(e.currentTarget.value)
163168
}
164-
leftSection={<i className="bi bi-search fs-8 ps-1 " />}
169+
leftSection={<IconSearch size={16} className="ps-1" />}
165170
onKeyDown={handleKeyDown}
166171
rightSection={
167172
value ? (
@@ -208,7 +213,11 @@ const AppNavGroupLabel = ({
208213
}) => {
209214
return (
210215
<div className={styles.listGroupName} onClick={onClick}>
211-
<i className={`bi bi-chevron-${collapsed ? 'right' : 'down'}`} />
216+
{collapsed ? (
217+
<IconChevronRight size={14} />
218+
) : (
219+
<IconChevronDown size={14} />
220+
)}
212221
<div>{name}</div>
213222
</div>
214223
);
@@ -486,20 +495,25 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
486495
draggable
487496
data-savedsearchid={savedSearch.id}
488497
>
489-
<div className="d-inline-block text-truncate">{savedSearch.name}</div>
490-
{Array.isArray(savedSearch.alerts) && savedSearch.alerts.length > 0 ? (
491-
savedSearch.alerts.some(a => a.state === AlertState.ALERT) ? (
492-
<i
493-
className="bi bi-bell float-end text-danger ms-1"
494-
title="Has Alerts and is in ALERT state"
495-
></i>
496-
) : (
497-
<i
498-
className="bi bi-bell float-end ms-1"
499-
title="Has Alerts and is in OK state"
500-
></i>
501-
)
502-
) : null}
498+
<Group gap={2}>
499+
<div className="d-inline-block text-truncate">{savedSearch.name}</div>
500+
{Array.isArray(savedSearch.alerts) &&
501+
savedSearch.alerts.length > 0 ? (
502+
savedSearch.alerts.some(a => a.state === AlertState.ALERT) ? (
503+
<IconBellFilled
504+
size={14}
505+
className="float-end text-danger ms-1"
506+
aria-label="Has Alerts and is in ALERT state"
507+
/>
508+
) : (
509+
<IconBell
510+
size={14}
511+
className="float-end ms-1"
512+
aria-label="Has Alerts and is in OK state"
513+
/>
514+
)
515+
) : null}
516+
</Group>
503517
</Link>
504518
),
505519
[

packages/app/src/AuthPage.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
Stack,
1515
TextInput,
1616
} from '@mantine/core';
17+
import { IconAt, IconLock } from '@tabler/icons-react';
1718

1819
import api from './api';
1920
import * as config from './config';
@@ -150,7 +151,7 @@ export default function AuthPage({ action }: { action: 'register' | 'login' }) {
150151
withAsterisk={false}
151152
placeholder="[email protected]"
152153
type="email"
153-
leftSection={<i className="bi bi-at fs-5" />}
154+
leftSection={<IconAt size={18} />}
154155
error={errors.email?.message}
155156
required
156157
{...form.email}
@@ -159,7 +160,7 @@ export default function AuthPage({ action }: { action: 'register' | 'login' }) {
159160
size="md"
160161
label="Password"
161162
withAsterisk={false}
162-
leftSection={<i className="bi bi-lock-fill" />}
163+
leftSection={<IconLock size={16} />}
163164
error={errors.password?.message}
164165
required
165166
placeholder="Password"
@@ -179,7 +180,7 @@ export default function AuthPage({ action }: { action: 'register' | 'login' }) {
179180
size="md"
180181
required
181182
withAsterisk={false}
182-
leftSection={<i className="bi bi-lock-fill" />}
183+
leftSection={<IconLock size={16} />}
183184
error={errors.confirmPassword?.message}
184185
placeholder="Confirm Password"
185186
{...form.confirmPassword}

packages/app/src/ClickhousePage.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
Text,
2323
Tooltip,
2424
} from '@mantine/core';
25+
import { IconRefresh } from '@tabler/icons-react';
2526
import ReactCodeMirror from '@uiw/react-codemirror';
2627

2728
import { ConnectionSelectControlled } from '@/components/ConnectionSelect';
@@ -529,7 +530,7 @@ function ClickhousePage() {
529530
aria-label="Refresh dashboard"
530531
px="xs"
531532
>
532-
<i className="bi bi-arrow-clockwise fs-5"></i>
533+
<IconRefresh size={18} />
533534
</Button>
534535
</Tooltip>
535536
</Group>

0 commit comments

Comments
 (0)