diff --git a/kafka-ui-react-app/src/components/App.scss b/kafka-ui-react-app/src/components/App.scss index 5d13aafcd6..3e920f736a 100644 --- a/kafka-ui-react-app/src/components/App.scss +++ b/kafka-ui-react-app/src/components/App.scss @@ -17,7 +17,7 @@ $navbar-width: 250px; z-index: 20; } - &__navbar { + &__sidebar{ width: $navbar-width; display: flex; flex-direction: column; @@ -28,6 +28,19 @@ $navbar-width: 250px; bottom: 0; padding: 20px 20px; overflow-y: scroll; + transition: width .25s,opacity .25s,transform .25s,-webkit-transform .25s; + + &Overlay { + position: fixed; + top: 0; + height: 120vh; + z-index: 99; + display: block; + visibility: hidden; + opacity: 0; + -webkit-transition: all .5s ease; + transition: all .5s ease; + } } &__alerts { @@ -47,3 +60,35 @@ $navbar-width: 250px; .react-datepicker-popper { z-index: 30 !important; } + +@media screen and (max-width: 1023px) { + .Layout { + &__container { + margin-left: initial; + margin-top: 1.5rem; + } + + &__sidebar { + left: -$navbar-width; + z-index: 100; + } + + &__alerts { + max-width: initial; + } + + &--sidebarVisible { + .Layout__sidebar { + transform: translate3d($navbar-width,0,0); + + &Overlay { + background-color: rgba(34,41,47,.5); + left: 0; + right: 0; + opacity: 1; + visibility: visible; + } + } + } + } +} diff --git a/kafka-ui-react-app/src/components/App.tsx b/kafka-ui-react-app/src/components/App.tsx index 29f81d5828..e659f11986 100644 --- a/kafka-ui-react-app/src/components/App.tsx +++ b/kafka-ui-react-app/src/components/App.tsx @@ -1,51 +1,97 @@ import './App.scss'; import React from 'react'; -import { Switch, Route } from 'react-router-dom'; +import cx from 'classnames'; +import { Cluster } from 'generated-sources'; +import { Switch, Route, useLocation } from 'react-router-dom'; import { GIT_TAG, GIT_COMMIT } from 'lib/constants'; import { Alerts } from 'redux/interfaces'; -import NavContainer from './Nav/NavContainer'; +import Nav from './Nav/Nav'; import PageLoader from './common/PageLoader/PageLoader'; import Dashboard from './Dashboard/Dashboard'; -import Cluster from './Cluster/Cluster'; +import ClusterPage from './Cluster/Cluster'; import Version from './Version/Version'; import Alert from './Alert/Alert'; export interface AppProps { isClusterListFetched?: boolean; alerts: Alerts; + clusters: Cluster[]; fetchClustersList: () => void; } const App: React.FC = ({ isClusterListFetched, alerts, + clusters, fetchClustersList, }) => { + const [isSidebarVisible, setIsSidebarVisible] = React.useState(false); + + const onBurgerClick = React.useCallback( + () => setIsSidebarVisible(!isSidebarVisible), + [isSidebarVisible] + ); + + const closeSidebar = React.useCallback(() => setIsSidebarVisible(false), []); + + const location = useLocation(); + + React.useEffect(() => { + closeSidebar(); + }, [location]); + React.useEffect(() => { fetchClustersList(); }, [fetchClustersList]); return ( -
+
- +
+
+ diff --git a/kafka-ui-react-app/src/components/ConsumerGroups/Details/Details.tsx b/kafka-ui-react-app/src/components/ConsumerGroups/Details/Details.tsx index 42ee3862c6..b6ab8ce01e 100644 --- a/kafka-ui-react-app/src/components/ConsumerGroups/Details/Details.tsx +++ b/kafka-ui-react-app/src/components/ConsumerGroups/Details/Details.tsx @@ -54,28 +54,30 @@ const Details: React.FC = ({ {isFetched ? (
- - - - - - - - - - - - - - {items.map((consumer) => ( - - ))} - -
Consumer IDHostTopicPartitionMessages behindCurrent offsetEnd offset
+
+ + + + + + + + + + + + + + {items.map((consumer) => ( + + ))} + +
Consumer IDHostTopicPartitionMessages behindCurrent offsetEnd offset
+
) : ( diff --git a/kafka-ui-react-app/src/components/ConsumerGroups/List/List.tsx b/kafka-ui-react-app/src/components/ConsumerGroups/List/List.tsx index 0ca2012892..258811264e 100644 --- a/kafka-ui-react-app/src/components/ConsumerGroups/List/List.tsx +++ b/kafka-ui-react-app/src/components/ConsumerGroups/List/List.tsx @@ -36,29 +36,31 @@ const List: React.FC = ({ consumerGroups }) => { />
- - - - - - - - - - {consumerGroups - .filter( - (consumerGroup) => - !searchText || - consumerGroup?.consumerGroupId?.indexOf(searchText) >= 0 - ) - .map((consumerGroup) => ( - - ))} - -
Consumer group IDNum of consumersNum of topics
+
+ + + + + + + + + + {consumerGroups + .filter( + (consumerGroup) => + !searchText || + consumerGroup?.consumerGroupId?.indexOf(searchText) >= 0 + ) + .map((consumerGroup) => ( + + ))} + +
Consumer group IDNum of consumersNum of topics
+
) : ( 'No active consumer groups' diff --git a/kafka-ui-react-app/src/components/Nav/Nav.tsx b/kafka-ui-react-app/src/components/Nav/Nav.tsx index fe49c9c3b8..3b4c123ad5 100644 --- a/kafka-ui-react-app/src/components/Nav/Nav.tsx +++ b/kafka-ui-react-app/src/components/Nav/Nav.tsx @@ -5,7 +5,7 @@ import { Cluster } from 'generated-sources'; import ClusterMenu from './ClusterMenu'; interface Props { - isClusterListFetched: boolean; + isClusterListFetched?: boolean; clusters: Cluster[]; className?: string; } diff --git a/kafka-ui-react-app/src/components/Nav/NavContainer.ts b/kafka-ui-react-app/src/components/Nav/NavContainer.ts deleted file mode 100644 index 392d25d2c3..0000000000 --- a/kafka-ui-react-app/src/components/Nav/NavContainer.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { connect } from 'react-redux'; -import { - getIsClusterListFetched, - getClusterList, -} from 'redux/reducers/clusters/selectors'; -import { RootState } from 'redux/interfaces'; -import Nav from './Nav'; - -const mapStateToProps = (state: RootState) => ({ - isClusterListFetched: getIsClusterListFetched(state), - clusters: getClusterList(state), -}); - -export default connect(mapStateToProps)(Nav); diff --git a/kafka-ui-react-app/src/components/Nav/__tests__/Nav.spec.tsx b/kafka-ui-react-app/src/components/Nav/__tests__/Nav.spec.tsx new file mode 100644 index 0000000000..8f5bdb519b --- /dev/null +++ b/kafka-ui-react-app/src/components/Nav/__tests__/Nav.spec.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { onlineClusterPayload } from 'redux/reducers/clusters/__test__/fixtures'; +import Nav from '../Nav'; + +describe('Nav', () => { + it('renders loader', () => { + const wrapper = shallow(