From e8e50f226164bfa0d5cde900c9194a781609e2c7 Mon Sep 17 00:00:00 2001 From: Andy Pickering Date: Tue, 26 May 2026 15:01:30 +0900 Subject: [PATCH] Enable TypeScript noImplicitAny option & fix types as necessary --- package-lock.json | 22 ++++++++++++++++++++++ package.json | 3 +++ src/components/AttachLogModal.tsx | 10 ++++++---- src/components/AttachmentModal.tsx | 6 +++--- src/components/AttachmentsSizeAlert.tsx | 5 ++++- src/components/Prompt.tsx | 22 +++++++++++++--------- src/hooks/usePopover.ts | 4 ++-- src/redux-reducers.ts | 4 ++-- src/validation.ts | 2 +- tsconfig.json | 1 - 10 files changed, 56 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 57213ca8..4df7bfbb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,8 @@ "@patternfly/react-code-editor": "6.4.3", "@patternfly/react-core": "6.4.3", "@patternfly/react-icons": "6.4.0", + "@types/js-yaml": "4.0.9", + "@types/murmurhash-js": "1.0.7", "copy-webpack-plugin": "14.0.0", "css-loader": "^7.1.4", "dompurify": "3.4.2", @@ -37,6 +39,7 @@ }, "devDependencies": { "@cypress/grep": "6.0.0", + "@types/lodash": "4.17.24", "@types/node": "^22.19.17", "@types/react": "^18.3.27", "@typescript-eslint/eslint-plugin": "^8.58.1", @@ -2213,12 +2216,25 @@ "@types/node": "*" } }, + "node_modules/@types/js-yaml": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", + "license": "MIT" + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "license": "MIT" }, + "node_modules/@types/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -2246,6 +2262,12 @@ "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "license": "MIT" }, + "node_modules/@types/murmurhash-js": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/murmurhash-js/-/murmurhash-js-1.0.7.tgz", + "integrity": "sha512-XM6078Du3jaEJVwpxmPZsJQDMzWabjY4ILQQvW4VPBzTULd+Fjs2Z54s+OrLzDRxgs6J09YyDISnZDlltYAchw==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.19.17", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz", diff --git a/package.json b/package.json index 966cf59d..ad1463d5 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,9 @@ "@patternfly/react-code-editor": "6.4.3", "@patternfly/react-core": "6.4.3", "@patternfly/react-icons": "6.4.0", + "@types/js-yaml": "4.0.9", + "@types/lodash": "4.17.24", + "@types/murmurhash-js": "1.0.7", "copy-webpack-plugin": "14.0.0", "css-loader": "^7.1.4", "dompurify": "3.4.2", diff --git a/src/components/AttachLogModal.tsx b/src/components/AttachLogModal.tsx index 904a0f4c..2548c6d3 100644 --- a/src/components/AttachLogModal.tsx +++ b/src/components/AttachLogModal.tsx @@ -5,6 +5,7 @@ import { useDispatch } from 'react-redux'; import { consoleFetchText, K8sResourceKind, + Selector, useK8sWatchResource, } from '@openshift-console/dynamic-plugin-sdk'; import { @@ -259,9 +260,9 @@ const AttachLogModal: React.FC = ({ isOpen, onClose, resour isCronJob ? { isList: true, kind: 'Job', namespace } : null, ); - let selector; + let selector: Selector | undefined; if (kind === 'Job') { - selector = { 'job-name': name }; + selector = { matchLabels: { 'job-name': name } }; } else if (isCronJob) { const ownedJobNames = (jobs || []) .filter((job) => @@ -283,7 +284,7 @@ const AttachLogModal: React.FC = ({ isOpen, onClose, resour selector = undefined; } } else if (kind === 'VirtualMachine' || kind === 'VirtualMachineInstance') { - selector = { 'vm.kubevirt.io/name': name }; + selector = { matchLabels: { 'vm.kubevirt.io/name': name } }; } else if (scaleTarget && scaleTargetLoaded && !scaleTargetError) { selector = scaleTarget.spec?.selector; } else { @@ -299,7 +300,8 @@ const AttachLogModal: React.FC = ({ isOpen, onClose, resour const changePod = (newPod: K8sResourceKind) => { if (newPod) { setPod(newPod); - const newContainers = newPod.spec?.containers?.map((c) => c.name).sort() ?? []; + const newContainers = + newPod.spec?.containers?.map((c: { name: string }) => c.name).sort() ?? []; setContainers(newContainers); setContainer(newContainers[0]); } diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index b7f18a4b..42b6ecbd 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; -import { CodeEditor, Language } from '@patternfly/react-code-editor'; +import { CodeEditor, EditorDidMount, Language } from '@patternfly/react-code-editor'; import { ActionGroup, Button, @@ -50,10 +50,10 @@ type EditorProps = { const Editor: React.FC = ({ onChange }) => { const attachment: Attachment = useSelector((s: State) => s.plugins?.ols?.get('openAttachment')); - const onEditorDidMount = (_editor, monaco) => { + const onEditorDidMount: EditorDidMount = (_editor, monaco) => { // Work around crash when CodeEditor attempts to call this nonexistent function // TODO: Figure out why this is happening - monaco.editor.onDidChangeMarkers = () => {}; + (monaco.editor as { onDidChangeMarkers: () => void }).onDidChangeMarkers = () => {}; }; const [isDarkTheme] = useIsDarkTheme(); diff --git a/src/components/AttachmentsSizeAlert.tsx b/src/components/AttachmentsSizeAlert.tsx index 5c793991..d1a43d95 100644 --- a/src/components/AttachmentsSizeAlert.tsx +++ b/src/components/AttachmentsSizeAlert.tsx @@ -4,6 +4,7 @@ import { useSelector } from 'react-redux'; import { Alert } from '@patternfly/react-core'; import { State } from '../redux-reducers'; +import { Attachment } from '../types'; const MAX_CHARS = 1000000; @@ -12,7 +13,9 @@ const AttachmentsSizeAlert: React.FC = () => { const attachments = useSelector((s: State) => s.plugins?.ols?.get('attachments')); - const totalChars = attachments.valueSeq().reduce((sum, a) => sum + a.value.length, 0); + const totalChars = attachments + .valueSeq() + .reduce((sum: number, a: Attachment) => sum + a.value.length, 0); if (totalChars <= MAX_CHARS) { return null; diff --git a/src/components/Prompt.tsx b/src/components/Prompt.tsx index 7f6b0fba..45629c20 100644 --- a/src/components/Prompt.tsx +++ b/src/components/Prompt.tsx @@ -8,6 +8,10 @@ import { consoleFetch, consoleFetchJSON, K8sResourceKind, + PrometheusAlert, + PrometheusRule, + PrometheusRulesResponse, + Silence, useK8sWatchResource, } from '@openshift-console/dynamic-plugin-sdk'; import { MessageBar } from '@patternfly/chatbot'; @@ -184,8 +188,8 @@ const Prompt: React.FC = ({ scrollIntoView }) => { reader.onload = (event) => { try { const yaml = event.target?.result as string; - const content = loadYAML(yaml); - if (typeof content !== 'object') { + const content = loadYAML(yaml) as K8sResourceKind | null; + if (typeof content !== 'object' || content === null) { setError(t('Uploaded file is not valid YAML')); return; } @@ -230,8 +234,8 @@ const Prompt: React.FC = ({ scrollIntoView }) => { const labels = Object.fromEntries(new URLSearchParams(location.search)); const alertsEndpoint = labels.cluster ? ALERTS_THANOS_ENDPOINT : ALERTS_ENDPOINT; consoleFetchJSON(alertsEndpoint, 'get', getRequestInitWithAuthHeader()) - .then((response) => { - let alert; + .then((response: PrometheusRulesResponse) => { + let alert: PrometheusAlert | undefined; each(response?.data?.groups, (group) => { each(group.rules, (rule) => { alert = rule.alerts?.find((a) => isMatch(labels, a.labels)); @@ -280,7 +284,7 @@ const Prompt: React.FC = ({ scrollIntoView }) => { } else if (kind === 'Silence') { setLoading(); consoleFetchJSON(`${SILENCE_ENDPOINT}/${name}`, 'get', getRequestInitWithAuthHeader()) - .then((silence) => { + .then((silence: Silence) => { try { const silenceName = silence.matchers @@ -307,8 +311,8 @@ const Prompt: React.FC = ({ scrollIntoView }) => { const ruleLabels = Object.fromEntries(new URLSearchParams(location.search)); const rulesEndpoint = ruleLabels.cluster ? ALERTS_THANOS_ENDPOINT : ALERTS_ENDPOINT; consoleFetchJSON(rulesEndpoint, 'get', getRequestInitWithAuthHeader()) - .then((response) => { - let matchedRule; + .then((response: PrometheusRulesResponse) => { + let matchedRule: PrometheusRule | undefined; each(response?.data?.groups, (group) => { const found = group.rules?.find( (rule) => rule.type === 'alerting' && alertingRuleID(group, rule) === name, @@ -594,7 +598,7 @@ const Prompt: React.FC = ({ scrollIntoView }) => { dispatch( chatHistoryPush({ - attachments: attachments.map((a) => omit(a, 'originalValue')), + attachments: attachments.map((a: Attachment) => omit(a, 'originalValue')), hidden: hidePrompt, text: query, who: 'user', @@ -924,7 +928,7 @@ const Prompt: React.FC = ({ scrollIntoView }) => { hasStopButton={isStreaming} innerRef={textareaRef} isSendButtonDisabled={!query || query.trim().length === 0} - onChange={(e) => onChange(e, e.target.value)} + onChange={(e: React.ChangeEvent) => onChange(e, e.target.value)} onSendMessage={onSubmit} placeholder={ isTroubleshooting diff --git a/src/hooks/usePopover.ts b/src/hooks/usePopover.ts index 0d455ea6..316bcd4d 100644 --- a/src/hooks/usePopover.ts +++ b/src/hooks/usePopover.ts @@ -6,7 +6,7 @@ import Popover from '../components/Popover'; const POPOVER_ID = 'plugin__lightspeed-console-plugin__POPOVER_ID'; -const usePopover = () => { +const usePopover = (): null => { const [isLaunched, , setLaunched] = useBoolean(false); const launchModal = useModal(); @@ -18,7 +18,7 @@ const usePopover = () => { } }, [isLaunched, launchModal, setLaunched]); - return []; + return null; }; export default usePopover; diff --git a/src/redux-reducers.ts b/src/redux-reducers.ts index b2709d5a..2c8966e2 100644 --- a/src/redux-reducers.ts +++ b/src/redux-reducers.ts @@ -77,14 +77,14 @@ const reducer = (state: OLSState, action: OLSAction): OLSState => { case ActionType.ChatHistoryUpdateByID: { const index = state .get('chatHistory') - .findIndex((entry) => entry.get('id') === action.payload.id); + .findIndex((entry: ImmutableMap) => entry.get('id') === action.payload.id); return state.mergeIn(['chatHistory', index], action.payload.entry); } case ActionType.ChatHistoryUpdateTool: { const index = state .get('chatHistory') - .findIndex((entry) => entry.get('id') === action.payload.id); + .findIndex((entry: ImmutableMap) => entry.get('id') === action.payload.id); return state.mergeIn( ['chatHistory', index, 'tools', action.payload.toolID], action.payload.tool, diff --git a/src/validation.ts b/src/validation.ts index f1051ac3..1fac82af 100644 --- a/src/validation.ts +++ b/src/validation.ts @@ -14,7 +14,7 @@ export const alertingRuleID = ( rule.query, ..._map(rule.labels, (v, k) => `${v}=${k}`), ].join(','); - return String(murmur3(key, 'monitoring-salt')); + return String(murmur3(key)); }; export const isValidAlertName = (value: string | null | undefined): boolean => diff --git a/tsconfig.json b/tsconfig.json index 6e06a1d1..478a194b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,6 @@ "jsx": "react-jsx", "allowJs": true, "strict": true, - "noImplicitAny": false, "strictNullChecks": false, "noUnusedLocals": true, "sourceMap": false,