@@ -19,11 +19,17 @@ import Box from '@mui/material/Box';
1919import Button from '@mui/material/Button' ;
2020import { useTheme } from '@mui/material/styles' ;
2121import Typography from '@mui/material/Typography' ;
22- import { useMemo } from 'react' ;
22+ import {
23+ MRT_ColumnFiltersState ,
24+ MRT_SortingState ,
25+ MRT_VisibilityState ,
26+ } from 'material-react-table' ;
27+ import { useCallback , useMemo , useState } from 'react' ;
2328import { useTranslation } from 'react-i18next' ;
2429import { generatePath , useHistory } from 'react-router-dom' ;
2530import { getClusterAppearanceFromMeta } from '../../../helpers/clusterAppearance' ;
2631import { isElectron } from '../../../helpers/isElectron' ;
32+ import { loadTableSettings , storeTableSettings } from '../../../helpers/tableSettings' ;
2733import { formatClusterPathParam } from '../../../lib/cluster' ;
2834import { useClustersConf , useClustersVersion } from '../../../lib/k8s' ;
2935import { ApiError } from '../../../lib/k8s/api/v2/ApiError' ;
@@ -34,6 +40,7 @@ import { useTypedSelector } from '../../../redux/hooks';
3440import { Loader } from '../../common' ;
3541import Link from '../../common/Link' ;
3642import Table from '../../common/Table' ;
43+ import { useLocalStorageState } from '../../globalSearch/useLocalStorageState' ;
3744import ClusterBadge from '../../Sidebar/ClusterBadge' ;
3845import ClusterContextMenu from './ClusterContextMenu' ;
3946import { MULTI_HOME_ENABLED } from './config' ;
@@ -115,6 +122,8 @@ export interface ClusterTableProps {
115122/**
116123 * ClusterTable component displays a table of clusters with their status, origin, and version.
117124 */
125+ const CLUSTER_TABLE_ID = 'home-clusters' ;
126+
118127export default function ClusterTable ( {
119128 customNameClusters,
120129 versions,
@@ -125,6 +134,54 @@ export default function ClusterTable({
125134 const history = useHistory ( ) ;
126135 const { t } = useTranslation ( [ 'translation' ] ) ;
127136
137+ const [ columnVisibility , setColumnVisibility ] = useState < MRT_VisibilityState > ( ( ) => {
138+ const visibility : Record < string , boolean > = { } ;
139+ const stored = loadTableSettings ( CLUSTER_TABLE_ID ) ;
140+ stored . forEach ( ( { id, show } ) => ( visibility [ id ] = show ) ) ;
141+ return visibility ;
142+ } ) ;
143+
144+ const [ sorting , setSorting ] = useLocalStorageState < MRT_SortingState > (
145+ `table_sorting.${ CLUSTER_TABLE_ID } ` ,
146+ [ { id : 'name' , desc : false } ]
147+ ) ;
148+
149+ const [ columnFilters , setColumnFilters ] = useLocalStorageState < MRT_ColumnFiltersState > (
150+ `table_filters.${ CLUSTER_TABLE_ID } ` ,
151+ [ ]
152+ ) ;
153+
154+ const handleColumnVisibilityChange = useCallback (
155+ ( updater : MRT_VisibilityState | ( ( old : MRT_VisibilityState ) => MRT_VisibilityState ) ) => {
156+ setColumnVisibility ( oldCols => {
157+ const newCols = typeof updater === 'function' ? updater ( oldCols ) : updater ;
158+ const colsToStore = Object . entries ( newCols ) . map ( ( [ id , show ] ) => ( {
159+ id,
160+ show : ( show ?? true ) as boolean ,
161+ } ) ) ;
162+ storeTableSettings ( CLUSTER_TABLE_ID , colsToStore ) ;
163+ return newCols ;
164+ } ) ;
165+ } ,
166+ [ ]
167+ ) ;
168+
169+ const handleSortingChange = useCallback (
170+ ( updater : MRT_SortingState | ( ( old : MRT_SortingState ) => MRT_SortingState ) ) => {
171+ setSorting ( old => ( typeof updater === 'function' ? updater ( old ) : updater ) ) ;
172+ } ,
173+ [ setSorting ]
174+ ) ;
175+
176+ const handleColumnFiltersChange = useCallback (
177+ (
178+ updater : MRT_ColumnFiltersState | ( ( old : MRT_ColumnFiltersState ) => MRT_ColumnFiltersState )
179+ ) => {
180+ setColumnFilters ( old => ( typeof updater === 'function' ? updater ( old ) : updater ) ) ;
181+ } ,
182+ [ setColumnFilters ]
183+ ) ;
184+
128185 /**
129186 * Gets the origin of a cluster.
130187 *
@@ -206,22 +263,29 @@ export default function ClusterTable({
206263 } ,
207264 } ,
208265 {
266+ id : 'origin' ,
209267 header : t ( 'Origin' ) ,
210268 accessorFn : cluster => getOrigin ( cluster ) ,
211269 Cell : ( { row : { original } } ) => (
212270 < Typography variant = "body2" > { getOrigin ( ( clusters || { } ) [ original . name ] ) } </ Typography >
213271 ) ,
214272 } ,
215273 {
274+ id : 'status' ,
216275 header : t ( 'Status' ) ,
217276 accessorFn : cluster =>
218277 errors [ cluster ?. name ] === null ? 'Active' : errors [ cluster ?. name ] ?. message ,
219278 Cell : ( { row : { original } } ) => (
220279 < ClusterStatus error = { errors [ original . name ] } cluster = { original } />
221280 ) ,
222281 } ,
223- { header : t ( 'Warnings' ) , accessorFn : cluster => warningLabels [ cluster ?. name ] } ,
224282 {
283+ id : 'warnings' ,
284+ header : t ( 'Warnings' ) ,
285+ accessorFn : cluster => warningLabels [ cluster ?. name ] ,
286+ } ,
287+ {
288+ id : 'version' ,
225289 header : t ( 'glossary|Kubernetes Version' ) ,
226290 accessorFn : ( { name } ) => versions [ name ] ?. gitVersion || '⋯' ,
227291 } ,
@@ -250,9 +314,14 @@ export default function ClusterTable({
250314 }
251315 : false
252316 }
253- initialState = { {
254- sorting : [ { id : 'name' , desc : false } ] ,
317+ state = { {
318+ columnVisibility,
319+ sorting,
320+ columnFilters,
255321 } }
322+ onColumnVisibilityChange = { handleColumnVisibilityChange }
323+ onSortingChange = { handleSortingChange }
324+ onColumnFiltersChange = { handleColumnFiltersChange }
256325 muiToolbarAlertBannerProps = { {
257326 sx : theme => ( {
258327 background : theme . palette . background . muted ,
0 commit comments