diff --git a/internal/lookout/ui/src/App.tsx b/internal/lookout/ui/src/App.tsx
index 453f2336614..66903d5d162 100644
--- a/internal/lookout/ui/src/App.tsx
+++ b/internal/lookout/ui/src/App.tsx
@@ -134,6 +134,7 @@ export function App(props: AppProps): JSX.Element {
logService={props.v2LogService}
cordonService={props.v2CordonService}
debug={props.debugEnabled}
+ autoRefreshMs={props.jobsAutoRefreshMs}
/>
}
/>
diff --git a/internal/lookout/ui/src/components/AutoRefreshToggle.tsx b/internal/lookout/ui/src/components/AutoRefreshToggle.tsx
index 6eca4efa440..eaa2c8f1406 100644
--- a/internal/lookout/ui/src/components/AutoRefreshToggle.tsx
+++ b/internal/lookout/ui/src/components/AutoRefreshToggle.tsx
@@ -20,7 +20,7 @@ export default function AutoRefreshToggle(props: AutoRefreshToggle) {
color="primary"
/>
}
- label="Auto-refresh"
+ label="Auto refresh"
labelPlacement="start"
/>
diff --git a/internal/lookout/ui/src/components/lookoutV2/JobsTableActionBar.tsx b/internal/lookout/ui/src/components/lookoutV2/JobsTableActionBar.tsx
index cf2a906ab14..2da3e7dc22d 100644
--- a/internal/lookout/ui/src/components/lookoutV2/JobsTableActionBar.tsx
+++ b/internal/lookout/ui/src/components/lookoutV2/JobsTableActionBar.tsx
@@ -1,6 +1,7 @@
import React, { memo, useCallback, useMemo, useState } from "react"
import { Divider, Button, Checkbox, FormControlLabel, FormGroup, Tooltip } from "@mui/material"
+import AutoRefreshToggle from "components/AutoRefreshToggle"
import RefreshButton from "components/RefreshButton"
import ColumnSelect from "components/lookoutV2/ColumnSelect"
import GroupBySelect from "components/lookoutV2/GroupBySelect"
@@ -25,6 +26,8 @@ export interface JobsTableActionBarProps {
activeJobSets: boolean
onActiveJobSetsChanged: (newVal: boolean) => void
onRefresh: () => void
+ autoRefresh: boolean
+ onAutoRefreshChange: (autoRefresh: boolean) => void
onAddAnnotationColumn: (annotationKey: string) => void
onRemoveAnnotationColumn: (colId: ColumnId) => void
onEditAnnotationColumn: (colId: ColumnId, annotationKey: string) => void
@@ -49,6 +52,8 @@ export const JobsTableActionBar = memo(
activeJobSets,
onActiveJobSetsChanged,
onRefresh,
+ autoRefresh,
+ onAutoRefreshChange,
onAddAnnotationColumn,
onRemoveAnnotationColumn,
onEditAnnotationColumn,
@@ -110,10 +115,12 @@ export const JobsTableActionBar = memo(
+
+
+
-
{
logService={logService}
cordonService={new FakeCordonService()}
debug={false}
+ autoRefreshMs={30000}
/>
)
diff --git a/internal/lookout/ui/src/containers/lookoutV2/JobsTableContainer.tsx b/internal/lookout/ui/src/containers/lookoutV2/JobsTableContainer.tsx
index dd4fe03eb8e..2b61f3b3448 100644
--- a/internal/lookout/ui/src/containers/lookoutV2/JobsTableContainer.tsx
+++ b/internal/lookout/ui/src/containers/lookoutV2/JobsTableContainer.tsx
@@ -41,6 +41,7 @@ import _ from "lodash"
import { isJobGroupRow, JobRow, JobTableRow } from "models/jobsTableModels"
import { Job, JobFilter, JobId, Match, SortDirection } from "models/lookoutV2Models"
import { useLocation, useNavigate, useParams } from "react-router-dom"
+import IntervalService from "services/IntervalService"
import { IGetJobsService } from "services/lookoutV2/GetJobsService"
import { IGetRunErrorService } from "services/lookoutV2/GetRunErrorService"
import { IGroupJobsService } from "services/lookoutV2/GroupJobsService"
@@ -87,6 +88,7 @@ interface JobsTableContainerProps {
logService: ILogService
cordonService: ICordonService
debug: boolean
+ autoRefreshMs: number
}
export type LookoutColumnFilter = {
@@ -130,6 +132,7 @@ export const JobsTableContainer = ({
logService,
cordonService,
debug,
+ autoRefreshMs,
}: JobsTableContainerProps) => {
const openSnackbar = useCustomSnackbar()
@@ -176,6 +179,21 @@ export const JobsTableContainer = ({
})
const { pageIndex, pageSize } = useMemo(() => pagination, [pagination])
+ const [autoRefresh, setAutoRefresh] = useState(
+ initialPrefs.autoRefresh === undefined ? true : initialPrefs.autoRefresh,
+ )
+
+ const autoRefreshService = useMemo(() => new IntervalService(autoRefreshMs), [autoRefreshMs])
+
+ const onAutoRefreshChange = (autoRefresh: boolean) => {
+ setAutoRefresh(autoRefresh)
+ if (autoRefresh) {
+ autoRefreshService.start()
+ } else {
+ autoRefreshService.stop()
+ }
+ }
+
// Filtering
const [columnFilterState, setColumnFilterState] = useState(initialPrefs.filters)
const [lookoutFilters, setLookoutFilters] = useState([]) // Parsed later
@@ -251,6 +269,7 @@ export const JobsTableContainer = ({
sidebarJobId: sidebarJobId,
sidebarWidth: sidebarWidth,
activeJobSets: activeJobSets,
+ autoRefresh: autoRefresh,
}
}
@@ -290,6 +309,9 @@ export const JobsTableContainer = ({
if (prefs.activeJobSets !== undefined) {
setActiveJobSets(prefs.activeJobSets)
}
+ if (prefs.autoRefresh !== undefined) {
+ onAutoRefreshChange(prefs.autoRefresh)
+ }
// Have to manually set text fields to the filter values since they are uncontrolled
setTextFields(prefs.filters)
@@ -318,6 +340,7 @@ export const JobsTableContainer = ({
sidebarJobId,
sidebarWidth,
activeJobSets,
+ autoRefresh,
])
const addCustomView = (name: string) => {
@@ -346,6 +369,14 @@ export const JobsTableContainer = ({
setRowsToFetch(pendingDataForAllVisibleData(expanded, data, pageSize, pageIndex * pageSize))
}
+ useEffect(() => {
+ autoRefreshService.registerCallback(onRefresh)
+ if (autoRefresh) {
+ autoRefreshService.start()
+ }
+ return () => autoRefreshService.stop()
+ }, [])
+
const onColumnVisibilityChange = (colIdToToggle: ColumnId) => {
// Refresh if we make a new aggregate column visible
let shouldRefresh = false
@@ -710,6 +741,8 @@ export const JobsTableContainer = ({
onRefresh()
}}
onRefresh={onRefresh}
+ autoRefresh={autoRefresh}
+ onAutoRefreshChange={onAutoRefreshChange}
onAddAnnotationColumn={addAnnotationCol}
onRemoveAnnotationColumn={removeAnnotationCol}
onEditAnnotationColumn={editAnnotationCol}
diff --git a/internal/lookout/ui/src/services/lookoutV2/JobsTablePreferencesService.ts b/internal/lookout/ui/src/services/lookoutV2/JobsTablePreferencesService.ts
index 2651cf902a0..75270fb16f9 100644
--- a/internal/lookout/ui/src/services/lookoutV2/JobsTablePreferencesService.ts
+++ b/internal/lookout/ui/src/services/lookoutV2/JobsTablePreferencesService.ts
@@ -30,6 +30,7 @@ export interface JobsTablePreferences {
sidebarJobId: JobId | undefined
sidebarWidth?: number
activeJobSets?: boolean
+ autoRefresh?: boolean
}
// Need two 'defaults'
@@ -81,6 +82,8 @@ export interface QueryStringPrefs {
sb: string | undefined
// This is a boolean field, but the qs library turns it into a string.
active: string | undefined
+ // This is a boolean field, but the qs library turns it into a string.
+ refresh: string | undefined
}
const toQueryStringSafe = (prefs: JobsTablePreferences): QueryStringPrefs => {
@@ -105,6 +108,7 @@ const toQueryStringSafe = (prefs: JobsTablePreferences): QueryStringPrefs => {
ps: prefs.pageSize.toString(),
sb: prefs.sidebarJobId,
active: prefs.activeJobSets === undefined ? undefined : `${prefs.activeJobSets}`,
+ refresh: prefs.autoRefresh === undefined ? undefined : `${prefs.autoRefresh}`,
}
}
@@ -124,7 +128,7 @@ const columnMatchesFromQueryStringFilters = (f: QueryStringJobFilter[]): Record<
}
const fromQueryStringSafe = (serializedPrefs: Partial): Partial => {
- const { g, e, page, ps, sort, f, sb, active } = serializedPrefs
+ const { g, e, page, ps, sort, f, sb, active, refresh } = serializedPrefs
return {
...(g && Array.isArray(g) && g.every((a) => typeof a === "string") && { groupedColumns: g as ColumnId[] }),
...(e && { expandedState: Object.fromEntries(e.map((rowId) => [rowId, true])) }),
@@ -137,6 +141,7 @@ const fromQueryStringSafe = (serializedPrefs: Partial): Partia
...(f && { columnMatches: columnMatchesFromQueryStringFilters(f) }),
...(sb && { sidebarJobId: sb }),
...(active && { activeJobSets: active.toLowerCase() === "true" }),
+ ...(refresh && { autoRefresh: refresh.toLowerCase() === "true" }),
}
}
@@ -182,6 +187,7 @@ const mergeQueryParamsAndLocalStorage = (
}
mergeColumnMatches(mergedPrefs.columnMatches, queryParamPrefs.columnMatches)
mergedPrefs.activeJobSets = queryParamPrefs.activeJobSets
+ mergedPrefs.autoRefresh = queryParamPrefs.autoRefresh
}
return mergedPrefs
}