diff --git a/frontend/src/components/App/Layout.tsx b/frontend/src/components/App/Layout.tsx
index 912d32238fd..4508c95a18e 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 00000000000..97c36d7e567
--- /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 cb576dc8798..0c0ca2cdbd0 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.General.stories.storyshot b/frontend/src/components/App/Settings/__snapshots__/Settings.General.stories.storyshot
index 0eb57d483ad..ed51e14095c 100644
--- a/frontend/src/components/App/Settings/__snapshots__/Settings.General.stories.storyshot
+++ b/frontend/src/components/App/Settings/__snapshots__/Settings.General.stories.storyshot
@@ -151,6 +151,46 @@
+
+ Details on list view
+
+
+
+
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 00000000000..8905651a3ed
--- /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
+
+
+
+
+
+ English
+
+
+
+
+
+
+
+ Theme
+
+
+
+
+
+
+
+
+ Drawer Mode
+
+
+
+
+
+ Number of rows for tables
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+ 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 00000000000..5fe04643f74
--- /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.stories.tsx b/frontend/src/components/common/Link.stories.tsx
index 54dfdf80b5a..905fa67338a 100644
--- a/frontend/src/components/common/Link.stories.tsx
+++ b/frontend/src/components/common/Link.stories.tsx
@@ -1,15 +1,23 @@
import { Meta, StoryFn } from '@storybook/react';
+import React from 'react';
+import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
+import { createStore } from 'redux';
+import reducers from '../../redux/reducers/reducers';
import Link, { LinkProps } from './Link';
+const store = createStore(reducers);
+
export default {
title: 'Link',
component: Link,
decorators: [
Story => (
-
-
-
+
+
+
+
+
),
],
} as Meta;
diff --git a/frontend/src/components/common/Link.tsx b/frontend/src/components/common/Link.tsx
index 0551ee387eb..345de2042d9 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,8 @@ export interface LinkObjectProps extends LinkBaseProps {
}
function PureLink(props: React.PropsWithChildren) {
- if ((props as LinkObjectProps).kubeObject) {
- const { kubeObject, ...otherProps } = props as LinkObjectProps;
- return (
-
- {props.children || kubeObject!.getName()}
-
- );
- }
+ const { routeName, params = {}, search, state, ...otherProps } = props as LinkObjectProps;
- const { routeName, params = {}, search, state, ...otherProps } = props as LinkProps;
return (
) {
}
export default function Link(props: React.PropsWithChildren) {
- const { tooltip, ...otherProps } = props;
+ const drawerEnabled = useTypedSelector(state => state.drawerMode.isDetailDrawerEnabled);
+ const dispatch = useDispatch();
+
+ const { tooltip, kubeObject, ...otherProps } = props as LinkObjectProps;
+
if (tooltip) {
let tooltipText = '';
if (typeof tooltip === 'string') {
@@ -77,5 +77,32 @@ export default function Link(props: React.PropsWithChildren
+ {drawerEnabled === true && props.kubeObject ? (
+ {
+ if (drawerEnabled) {
+ dispatch(setSelectedResource(kubeObject!));
+ window.history.pushState(
+ { path: kubeObject.getDetailsLink() },
+ '',
+ kubeObject.getDetailsLink()
+ );
+ }
+ }}
+ >
+ {props.children || kubeObject.getName()}
+
+ ) : (
+
+ {props.children || kubeObject.getName()}
+
+ )}
+ >
+ );
+ }
+
return ;
}
diff --git a/frontend/src/components/common/Resource/ResourceTable.stories.tsx b/frontend/src/components/common/Resource/ResourceTable.stories.tsx
index a86259197c0..ad7257fb3b7 100644
--- a/frontend/src/components/common/Resource/ResourceTable.stories.tsx
+++ b/frontend/src/components/common/Resource/ResourceTable.stories.tsx
@@ -1,14 +1,29 @@
import { configureStore } from '@reduxjs/toolkit';
import { Meta, StoryFn } from '@storybook/react';
+import { Provider } from 'react-redux';
+import { MemoryRouter } from 'react-router-dom';
+import { createStore } from 'redux';
import { useMockListQuery } from '../../../helpers/testHelpers';
import Pod, { KubePod } from '../../../lib/k8s/pod';
+import reducers from '../../../redux/reducers/reducers';
import { INITIAL_STATE as UI_INITIAL_STATE } from '../../../redux/reducers/ui';
import { TestContext } from '../../../test';
import ResourceTable, { ResourceTableFromResourceClassProps } from './ResourceTable';
+const store = createStore(reducers);
+
export default {
title: 'ResourceTable',
component: ResourceTable,
+ decorators: [
+ Story => (
+
+
+
+
+
+ ),
+ ],
argTypes: {},
} as Meta;
@@ -25,6 +40,7 @@ const TemplateWithFilter: StoryFn<{
filter: { namespaces: new Set(), search: '' },
config: { settings: { tableRowsPerPageOptions: [10, 20, 50, 100] } },
ui: UI_INITIAL_STATE,
+ drawerMode: { isDetailDrawerEnabled: false },
}
) => state,
preloadedState: {
@@ -41,6 +57,7 @@ const TemplateWithFilter: StoryFn<{
resourceTable: {
tableColumnsProcessors: [],
},
+ drawerMode: { isDetailDrawerEnabled: false },
},
});
diff --git a/frontend/src/i18n/locales/de/translation.json b/frontend/src/i18n/locales/de/translation.json
index 73270aaa67a..8fa154ef473 100644
--- a/frontend/src/i18n/locales/de/translation.json
+++ b/frontend/src/i18n/locales/de/translation.json
@@ -53,8 +53,9 @@
"Delete Plugin": "",
"Are you sure you want to delete this plugin?": "",
"Save": "",
- "Uh-oh! Something went wrong.": "Oh-oh! Etwas ist schief gelaufen.",
+ "Uh-oh! Something went wrong.": "",
"Error loading {{ routeName }}": "",
+ "Drawer Mode": "",
"Enter a value between {{ minRows }} and {{ maxRows }}.": "Geben Sie einen Wert zwischen {{ minRows }} und {{ maxRows }} ein.",
"Custom row value": "Benutzerdefinierter Zeilenwert",
"Apply": "Anwenden",
@@ -63,6 +64,7 @@
"Version": "Version",
"Language": "Sprache",
"Theme": "Design",
+ "Details on list view": "",
"Number of rows for tables": "Zeilen pro Tabelle",
"Timezone to display for dates": "Zeitzone",
"Namespaces must contain only lowercase alphanumeric characters or '-', and must start and end with an alphanumeric character.": "Namespaces dürfen nur alphanumerische Kleinbuchstaben oder \"-\" enthalten und müssen mit einem alphanumerischen Zeichen beginnen und enden.",
diff --git a/frontend/src/i18n/locales/en/translation.json b/frontend/src/i18n/locales/en/translation.json
index f4beb9243e4..db0d587e7cd 100644
--- a/frontend/src/i18n/locales/en/translation.json
+++ b/frontend/src/i18n/locales/en/translation.json
@@ -55,6 +55,7 @@
"Save": "Save",
"Uh-oh! Something went wrong.": "Uh-oh! Something went wrong.",
"Error loading {{ routeName }}": "Error loading {{ routeName }}",
+ "Drawer Mode": "Drawer Mode",
"Enter a value between {{ minRows }} and {{ maxRows }}.": "Enter a value between {{ minRows }} and {{ maxRows }}.",
"Custom row value": "Custom row value",
"Apply": "Apply",
@@ -63,6 +64,7 @@
"Version": "Version",
"Language": "Language",
"Theme": "Theme",
+ "Details on list view": "Details on list view",
"Number of rows for tables": "Number of rows for tables",
"Timezone to display for dates": "Timezone to display for dates",
"Namespaces must contain only lowercase alphanumeric characters or '-', and must start and end with an alphanumeric character.": "Namespaces must contain only lowercase alphanumeric characters or '-', and must start and end with an alphanumeric character.",
diff --git a/frontend/src/i18n/locales/es/translation.json b/frontend/src/i18n/locales/es/translation.json
index f746435cf19..6d763aadc65 100644
--- a/frontend/src/i18n/locales/es/translation.json
+++ b/frontend/src/i18n/locales/es/translation.json
@@ -55,6 +55,7 @@
"Save": "",
"Uh-oh! Something went wrong.": "¡Ups! Algo ha fallado.",
"Error loading {{ routeName }}": "",
+ "Drawer Mode": "",
"Enter a value between {{ minRows }} and {{ maxRows }}.": "Introduzca un valor entre {{ minRows }} y {{ maxRows }}.",
"Custom row value": "Núm. de líneas personalizado",
"Apply": "Aplicar",
@@ -63,6 +64,7 @@
"Version": "Versión",
"Language": "Idioma",
"Theme": "Tema",
+ "Details on list view": "",
"Number of rows for tables": "Núm. de líneas para las tablas",
"Timezone to display for dates": "Huso horario para mostrar en fechas",
"Namespaces must contain only lowercase alphanumeric characters or '-', and must start and end with an alphanumeric character.": "Los espacios de nombre deben contener solo caracteres alfanuméricos en minúsculas o '-', y deben comenzar y terminar con un carácter alfanumérico.",
diff --git a/frontend/src/i18n/locales/fr/translation.json b/frontend/src/i18n/locales/fr/translation.json
index 921ccd5b8d6..5dc0742afcf 100644
--- a/frontend/src/i18n/locales/fr/translation.json
+++ b/frontend/src/i18n/locales/fr/translation.json
@@ -55,6 +55,7 @@
"Save": "",
"Uh-oh! Something went wrong.": "Uh-oh ! Quelque chose s'est mal passé.",
"Error loading {{ routeName }}": "",
+ "Drawer Mode": "",
"Enter a value between {{ minRows }} and {{ maxRows }}.": "Entrez une valeur entre {{ minRows }} et {{ maxRows }}.",
"Custom row value": "Valeur de ligne personnalisée",
"Apply": "Appliquer",
@@ -63,6 +64,7 @@
"Version": "Version",
"Language": "Langue",
"Theme": "Thème",
+ "Details on list view": "",
"Number of rows for tables": "Nombre de lignes pour les tableaux",
"Timezone to display for dates": "Fuseau horaire à afficher pour les dates",
"Namespaces must contain only lowercase alphanumeric characters or '-', and must start and end with an alphanumeric character.": "Les espaces de noms ne doivent contenir que des caractères alphanumériques minuscules ou '-', et doivent commencer et se terminer par un caractère alphanumérique.",
diff --git a/frontend/src/i18n/locales/pt/translation.json b/frontend/src/i18n/locales/pt/translation.json
index ebb483ecf94..a73854e7834 100644
--- a/frontend/src/i18n/locales/pt/translation.json
+++ b/frontend/src/i18n/locales/pt/translation.json
@@ -55,6 +55,7 @@
"Save": "",
"Uh-oh! Something went wrong.": "Oh-oh! Algo correu mal.",
"Error loading {{ routeName }}": "",
+ "Drawer Mode": "",
"Enter a value between {{ minRows }} and {{ maxRows }}.": "Introduza um valor entre {{ minRows }} e {{ maxRows }}.",
"Custom row value": "Núm. de linhas personalizado",
"Apply": "Aplicar",
@@ -63,6 +64,7 @@
"Version": "Versão",
"Language": "Idioma",
"Theme": "Tema",
+ "Details on list view": "",
"Number of rows for tables": "Núm. de linhas para as tabelas",
"Timezone to display for dates": "Fuso horário para mostrar em datas",
"Namespaces must contain only lowercase alphanumeric characters or '-', and must start and end with an alphanumeric character.": "Os namespaces devem conter apenas caracteres alfanuméricos minúsculos ou '-', e devem começar e terminar com um carácter alfanumérico.",
diff --git a/frontend/src/redux/drawerModeSlice.ts b/frontend/src/redux/drawerModeSlice.ts
new file mode 100644
index 00000000000..cfac237e934
--- /dev/null
+++ b/frontend/src/redux/drawerModeSlice.ts
@@ -0,0 +1,36 @@
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+import { KubeObject } from '../lib/k8s/KubeObject';
+
+interface DrawerModeState {
+ isDetailDrawerEnabled: boolean;
+ selectedResource: KubeObject | undefined;
+}
+
+const getLocalDrawerStatus = (key: string) => {
+ 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 7ce7debc451..beca4c85cb6 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;