Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions web/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ const BreadcrumbProvidercontainer = dynamic(
{ ssr: false },
)

const AutoRefreshProvidercontainer = dynamic(
() =>
import('../common/AutoRefreshProvider/AutoRefreshProviderContainer').then(
(mod) => mod.AutoRefreshProvidercontainer,
),
{ ssr: false },
)

export const metadata = {
title: 'Heimdall',
description: 'Welcome to the Heimdall application',
Expand All @@ -39,11 +47,13 @@ export default async function RootLayout({
<ReactQueryProvider>
<div className='App'>
<BreadcrumbProvidercontainer>
<LeftNavContainer />
<main className='app-content-layout'>
<HeaderContent />
<div className='App-content'>{children}</div>
</main>
<AutoRefreshProvidercontainer>
<LeftNavContainer />
<main className='app-content-layout'>
<HeaderContent />
<div className='App-content'>{children}</div>
</main>
</AutoRefreshProvidercontainer>
</BreadcrumbProvidercontainer>
</div>
</ReactQueryProvider>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use client'

import { AutoRefreshProvider } from './context'

export const AutoRefreshProvidercontainer: React.FC<{
children: React.ReactNode
}> = ({ children }) => {
return <AutoRefreshProvider>{children}</AutoRefreshProvider>
}
63 changes: 63 additions & 0 deletions web/src/common/AutoRefreshProvider/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use client'

import React, { createContext, useCallback, useEffect, useState } from 'react'

type RefreshInterval = {
label: string
value: number
}

type ContextStateType = {
refreshInterval: RefreshInterval
updateRefreshInterval: (interval: RefreshInterval) => void
}

export const AutoRefreshContext = createContext<ContextStateType>({
refreshInterval: { label: 'OFF', value: 0 }, // Default 0 seconds
updateRefreshInterval: () => {},
})

const { Provider } = AutoRefreshContext

export const AutoRefreshProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const [refreshInterval, setRefreshInterval] = useState<RefreshInterval>(
() => {
if (typeof window !== 'undefined') {
const savedInterval = localStorage.getItem('refreshInterval')
try {
return savedInterval
? JSON.parse(savedInterval)
: { label: 'OFF', value: 0 }
} catch (error) {
console.error(
'Error parsing refresh interval from localStorage',
error,
)
return { label: 'OFF', value: 0 }
}
}
return { label: 'OFF', value: 0 }
},
)

const updateRefreshInterval = useCallback((interval: RefreshInterval) => {
setRefreshInterval(interval)
}, [])

useEffect(() => {
localStorage.setItem('refreshInterval', JSON.stringify(refreshInterval))
}, [refreshInterval])

return (
<Provider
value={{
refreshInterval,
updateRefreshInterval,
}}
>
{children}
</Provider>
)
}
46 changes: 46 additions & 0 deletions web/src/common/AutoRefreshSelect/AutoRefreshSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use client'

import { Select } from '@patterninc/react-ui'
import { useContext, useState } from 'react'
import { AutoRefreshContext } from '../AutoRefreshProvider/context'
import styles from './auto-fresh-select.module.scss'

export type RefreshInterval = {
label: string
value: number
}

const refreshOptions = [
{ label: 'OFF', value: 0 },
{ label: '5 seconds', value: 5000 },
{ label: '15 seconds', value: 15000 },
{ label: '30 seconds', value: 30000 },
{ label: '1 minute', value: 60000 },
{ label: '5 minutes', value: 300000 },
]

export const AutoRefreshSelect = () => {
const { refreshInterval, updateRefreshInterval } =
useContext(AutoRefreshContext)
const [intervalValue, setIntervalValue] = useState<RefreshInterval>(
refreshInterval || { label: 'OFF', value: 0 },
)

return (
<div className={styles.autoFreshSelectContainer}>
<span>Auto Refresh:</span>
<div className={styles.autoRefreshSelect}>
<Select
options={refreshOptions}
optionKeyName={'label'}
labelKeyName={'label'}
selectedItem={intervalValue}
onChange={(option) => {
setIntervalValue(option)
updateRefreshInterval(option)
}}
/>
</div>
</div>
)
}
10 changes: 10 additions & 0 deletions web/src/common/AutoRefreshSelect/auto-fresh-select.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.autoFreshSelectContainer {
display: flex;
flex-direction: row;
gap: 8px;
align-items: center;
}

.autoRefreshSelect {
width: 104px; // Fixed width ensures the popover menu inherits the same width, preventing options from being cut off or extending beyond the window when selecting longer options like "OFF"
}
2 changes: 2 additions & 0 deletions web/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Breadcrumbs } from '@patterninc/react-ui'
import { useRouter } from 'next/navigation'
import { BreadcrumbContext } from '@/common/BreadCrumbsProvider/context'
import styles from './_header.module.scss'
import { AutoRefreshSelect } from '@/common/AutoRefreshSelect/AutoRefreshSelect'

const Header = () => {
const { breadcrumbs, breadcrumbCallout } = useContext(BreadcrumbContext)
Expand All @@ -21,6 +22,7 @@ const Header = () => {
}}
backButtonProps={{ text: 'Back' }}
/>
{breadcrumbs.length <= 1 && <AutoRefreshSelect />}
</div>
)
}
Expand Down
4 changes: 3 additions & 1 deletion web/src/modules/Clusters/Clusters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ import {
} from '@/common/Services'
import { useQueryState } from 'nuqs'
import { FilterStatesType } from '@patterninc/react-ui/dist/components/Filter/FilterMenu'
import { AutoRefreshContext } from '@/common/AutoRefreshProvider/context'

const Cluster = (): React.JSX.Element => {
const { updateBreadcrumbs } = useContext(BreadcrumbContext)

const { refreshInterval } = useContext(AutoRefreshContext)
const [clusterId, setClusterId] = useQueryState('id', { defaultValue: '' })
const [clusterName, setClusterName] = useQueryState('name', {
defaultValue: '',
Expand Down Expand Up @@ -84,6 +85,7 @@ const Cluster = (): React.JSX.Element => {
const { data, isLoading, isSuccess } = useQuery({
queryKey: ['clusters', filterParams],
queryFn: () => getClusters(filterParams),
refetchInterval: refreshInterval.value,
})

const { data: statusData } = useQuery({
Expand Down
3 changes: 3 additions & 0 deletions web/src/modules/Commands/Commands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ import {
noDataAvailableDescription,
sortData,
} from '@/common/Services'
import { AutoRefreshContext } from '@/common/AutoRefreshProvider/context'

const Commands = (): React.JSX.Element => {
const { updateBreadcrumbs } = useContext(BreadcrumbContext)
const { refreshInterval } = useContext(AutoRefreshContext)
const [commandId, setCommandId] = useQueryState('id', { defaultValue: '' })
const [commandName, setCommandName] = useQueryState('name', {
defaultValue: '',
Expand Down Expand Up @@ -70,6 +72,7 @@ const Commands = (): React.JSX.Element => {
const { data, isSuccess, isLoading } = useQuery({
queryKey: ['commands', filterParams],
queryFn: () => getCommands(filterParams),
refetchInterval: refreshInterval.value,
})

const { data: statusData } = useQuery({
Expand Down
3 changes: 3 additions & 0 deletions web/src/modules/Jobs/Jobs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
noDataAvailableDescription,
sortData,
} from '@/common/Services'
import { AutoRefreshContext } from '@/common/AutoRefreshProvider/context'

type FilterType = {
id: string
Expand All @@ -36,6 +37,7 @@ type FilterType = {

const Jobs = (): React.JSX.Element => {
const { updateBreadcrumbs } = useContext(BreadcrumbContext)
const { refreshInterval } = useContext(AutoRefreshContext)

const [jobId, setJobId] = useQueryState('id', { defaultValue: '' })
const [name, setName] = useQueryState('name', { defaultValue: '' })
Expand Down Expand Up @@ -90,6 +92,7 @@ const Jobs = (): React.JSX.Element => {
getNextPageParam: (lastPage) => lastPage?.nextPage,
enabled: !!filterParams,
initialPageParam: 1,
refetchInterval: refreshInterval.value,
})

const { data: jobStatus } = useQuery({
Expand Down