From 8011609e00347d5d4b900baa644ca04514a0ce63 Mon Sep 17 00:00:00 2001 From: Robert Sun <107655677+rsun19@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:50:54 -0400 Subject: [PATCH] first round of updates to disable type assertions --- frontend/.eslintrc | 12 ++++ .../src/__tests__/unit/testUtils/hooks.ts | 7 +-- frontend/src/api/errorUtils.ts | 2 +- frontend/src/api/modelRegistry/errorUtils.ts | 2 +- frontend/src/api/pipelines/errorUtils.ts | 6 +- frontend/src/api/prometheus/serving.ts | 24 ++++--- frontend/src/api/trustyai/errorUtils.ts | 3 +- frontend/src/app/AppContext.ts | 10 +-- frontend/src/components/DocCardBadges.tsx | 63 ++++++++++--------- frontend/src/components/OdhDocListItem.tsx | 29 +++++---- frontend/src/components/ToastNotification.tsx | 3 +- .../dashboard/DashboardSearchField.tsx | 3 +- .../concepts/distributedWorkloads/utils.tsx | 3 +- frontend/src/concepts/metrics/utils.ts | 7 ++- .../context/ModelRegistryContext.tsx | 1 + .../content/PipelineAndVersionContext.tsx | 6 +- .../PipelineRunArtifactSelect.tsx | 6 +- .../ConfusionMatrixCompare.tsx | 4 +- .../metricsSection/confusionMatrix/utils.ts | 9 ++- .../compareRuns/metricsSection/roc/utils.ts | 17 ++--- .../compareRuns/metricsSection/utils.ts | 10 +-- .../ConfigurePipelinesServerModal.tsx | 3 +- .../pipelines/content/createRun/RunPage.tsx | 2 +- .../content/tables/usePipelineFilter.ts | 12 +++- .../pipelines/context/MlmdListContext.tsx | 1 + .../pipelines/context/PipelinesContext.tsx | 3 + .../src/concepts/projects/ProjectsContext.tsx | 10 ++- .../trustyai/context/TrustyAIContext.tsx | 1 + .../AcceleratorIdentifierMultiselect.tsx | 6 +- .../home/resources/useSpecifiedResources.tsx | 4 +- .../learningCenter/LearningCenterToolbar.tsx | 4 +- .../ModelVersionSelector.tsx | 6 +- .../ModelVersions/ModelVersionListView.tsx | 3 +- .../ModelVersionsArchiveListView.tsx | 3 +- .../RegisteredModelListView.tsx | 3 +- .../RegisteredModelsArchiveListView.tsx | 3 +- ...ustomServingRuntimeAPIProtocolSelector.tsx | 3 +- .../customServingRuntimes/utils.ts | 12 +++- .../modelServing/screens/global/utils.ts | 14 +++-- .../metrics/EnsureMetricsAvailable.tsx | 5 +- .../modelServing/screens/metrics/utils.tsx | 3 +- .../screens/admin/NotebookControllerTabs.tsx | 3 +- .../server/EnvironmentVariablesField.tsx | 3 +- .../server/EnvironmentVariablesRow.tsx | 4 +- .../executions/details/ExecutionDetails.tsx | 4 +- .../global/runs/GlobalPipelineRunsTabs.tsx | 4 +- .../pages/projects/ProjectDetailsContext.tsx | 1 + .../deployedModels/DeployedModelsSection.tsx | 13 ++-- .../environmentVariables/EnvConfigMap.tsx | 5 +- .../environmentVariables/EnvSecret.tsx | 5 +- .../EnvTypeSelectField.tsx | 3 +- .../spawner/environmentVariables/utils.ts | 8 ++- .../projects/screens/spawner/spawnerUtils.ts | 5 +- .../screens/spawner/useBuildStatuses.ts | 4 +- frontend/src/redux/context.ts | 1 + frontend/src/redux/store/store.ts | 4 +- .../utilities/useAcceleratorProfileState.ts | 6 +- frontend/src/utilities/useDraggableTable.ts | 2 +- .../utilities/useWatchNotebooksForUsers.tsx | 11 ++-- frontend/src/utilities/utils.ts | 5 +- 60 files changed, 266 insertions(+), 153 deletions(-) diff --git a/frontend/.eslintrc b/frontend/.eslintrc index cca83da5be..ec95917b9b 100755 --- a/frontend/.eslintrc +++ b/frontend/.eslintrc @@ -315,6 +315,18 @@ } ] } + }, + { + "files": ["*.ts", "*.tsx"], + "excludedFiles": ["**/__mocks__/**", "**/__tests__/**"], + "rules": { + "@typescript-eslint/consistent-type-assertions": [ + "error", + { + "assertionStyle": "never" + } + ] + } } ] } diff --git a/frontend/src/__tests__/unit/testUtils/hooks.ts b/frontend/src/__tests__/unit/testUtils/hooks.ts index c82a2ff7cd..86c308422f 100644 --- a/frontend/src/__tests__/unit/testUtils/hooks.ts +++ b/frontend/src/__tests__/unit/testUtils/hooks.ts @@ -67,8 +67,8 @@ export const renderHook = < options?: RenderHookOptions, ): RenderHookResultExt => { let updateCount = 0; - let prevResult: Result | undefined; - let currentResult: Result | undefined; + let prevResult: Result; + let currentResult: Result; const renderResult = renderHookRTL((props) => { updateCount++; @@ -80,8 +80,7 @@ export const renderHook = < const renderResultExt: RenderHookResultExt = { ...renderResult, - getPreviousResult: () => - updateCount > 1 ? (prevResult as Result) : renderResult.result.current, + getPreviousResult: () => (updateCount > 1 ? prevResult : renderResult.result.current), getUpdateCount: () => updateCount, diff --git a/frontend/src/api/errorUtils.ts b/frontend/src/api/errorUtils.ts index e972b16c41..2e5e19e05a 100644 --- a/frontend/src/api/errorUtils.ts +++ b/frontend/src/api/errorUtils.ts @@ -2,7 +2,7 @@ import { K8sStatus } from '@openshift/dynamic-plugin-sdk-utils'; import { AxiosError } from 'axios'; export const isK8sStatus = (data: unknown): data is K8sStatus => - (data as K8sStatus).kind === 'Status'; + typeof data === 'object' && data !== null && 'kind' in data && data.kind === 'Status'; export class K8sStatusError extends Error { public statusObject: K8sStatus; diff --git a/frontend/src/api/modelRegistry/errorUtils.ts b/frontend/src/api/modelRegistry/errorUtils.ts index d9a3238d74..1282802199 100644 --- a/frontend/src/api/modelRegistry/errorUtils.ts +++ b/frontend/src/api/modelRegistry/errorUtils.ts @@ -2,7 +2,7 @@ import { ModelRegistryError } from '~/concepts/modelRegistry/types'; import { isCommonStateError } from '~/utilities/useFetchState'; const isError = (e: unknown): e is ModelRegistryError => - ['code', 'message'].every((key) => key in (e as ModelRegistryError)); + typeof e === 'object' && e !== null && ['code', 'message'].every((key) => key in e); export const handleModelRegistryFailures = (promise: Promise): Promise => promise diff --git a/frontend/src/api/pipelines/errorUtils.ts b/frontend/src/api/pipelines/errorUtils.ts index 384e3d6d2f..4efaa5da7c 100644 --- a/frontend/src/api/pipelines/errorUtils.ts +++ b/frontend/src/api/pipelines/errorUtils.ts @@ -14,10 +14,12 @@ type ResultErrorKF = { }; const isErrorKF = (e: unknown): e is ErrorKF => - ['error', 'code', 'message'].every((key) => key in (e as ErrorKF)); + typeof e === 'object' && e !== null && ['error', 'code', 'message'].every((key) => key in e); const isErrorDetailsKF = (result: unknown): result is ResultErrorKF => - ['error_details', 'error_message'].every((key) => key in (result as ResultErrorKF)); + typeof result === 'object' && + result !== null && + ['error_details', 'error_message'].every((key) => key in result); export const handlePipelineFailures = (promise: Promise): Promise => promise diff --git a/frontend/src/api/prometheus/serving.ts b/frontend/src/api/prometheus/serving.ts index 9cf7f35188..749634b11a 100644 --- a/frontend/src/api/prometheus/serving.ts +++ b/frontend/src/api/prometheus/serving.ts @@ -43,7 +43,7 @@ export const useModelServingMetrics = ( const serverRequestCount = useQueryRangeResourceData( performanceMetricsAreaAvailable && type === PerformanceMetricType.SERVER, - (queries as { [key in ServerMetricType]: string })[ServerMetricType.REQUEST_COUNT], + ServerMetricType.REQUEST_COUNT in queries ? queries[ServerMetricType.REQUEST_COUNT] : '', end, timeframe, defaultResponsePredicate, @@ -53,7 +53,9 @@ export const useModelServingMetrics = ( const serverAverageResponseTime = useQueryRangeResourceData( performanceMetricsAreaAvailable && type === PerformanceMetricType.SERVER, - (queries as { [key in ServerMetricType]: string })[ServerMetricType.AVG_RESPONSE_TIME], + ServerMetricType.AVG_RESPONSE_TIME in queries + ? queries[ServerMetricType.AVG_RESPONSE_TIME] + : '', end, timeframe, prometheusQueryRangeResponsePredicate, @@ -62,7 +64,7 @@ export const useModelServingMetrics = ( const serverCPUUtilization = useQueryRangeResourceData( performanceMetricsAreaAvailable && type === PerformanceMetricType.SERVER, - (queries as { [key in ServerMetricType]: string })[ServerMetricType.CPU_UTILIZATION], + ServerMetricType.CPU_UTILIZATION in queries ? queries[ServerMetricType.CPU_UTILIZATION] : '', end, timeframe, defaultResponsePredicate, @@ -71,7 +73,9 @@ export const useModelServingMetrics = ( const serverMemoryUtilization = useQueryRangeResourceData( performanceMetricsAreaAvailable && type === PerformanceMetricType.SERVER, - (queries as { [key in ServerMetricType]: string })[ServerMetricType.MEMORY_UTILIZATION], + ServerMetricType.MEMORY_UTILIZATION in queries + ? queries[ServerMetricType.MEMORY_UTILIZATION] + : '', end, timeframe, defaultResponsePredicate, @@ -80,7 +84,9 @@ export const useModelServingMetrics = ( const modelRequestSuccessCount = useQueryRangeResourceData( performanceMetricsAreaAvailable && type === PerformanceMetricType.MODEL, - (queries as { [key in ModelMetricType]: string })[ModelMetricType.REQUEST_COUNT_SUCCESS], + ModelMetricType.REQUEST_COUNT_SUCCESS in queries + ? queries[ModelMetricType.REQUEST_COUNT_SUCCESS] + : '', end, timeframe, defaultResponsePredicate, @@ -89,7 +95,9 @@ export const useModelServingMetrics = ( const modelRequestFailedCount = useQueryRangeResourceData( performanceMetricsAreaAvailable && type === PerformanceMetricType.MODEL, - (queries as { [key in ModelMetricType]: string })[ModelMetricType.REQUEST_COUNT_FAILED], + ModelMetricType.REQUEST_COUNT_FAILED in queries + ? queries[ModelMetricType.REQUEST_COUNT_FAILED] + : '', end, timeframe, defaultResponsePredicate, @@ -98,7 +106,7 @@ export const useModelServingMetrics = ( const modelTrustyAISPD = useQueryRangeResourceData( biasMetricsAreaAvailable && type === PerformanceMetricType.MODEL, - (queries as { [key in ModelMetricType]: string })[ModelMetricType.TRUSTY_AI_SPD], + ModelMetricType.TRUSTY_AI_SPD in queries ? queries[ModelMetricType.TRUSTY_AI_SPD] : '', end, timeframe, prometheusQueryRangeResponsePredicate, @@ -108,7 +116,7 @@ export const useModelServingMetrics = ( const modelTrustyAIDIR = useQueryRangeResourceData( biasMetricsAreaAvailable && type === PerformanceMetricType.MODEL, - (queries as { [key in ModelMetricType]: string })[ModelMetricType.TRUSTY_AI_DIR], + ModelMetricType.TRUSTY_AI_DIR in queries ? queries[ModelMetricType.TRUSTY_AI_DIR] : '', end, timeframe, prometheusQueryRangeResponsePredicate, diff --git a/frontend/src/api/trustyai/errorUtils.ts b/frontend/src/api/trustyai/errorUtils.ts index 60fd07a7f6..6f3625f38e 100644 --- a/frontend/src/api/trustyai/errorUtils.ts +++ b/frontend/src/api/trustyai/errorUtils.ts @@ -9,8 +9,7 @@ type TrustyAIClientErrorViolation = { }; const isTrustyAIClientError = (e: unknown): e is TrustyAIClientError => - typeof e === 'object' && - ['title', 'status', 'violations'].every((key) => key in (e as TrustyAIClientError)); + typeof e === 'object' && e !== null && ['title', 'status', 'violations'].every((key) => key in e); export const handleTrustyAIFailures = (promise: Promise): Promise => promise.then((result) => { diff --git a/frontend/src/app/AppContext.ts b/frontend/src/app/AppContext.ts index bdc0141450..2b51e99c15 100644 --- a/frontend/src/app/AppContext.ts +++ b/frontend/src/app/AppContext.ts @@ -8,13 +8,7 @@ type AppContextProps = { storageClasses: StorageClassKind[]; }; -const defaultAppContext: AppContextProps = { - buildStatuses: [], - // At runtime dashboardConfig is never null -- DO NOT DO THIS usually - dashboardConfig: null as unknown as DashboardConfigKind, - storageClasses: [] as StorageClassKind[], -}; - -export const AppContext = React.createContext(defaultAppContext); +// eslint-disable-next-line @typescript-eslint/consistent-type-assertions +export const AppContext = React.createContext({} as AppContextProps); export const useAppContext = (): AppContextProps => React.useContext(AppContext); diff --git a/frontend/src/components/DocCardBadges.tsx b/frontend/src/components/DocCardBadges.tsx index 9a82f54235..4c032627b7 100644 --- a/frontend/src/components/DocCardBadges.tsx +++ b/frontend/src/components/DocCardBadges.tsx @@ -5,7 +5,7 @@ import { QuickStartContext, QuickStartContextValues } from '@patternfly/quicksta import { OdhDocument, OdhDocumentType } from '~/types'; import { getQuickStartCompletionStatus, CompletionStatusEnum } from '~/utilities/quickStartUtils'; import { DOC_TYPE_TOOLTIPS } from '~/utilities/const'; -import { getLabelColorForDocType, getDuration } from '~/utilities/utils'; +import { getLabelColorForDocType, getDuration, asEnumMember } from '~/utilities/utils'; import { DOC_TYPE_LABEL } from '~/pages/learningCenter/const'; import './OdhCard.scss'; @@ -19,7 +19,7 @@ const DocCardBadges: React.FC = ({ odhDoc }) => { const [completionStatus, setCompletionStatus] = React.useState< CompletionStatusEnum | undefined >(); - const docType = odhDoc.spec.type as OdhDocumentType; + const docType = asEnumMember(odhDoc.spec.type, OdhDocumentType); const docName = odhDoc.metadata.name; const duration = odhDoc.spec.durationMinutes; @@ -32,35 +32,38 @@ const DocCardBadges: React.FC = ({ odhDoc }) => { } }, [qsContext, docType, docName]); - const label = DOC_TYPE_LABEL[docType] || 'Documentation'; + if (docType !== null) { + const label = DOC_TYPE_LABEL[docType] || 'Documentation'; - return ( - - - - - {duration ? ( - - ) : null} - {completionStatus === CompletionStatusEnum.InProgress ? ( - - ) : null} - {completionStatus === CompletionStatusEnum.Success ? ( - - ) : null} - {completionStatus === CompletionStatusEnum.Failed ? ( - - ) : null} - - ); + return ( + + + + + {duration ? ( + + ) : null} + {completionStatus === CompletionStatusEnum.InProgress ? ( + + ) : null} + {completionStatus === CompletionStatusEnum.Success ? ( + + ) : null} + {completionStatus === CompletionStatusEnum.Failed ? ( + + ) : null} + + ); + } + return null; }; export default DocCardBadges; diff --git a/frontend/src/components/OdhDocListItem.tsx b/frontend/src/components/OdhDocListItem.tsx index 61414f2916..8386b2db30 100644 --- a/frontend/src/components/OdhDocListItem.tsx +++ b/frontend/src/components/OdhDocListItem.tsx @@ -5,7 +5,7 @@ import { ExternalLinkAltIcon } from '@patternfly/react-icons'; import { OdhDocument, OdhDocumentType } from '~/types'; import { getQuickStartLabel, launchQuickStart } from '~/utilities/quickStartUtils'; import { DOC_TYPE_TOOLTIPS } from '~/utilities/const'; -import { getDuration } from '~/utilities/utils'; +import { asEnumMember, getDuration } from '~/utilities/utils'; import { useQuickStartCardSelected } from './useQuickStartCardSelected'; import FavoriteButton from './FavoriteButton'; @@ -26,18 +26,21 @@ const OdhDocListItem: React.FC = ({ odhDoc, favorite, updateFav }; const renderTypeBadge = () => { - const docType = odhDoc.spec.type as OdhDocumentType; - const typeBadgeClasses = classNames('odh-list-item__partner-badge odh-m-doc', { - 'odh-m-documentation': docType === OdhDocumentType.Documentation, - 'odh-m-tutorial': docType === OdhDocumentType.Tutorial, - 'odh-m-quick-start': docType === OdhDocumentType.QuickStart, - 'odh-m-how-to': docType === OdhDocumentType.HowTo, - }); - return ( - -
{odhDoc.spec.type}
-
- ); + const docType = asEnumMember(odhDoc.spec.type, OdhDocumentType); + if (docType !== null) { + const typeBadgeClasses = classNames('odh-list-item__partner-badge odh-m-doc', { + 'odh-m-documentation': docType === OdhDocumentType.Documentation, + 'odh-m-tutorial': docType === OdhDocumentType.Tutorial, + 'odh-m-quick-start': docType === OdhDocumentType.QuickStart, + 'odh-m-how-to': docType === OdhDocumentType.HowTo, + }); + return ( + +
{odhDoc.spec.type}
+
+ ); + } + return null; }; const renderDocLink = () => { diff --git a/frontend/src/components/ToastNotification.tsx b/frontend/src/components/ToastNotification.tsx index 4f2a2299ab..b0a945705b 100644 --- a/frontend/src/components/ToastNotification.tsx +++ b/frontend/src/components/ToastNotification.tsx @@ -3,6 +3,7 @@ import { Alert, AlertActionCloseButton, AlertVariant } from '@patternfly/react-c import { AppNotification } from '~/redux/types'; import { ackNotification, hideNotification } from '~/redux/actions/actions'; import { useAppDispatch } from '~/redux/hooks'; +import { asEnumMember } from '~/utilities/utils'; const TOAST_NOTIFICATION_TIMEOUT = 8 * 1000; @@ -36,7 +37,7 @@ const ToastNotification: React.FC = ({ notification }) = return ( dispatch(ackNotification(notification))} /> diff --git a/frontend/src/concepts/dashboard/DashboardSearchField.tsx b/frontend/src/concepts/dashboard/DashboardSearchField.tsx index 18d45e1da6..f8c0a88051 100644 --- a/frontend/src/concepts/dashboard/DashboardSearchField.tsx +++ b/frontend/src/concepts/dashboard/DashboardSearchField.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { InputGroup, SearchInput, InputGroupItem } from '@patternfly/react-core'; import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import { asEnumMember } from '~/utilities/utils'; // List all the possible search fields here export enum SearchType { @@ -48,7 +49,7 @@ const DashboardSearchField: React.FC = ({ }))} value={searchType} onChange={(key) => { - onSearchTypeChange(key as SearchType); + onSearchTypeChange(asEnumMember(key, SearchType)!); }} icon={icon} /> diff --git a/frontend/src/concepts/distributedWorkloads/utils.tsx b/frontend/src/concepts/distributedWorkloads/utils.tsx index db466618d7..29a4de3785 100644 --- a/frontend/src/concepts/distributedWorkloads/utils.tsx +++ b/frontend/src/concepts/distributedWorkloads/utils.tsx @@ -34,6 +34,7 @@ import { convertToUnit, } from '~/utilities/valueUnits'; import { WorkloadWithUsage } from '~/api'; +import { isEnumMember } from '~/utilities/utils'; export enum WorkloadStatusType { Pending = 'Pending', @@ -166,7 +167,7 @@ export const getWorkloadName = (workload: WorkloadKind): string => workload.metadata?.name || 'Unnamed'; export const isKnownWorkloadOwnerType = (s: string): s is WorkloadOwnerType => - (Object.values(WorkloadOwnerType) as string[]).includes(s); + isEnumMember(s, WorkloadOwnerType); export const getWorkloadOwner = ( workload: WorkloadKind, diff --git a/frontend/src/concepts/metrics/utils.ts b/frontend/src/concepts/metrics/utils.ts index 1f44bc91cf..e1573ab6a2 100644 --- a/frontend/src/concepts/metrics/utils.ts +++ b/frontend/src/concepts/metrics/utils.ts @@ -1,12 +1,15 @@ import { SelectOptionObject } from '@patternfly/react-core/deprecated'; import { TimeframeTitle, RefreshIntervalTitle } from '~/concepts/metrics/types'; +import { asEnumMember } from '~/utilities/utils'; export const isTimeframeTitle = ( timeframe: string | SelectOptionObject, ): timeframe is TimeframeTitle => - Object.values(TimeframeTitle).includes(timeframe as TimeframeTitle); + Object.values(TimeframeTitle).includes(asEnumMember(timeframe.toString(), TimeframeTitle)!); export const isRefreshIntervalTitle = ( refreshInterval: string | SelectOptionObject, ): refreshInterval is RefreshIntervalTitle => - Object.values(RefreshIntervalTitle).includes(refreshInterval as RefreshIntervalTitle); + Object.values(RefreshIntervalTitle).includes( + asEnumMember(refreshInterval.toString(), RefreshIntervalTitle)!, + ); diff --git a/frontend/src/concepts/modelRegistry/context/ModelRegistryContext.tsx b/frontend/src/concepts/modelRegistry/context/ModelRegistryContext.tsx index eb3bdce52d..dfde7ebcc8 100644 --- a/frontend/src/concepts/modelRegistry/context/ModelRegistryContext.tsx +++ b/frontend/src/concepts/modelRegistry/context/ModelRegistryContext.tsx @@ -28,6 +28,7 @@ export const ModelRegistryContext = React.createContext undefined, refreshState: async () => undefined, diff --git a/frontend/src/concepts/pipelines/content/PipelineAndVersionContext.tsx b/frontend/src/concepts/pipelines/content/PipelineAndVersionContext.tsx index eed1a71d94..f298573f56 100644 --- a/frontend/src/concepts/pipelines/content/PipelineAndVersionContext.tsx +++ b/frontend/src/concepts/pipelines/content/PipelineAndVersionContext.tsx @@ -77,10 +77,10 @@ const PipelineAndVersionContextProvider: React.FC ({ pipelines: selectedPipelines, - versions: (Object.values(selectedVersions) as SelectedVersion[]) + versions: Object.values(selectedVersions) .map((selectedVersion) => - selectedVersion.versions.map((version) => ({ - pipelineName: selectedVersion.pipelineName, + selectedVersion!.versions.map((version) => ({ + pipelineName: selectedVersion!.pipelineName, version, })), ) diff --git a/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/PipelineRunArtifactSelect.tsx b/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/PipelineRunArtifactSelect.tsx index b016f14639..f262b1f01a 100644 --- a/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/PipelineRunArtifactSelect.tsx +++ b/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/PipelineRunArtifactSelect.tsx @@ -49,10 +49,10 @@ export const PipelineRunArtifactSelect = ({ isOpen={isOpen} selected={selectedItemTitles} onSelect={(_event, value) => { - if (selectedItemTitles.includes(value as string)) { + if (typeof value === 'string' && selectedItemTitles.includes(value)) { setSelectedItemTitles(selectedItemTitles.filter((id) => id !== value)); - } else { - setSelectedItemTitles([...selectedItemTitles, value as string]); + } else if (typeof value === 'string') { + setSelectedItemTitles([...selectedItemTitles, value]); } }} onOpenChange={(nextOpen: boolean) => setIsOpen(nextOpen)} diff --git a/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/confusionMatrix/ConfusionMatrixCompare.tsx b/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/confusionMatrix/ConfusionMatrixCompare.tsx index 60ec951f71..c8205ed80c 100644 --- a/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/confusionMatrix/ConfusionMatrixCompare.tsx +++ b/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/confusionMatrix/ConfusionMatrixCompare.tsx @@ -55,7 +55,7 @@ const ConfusionMatrixCompare: React.FC = ({ const data = customProperties.get('confusionMatrix')?.getStructValue()?.toJavaScript(); if (data) { - const confusionMatrixData = data.struct as unknown; + const confusionMatrixData: unknown = data.struct; if (isConfusionMatrix(confusionMatrixData)) { const runId = fullPath.run.run_id; const title = getFullArtifactPathLabel(fullPath); @@ -79,7 +79,9 @@ const ConfusionMatrixCompare: React.FC = ({ return acc; }, { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions runMap: {} as Record, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions configMap: {} as Record, }, ), diff --git a/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/confusionMatrix/utils.ts b/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/confusionMatrix/utils.ts index 47fea29c76..2891587bd9 100644 --- a/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/confusionMatrix/utils.ts +++ b/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/confusionMatrix/utils.ts @@ -1,8 +1,12 @@ import { ConfusionMatrixInput } from '~/concepts/pipelines/content/artifacts/charts/confusionMatrix/types'; export const isConfusionMatrix = (obj: unknown): obj is ConfusionMatrixInput => { - const matrix = obj as ConfusionMatrixInput; + const matrix = obj; return ( + typeof matrix === 'object' && + matrix !== null && + 'annotationSpecs' in matrix && + 'rows' in matrix && Array.isArray(matrix.annotationSpecs) && matrix.annotationSpecs.every( (annotationSpec) => @@ -10,7 +14,8 @@ export const isConfusionMatrix = (obj: unknown): obj is ConfusionMatrixInput => ) && Array.isArray(matrix.rows) && matrix.rows.every( - (row) => Array.isArray(row.row) && row.row.every((value) => typeof value === 'number'), + (row) => + Array.isArray(row.row) && row.row.every((value: unknown) => typeof value === 'number'), ) ); }; diff --git a/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/roc/utils.ts b/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/roc/utils.ts index c3bf9da5d8..c0859b5af6 100644 --- a/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/roc/utils.ts +++ b/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/roc/utils.ts @@ -2,14 +2,15 @@ import { JavaScriptValue } from 'google-protobuf/google/protobuf/struct_pb'; import { ROCCurveConfig } from '~/concepts/pipelines/content/artifacts/charts/ROCCurve'; import { ConfidenceMetric } from './types'; -export const isConfidenceMetric = (obj: JavaScriptValue): obj is ConfidenceMetric => { - const metric = obj as ConfidenceMetric; - return ( - typeof metric.confidenceThreshold === 'number' && - typeof metric.falsePositiveRate === 'number' && - typeof metric.recall === 'number' - ); -}; +export const isConfidenceMetric = (obj: JavaScriptValue): obj is ConfidenceMetric => + typeof obj === 'object' && + obj !== null && + 'confidenceThreshold' in obj && + 'falsePositiveRate' in obj && + 'recall' in obj && + obj.confidenceThreshold === 'number' && + obj.falsePositiveRate === 'number' && + obj.recall === 'number'; export const buildRocCurveConfig = ( confidenceMetricsArray: ConfidenceMetric[], diff --git a/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/utils.ts b/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/utils.ts index 38a034f605..b5907e164e 100644 --- a/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/utils.ts +++ b/frontend/src/concepts/pipelines/content/compareRuns/metricsSection/utils.ts @@ -58,7 +58,7 @@ export const getRunArtifacts = (mlmdPackages: PipelineRunRelatedMlmd[]): RunArti linkedArtifacts.push({ event, artifact, - } as LinkedArtifact); + }); } else { throw new Error(`The artifact with the following ID was not found: ${artifactId}`); } @@ -66,12 +66,12 @@ export const getRunArtifacts = (mlmdPackages: PipelineRunRelatedMlmd[]): RunArti return { execution, linkedArtifacts, - } as ExecutionArtifact; + }; }); return { run: mlmdPackage.run, executionArtifacts, - } as RunArtifact; + }; }); export const filterRunArtifactsByType = ( @@ -102,14 +102,14 @@ export const filterRunArtifactsByType = ( typeExecutions.push({ execution: e.execution, linkedArtifacts: typeArtifacts, - } as ExecutionArtifact); + }); } } if (typeExecutions.length > 0) { typeRuns.push({ run: runArtifact.run, executionArtifacts: typeExecutions, - } as RunArtifact); + }); } } return typeRuns; diff --git a/frontend/src/concepts/pipelines/content/configurePipelinesServer/ConfigurePipelinesServerModal.tsx b/frontend/src/concepts/pipelines/content/configurePipelinesServer/ConfigurePipelinesServerModal.tsx index 252de75602..ccb6e20158 100644 --- a/frontend/src/concepts/pipelines/content/configurePipelinesServer/ConfigurePipelinesServerModal.tsx +++ b/frontend/src/concepts/pipelines/content/configurePipelinesServer/ConfigurePipelinesServerModal.tsx @@ -6,6 +6,7 @@ import { createPipelinesCR, deleteSecret } from '~/api'; import useDataConnections from '~/pages/projects/screens/detail/data-connections/useDataConnections'; import { EMPTY_AWS_PIPELINE_DATA } from '~/pages/projects/dataConnections/const'; import DashboardModalFooter from '~/concepts/dashboard/DashboardModalFooter'; +import { asEnumMember } from '~/utilities/utils'; import { PipelinesDatabaseSection } from './PipelinesDatabaseSection'; import { ObjectStorageSection } from './ObjectStorageSection'; import { @@ -48,7 +49,7 @@ export const ConfigurePipelinesServerModal: React.FC DATABASE_CONNECTION_FIELDS.filter((field) => field.isRequired) .map((field) => field.key) - .includes(key as DatabaseConnectionKeys) + .includes(asEnumMember(key, DatabaseConnectionKeys)!) ? !!value : true, ); diff --git a/frontend/src/concepts/pipelines/content/createRun/RunPage.tsx b/frontend/src/concepts/pipelines/content/createRun/RunPage.tsx index 8761f6f942..8a62b397d9 100644 --- a/frontend/src/concepts/pipelines/content/createRun/RunPage.tsx +++ b/frontend/src/concepts/pipelines/content/createRun/RunPage.tsx @@ -118,7 +118,7 @@ const RunPage: React.FC = ({ cloneRun, contextPath, testId }) => { > diff --git a/frontend/src/concepts/pipelines/content/tables/usePipelineFilter.ts b/frontend/src/concepts/pipelines/content/tables/usePipelineFilter.ts index 9a1cd1031d..e0165a5700 100644 --- a/frontend/src/concepts/pipelines/content/tables/usePipelineFilter.ts +++ b/frontend/src/concepts/pipelines/content/tables/usePipelineFilter.ts @@ -20,7 +20,17 @@ export const getDataValue = void; } +// eslint-disable-next-line @typescript-eslint/consistent-type-assertions const MlmdListContext = React.createContext({} as MlmdListContextProps); export const MlmdListContextProvider: React.FC = ({ children }) => { diff --git a/frontend/src/concepts/pipelines/context/PipelinesContext.tsx b/frontend/src/concepts/pipelines/context/PipelinesContext.tsx index 83af9ea8f0..539b340502 100644 --- a/frontend/src/concepts/pipelines/context/PipelinesContext.tsx +++ b/frontend/src/concepts/pipelines/context/PipelinesContext.tsx @@ -50,6 +50,7 @@ const PipelinesContext = React.createContext({ serverTimedOut: false, ignoreTimedOut: () => undefined, namespace: '', + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions project: null as unknown as ProjectKind, refreshState: async () => undefined, refreshAPIState: () => undefined, @@ -57,7 +58,9 @@ const PipelinesContext = React.createContext({ loading: false, data: null, }), + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions apiState: { apiAvailable: false, api: null as unknown as PipelineAPIState['api'] }, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions metadataStoreServiceClient: null as unknown as MetadataStoreServicePromiseClient, }); diff --git a/frontend/src/concepts/projects/ProjectsContext.tsx b/frontend/src/concepts/projects/ProjectsContext.tsx index dce7d107cc..97ed7b2265 100644 --- a/frontend/src/concepts/projects/ProjectsContext.tsx +++ b/frontend/src/concepts/projects/ProjectsContext.tsx @@ -50,11 +50,19 @@ type ProjectsProviderProps = { children: React.ReactNode; }; +const isError = (obj: unknown): obj is Error => + typeof obj === 'object' && + obj !== null && + 'name' in obj && + 'message' in obj && + typeof obj.name === 'string' && + typeof obj.message === 'string'; + const ProjectsContextProvider: React.FC = ({ children }) => { const [preferredProject, setPreferredProject] = React.useState(null); const [projectData, loaded, error] = useProjects(); - const loadError = error as Error | undefined; + const loadError = isError(error) ? error : undefined; const { dashboardNamespace } = useDashboardNamespace(); const { projects, dataScienceProjects, modelServingProjects, nonActiveProjects } = React.useMemo( diff --git a/frontend/src/concepts/trustyai/context/TrustyAIContext.tsx b/frontend/src/concepts/trustyai/context/TrustyAIContext.tsx index 1d8485d236..ba3e956397 100644 --- a/frontend/src/concepts/trustyai/context/TrustyAIContext.tsx +++ b/frontend/src/concepts/trustyai/context/TrustyAIContext.tsx @@ -30,6 +30,7 @@ export const TrustyAIContext = React.createContext({ data: DEFAULT_CONTEXT_DATA, refreshState: async () => undefined, refreshAPIState: () => undefined, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions apiState: { apiAvailable: false, api: null as unknown as TrustyAPIState['api'] }, }); diff --git a/frontend/src/pages/BYONImages/BYONImageModal/AcceleratorIdentifierMultiselect.tsx b/frontend/src/pages/BYONImages/BYONImageModal/AcceleratorIdentifierMultiselect.tsx index a71eb628e4..5e646a6c60 100644 --- a/frontend/src/pages/BYONImages/BYONImageModal/AcceleratorIdentifierMultiselect.tsx +++ b/frontend/src/pages/BYONImages/BYONImageModal/AcceleratorIdentifierMultiselect.tsx @@ -170,7 +170,11 @@ export const AcceleratorIdentifierMultiselect: React.FC onSelect(selection as string)} + onSelect={(ev, selection) => { + if (typeof selection === 'string') { + onSelect(selection); + } + }} onOpenChange={() => setIsOpen(false)} toggle={toggle} > diff --git a/frontend/src/pages/home/resources/useSpecifiedResources.tsx b/frontend/src/pages/home/resources/useSpecifiedResources.tsx index 3e27c6fe7a..85d2ba37f9 100644 --- a/frontend/src/pages/home/resources/useSpecifiedResources.tsx +++ b/frontend/src/pages/home/resources/useSpecifiedResources.tsx @@ -10,13 +10,13 @@ export const useSpecifiedResources = ( if (!loaded || loadError) { return { docs: [], loaded, loadError }; } - const foundDocs = specifiedDocs.reduce((acc, included) => { + const foundDocs = specifiedDocs.reduce((acc, included) => { const doc = docs.find((d) => d.metadata.name === included.name && d.kind === included.kind); if (doc) { acc.push(doc); } return acc; - }, [] as OdhDocument[]); + }, []); return { docs: foundDocs, loaded, loadError }; }, [docs, specifiedDocs, loadError, loaded]); }; diff --git a/frontend/src/pages/learningCenter/LearningCenterToolbar.tsx b/frontend/src/pages/learningCenter/LearningCenterToolbar.tsx index fda12ae799..bf10b8b391 100644 --- a/frontend/src/pages/learningCenter/LearningCenterToolbar.tsx +++ b/frontend/src/pages/learningCenter/LearningCenterToolbar.tsx @@ -113,7 +113,7 @@ const LearningCenterToolbar: React.FC = ({ const onSortTypeSelect = React.useCallback( (e: React.MouseEvent | React.ChangeEvent) => { setIsSortTypeDropdownOpen(false); - const selection = (e.target as Element).getAttribute('data-key') ?? ''; + const selection = e.target instanceof Element ? e.target.getAttribute('data-key') ?? '' : ''; setQueryArgument(navigate, DOC_SORT_KEY, selection); }, [navigate], @@ -133,7 +133,7 @@ const LearningCenterToolbar: React.FC = ({ const onSortOrderSelect = React.useCallback( (e: React.MouseEvent | React.ChangeEvent) => { setIsSortOrderDropdownOpen(false); - const selection = (e.target as Element).getAttribute('data-key') ?? ''; + const selection = e.target instanceof Element ? e.target.getAttribute('data-key') ?? '' : ''; setQueryArgument(navigate, DOC_SORT_ORDER_KEY, selection); }, [navigate], diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionSelector.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionSelector.tsx index cf00d689ea..80aadb7cca 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionSelector.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionSelector.tsx @@ -53,8 +53,10 @@ const ModelVersionSelector: React.FC = ({ const menu = ( { - onSelect(itemId as string); - setOpen(false); + if (typeof itemId === 'string') { + onSelect(itemId); + setOpen(false); + } }} data-id="model-version-selector-menu" ref={menuRef} diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx index 049454ed25..a6609394e1 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx @@ -22,6 +22,7 @@ import EmptyModelRegistryState from '~/pages/modelRegistry/screens/components/Em import { filterModelVersions } from '~/pages/modelRegistry/screens/utils'; import { ModelRegistrySelectorContext } from '~/concepts/modelRegistry/context/ModelRegistrySelectorContext'; import { modelVersionArchiveUrl } from '~/pages/modelRegistry/screens/routeUtils'; +import { asEnumMember } from '~/utilities/utils'; import ModelVersionsTable from './ModelVersionsTable'; type ModelVersionListViewProps = { @@ -89,7 +90,7 @@ const ModelVersionListView: React.FC = ({ }))} value={searchType} onChange={(newSearchType) => { - setSearchType(newSearchType as SearchType); + setSearchType(asEnumMember(newSearchType, SearchType)!); }} icon={} /> diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionsArchiveListView.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionsArchiveListView.tsx index e7bf2dcc50..3450942f69 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionsArchiveListView.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionsArchiveListView.tsx @@ -13,6 +13,7 @@ import { ModelVersion } from '~/concepts/modelRegistry/types'; import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; import { filterModelVersions } from '~/pages/modelRegistry/screens/utils'; import EmptyModelRegistryState from '~/pages/modelRegistry/screens/components/EmptyModelRegistryState'; +import { asEnumMember } from '~/utilities/utils'; import ModelVersionsArchiveTable from './ModelVersionsArchiveTable'; type ModelVersionsArchiveListViewProps = { @@ -63,7 +64,7 @@ const ModelVersionsArchiveListView: React.FC }))} value={searchType} onChange={(newSearchType) => { - setSearchType(newSearchType as SearchType); + setSearchType(asEnumMember(newSearchType, SearchType)!); }} icon={} /> diff --git a/frontend/src/pages/modelRegistry/screens/RegisteredModels/RegisteredModelListView.tsx b/frontend/src/pages/modelRegistry/screens/RegisteredModels/RegisteredModelListView.tsx index 561cee5da8..e6ce7d2eed 100644 --- a/frontend/src/pages/modelRegistry/screens/RegisteredModels/RegisteredModelListView.tsx +++ b/frontend/src/pages/modelRegistry/screens/RegisteredModels/RegisteredModelListView.tsx @@ -9,6 +9,7 @@ import { filterRegisteredModels } from '~/pages/modelRegistry/screens/utils'; import { ModelRegistrySelectorContext } from '~/concepts/modelRegistry/context/ModelRegistrySelectorContext'; import EmptyModelRegistryState from '~/pages/modelRegistry/screens/components/EmptyModelRegistryState'; import { registeredModelArchiveUrl } from '~/pages/modelRegistry/screens/routeUtils'; +import { asEnumMember } from '~/utilities/utils'; import RegisteredModelTable from './RegisteredModelTable'; import RegisteredModelsTableToolbar from './RegisteredModelsTableToolbar'; @@ -71,7 +72,7 @@ const RegisteredModelListView: React.FC = ({ }))} value={searchType} onChange={(newSearchType) => { - setSearchType(newSearchType as SearchType); + setSearchType(asEnumMember(newSearchType, SearchType)!); }} icon={} /> diff --git a/frontend/src/pages/modelRegistry/screens/RegisteredModelsArchive/RegisteredModelsArchiveListView.tsx b/frontend/src/pages/modelRegistry/screens/RegisteredModelsArchive/RegisteredModelsArchiveListView.tsx index 7e5de0392c..2196f2cd53 100644 --- a/frontend/src/pages/modelRegistry/screens/RegisteredModelsArchive/RegisteredModelsArchiveListView.tsx +++ b/frontend/src/pages/modelRegistry/screens/RegisteredModelsArchive/RegisteredModelsArchiveListView.tsx @@ -13,6 +13,7 @@ import { RegisteredModel } from '~/concepts/modelRegistry/types'; import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; import { filterRegisteredModels } from '~/pages/modelRegistry/screens/utils'; import EmptyModelRegistryState from '~/pages/modelRegistry/screens/components/EmptyModelRegistryState'; +import { asEnumMember } from '~/utilities/utils'; import RegisteredModelsArchiveTable from './RegisteredModelsArchiveTable'; type RegisteredModelsArchiveListViewProps = { @@ -68,7 +69,7 @@ const RegisteredModelsArchiveListView: React.FC { - setSearchType(newSearchType as SearchType); + setSearchType(asEnumMember(newSearchType, SearchType)!); }} icon={} /> diff --git a/frontend/src/pages/modelServing/customServingRuntimes/CustomServingRuntimeAPIProtocolSelector.tsx b/frontend/src/pages/modelServing/customServingRuntimes/CustomServingRuntimeAPIProtocolSelector.tsx index 2b9d485279..b900cca5d0 100644 --- a/frontend/src/pages/modelServing/customServingRuntimes/CustomServingRuntimeAPIProtocolSelector.tsx +++ b/frontend/src/pages/modelServing/customServingRuntimes/CustomServingRuntimeAPIProtocolSelector.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { FormGroup } from '@patternfly/react-core'; import { ServingRuntimeAPIProtocol, ServingRuntimePlatform } from '~/types'; import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import { asEnumMember } from '~/utilities/utils'; type CustomServingRuntimeAPIProtocolSelectorProps = { selectedAPIProtocol: ServingRuntimeAPIProtocol | undefined; @@ -50,7 +51,7 @@ const CustomServingRuntimeAPIProtocolSelector: React.FC< isDisabled={isOnlyModelMesh} options={options} value={selectedAPIProtocol || ''} - onChange={(key) => setSelectedAPIProtocol(key as ServingRuntimeAPIProtocol)} + onChange={(key) => setSelectedAPIProtocol(asEnumMember(key, ServingRuntimeAPIProtocol)!)} /> ); diff --git a/frontend/src/pages/modelServing/customServingRuntimes/utils.ts b/frontend/src/pages/modelServing/customServingRuntimes/utils.ts index 21330644fc..c1878acab0 100644 --- a/frontend/src/pages/modelServing/customServingRuntimes/utils.ts +++ b/frontend/src/pages/modelServing/customServingRuntimes/utils.ts @@ -2,6 +2,7 @@ import { K8sResourceCommon } from '@openshift/dynamic-plugin-sdk-utils'; import { ServingRuntimeKind, TemplateKind } from '~/k8sTypes'; import { getDisplayNameFromK8sResource } from '~/concepts/k8s/utils'; import { ServingRuntimeAPIProtocol, ServingRuntimePlatform } from '~/types'; +import { asEnumMember } from '~/utilities/utils'; export const getTemplateEnabled = ( template: TemplateKind, @@ -142,8 +143,10 @@ export const getAPIProtocolFromTemplate = ( if (!template.metadata.annotations?.['opendatahub.io/apiProtocol']) { return undefined; } - - return template.metadata.annotations['opendatahub.io/apiProtocol'] as ServingRuntimeAPIProtocol; + return asEnumMember( + template.metadata.annotations['opendatahub.io/apiProtocol'], + ServingRuntimeAPIProtocol, + )!; }; export const getAPIProtocolFromServingRuntime = ( @@ -152,5 +155,8 @@ export const getAPIProtocolFromServingRuntime = ( if (!resource.metadata.annotations?.['opendatahub.io/apiProtocol']) { return undefined; } - return resource.metadata.annotations['opendatahub.io/apiProtocol'] as ServingRuntimeAPIProtocol; + return asEnumMember( + resource.metadata.annotations['opendatahub.io/apiProtocol'], + ServingRuntimeAPIProtocol, + )!; }; diff --git a/frontend/src/pages/modelServing/screens/global/utils.ts b/frontend/src/pages/modelServing/screens/global/utils.ts index f4098f7c8c..3d9b87fc2e 100644 --- a/frontend/src/pages/modelServing/screens/global/utils.ts +++ b/frontend/src/pages/modelServing/screens/global/utils.ts @@ -2,6 +2,7 @@ import { InferenceServiceKind, ProjectKind, SecretKind, PodKind } from '~/k8sTyp import { getDisplayNameFromK8sResource } from '~/concepts/k8s/utils'; import { getProjectDisplayName } from '~/concepts/projects/utils'; import { InferenceServiceModelState, ModelStatus } from '~/pages/modelServing/screens/types'; +import { asEnumMember } from '~/utilities/utils'; export const getInferenceServiceDisplayName = (is: InferenceServiceKind): string => getDisplayNameFromK8sResource(is); @@ -11,10 +12,15 @@ export const getTokenDisplayName = (secret: SecretKind): string => export const getInferenceServiceActiveModelState = ( is: InferenceServiceKind, -): InferenceServiceModelState => - is.status?.modelStatus.states.activeModelState || - is.status?.modelStatus.states.targetModelState || - InferenceServiceModelState.UNKNOWN; +): InferenceServiceModelState => { + if (typeof is.status?.modelStatus.states.activeModelState !== 'undefined') { + return asEnumMember(is.status.modelStatus.states.activeModelState, InferenceServiceModelState)!; + } + if (typeof is.status?.modelStatus.states.targetModelState !== 'undefined') { + return asEnumMember(is.status.modelStatus.states.targetModelState, InferenceServiceModelState)!; + } + return InferenceServiceModelState.UNKNOWN; +}; export const getInferenceServiceStatusMessage = (is: InferenceServiceKind): string => { const activeModelState = is.status?.modelStatus.states.activeModelState; diff --git a/frontend/src/pages/modelServing/screens/metrics/EnsureMetricsAvailable.tsx b/frontend/src/pages/modelServing/screens/metrics/EnsureMetricsAvailable.tsx index ce103ca17f..4a122e2101 100644 --- a/frontend/src/pages/modelServing/screens/metrics/EnsureMetricsAvailable.tsx +++ b/frontend/src/pages/modelServing/screens/metrics/EnsureMetricsAvailable.tsx @@ -27,8 +27,9 @@ const EnsureMetricsAvailable: React.FC = ({ let readyCount = 0; metrics.forEach((metric) => { - if (data[metric].error) { - error = data[metric].error as AxiosError; + const axiosError = data[metric].error; + if (axiosError && axiosError instanceof AxiosError) { + error = axiosError; } if (data[metric].loaded) { readyCount++; diff --git a/frontend/src/pages/modelServing/screens/metrics/utils.tsx b/frontend/src/pages/modelServing/screens/metrics/utils.tsx index f82f06e592..328e2d9916 100644 --- a/frontend/src/pages/modelServing/screens/metrics/utils.tsx +++ b/frontend/src/pages/modelServing/screens/metrics/utils.tsx @@ -14,6 +14,7 @@ import { BIAS_THRESHOLD_COLOR, } from '~/pages/modelServing/screens/metrics/const'; import { PROMETHEUS_REQUEST_RESOLUTION } from '~/concepts/metrics/const'; +import { asEnumMember } from '~/utilities/utils'; import { BiasSelectOption, DomainCalculator, @@ -220,7 +221,7 @@ export const checkConfigurationFieldsValid = ( export const isMetricType = ( metricType: string | SelectOptionObject, ): metricType is BiasMetricType => - Object.values(BiasMetricType).includes(metricType as BiasMetricType); + Object.values(BiasMetricType).includes(asEnumMember(metricType.toString(), BiasMetricType)!); export const byId = (arg: U): ((arg: T) => boolean) => diff --git a/frontend/src/pages/notebookController/screens/admin/NotebookControllerTabs.tsx b/frontend/src/pages/notebookController/screens/admin/NotebookControllerTabs.tsx index e85b2193fb..cd66afc1d3 100644 --- a/frontend/src/pages/notebookController/screens/admin/NotebookControllerTabs.tsx +++ b/frontend/src/pages/notebookController/screens/admin/NotebookControllerTabs.tsx @@ -3,6 +3,7 @@ import { Tab, Tabs, TabTitleText } from '@patternfly/react-core'; import { NotebookControllerTabTypes } from '~/pages/notebookController/const'; import NotebookServerRoutes from '~/pages/notebookController/screens/server/NotebookServerRoutes'; import { NotebookControllerContext } from '~/pages/notebookController/NotebookControllerContext'; +import { asEnumMember } from '~/utilities/utils'; import NotebookAdmin from './NotebookAdmin'; const NotebookControllerTabs: React.FC = () => { @@ -16,7 +17,7 @@ const NotebookControllerTabs: React.FC = () => { unmountOnExit onSelect={(e, eventKey) => { setImpersonating(); - setCurrentAdminTab(eventKey as NotebookControllerTabTypes); + setCurrentAdminTab(asEnumMember(eventKey, NotebookControllerTabTypes)!); }} > = ({ type={ showPassword && variableType === 'password' ? TextInputTypes.text - : (variable.type as TextInputTypes) + : asEnumMember(variable.type, TextInputTypes)! } value={variable.value} onChange={(e, newValue) => diff --git a/frontend/src/pages/notebookController/screens/server/EnvironmentVariablesRow.tsx b/frontend/src/pages/notebookController/screens/server/EnvironmentVariablesRow.tsx index 84a99a7aca..4b3192712e 100644 --- a/frontend/src/pages/notebookController/screens/server/EnvironmentVariablesRow.tsx +++ b/frontend/src/pages/notebookController/screens/server/EnvironmentVariablesRow.tsx @@ -82,7 +82,9 @@ const EnvironmentVariablesRow: React.FC = ({ onToggle={() => setTypeDropdownOpen(!typeDropdownOpen)} aria-labelledby="container-size" selections={variableRow.variableType} - onSelect={(e, selection) => updateVariableType(selection as string)} + onSelect={(e, selection) => { + updateVariableType(selection.toString()); + }} > {selectOptions} diff --git a/frontend/src/pages/pipelines/global/experiments/executions/details/ExecutionDetails.tsx b/frontend/src/pages/pipelines/global/experiments/executions/details/ExecutionDetails.tsx index 8937264044..e53f60ed86 100644 --- a/frontend/src/pages/pipelines/global/experiments/executions/details/ExecutionDetails.tsx +++ b/frontend/src/pages/pipelines/global/experiments/executions/details/ExecutionDetails.tsx @@ -46,10 +46,10 @@ const ExecutionDetails: PipelineCoreDetailsPageComponent = ({ breadcrumbPath, co const [artifactTypes, artifactTypesLoaded] = useGetArtifactTypes(); const allEvents = parseEventsByType(eventsResponse); - const artifactTypeMap = artifactTypes.reduce((acc, artifactType) => { + const artifactTypeMap = artifactTypes.reduce>((acc, artifactType) => { acc[artifactType.getId()] = artifactType.getName(); return acc; - }, {} as Record); + }, {}); const error = executionError || eventsError; diff --git a/frontend/src/pages/pipelines/global/runs/GlobalPipelineRunsTabs.tsx b/frontend/src/pages/pipelines/global/runs/GlobalPipelineRunsTabs.tsx index a2e2e6a45e..00189563d5 100644 --- a/frontend/src/pages/pipelines/global/runs/GlobalPipelineRunsTabs.tsx +++ b/frontend/src/pages/pipelines/global/runs/GlobalPipelineRunsTabs.tsx @@ -30,7 +30,9 @@ const GlobalPipelineRunsTab: React.FC = () => { return ( setSearchParams({ runType: tabId as PipelineRunType })} + onSelect={(_event, tabId) => { + setSearchParams({ runType: asEnumMember(tabId, PipelineRunType)! }); + }} aria-label="Pipeline run page tabs" role="region" className="odh-pipeline-runs-page-tabs" diff --git a/frontend/src/pages/projects/ProjectDetailsContext.tsx b/frontend/src/pages/projects/ProjectDetailsContext.tsx index f7e64820a5..b9873e7b8d 100644 --- a/frontend/src/pages/projects/ProjectDetailsContext.tsx +++ b/frontend/src/pages/projects/ProjectDetailsContext.tsx @@ -54,6 +54,7 @@ type ProjectDetailsContextType = { export const ProjectDetailsContext = React.createContext({ // We never will get into a case without a project, so fudge the default value + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions currentProject: null as unknown as ProjectKind, refreshAllProjectData: () => undefined, filterTokens: () => [], diff --git a/frontend/src/pages/projects/screens/detail/overview/serverModels/deployedModels/DeployedModelsSection.tsx b/frontend/src/pages/projects/screens/detail/overview/serverModels/deployedModels/DeployedModelsSection.tsx index 6a2b420559..0561d4d81e 100644 --- a/frontend/src/pages/projects/screens/detail/overview/serverModels/deployedModels/DeployedModelsSection.tsx +++ b/frontend/src/pages/projects/screens/detail/overview/serverModels/deployedModels/DeployedModelsSection.tsx @@ -58,11 +58,14 @@ const DeployedModelsSection: React.FC = ({ isMultiPl return; } if (isMultiPlatform) { - const modelInferenceServices = modelServers.reduce((acc, modelServer) => { - const services = getInferenceServiceFromServingRuntime(inferenceServices, modelServer); - acc.push(...services); - return acc; - }, [] as InferenceServiceKind[]); + const modelInferenceServices = modelServers.reduce( + (acc, modelServer) => { + const services = getInferenceServiceFromServingRuntime(inferenceServices, modelServer); + acc.push(...services); + return acc; + }, + [], + ); setDeployedModels(modelInferenceServices); } else { setDeployedModels(inferenceServices); diff --git a/frontend/src/pages/projects/screens/spawner/environmentVariables/EnvConfigMap.tsx b/frontend/src/pages/projects/screens/spawner/environmentVariables/EnvConfigMap.tsx index 087af37f9d..e947810c87 100644 --- a/frontend/src/pages/projects/screens/spawner/environmentVariables/EnvConfigMap.tsx +++ b/frontend/src/pages/projects/screens/spawner/environmentVariables/EnvConfigMap.tsx @@ -4,6 +4,7 @@ import { EnvironmentVariableType, EnvVariableData, } from '~/pages/projects/types'; +import { asEnumMember } from '~/utilities/utils'; import EnvDataTypeField from './EnvDataTypeField'; import GenericKeyValuePairField from './GenericKeyValuePairField'; import { EMPTY_KEY_VALUE_PAIR } from './const'; @@ -22,7 +23,9 @@ const DEFAULT_ENV: EnvVariableData = { const EnvConfigMap: React.FC = ({ env = DEFAULT_ENV, onUpdate }) => ( onUpdate({ ...env, category: value as ConfigMapCategory, data: [] })} + onSelection={(value) => + onUpdate({ ...env, category: asEnumMember(value, ConfigMapCategory)!, data: [] }) + } options={{ [ConfigMapCategory.GENERIC]: { label: 'Key / value', diff --git a/frontend/src/pages/projects/screens/spawner/environmentVariables/EnvSecret.tsx b/frontend/src/pages/projects/screens/spawner/environmentVariables/EnvSecret.tsx index b5abf71d37..aab8fe07c0 100644 --- a/frontend/src/pages/projects/screens/spawner/environmentVariables/EnvSecret.tsx +++ b/frontend/src/pages/projects/screens/spawner/environmentVariables/EnvSecret.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { EnvironmentVariableType, EnvVariableData, SecretCategory } from '~/pages/projects/types'; +import { asEnumMember } from '~/utilities/utils'; import EnvDataTypeField from './EnvDataTypeField'; import GenericKeyValuePairField from './GenericKeyValuePairField'; import { EMPTY_KEY_VALUE_PAIR } from './const'; @@ -18,7 +19,9 @@ const DEFAULT_ENV: EnvVariableData = { const EnvSecret: React.FC = ({ env = DEFAULT_ENV, onUpdate }) => ( onUpdate({ ...env, category: value as SecretCategory, data: [] })} + onSelection={(value) => + onUpdate({ ...env, category: asEnumMember(value, SecretCategory), data: [] }) + } options={{ [SecretCategory.GENERIC]: { label: 'Key / value', diff --git a/frontend/src/pages/projects/screens/spawner/environmentVariables/EnvTypeSelectField.tsx b/frontend/src/pages/projects/screens/spawner/environmentVariables/EnvTypeSelectField.tsx index 259f796cb3..7da1b371f9 100644 --- a/frontend/src/pages/projects/screens/spawner/environmentVariables/EnvTypeSelectField.tsx +++ b/frontend/src/pages/projects/screens/spawner/environmentVariables/EnvTypeSelectField.tsx @@ -4,6 +4,7 @@ import { Select, SelectOption } from '@patternfly/react-core/deprecated'; import { MinusCircleIcon } from '@patternfly/react-icons'; import { EnvironmentVariableType, EnvVariable } from '~/pages/projects/types'; import IndentSection from '~/pages/projects/components/IndentSection'; +import { asEnumMember } from '~/utilities/utils'; import EnvTypeSwitch from './EnvTypeSwitch'; type EnvTypeSelectFieldProps = { @@ -33,7 +34,7 @@ const EnvTypeSelectField: React.FC = ({ onSelect={(e, value) => { if (typeof value === 'string') { onUpdate({ - type: value as EnvironmentVariableType, + type: asEnumMember(value, EnvironmentVariableType)!, }); setOpen(false); } diff --git a/frontend/src/pages/projects/screens/spawner/environmentVariables/utils.ts b/frontend/src/pages/projects/screens/spawner/environmentVariables/utils.ts index d49b49aae5..e73f077feb 100644 --- a/frontend/src/pages/projects/screens/spawner/environmentVariables/utils.ts +++ b/frontend/src/pages/projects/screens/spawner/environmentVariables/utils.ts @@ -7,12 +7,14 @@ export const removeArrayItem = (values: T[], index: number): T[] => values.filter((v, i) => i !== index); export const isConfigMapKind = (object: unknown): object is ConfigMapKind => - (object as ConfigMapKind).kind === 'ConfigMap'; + typeof object === 'object' && object !== null && 'kind' in object && object.kind === 'ConfigMap'; export const isSecretKind = (object: unknown): object is SecretKind => - (object as SecretKind).kind === 'Secret'; + typeof object === 'object' && object !== null && 'kind' in object && object.kind === 'Secret'; export const isStringKeyValuePairObject = (object: unknown): object is Record => - Object.entries(object as Record).every( + typeof object === 'object' && + object !== null && + Object.entries(object).every( ([key, value]) => typeof key === 'string' && typeof value === 'string', ); diff --git a/frontend/src/pages/projects/screens/spawner/spawnerUtils.ts b/frontend/src/pages/projects/screens/spawner/spawnerUtils.ts index 54bbf8397f..b68507988d 100644 --- a/frontend/src/pages/projects/screens/spawner/spawnerUtils.ts +++ b/frontend/src/pages/projects/screens/spawner/spawnerUtils.ts @@ -81,7 +81,10 @@ export const getImageVersionSelectOptionObject = ( export const isImageVersionSelectOptionObject = ( object: unknown, ): object is ImageVersionSelectOptionObjectType => - (object as ImageVersionSelectOptionObjectType | undefined)?.imageVersion !== undefined; + typeof object === 'object' && + object !== null && + 'imageVersion' in object && + object.imageVersion !== undefined; /******************* Compare utils for sorting *******************/ const getBuildNumber = (build: BuildKind): number => { const buildNumber = build.metadata.annotations?.['openshift.io/build.number'] || '-1'; diff --git a/frontend/src/pages/projects/screens/spawner/useBuildStatuses.ts b/frontend/src/pages/projects/screens/spawner/useBuildStatuses.ts index 4c2c3987f3..0e08b4e05f 100644 --- a/frontend/src/pages/projects/screens/spawner/useBuildStatuses.ts +++ b/frontend/src/pages/projects/screens/spawner/useBuildStatuses.ts @@ -1,7 +1,7 @@ import * as React from 'react'; import { getNotebookBuildConfigs, getBuildsForBuildConfig } from '~/api'; import useNotification from '~/utilities/useNotification'; -import { BuildConfigKind, BuildKind, BuildPhase } from '~/k8sTypes'; +import { BuildConfigKind, BuildPhase } from '~/k8sTypes'; import { BuildStatus } from './types'; import { compareBuilds } from './spawnerUtils'; @@ -26,7 +26,7 @@ const useBuildStatuses = (namespace?: string): BuildStatus[] => { imageStreamVersion: buildConfig.spec.output.to.name, }; } - const mostRecent = builds.toSorted(compareBuilds).pop() as BuildKind; + const mostRecent = builds.toSorted(compareBuilds)[builds.length - 1]; return { name: buildNotebookName, status: mostRecent.status.phase, diff --git a/frontend/src/redux/context.ts b/frontend/src/redux/context.ts index 82105b8f35..e93bf2751a 100644 --- a/frontend/src/redux/context.ts +++ b/frontend/src/redux/context.ts @@ -2,5 +2,6 @@ import * as React from 'react'; import { ReactReduxContextValue } from 'react-redux'; export const ReduxContext = React.createContext( + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions {} as ReactReduxContextValue, ); diff --git a/frontend/src/redux/store/store.ts b/frontend/src/redux/store/store.ts index 5eb7522efd..aa01b385ce 100644 --- a/frontend/src/redux/store/store.ts +++ b/frontend/src/redux/store/store.ts @@ -5,7 +5,7 @@ import appReducer from '~/redux/reducers/appReducer'; import { ODH_PRODUCT_NAME } from '~/utilities/const'; const composeEnhancers = - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/consistent-type-assertions (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?.({ name: ODH_PRODUCT_NAME, }) || compose; @@ -16,7 +16,7 @@ export const store = configureStore(); // Create a separate for the for the dynamic plugin SDK const sdkComposeEnhancers = - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/consistent-type-assertions (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?.({ name: `${ODH_PRODUCT_NAME} - Dynamic Plugin SDK`, }) || compose; diff --git a/frontend/src/utilities/useAcceleratorProfileState.ts b/frontend/src/utilities/useAcceleratorProfileState.ts index f777fc594b..2ac77eaaf2 100644 --- a/frontend/src/utilities/useAcceleratorProfileState.ts +++ b/frontend/src/utilities/useAcceleratorProfileState.ts @@ -10,7 +10,7 @@ import { TolerationOperator, } from '~/types'; import useGenericObjectState, { GenericObjectState } from '~/utilities/useGenericObjectState'; -import { getAcceleratorProfileCount } from '~/utilities/utils'; +import { getAcceleratorProfileCount, isEnumMember } from '~/utilities/utils'; export type AcceleratorProfileState = { acceleratorProfile?: AcceleratorProfileKind; @@ -65,9 +65,9 @@ const useAcceleratorProfileState = ( } else { // check if there is accelerator usage in the container // this is to handle the case where the accelerator is disabled, deleted, or empty - const containerResourceAttributes = Object.values(ContainerResourceAttributes) as string[]; + const containerResourceAttributes = Object.values(ContainerResourceAttributes); const possibleAcceleratorRequests = Object.entries(resources.requests ?? {}) - .filter(([key]) => !containerResourceAttributes.includes(key)) + .filter(([key]) => !isEnumMember(key, containerResourceAttributes)) .map(([key, value]) => ({ identifier: key, count: value })); if (possibleAcceleratorRequests.length > 0) { // check if they are just using the nvidia.com/gpu diff --git a/frontend/src/utilities/useDraggableTable.ts b/frontend/src/utilities/useDraggableTable.ts index 6fa8540dcb..06a376fe31 100644 --- a/frontend/src/utilities/useDraggableTable.ts +++ b/frontend/src/utilities/useDraggableTable.ts @@ -125,7 +125,7 @@ const useDraggableTable = ( return; } - const curListItem = (evt.target as HTMLTableSectionElement).closest('tr'); + const curListItem = evt.target instanceof HTMLElement ? evt.target.closest('tr') : null; if ( !curListItem || !bodyRef.current.contains(curListItem) || diff --git a/frontend/src/utilities/useWatchNotebooksForUsers.tsx b/frontend/src/utilities/useWatchNotebooksForUsers.tsx index 13a09e4f75..9451a16d0c 100644 --- a/frontend/src/utilities/useWatchNotebooksForUsers.tsx +++ b/frontend/src/utilities/useWatchNotebooksForUsers.tsx @@ -54,10 +54,13 @@ const useWatchNotebooksForUsers = ( setLoadError(undefined); } - const newNotebooks = successes.reduce((acc, { value }) => { - acc[value.name] = value.data; - return acc; - }, {} as UsernameMap); + const newNotebooks = successes.reduce>( + (acc, { value }) => { + acc[value.name] = value.data; + return acc; + }, + {}, + ); setNotebooks((prevState) => ({ ...prevState, ...newNotebooks })); setLoaded(true); }) diff --git a/frontend/src/utilities/utils.ts b/frontend/src/utilities/utils.ts index 2b7def86e2..80f46e0b91 100644 --- a/frontend/src/utilities/utils.ts +++ b/frontend/src/utilities/utils.ts @@ -140,7 +140,10 @@ export const getDashboardMainContainer = (): HTMLElement => document.getElementById(DASHBOARD_MAIN_CONTAINER_ID) || document.body; export const isHTMLInputElement = (object: unknown): object is HTMLInputElement => - (object as Partial).value !== undefined; + object instanceof HTMLInputElement; + +export const isHTMLTableSectionElement = (object: unknown): object is HTMLTableSectionElement => + object instanceof HTMLTableSectionElement; export const normalizeBetween = (value: number, min?: number, max?: number): number => { let returnedValue = value;