diff --git a/src/components/records/RecordBadge.tsx b/src/components/records/RecordBadge.tsx index 704b0925e0aac90147f5b9baa62b8bac6fe59faf..b515584407db8c17639f0e891dba1d1aa5485312 100644 --- a/src/components/records/RecordBadge.tsx +++ b/src/components/records/RecordBadge.tsx @@ -1,7 +1,14 @@ import { IconBadge, InternalLink } from "@ess-ics/ce-ui-common"; +import { type SxProps } from "@mui/material"; import { RecordStatusIcon } from "./RecordIcons"; +import { Record } from "../../store/deployApi"; -export function RecordBadge({ record, ...rest }) { +interface RecordBadgeProps { + record: Record; + sx?: SxProps; +} + +export function RecordBadge({ record, sx }: RecordBadgeProps) { return ( <IconBadge icon={<RecordStatusIcon record={record} />} @@ -14,7 +21,7 @@ export function RecordBadge({ record, ...rest }) { {record?.iocName} </InternalLink> } - {...rest} + sx={sx} /> ); } diff --git a/src/components/records/RecordHostLink.tsx b/src/components/records/RecordHostLink.tsx index d2d80c10720c91d24284cb71d92817d73473e16d..7d004aac6bc5a5e6980df0b1ae19aa996f95e5a1 100644 --- a/src/components/records/RecordHostLink.tsx +++ b/src/components/records/RecordHostLink.tsx @@ -1,14 +1,13 @@ import { Grid, Skeleton, Typography } from "@mui/material"; import { InternalLink, EllipsisText, EmptyValue } from "@ess-ics/ce-ui-common"; -import { useFindNetBoxHostByFqdnQuery } from "../../store/deployApi"; +import { + HostInfoWithId, + useFindNetBoxHostByFqdnQuery +} from "../../store/deployApi"; -function shortenFqdn(fqdn) { - return fqdn.split(".")[0]; -} - -function createHostLink(fqdn, hostInfo) { +function createHostLink(hostInfo: HostInfoWithId, fqdn?: string) { // if the fqdn field is empty for some reason - if (fqdn === null || fqdn.trim() === "") { + if (fqdn === null || fqdn?.trim() === "") { return <EmptyValue />; } @@ -20,7 +19,7 @@ function createHostLink(fqdn, hostInfo) { label={`Record host details, ${fqdn}}`} width="100%" > - <EllipsisText>{shortenFqdn(fqdn)}</EllipsisText> + <EllipsisText>{fqdn?.split(".")[0]}</EllipsisText> </InternalLink> ); } @@ -28,8 +27,11 @@ function createHostLink(fqdn, hostInfo) { return <Typography>{fqdn}</Typography>; } -export const RecordHostLink = ({ fqdn }) => { - const { data: hostInfo, isLoading } = useFindNetBoxHostByFqdnQuery({ fqdn }); +export const RecordHostLink = ({ fqdn }: { fqdn?: string }) => { + const { data: hostInfo, isLoading } = useFindNetBoxHostByFqdnQuery( + { fqdn: fqdn ?? "" }, + { skip: !fqdn } + ); return ( <Grid @@ -41,7 +43,7 @@ export const RecordHostLink = ({ fqdn }) => { {isLoading || !hostInfo ? ( <Skeleton width="100%" /> ) : ( - createHostLink(fqdn, hostInfo) + createHostLink(hostInfo, fqdn) )} </Grid> ); diff --git a/src/components/records/RecordIcons.tsx b/src/components/records/RecordIcons.tsx index 2bf7b9cfebb5aa86de0d005aa8b6bb3b7d51c961..3ae0e2cc5eab990db2c1bfacbe3dc81a6aef3f0e 100644 --- a/src/components/records/RecordIcons.tsx +++ b/src/components/records/RecordIcons.tsx @@ -1,3 +1,4 @@ +import { ReactElement } from "react"; import { useTheme } from "@mui/material"; import { LabeledIcon } from "@ess-ics/ce-ui-common"; import { @@ -5,28 +6,29 @@ import { RadioButtonUnchecked, HelpOutline } from "@mui/icons-material"; +import { Record as ApiRecord } from "../../store/deployApi"; -export function RecordStatusIcon({ record }) { +export function RecordStatusIcon({ record }: { record: ApiRecord }) { const theme = useTheme(); const { pvStatus } = record; - const iconConfig = { + const iconConfig: Record<string, { title: string; icon: ReactElement }> = { active: { title: "Active", - icon: Brightness1 + icon: <Brightness1 /> }, inactive: { title: "Inactive", - icon: RadioButtonUnchecked + icon: <RadioButtonUnchecked /> }, null: { title: "Unknown", - icon: HelpOutline + icon: <HelpOutline /> } }; - const state = pvStatus ? pvStatus.toLowerCase() : null; + const state = pvStatus ? pvStatus.toLowerCase() : "null"; const iconStyle = { fill: theme.palette.status.icons }; const iconTitle = iconConfig[state].title; const statusIcon = iconConfig[state].icon; diff --git a/src/components/records/RecordSearch.tsx b/src/components/records/RecordSearch.tsx index e05059ffdb72e35b8e1879e54ba789b9b9878e2e..3a9c0149be1bf8b42fcafe328779603a42707d93 100644 --- a/src/components/records/RecordSearch.tsx +++ b/src/components/records/RecordSearch.tsx @@ -6,20 +6,33 @@ import { RecordTable } from "./RecordTable"; import { initRequestParams } from "../common/Helper"; import { ROWS_PER_PAGE } from "../../constants"; import { useLazyFindAllRecordsQuery } from "../../store/deployApi"; +import { Pagination } from "../../types/common"; -export function RecordSearch({ iocName, rowType, isExpanded }) { +interface RecordSearchProps { + iocName?: string; + rowType: "records" | "iocDetails" | undefined; + isExpanded: boolean; +} + +export function RecordSearch({ + iocName, + rowType, + isExpanded +}: RecordSearchProps) { const [ getRecords, { data: records, isLoading: loading, isSuccess: dataReady } ] = useLazyFindAllRecordsQuery(); const [searchParams, setSearchParams] = useSearchParams({ query: "" }); - const [recordFilter, setRecordFilter] = useState(); + const [recordFilter, setRecordFilter] = useState< + "ACTIVE" | "INACTIVE" | undefined + >(undefined); const [tabIndex, setTabIndex] = useState(0); - const handleTabChange = (tab) => { + const handleTabChange = (tab: number) => { if (tab === 0) { - setRecordFilter(null); + setRecordFilter(undefined); } else if (tab === 1) { setRecordFilter("ACTIVE"); } else if (tab === 2) { @@ -43,23 +56,27 @@ export function RecordSearch({ iocName, rowType, isExpanded }) { useEffect(() => { if (isExpanded) { const requestParams = initRequestParams(pagination); - requestParams.pv_status = recordFilter; - requestParams.text = searchParams.get("query"); - requestParams.ioc_name = iocName; - getRecords(requestParams); + + getRecords({ + pvStatus: recordFilter, + text: searchParams.get("query") || undefined, + iocName: iocName, + ...requestParams, + limit: requestParams.limit.toString() + }); } }, [getRecords, recordFilter, searchParams, pagination, iocName, isExpanded]); // Callback for searchbar, called whenever user updates search const setSearch = useCallback( - (query) => { + (query: string) => { setSearchParams({ query }, { replace: true }); }, [setSearchParams] ); // Invoked by Table on change to pagination - const onPage = (params) => { + const onPage = (params: Pagination) => { setPagination(params); }; diff --git a/src/components/records/RecordTable.tsx b/src/components/records/RecordTable.tsx index 6c21de1e3ae5db092a42cd1cab5a562312d2226f..2f0d3709845d2b98e9dfd1b09e76b81f90498394 100644 --- a/src/components/records/RecordTable.tsx +++ b/src/components/records/RecordTable.tsx @@ -7,6 +7,11 @@ import { import { Grid } from "@mui/material"; import { RecordStatusIcon } from "./RecordIcons"; import { RecordHostLink } from "./RecordHostLink"; +import { Pagination } from "../../types/common"; +import type { + PagedRecordResponse, + Record as ApiRecord +} from "../../store/deployApi"; const recordsColumns = [ { @@ -50,10 +55,10 @@ const iocDetailsColumns = [ { field: "iocVersion", headerName: "Version", width: "15ch", sortable: false } ]; -function createRecordName(record) { +function createRecordName(record: ApiRecord) { return ( <InternalLink - to={`/records/${encodeURIComponent(record.name)}`} + to={`/records/${encodeURIComponent(record?.name || "")}`} label={`Record details, ${record.name}`} width="100%" > @@ -77,7 +82,7 @@ function createRecordName(record) { ); } -function createRecordDescription(description) { +function createRecordDescription(description?: string) { return ( <> {description ? ( @@ -89,7 +94,7 @@ function createRecordDescription(description) { ); } -function createIocLink(record) { +function createIocLink(record: ApiRecord) { // IOC ID only exists if it has been created in the DB -> avoid linking if it hasn't been created if (record.iocId) { return ( @@ -106,7 +111,7 @@ function createIocLink(record) { return record.iocName; } -function createRecordsRow(record) { +function createRecordsRow(record: ApiRecord) { return { id: record.name, bulb: ( @@ -120,13 +125,13 @@ function createRecordsRow(record) { </Grid> ), name: createRecordName(record), - description: createRecordDescription(record.description), + description: createRecordDescription(record?.description), iocName: createIocLink(record), hostName: <RecordHostLink fqdn={record.hostName} /> }; } -function createIocDetailsRow(record) { +function createIocDetailsRow(record: ApiRecord) { return { id: record.name, bulb: ( @@ -139,26 +144,41 @@ function createIocDetailsRow(record) { <RecordStatusIcon record={record} /> </Grid> ), - description: createRecordDescription(record.description), name: createRecordName(record), + description: createRecordDescription(record.description), iocVersion: <EllipsisText>{record.iocVersion}</EllipsisText> }; } +interface RecordTableProps { + records?: PagedRecordResponse; + rowType?: "records" | "iocDetails"; + loading: boolean; + pagination: Pagination; + onPage: (params: Pagination) => void; +} + +type TableTypeSpecificsType = { + records: [typeof recordsColumns, typeof createRecordsRow]; + iocDetails: [typeof iocDetailsColumns, typeof createIocDetailsRow]; +}; + export function RecordTable({ records, rowType = "records", loading, pagination, onPage -}) { - const tableTypeSpecifics = { +}: RecordTableProps) { + const tableTypeSpecifics: TableTypeSpecificsType = { records: [recordsColumns, createRecordsRow], iocDetails: [iocDetailsColumns, createIocDetailsRow] }; const [columns, createRow] = tableTypeSpecifics[rowType]; - const rows = (records?.recordList ?? []).map((record) => createRow(record)); + const rows = (records?.recordList ?? []).map((record: ApiRecord) => + createRow(record) + ); return ( <Table