App.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import React, { Suspense, useCallback } from 'react';
  2. import { Routes, Route, useLocation } from 'react-router-dom';
  3. import { GIT_TAG, GIT_COMMIT } from 'lib/constants';
  4. import { clusterPath, getNonExactPath } from 'lib/paths';
  5. import Nav from 'components/Nav/Nav';
  6. import PageLoader from 'components/common/PageLoader/PageLoader';
  7. import Dashboard from 'components/Dashboard/Dashboard';
  8. import ClusterPage from 'components/Cluster/Cluster';
  9. import Version from 'components/Version/Version';
  10. import Alerts from 'components/Alerts/Alerts';
  11. import { ThemeProvider } from 'styled-components';
  12. import theme from 'theme/theme';
  13. import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
  14. import * as S from './App.styled';
  15. import Logo from './common/Logo/Logo';
  16. import GitIcon from './common/Icons/GitIcon';
  17. import DiscordIcon from './common/Icons/DiscordIcon';
  18. const queryClient = new QueryClient({
  19. defaultOptions: {
  20. queries: {
  21. suspense: true,
  22. },
  23. },
  24. });
  25. const App: React.FC = () => {
  26. const [isSidebarVisible, setIsSidebarVisible] = React.useState(false);
  27. const onBurgerClick = () => setIsSidebarVisible(!isSidebarVisible);
  28. const closeSidebar = useCallback(() => setIsSidebarVisible(false), []);
  29. const location = useLocation();
  30. React.useEffect(() => {
  31. closeSidebar();
  32. }, [location, closeSidebar]);
  33. return (
  34. <QueryClientProvider client={queryClient}>
  35. <ThemeProvider theme={theme}>
  36. <S.Layout>
  37. <S.Navbar role="navigation" aria-label="Page Header">
  38. <S.NavbarBrand>
  39. <S.NavbarBrand>
  40. <S.NavbarBurger
  41. onClick={onBurgerClick}
  42. onKeyDown={onBurgerClick}
  43. role="button"
  44. tabIndex={0}
  45. aria-label="burger"
  46. >
  47. <S.Span role="separator" />
  48. <S.Span role="separator" />
  49. <S.Span role="separator" />
  50. </S.NavbarBurger>
  51. <S.Hyperlink to="/">
  52. <Logo />
  53. UI for Apache Kafka
  54. </S.Hyperlink>
  55. <S.NavbarItem>
  56. {GIT_TAG && <Version tag={GIT_TAG} commit={GIT_COMMIT} />}
  57. </S.NavbarItem>
  58. </S.NavbarBrand>
  59. </S.NavbarBrand>
  60. <S.NavbarSocial>
  61. <S.LogoutLink href="/logout">
  62. <S.LogoutButton buttonType="primary" buttonSize="M">
  63. Log out
  64. </S.LogoutButton>
  65. </S.LogoutLink>
  66. <S.SocialLink
  67. href="https://github.com/provectus/kafka-ui"
  68. target="_blank"
  69. >
  70. <GitIcon />
  71. </S.SocialLink>
  72. <S.SocialLink
  73. href="https://discord.com/invite/4DWzD7pGE5"
  74. target="_blank"
  75. >
  76. <DiscordIcon />
  77. </S.SocialLink>
  78. </S.NavbarSocial>
  79. </S.Navbar>
  80. <S.Container>
  81. <S.Sidebar aria-label="Sidebar" $visible={isSidebarVisible}>
  82. <Suspense fallback={<PageLoader />}>
  83. <Nav />
  84. </Suspense>
  85. </S.Sidebar>
  86. <S.Overlay
  87. $visible={isSidebarVisible}
  88. onClick={closeSidebar}
  89. onKeyDown={closeSidebar}
  90. tabIndex={-1}
  91. aria-hidden="true"
  92. aria-label="Overlay"
  93. />
  94. <Routes>
  95. {['/', '/ui', '/ui/clusters'].map((path) => (
  96. <Route
  97. key="Home" // optional: avoid full re-renders on route changes
  98. path={path}
  99. element={<Dashboard />}
  100. />
  101. ))}
  102. <Route
  103. path={getNonExactPath(clusterPath())}
  104. element={<ClusterPage />}
  105. />
  106. </Routes>
  107. </S.Container>
  108. <S.AlertsContainer role="toolbar">
  109. <Alerts />
  110. </S.AlertsContainer>
  111. </S.Layout>
  112. </ThemeProvider>
  113. </QueryClientProvider>
  114. );
  115. };
  116. export default App;