diff --git a/.changeset/semantic-color-tokens.md b/.changeset/semantic-color-tokens.md new file mode 100644 index 000000000..e0cef9738 --- /dev/null +++ b/.changeset/semantic-color-tokens.md @@ -0,0 +1,5 @@ +--- +"@hyperdx/app": minor +--- + +feat: Remove `bootstrap`, `react-bootstrap` and unused `react-bootstrap-range-slider`, adopt semantic tokens, and improve Mantine UI usage diff --git a/packages/app/package.json b/packages/app/package.json index 504515111..e79e0a29f 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -50,7 +50,6 @@ "@uiw/codemirror-themes": "^4.23.3", "@uiw/react-codemirror": "^4.23.3", "@xyflow/react": "^12.9.0", - "bootstrap": "^5.1.3", "chrono-node": "^2.7.8", "classnames": "^2.3.1", "crypto-js": "^4.2.0", @@ -76,8 +75,6 @@ "nuqs": "^1.17.0", "object-hash": "^3.0.0", "react": "18.3.1", - "react-bootstrap": "^2.4.0", - "react-bootstrap-range-slider": "^3.0.8", "react-copy-to-clipboard": "^5.1.0", "react-dom": "18.3.1", "react-error-boundary": "^3.1.4", diff --git a/packages/app/pages/_app.tsx b/packages/app/pages/_app.tsx index 5d9086568..bac4fce90 100644 --- a/packages/app/pages/_app.tsx +++ b/packages/app/pages/_app.tsx @@ -5,7 +5,6 @@ import Head from 'next/head'; import { NextAdapter } from 'next-query-params'; import randomUUID from 'crypto-randomuuid'; import { enableMapSet } from 'immer'; -import SSRProvider from 'react-bootstrap/SSRProvider'; import { QueryParamProvider } from 'use-query-params'; import HyperDX from '@hyperdx/browser'; import { ColorSchemeScript } from '@mantine/core'; @@ -96,13 +95,11 @@ export default function MyApp({ Component, pageProps }: AppPropsWithLayout) { }, []); useEffect(() => { - document.documentElement.className = - userPreferences.theme === 'dark' ? 'hdx-theme-dark' : 'hdx-theme-light'; // TODO: Remove after migration to Mantine document.body.style.fontFamily = userPreferences.font ? `"${userPreferences.font}", sans-serif` : '"IBM Plex Mono"'; - }, [userPreferences.theme, userPreferences.font]); + }, [userPreferences.font]); const getLayout = Component.getLayout ?? (page => page); @@ -117,23 +114,26 @@ export default function MyApp({ Component, pageProps }: AppPropsWithLayout) { /> - + - - - - - - {getLayout()} - {confirmModal} - - - {background} - - - - + + + + + {getLayout()} + {confirmModal} + + + {background} + + + ); } diff --git a/packages/app/src/AlertsPage.tsx b/packages/app/src/AlertsPage.tsx index cf1054904..ae3a1471f 100644 --- a/packages/app/src/AlertsPage.tsx +++ b/packages/app/src/AlertsPage.tsx @@ -58,7 +58,7 @@ function AlertHistoryCardList({ history }: { history: AlertHistory[] }) { return (
{paddingItems.map((_, index) => ( - +
))} @@ -84,7 +84,7 @@ function AlertDetails({ alert }: { alert: AlertsPageItem }) { {alert.dashboard?.name} {tileName ? ( <> - + {tileName} ) : null} @@ -123,7 +123,7 @@ function AlertDetails({ alert }: { alert: AlertsPageItem }) { <> If value is {alert.thresholdType === 'above' ? 'over' : 'under'}{' '} {alert.threshold} - · + · ); }, [alert]); @@ -172,16 +172,16 @@ function AlertDetails({ alert }: { alert: AlertsPageItem }) { className={styles.alertLink} title={linkTitle} > - + {alertName}
-
+
{alertType} {notificationMethod} {alert.createdBy && ( <> - · + · Created by {alert.createdBy.name || alert.createdBy.email} @@ -219,7 +219,7 @@ function AlertCardList({ alerts }: { alerts: AlertsPageItem[] }) { OK
{okData.length === 0 && ( -
No alerts
+
No alerts
)} {okData.map((alert, index) => ( @@ -243,7 +243,7 @@ export default function AlertsPage() {
} + icon={} color="gray" py="xs" mt="md" @@ -259,19 +259,15 @@ export default function AlertsPage() { from dashboard charts and saved searches. {isLoading ? ( -
- Loading... -
+
Loading...
) : isError ? ( -
Error
+
Error
) : alerts?.length ? ( <> ) : ( -
- No alerts created yet -
+
No alerts created yet
)}
diff --git a/packages/app/src/AppNav.components.tsx b/packages/app/src/AppNav.components.tsx index 620b31d0b..ef443349e 100644 --- a/packages/app/src/AppNav.components.tsx +++ b/packages/app/src/AppNav.components.tsx @@ -33,10 +33,8 @@ export const AppNavContext = React.createContext<{ export const AppNavCloudBanner = () => { return ( -
- - Ready to deploy on ClickHouse Cloud? - +
+ Ready to deploy on ClickHouse Cloud?
@@ -141,7 +132,7 @@ export const AppNavUserMenu = ({
- + )} @@ -213,21 +204,13 @@ export const AppNavHelpMenu = ({ ] = useDisclosure(false); // const isTeamHasNoData = useIsTeamHasNoData(); - const size = 28; return ( <> - + @@ -251,7 +229,7 @@ export const AppNavHelpMenu = ({ Help{' '} {version && ( - + v{version} )} @@ -295,7 +273,7 @@ export const AppNavHelpMenu = ({ export const AppNavLink = ({ className, label, - iconName, + icon, href, isExpanded, onToggle, @@ -303,7 +281,7 @@ export const AppNavLink = ({ }: { className?: string; label: React.ReactNode; - iconName: string; + icon: React.ReactNode; href: string; isExpanded?: boolean; onToggle?: () => void; @@ -320,37 +298,26 @@ export const AppNavLink = ({ data-testid={testId} href={href} className={cx( + styles.listLink, + { [styles.listLinkActive]: pathname?.includes(href) }, className, - 'text-decoration-none d-flex justify-content-between align-items-center fs-7 text-muted-hover', - { 'fw-600 text-success': pathname?.includes(href) }, )} + style={{ display: 'flex', alignItems: 'center' }} > - - {' '} - {!isCollapsed && ( - - {label} - {isBeta && ( - - Beta - - )} - - )} + + {icon} + {!isCollapsed && {label}} + {!isCollapsed && isBeta && ( + + Beta + + )} {!isCollapsed && onToggle && ( diff --git a/packages/app/src/AppNav.tsx b/packages/app/src/AppNav.tsx index 7dbc8977d..8bdab0395 100644 --- a/packages/app/src/AppNav.tsx +++ b/packages/app/src/AppNav.tsx @@ -13,6 +13,7 @@ import { import HyperDX from '@hyperdx/browser'; import { AlertState } from '@hyperdx/common-utils/dist/types'; import { + ActionIcon, Badge, Box, Button, @@ -24,6 +25,16 @@ import { ScrollArea, } from '@mantine/core'; import { useDisclosure, useLocalStorage } from '@mantine/hooks'; +import { + IconBell, + IconChartDots, + IconDeviceLaptop, + IconLayoutGrid, + IconLayoutSidebarLeftCollapse, + IconSettings, + IconSitemap, + IconTable, +} from '@tabler/icons-react'; import { useCreateDashboard, @@ -66,10 +77,10 @@ function NewDashboardButton() { @@ -81,10 +92,10 @@ function NewDashboardButton() { + +
} href="/search" className={cx({ 'text-success fw-600': @@ -667,13 +674,7 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
{isLogViewsLoading ? ( - + ) : ( !IS_LOCAL_MODE && ( <> @@ -719,28 +720,32 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) { } /> {!IS_LOCAL_MODE && ( - + } + /> )} } /> } isBeta /> } isExpanded={isDashboardsExpanded} onToggle={() => setIsDashboardExpanded(!isDashboardsExpanded)} /> @@ -751,13 +756,7 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) { {isDashboardsLoading ? ( - + ) : ( !IS_LOCAL_MODE && ( <> @@ -811,8 +810,8 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) { @@ -821,8 +820,8 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) { @@ -832,8 +831,8 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) { } /> )} @@ -871,11 +870,9 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
-
+
{config.IS_OSS && isRegister ? 'Setup ' : isRegister @@ -136,7 +133,7 @@ export default function AuthPage({ action }: { action: 'register' | 'login' }) { HyperDX
{action === 'login' && ( -
Welcome back!
+
Welcome back!
)} {isRegister && config.IS_OSS === true && (
@@ -187,7 +184,7 @@ export default function AuthPage({ action }: { action: 'register' | 'login' }) { placeholder="Confirm Password" {...form.confirmPassword} /> - + @@ -243,19 +240,13 @@ export default function AuthPage({ action }: { action: 'register' | 'login' }) { )} {isRegister && config.IS_OSS === false && ( -
+
Already have an account? Log in{' '} instead.
)} {action === 'login' && config.IS_OSS === false && ( -
+
Don{"'"}t have an account yet?{' '} Register instead.
diff --git a/packages/app/src/AutocompleteInput.tsx b/packages/app/src/AutocompleteInput.tsx index 8ad602368..41afb53b9 100644 --- a/packages/app/src/AutocompleteInput.tsx +++ b/packages/app/src/AutocompleteInput.tsx @@ -1,7 +1,6 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import Fuse from 'fuse.js'; -import { OverlayTrigger } from 'react-bootstrap'; -import { Textarea, UnstyledButton } from '@mantine/core'; +import { Popover, Textarea, UnstyledButton } from '@mantine/core'; import { useQueryHistory } from '@/utils'; @@ -131,210 +130,198 @@ export default function AutocompleteInput({ const ref = useRef(null); return ( - { - // if opened is transitioning to false, but input is focused, ignore it - if (!opened && isSearchInputFocused) { - return; - } - - setIsInputDropdownOpen(opened); + 300 + ? inputRef.current?.clientWidth + : 720, + width: '100%', + zIndex, + }, }} - show={isInputDropdownOpen} - placement="bottom-start" - delay={{ show: 0, hide: 0 }} - overlay={({ style, ...props }) => ( -
+ +