From e92e9d727e8b4353f12534e97c1c1b9d291ffa71 Mon Sep 17 00:00:00 2001 From: Vincent T Date: Thu, 7 Nov 2024 11:30:01 -0500 Subject: [PATCH] frontend: DetailsDrawer: Add details drawer / drawer mode Signed-off-by: Vincent T --- frontend/src/components/App/Layout.tsx | 10 + .../App/Settings/DrawerModeButton.tsx | 59 ++++ .../src/components/App/Settings/Settings.tsx | 5 + .../__snapshots__/Settings.stories.storyshot | 329 ++++++++++++++++++ .../DetailsDrawer/DetailsDrawer.tsx | 37 ++ frontend/src/components/common/Link.tsx | 40 ++- frontend/src/i18n/locales/de/translation.json | 4 +- frontend/src/i18n/locales/en/translation.json | 2 + frontend/src/i18n/locales/es/translation.json | 2 + frontend/src/i18n/locales/fr/translation.json | 2 + frontend/src/i18n/locales/pt/translation.json | 2 + frontend/src/redux/drawerModeSlice.ts | 36 ++ frontend/src/redux/reducers/reducers.tsx | 2 + 13 files changed, 523 insertions(+), 7 deletions(-) create mode 100644 frontend/src/components/App/Settings/DrawerModeButton.tsx create mode 100644 frontend/src/components/App/Settings/__snapshots__/Settings.stories.storyshot create mode 100644 frontend/src/components/DetailsDrawer/DetailsDrawer.tsx create mode 100644 frontend/src/redux/drawerModeSlice.ts diff --git a/frontend/src/components/App/Layout.tsx b/frontend/src/components/App/Layout.tsx index 912d32238f..4508c95a18 100644 --- a/frontend/src/components/App/Layout.tsx +++ b/frontend/src/components/App/Layout.tsx @@ -7,6 +7,7 @@ import { styled } from '@mui/material/styles'; import { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; +import { useParams } from 'react-router-dom'; import { useClustersConf } from '../../lib/k8s'; import { request } from '../../lib/k8s/apiProxy'; import { Cluster } from '../../lib/k8s/cluster'; @@ -18,6 +19,7 @@ import store from '../../redux/stores/store'; import { fetchStatelessClusterKubeConfigs, isEqualClusterConfigs } from '../../stateless/'; import ActionsNotifier from '../common/ActionsNotifier'; import AlertNotification from '../common/AlertNotification'; +import DetailsDrawer from '../DetailsDrawer/DetailsDrawer'; import Sidebar, { NavigationTabs } from '../Sidebar'; import RouteSwitcher from './RouteSwitcher'; import TopBar from './TopBar'; @@ -109,6 +111,13 @@ export default function Layout({}: LayoutProps) { * indexDB and then sends the backend to parse it and then updates the parsed value into redux * store on an interval. * */ + // DETAIL DRAWER MODE + const isDetailDrawerEnabled = useTypedSelector(state => state.drawerMode.isDetailDrawerEnabled); + console.log('LAY - isDetailDrawerEnabled', isDetailDrawerEnabled); + + const params = useParams(); + console.log('LAY - params: ', params); + useEffect(() => { window.clusterConfigFetchHandler = setInterval( () => { @@ -232,6 +241,7 @@ export default function Layout({}: LayoutProps) { + {isDetailDrawerEnabled && } diff --git a/frontend/src/components/App/Settings/DrawerModeButton.tsx b/frontend/src/components/App/Settings/DrawerModeButton.tsx new file mode 100644 index 0000000000..97c36d7e56 --- /dev/null +++ b/frontend/src/components/App/Settings/DrawerModeButton.tsx @@ -0,0 +1,59 @@ +import { FormControlLabel, Switch } from '@mui/material'; +import React from 'react'; +import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useDispatch } from 'react-redux'; +import { setDetailDrawerEnabled } from '../../../redux/drawerModeSlice'; +import { useTypedSelector } from '../../../redux/reducers/reducers'; + +export default function DrawerModeButton() { + const dispatch = useDispatch(); + const { t } = useTranslation('translation'); + // This will fix the problem of the project refreshing the state away from needed position + + // DETAIL DRAWER MODE + const isDetailDrawerEnabled = useTypedSelector(state => state.drawerMode.isDetailDrawerEnabled); + // const localDetailDrawerEnabled = localStorage.getItem('detailDrawerEnabled'); + const [isDrawerEnabled, changeDetailDrawerEnabled] = useState(isDetailDrawerEnabled); + + if (isDetailDrawerEnabled) { + console.log('THE LOCAL STORAGE IS TRUE'); + dispatch(setDetailDrawerEnabled(true)); + console.log('READING FROM DISPATCHED STATE', isDetailDrawerEnabled); + } else { + console.log(" THE LOCAL STORAGE IS NULL, UNDEFINED, OR 'FALSE' "); + dispatch(setDetailDrawerEnabled(false)); + console.log('READING FROM DISPATCHED STATE', isDetailDrawerEnabled); + } + + console.log('BUTTON - isDetailDrawerEnabled', isDetailDrawerEnabled); + + // the useEffect will run everytime the isDrawerEnabled state changes, which is everytime the user clicks the switch button because the switch button changes the state of isDrawerEnabled + useEffect(() => { + dispatch(setDetailDrawerEnabled(isDrawerEnabled)); + console.log('ON SETTINGS'); + console.log(localStorage.getItem('detailDrawerEnabled')); + }, [isDrawerEnabled]); + + // this function takes in the current changes and updates it, this kicks off the useEffect that is listening for changes to newDrawerEnabled + function drawerModeToggle() { + console.log('drawerModeToggle'); + changeDetailDrawerEnabled(!isDrawerEnabled); + } + + // NOTICE THAT WE DO NOT USE isDrawerEnabled TO DETERMINE HOW THE SWITCH IS RENDERED UNDER THE CHECKED PROP, THIS IS BECAUSE THE USEEFFECT WILL RERENDER THE COMPONENT WITH THE NEW STATE + return ( + + } + // will need to replace label + label={t('translation|Drawer Mode')} + /> + ); +} diff --git a/frontend/src/components/App/Settings/Settings.tsx b/frontend/src/components/App/Settings/Settings.tsx index cb576dc879..0c0ca2cdbd 100644 --- a/frontend/src/components/App/Settings/Settings.tsx +++ b/frontend/src/components/App/Settings/Settings.tsx @@ -8,6 +8,7 @@ import { setAppSettings } from '../../../redux/configSlice'; import { defaultTableRowsPerPageOptions } from '../../../redux/configSlice'; import { ActionButton, NameValueTable, SectionBox } from '../../common'; import TimezoneSelect from '../../common/TimezoneSelect'; +import DrawerModeButton from './DrawerModeButton'; import { useSettings } from './hook'; import NumRowsInput from './NumRowsInput'; import ThemeChangeButton from './ThemeChangeButton'; @@ -65,6 +66,10 @@ export default function Settings() { name: t('translation|Theme'), value: , }, + { + name: t('translation|Details on list view'), + value: , + }, { name: t('translation|Number of rows for tables'), value: ( diff --git a/frontend/src/components/App/Settings/__snapshots__/Settings.stories.storyshot b/frontend/src/components/App/Settings/__snapshots__/Settings.stories.storyshot new file mode 100644 index 0000000000..8905651a3e --- /dev/null +++ b/frontend/src/components/App/Settings/__snapshots__/Settings.stories.storyshot @@ -0,0 +1,329 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Storyshots Settings General 1`] = ` +
+ +
+
+
+
+

+ General Settings +

+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ Language +
+
+
+
+ + + +
+
+
+
+ Theme +
+
+
+ + +
+
+
+ Drawer Mode +
+
+ +
+
+ Number of rows for tables +
+
+
+
+ + + +
+
+
+
+ Timezone to display for dates +
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+
+`; diff --git a/frontend/src/components/DetailsDrawer/DetailsDrawer.tsx b/frontend/src/components/DetailsDrawer/DetailsDrawer.tsx new file mode 100644 index 0000000000..5fe04643f7 --- /dev/null +++ b/frontend/src/components/DetailsDrawer/DetailsDrawer.tsx @@ -0,0 +1,37 @@ +import { Box, Button, Drawer } from '@mui/material'; +import React from 'react'; +import { useDispatch } from 'react-redux'; +import { setSelectedResource } from '../../redux/drawerModeSlice'; +import { useTypedSelector } from '../../redux/reducers/reducers'; +import { KubeObjectDetails } from '../resourceMap/details/KubeNodeDetails'; + +export default function DetailsDrawer() { + const selectedResource = useTypedSelector(state => state.drawerMode.selectedResource); + + const dispatch = useDispatch(); + + function closeDrawer() { + dispatch(setSelectedResource(undefined)); + } + + console.log({ selectedResource }); + + return ( + <> + {selectedResource && ( + closeDrawer()}> + + + + + + + + + + )} + + ); +} diff --git a/frontend/src/components/common/Link.tsx b/frontend/src/components/common/Link.tsx index 0551ee387e..37251b3f7e 100644 --- a/frontend/src/components/common/Link.tsx +++ b/frontend/src/components/common/Link.tsx @@ -1,8 +1,11 @@ import MuiLink from '@mui/material/Link'; import React from 'react'; +import { useDispatch } from 'react-redux'; import { Link as RouterLink } from 'react-router-dom'; import { KubeObject } from '../../lib/k8s/KubeObject'; import { createRouteURL, RouteURLProps } from '../../lib/router'; +import { setSelectedResource } from '../../redux/drawerModeSlice'; +import { useTypedSelector } from '../../redux/reducers/reducers'; import { LightTooltip } from './Tooltip'; export interface LinkBaseProps { @@ -21,6 +24,7 @@ export interface LinkProps extends LinkBaseProps { state?: { [prop: string]: any; }; + drawerEnabled?: boolean; } export interface LinkObjectProps extends LinkBaseProps { @@ -29,16 +33,40 @@ export interface LinkObjectProps extends LinkBaseProps { } function PureLink(props: React.PropsWithChildren) { - if ((props as LinkObjectProps).kubeObject) { - const { kubeObject, ...otherProps } = props as LinkObjectProps; + const { + kubeObject, + routeName, + params = {}, + search, + state, + ...otherProps + } = props as LinkObjectProps; + + const drawerEnabled = useTypedSelector(state => state.drawerMode.isDetailDrawerEnabled); + const dispatch = useDispatch(); + + if ('kubeObject' in props) { return ( - - {props.children || kubeObject!.getName()} - + <> + {drawerEnabled === true && props.kubeObject ? ( + { + if (drawerEnabled) { + dispatch(setSelectedResource(kubeObject!)); + } + }} + > + {props.children || kubeObject.getName()} + + ) : ( + + {props.children || kubeObject.getName()} + + )} + ); } - const { routeName, params = {}, search, state, ...otherProps } = props as LinkProps; return ( { + const local = localStorage.getItem(key); + if (local === null) return false; + return local === 'true'; +}; + +const initialState: DrawerModeState = { + isDetailDrawerEnabled: getLocalDrawerStatus('detailDrawerEnabled'), + selectedResource: undefined, +}; + +const drawerModeSlice = createSlice({ + name: 'drawerMode', + initialState, + reducers: { + setDetailDrawerEnabled: (state, action: PayloadAction) => { + state.isDetailDrawerEnabled = action.payload; + localStorage.setItem('detailDrawerEnabled', `${action.payload}`); + }, + // todo + setSelectedResource: (state, action: any) => { + state.selectedResource = action.payload; + }, + }, +}); + +export const { setDetailDrawerEnabled, setSelectedResource } = drawerModeSlice.actions; +export default drawerModeSlice.reducer; diff --git a/frontend/src/redux/reducers/reducers.tsx b/frontend/src/redux/reducers/reducers.tsx index 7ce7debc45..beca4c85cb 100644 --- a/frontend/src/redux/reducers/reducers.tsx +++ b/frontend/src/redux/reducers/reducers.tsx @@ -6,6 +6,7 @@ import pluginsReducer from '../../plugin/pluginsSlice'; import actionButtons from '../actionButtonsSlice'; import clusterAction from '../clusterActionSlice'; import configReducer from '../configSlice'; +import drawerModeSlice from '../drawerModeSlice'; import filterReducer from '../filterSlice'; import eventCallbackReducer from '../headlampEventSlice'; import routesReducer from '../routesSlice'; @@ -31,6 +32,7 @@ const reducers = combineReducers({ detailsViewSections: detailsViewSectionReducer, eventCallbackReducer, pluginConfigs: pluginConfigReducer, + drawerMode: drawerModeSlice, }); export type RootState = ReturnType;