import React, { useCallback } from "react"; import { InjectedRouter } from "react-router"; import { SingleValue } from "react-select-5"; import { IGetHostSoftwareResponse } from "services/entities/hosts"; import { IGetDeviceSoftwareResponse } from "services/entities/device_user"; import { getNextLocationPath } from "utilities/helpers"; import { convertParamsToSnakeCase, QueryParams } from "utilities/url"; import { SUPPORT_LINK } from "utilities/constants"; import { HostPlatform, isAndroid } from "interfaces/platform"; import { IHostSoftwareWithUiStatus } from "interfaces/software"; import DropdownWrapper from "components/forms/fields/DropdownWrapper"; import TableContainer from "components/TableContainer"; import { ITableQueryData } from "components/TableContainer/TableContainer"; import { CustomOptionType } from "components/forms/fields/DropdownWrapper/DropdownWrapper"; import EmptySoftwareTable from "pages/SoftwarePage/components/tables/EmptySoftwareTable"; import TableCount from "components/TableContainer/TableCount"; import EmptyTable from "components/EmptyTable"; import CustomLink from "components/CustomLink"; import { DROPDOWN_OPTIONS, IHostSWLibraryDropdownFilterVal } from "../helpers"; const DEFAULT_PAGE_SIZE = 20; const baseClass = "host-sw-library-table"; interface IHostSoftwareLibraryTableProps { tableConfig: any; // TODO: type data?: IGetHostSoftwareResponse | IGetDeviceSoftwareResponse; enhancedData?: IHostSoftwareWithUiStatus[]; platform: HostPlatform; isLoading: boolean; router: InjectedRouter; sortHeader: string; sortDirection: "asc" | "desc"; searchQuery: string; page: number; pagePath: string; selfService: boolean; } const HostSoftwareLibraryTable = ({ tableConfig, data, enhancedData, platform, isLoading, router, sortHeader, sortDirection, searchQuery, selfService, page, pagePath, }: IHostSoftwareLibraryTableProps) => { const determineQueryParamChange = useCallback( (newTableQuery: ITableQueryData) => { const changedEntry = Object.entries(newTableQuery).find(([key, val]) => { switch (key) { case "searchQuery": return val !== searchQuery; case "sortDirection": return val !== sortDirection; case "sortHeader": return val !== sortHeader; case "pageIndex": return val !== page; default: return false; } }); return changedEntry?.[0] ?? ""; }, [page, searchQuery, sortDirection, sortHeader] ); const generateNewQueryParams = useCallback( (newTableQuery: ITableQueryData, changedParam: string) => { const newQueryParam: QueryParams = { query: newTableQuery.searchQuery, order_direction: newTableQuery.sortDirection, order_key: newTableQuery.sortHeader, page: changedParam === "pageIndex" ? newTableQuery.pageIndex : 0, ...(selfService && { self_service: "true" }), }; return newQueryParam; }, [selfService] ); // TODO: Look into useDebounceCallback with dependencies const onQueryChange = useCallback( async (newTableQuery: ITableQueryData) => { // we want to determine which query param has changed in order to // reset the page index to 0 if any other param has changed. const changedParam = determineQueryParamChange(newTableQuery); // if nothing has changed, don't update the route. this can happen when // this handler is called on the inital render. Can also happen when // the filter dropdown is changed. That is handled on the onChange handler // for the dropdown. if (changedParam === "") return; const newRoute = getNextLocationPath({ pathPrefix: pagePath, routeTemplate: "", queryParams: generateNewQueryParams(newTableQuery, changedParam), }); router.replace(newRoute); }, [determineQueryParamChange, pagePath, generateNewQueryParams, router] ); const handleCustomFilterDropdownChange = ( value: IHostSWLibraryDropdownFilterVal ) => { const queryParams: QueryParams = { query: searchQuery, orderDirection: sortDirection, orderKey: sortHeader, page: 0, // resets page index ...(value === "selfService" && { selfService: true }), }; router.replace( getNextLocationPath({ pathPrefix: pagePath, routeTemplate: "", queryParams: convertParamsToSnakeCase(queryParams), }) ); }; const count = data?.count || data?.software?.length || 0; const isSoftwareNotDetected = count === 0 && searchQuery === ""; const memoizedSoftwareCount = useCallback(() => { if (isSoftwareNotDetected) { return null; } return ; }, [count, isSoftwareNotDetected]); const memoizedEmptyComponent = useCallback(() => { return ; }, [searchQuery]); // Determines if a user should be able to filter or search in the table const hasData = data && data.software.length > 0; const hasQuery = searchQuery !== ""; const showFilterHeaders = hasData || hasQuery; if (isAndroid(platform)) { return ( Interested in installing software on Android hosts?{" "} } /> ); } const renderCustomControls = () => { return (
) => newValue && handleCustomFilterDropdownChange( newValue.value as IHostSWLibraryDropdownFilterVal ) } variant="table-filter" />
); }; return (
); }; export default HostSoftwareLibraryTable;