diff --git a/src/common/components/hosts/HostValidationGroups.tsx b/src/common/components/hosts/HostValidationGroups.tsx index a700e5d8eb..55dfc4348a 100644 --- a/src/common/components/hosts/HostValidationGroups.tsx +++ b/src/common/components/hosts/HostValidationGroups.tsx @@ -13,11 +13,12 @@ import { hostValidationGroupLabels, hostValidationLabels, } from '../../config'; -import { toSentence } from '../ui/table/utils'; - -import './HostValidationGroups.css'; +import { toSentence } from '../ui'; import Hostname from './Hostname'; import { useTranslation } from '../../hooks/use-translation-wrapper'; +import { getKeys } from '../../utils'; + +import './HostValidationGroups.css'; export type AdditionNtpSourcePropsType = { AdditionalNTPSourcesDialogToggleComponent?: React.FC; @@ -225,20 +226,18 @@ export const HostValidationGroups = ({ validationsInfo, ...props }: HostValidati const { t } = useTranslation(); return ( <> - {Object.keys(validationsInfo).map((groupName) => { - const groupLabel = hostValidationGroupLabels(t)[groupName] as string; + {getKeys(validationsInfo).map((groupName) => { + const validations = validationsInfo[groupName] || []; - const pendingValidations = (validationsInfo[groupName] as Validation[]).filter( - (v: Validation) => v.status === 'pending' && v.id !== 'ntp-synced', + const pendingValidations = validations.filter( + (v) => v.status === 'pending' && v.id !== 'ntp-synced', ); - const failedValidations = (validationsInfo[groupName] as Validation[]).filter( - (v: Validation) => - (v.status === 'failure' || v.status === 'error') && v.id !== 'ntp-synced', + const failedValidations = validations.filter( + (v) => (v.status === 'failure' || v.status === 'error') && v.id !== 'ntp-synced', ); - const softValidations = (validationsInfo[groupName] as Validation[]).filter( - (v: Validation) => - ['pending', 'failure', 'error'].includes(v.status) && v.id === 'ntp-synced', + const softValidations = validations.filter( + (v) => ['pending', 'failure', 'error'].includes(v.status) && v.id === 'ntp-synced', ); const getValidationGroupState = () => { @@ -262,6 +261,7 @@ export const HostValidationGroups = ({ validationsInfo, ...props }: HostValidati ); }; + const groupLabel = hostValidationGroupLabels(t)[groupName] as string; return ( diff --git a/src/common/components/ui/formik/utils.ts b/src/common/components/ui/formik/utils.ts index 7adc7f936f..2399716da0 100644 --- a/src/common/components/ui/formik/utils.ts +++ b/src/common/components/ui/formik/utils.ts @@ -6,6 +6,7 @@ import groupBy from 'lodash/groupBy'; import pickBy from 'lodash/pickBy'; import { OpenshiftVersionOptionType } from '../../../types'; import { ClusterNetwork, MachineNetwork, ServiceNetwork } from '../../../api'; +import { getKeys } from '../../../utils'; export const getFieldId = (fieldName: string, fieldType: string, unique?: string) => { unique = unique ? `${unique}-` : ''; @@ -29,7 +30,7 @@ export const trimCommaSeparatedList = (list: string) => export const getFormikErrorFields = ( errors: FormikErrors, touched: FormikTouched, -) => Object.keys(errors).filter((field) => touched[field]); +) => getKeys(errors).filter((field) => touched[field]); export const getDefaultOpenShiftVersion = (versions: OpenshiftVersionOptionType[]) => versions.find((v) => v.default)?.value || versions[0]?.value || ''; diff --git a/src/common/utils.ts b/src/common/utils.ts index cad8d5cc86..e70289c18a 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -14,3 +14,5 @@ export const getRandomString = (length: number) => Array(length + 1) .join((Math.random().toString(36) + '00000000000000000').slice(2, 18)) .slice(0, length); + +export const getKeys = (obj: T) => Object.keys(obj) as Array; diff --git a/src/ocm/components/clusterDetail/FailedOperatorsWarning.tsx b/src/ocm/components/clusterDetail/FailedOperatorsWarning.tsx index 08d5cccfa0..280d29cf5b 100644 --- a/src/ocm/components/clusterDetail/FailedOperatorsWarning.tsx +++ b/src/ocm/components/clusterDetail/FailedOperatorsWarning.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Alert, AlertVariant, Text, TextContent } from '@patternfly/react-core'; -import { MonitoredOperatorsList, operatorLabels } from '../../../common'; +import { MonitoredOperatorsList, operatorLabels, OperatorName } from '../../../common'; import { useTranslation } from '../../../common/hooks/use-translation-wrapper'; interface FailedOperatorsWarningProps { @@ -11,7 +11,7 @@ const FailedOperatorsWarning = ({ failedOperators }: FailedOperatorsWarningProps const { t } = useTranslation(); const operatorText = failedOperators.length === 1 - ? `${operatorLabels(t)[failedOperators[0].name || '']} operator` + ? `${operatorLabels(t)[(failedOperators[0].name as OperatorName) || '']} operator` : `${failedOperators.length} operators`; return ( diff --git a/src/ocm/components/clusterWizard/ClusterPlatformIntegrationHint.tsx b/src/ocm/components/clusterWizard/ClusterPlatformIntegrationHint.tsx index 2c8727fe96..30f58e55ea 100644 --- a/src/ocm/components/clusterWizard/ClusterPlatformIntegrationHint.tsx +++ b/src/ocm/components/clusterWizard/ClusterPlatformIntegrationHint.tsx @@ -50,7 +50,7 @@ export const ClusterPlatformIntegrationHint = ({ return null; } - const integrationBrand: string = integrationBrands[supportedPlatformIntegration] as string; + const integrationBrand = integrationBrands[supportedPlatformIntegration as SupportedPlatformType]; return ( { const failingValidations: HostValidationId[] = []; hosts?.forEach((host) => { const validationsInfo = stringToJSON(host.validationsInfo) || {}; - Object.keys(validationsInfo).forEach((group) => { + getKeys(validationsInfo).forEach((group) => { const f: (validation: HostValidation) => void = (validation) => { if (validation.status === 'failure') { failingValidations.push(validation.id); diff --git a/src/ocm/components/clusters/Clusters.tsx b/src/ocm/components/clusters/Clusters.tsx index 5c6f3dd4bb..da3fdb2123 100644 --- a/src/ocm/components/clusters/Clusters.tsx +++ b/src/ocm/components/clusters/Clusters.tsx @@ -23,7 +23,11 @@ import { Cluster, } from '../../../common'; import ClustersTable from './ClustersTable'; -import { fetchClustersAsync, deleteCluster } from '../../reducers/clusters/clustersSlice'; +import { + fetchClustersAsync, + deleteCluster, + ClustersDispatch, +} from '../../reducers/clusters/clustersSlice'; import { handleApiError, getApiErrorMessage } from '../../api/utils'; import ClusterBreadcrumbs from './ClusterBreadcrumbs'; import { routeBasePath } from '../../config'; @@ -42,7 +46,7 @@ const Clusters: React.FC = ({ history }) => { if (clustersUIState !== RELOADING) { uiState.current = clustersUIState; } - const dispatch = useDispatch(); + const dispatch = useDispatch(); const deleteClusterAsync = React.useCallback( async (clusterId: Cluster['id']) => { try { @@ -60,7 +64,7 @@ const Clusters: React.FC = ({ history }) => { [dispatch, addAlert], ); - const fetchClusters = React.useCallback(() => dispatch(fetchClustersAsync()), [dispatch]); + const fetchClusters = React.useCallback(() => void dispatch(fetchClustersAsync()), [dispatch]); React.useEffect(() => { fetchClusters(); }, [fetchClusters]); diff --git a/src/ocm/components/clusters/ClustersListToolbar.tsx b/src/ocm/components/clusters/ClustersListToolbar.tsx index dff9e728aa..c01e2b7da6 100644 --- a/src/ocm/components/clusters/ClustersListToolbar.tsx +++ b/src/ocm/components/clusters/ClustersListToolbar.tsx @@ -22,8 +22,8 @@ import { import { FilterIcon, SyncIcon } from '@patternfly/react-icons'; import { Cluster, clusterStatusLabels, isSelectEventChecked, ToolbarButton } from '../../../common'; import { ResourceUIState } from '../../../common'; -import { selectClustersUIState } from '../../selectors/clusters'; -import { fetchClustersAsync } from '../../reducers/clusters/clustersSlice'; +import { selectClustersUIState } from '../../selectors'; +import { ClustersDispatch, fetchClustersAsync } from '../../reducers/clusters'; import { routeBasePath } from '../../config'; import omit from 'lodash/omit'; import { TFunction } from 'i18next'; @@ -52,8 +52,8 @@ const ClustersListToolbar: React.FC = ({ const [isStatusExpanded, setStatusExpanded] = React.useState(false); const history = useHistory(); const clustersUIState = useSelector(selectClustersUIState); - const dispatch = useDispatch(); - const fetchClusters = React.useCallback(() => dispatch(fetchClustersAsync()), [dispatch]); + const dispatch = useDispatch(); + const fetchClusters = React.useCallback(() => void dispatch(fetchClustersAsync()), [dispatch]); const onClearAllFilters: ToolbarProps['clearAllFilters'] = () => { setFilters({ diff --git a/src/ocm/components/clusters/clusterPolling.ts b/src/ocm/components/clusters/clusterPolling.ts index 120b5a5a1c..2a6167dbff 100644 --- a/src/ocm/components/clusters/clusterPolling.ts +++ b/src/ocm/components/clusters/clusterPolling.ts @@ -7,6 +7,7 @@ import { forceReload, cancelForceReload, FetchErrorType, + ClusterDispatch, } from '../../reducers/clusters'; import { selectCurrentClusterState } from '../../selectors'; @@ -22,8 +23,11 @@ const shouldRefetch = (uiState: ResourceUIState, hasClusterData: boolean) => { }; export const useFetchCluster = (clusterId: string) => { - const dispatch = useDispatch(); - return React.useCallback(() => dispatch(fetchClusterAsync(clusterId)), [clusterId, dispatch]); + const dispatch = useDispatch(); + return React.useCallback( + () => void dispatch(fetchClusterAsync(clusterId)), + [clusterId, dispatch], + ); }; export const useClusterPolling = ( diff --git a/src/ocm/reducers/clusters/clustersSlice.ts b/src/ocm/reducers/clusters/clustersSlice.ts index cc304531eb..b169040f0c 100644 --- a/src/ocm/reducers/clusters/clustersSlice.ts +++ b/src/ocm/reducers/clusters/clustersSlice.ts @@ -1,4 +1,11 @@ -import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; +import { + createSlice, + createAsyncThunk, + PayloadAction, + ThunkDispatch, + AnyAction, + Dispatch, +} from '@reduxjs/toolkit'; import { Cluster, ResourceUIState } from '../../../common'; import { ClustersAPI } from '../../services/apis'; import { handleApiError, ocmClient } from '../../api'; @@ -23,6 +30,8 @@ type ClustersStateSlice = { uiState: ResourceUIState; }; +export type ClustersDispatch = ThunkDispatch & Dispatch; + const initialState: ClustersStateSlice = { data: [], uiState: ResourceUIState.LOADING }; export const clustersSlice = createSlice({ diff --git a/src/ocm/reducers/clusters/currentClusterSlice.ts b/src/ocm/reducers/clusters/currentClusterSlice.ts index 25eed2d764..b3cc907564 100644 --- a/src/ocm/reducers/clusters/currentClusterSlice.ts +++ b/src/ocm/reducers/clusters/currentClusterSlice.ts @@ -1,7 +1,14 @@ import findIndex from 'lodash/findIndex'; import set from 'lodash/set'; import { AxiosError } from 'axios'; -import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { + AnyAction, + createAsyncThunk, + createSlice, + Dispatch, + PayloadAction, + ThunkDispatch, +} from '@reduxjs/toolkit'; import { AssistedInstallerPermissionTypesListType, Cluster, @@ -29,6 +36,9 @@ type CurrentClusterStateSlice = { errorDetail?: FetchErrorType; }; +export type ClusterDispatch = ThunkDispatch & + Dispatch; + export const fetchClusterAsync = createAsyncThunk< Cluster | void, string, diff --git a/src/ocm/services/InfraEnvIdsCacheService.ts b/src/ocm/services/InfraEnvIdsCacheService.ts index aed0eae6f7..3e7fb02684 100644 --- a/src/ocm/services/InfraEnvIdsCacheService.ts +++ b/src/ocm/services/InfraEnvIdsCacheService.ts @@ -104,7 +104,7 @@ const InfraEnvIdsCacheService: InfraEnvStorage = { } infraEnvs.forEach((infraEnv) => { if (infraEnv.cpuArchitecture) { - cache[clusterId][infraEnv.cpuArchitecture] = infraEnv.id; + cache[clusterId][infraEnv.cpuArchitecture as CpuArchitecture] = infraEnv.id; } }); update(cache); diff --git a/src/ocm/services/OperatorsService.tsx b/src/ocm/services/OperatorsService.tsx index 0aa18e387c..12aa9ae270 100644 --- a/src/ocm/services/OperatorsService.tsx +++ b/src/ocm/services/OperatorsService.tsx @@ -8,9 +8,10 @@ import { OPERATOR_NAME_LVM, } from '../../common'; import { getOlmOperatorCreateParamsByName } from '../components/clusters/utils'; +import { getKeys } from '../../common/utils'; const hasActiveOperators = (values: OperatorsValues) => { - return Object.keys(values).some((operatorName) => !!values[operatorName]); + return getKeys(values).some((operatorParam) => values[operatorParam]); }; const OperatorsService = {