diff --git a/client/common/Button.tsx b/client/common/Button.tsx index d52abf3140..bde6106b00 100644 --- a/client/common/Button.tsx +++ b/client/common/Button.tsx @@ -80,7 +80,7 @@ export interface ButtonProps extends React.HTMLAttributes { /** * If using a native button, specifies on an onClick action */ - onClick?: () => void; + onClick?: (evt: React.MouseEvent) => void; /** * If using a button, then type is defines the type of button */ diff --git a/client/common/useSyncFormTranslations.ts b/client/common/useSyncFormTranslations.ts index 4a90362750..3212117399 100644 --- a/client/common/useSyncFormTranslations.ts +++ b/client/common/useSyncFormTranslations.ts @@ -1,30 +1,30 @@ import { useEffect, MutableRefObject } from 'react'; +import type { FormApi } from 'final-form'; -export interface FormLike { - getState(): { values: Record }; - reset(): void; - change(field: string, value: unknown): void; -} +// Generic FormLike that mirrors FormApi for any form value type +export interface FormLike> + extends Pick, 'getState' | 'reset' | 'change'> {} /** * This hook ensures that form values are preserved when the language changes. * @param formRef * @param language */ -export const useSyncFormTranslations = ( - formRef: MutableRefObject, +export const useSyncFormTranslations = >( + formRef: MutableRefObject | null>, language: string ) => { useEffect(() => { - const form = formRef.current; + const form = formRef?.current; if (!form) return; const { values } = form.getState(); form.reset(); - Object.keys(values).forEach((field) => { - if (values[field]) { - form.change(field, values[field]); + (Object.keys(values) as (keyof FormValues)[]).forEach((field) => { + const value = values[field]; + if (value !== undefined && value !== null && value !== '') { + form.change(field, value); } }); }, [language]); diff --git a/client/modules/App/App.jsx b/client/modules/App/App.jsx index 53b0c82c63..242b5244c8 100644 --- a/client/modules/App/App.jsx +++ b/client/modules/App/App.jsx @@ -6,7 +6,7 @@ import { showReduxDevTools } from '../../store'; import DevTools from './components/DevTools'; import { setPreviousPath } from '../IDE/actions/ide'; import { setLanguage } from '../IDE/actions/preferences'; -import CookieConsent from '../User/components/CookieConsent'; +import { CookieConsent } from '../User/components/CookieConsent'; function hideCookieConsent(pathname) { if (pathname.includes('/full/') || pathname.includes('/embed/')) { diff --git a/client/modules/IDE/components/Header/Toolbar.jsx b/client/modules/IDE/components/Header/Toolbar.jsx index fbf0b5d091..16ed74ff3e 100644 --- a/client/modules/IDE/components/Header/Toolbar.jsx +++ b/client/modules/IDE/components/Header/Toolbar.jsx @@ -20,7 +20,7 @@ import StopIcon from '../../../../images/stop.svg'; import PreferencesIcon from '../../../../images/preferences.svg'; import ProjectName from './ProjectName'; import VersionIndicator from '../VersionIndicator'; -import VisibilityDropdown from '../../../User/components/VisibilityDropdown'; +import { VisibilityDropdown } from '../../../User/components/VisibilityDropdown'; import { changeVisibility } from '../../actions/project'; const Toolbar = (props) => { diff --git a/client/modules/IDE/components/SketchListRowBase.jsx b/client/modules/IDE/components/SketchListRowBase.jsx index e1c4c80f13..d11cb8bf40 100644 --- a/client/modules/IDE/components/SketchListRowBase.jsx +++ b/client/modules/IDE/components/SketchListRowBase.jsx @@ -10,7 +10,7 @@ import { TableDropdown } from '../../../components/Dropdown/TableDropdown'; import { MenuItem } from '../../../components/Dropdown/MenuItem'; import { formatDateToString } from '../../../utils/formatDate'; import { getConfig } from '../../../utils/getConfig'; -import VisibilityDropdown from '../../User/components/VisibilityDropdown'; +import { VisibilityDropdown } from '../../User/components/VisibilityDropdown'; const ROOT_URL = getConfig('API_URL'); diff --git a/client/modules/User/components/APIKeyForm.jsx b/client/modules/User/components/APIKeyForm.tsx similarity index 83% rename from client/modules/User/components/APIKeyForm.jsx rename to client/modules/User/components/APIKeyForm.tsx index fda5945f87..cd77994f06 100644 --- a/client/modules/User/components/APIKeyForm.jsx +++ b/client/modules/User/components/APIKeyForm.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; @@ -6,31 +5,24 @@ import { Button, ButtonTypes } from '../../../common/Button'; import { PlusIcon } from '../../../common/icons'; import CopyableInput from '../../IDE/components/CopyableInput'; import { createApiKey, removeApiKey } from '../actions'; +import { APIKeyList } from './APIKeyList'; +import { RootState } from '../../../reducers'; +import { SanitisedApiKey } from '../../../../common/types'; -import APIKeyList from './APIKeyList'; - -export const APIKeyPropType = PropTypes.shape({ - id: PropTypes.string.isRequired, - token: PropTypes.string, - label: PropTypes.string.isRequired, - createdAt: PropTypes.string.isRequired, - lastUsedAt: PropTypes.string -}); - -const APIKeyForm = () => { +export const APIKeyForm = () => { const { t } = useTranslation(); - const apiKeys = useSelector((state) => state.user.apiKeys); + const apiKeys = useSelector((state: RootState) => state.user.apiKeys) ?? []; const dispatch = useDispatch(); const [keyLabel, setKeyLabel] = useState(''); - const addKey = (event) => { + const addKey = (event: React.FormEvent) => { event.preventDefault(); dispatch(createApiKey(keyLabel)); setKeyLabel(''); }; - const removeKey = (key) => { + const removeKey = (key: SanitisedApiKey) => { const message = t('APIKeyForm.ConfirmDelete', { key_label: key.label }); @@ -77,7 +69,7 @@ const APIKeyForm = () => {