diff --git a/invokeai/frontend/web/.storybook/ReduxInit.tsx b/invokeai/frontend/web/.storybook/ReduxInit.tsx index 5359e5868d..b4989c7556 100644 --- a/invokeai/frontend/web/.storybook/ReduxInit.tsx +++ b/invokeai/frontend/web/.storybook/ReduxInit.tsx @@ -1,21 +1,23 @@ -import { PropsWithChildren, memo, useEffect } from 'react'; -import { modelChanged } from '../src/features/controlLayers/store/paramsSlice'; -import { useAppDispatch } from '../src/app/store/storeHooks'; import { useGlobalModifiersInit } from '@invoke-ai/ui-library'; +import type { PropsWithChildren } from 'react'; +import { memo, useEffect } from 'react'; + +import { useAppDispatch } from '../src/app/store/storeHooks'; +import { modelChanged } from '../src/features/controlLayers/store/paramsSlice'; /** * Initializes some state for storybook. Must be in a different component * so that it is run inside the redux context. */ -export const ReduxInit = memo((props: PropsWithChildren) => { +export const ReduxInit = memo(({ children }: PropsWithChildren) => { const dispatch = useAppDispatch(); useGlobalModifiersInit(); useEffect(() => { dispatch( modelChanged({ model: { key: 'test_model', hash: 'some_hash', name: 'some name', base: 'sd-1', type: 'main' } }) ); - }, []); + }, [dispatch]); - return props.children; + return children; }); ReduxInit.displayName = 'ReduxInit'; diff --git a/invokeai/frontend/web/.storybook/preview.tsx b/invokeai/frontend/web/.storybook/preview.tsx index 8b21b48230..900c547d9c 100644 --- a/invokeai/frontend/web/.storybook/preview.tsx +++ b/invokeai/frontend/web/.storybook/preview.tsx @@ -1,17 +1,18 @@ -import { Preview } from '@storybook/react'; +import type { Preview } from '@storybook/react'; import { themes } from '@storybook/theming'; +import { $store } from 'app/store/nanostores/store'; import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import { Provider } from 'react-redux'; -import ThemeLocaleProvider from '../src/app/components/ThemeLocaleProvider'; -import { $baseUrl } from '../src/app/store/nanostores/baseUrl'; -import { createStore } from '../src/app/store/store'; + // TODO: Disabled for IDE performance issues with our translation JSON // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import translationEN from '../public/locales/en.json'; +import ThemeLocaleProvider from '../src/app/components/ThemeLocaleProvider'; +import { $baseUrl } from '../src/app/store/nanostores/baseUrl'; +import { createStore } from '../src/app/store/store'; import { ReduxInit } from './ReduxInit'; -import { $store } from 'app/store/nanostores/store'; i18n.use(initReactI18next).init({ lng: 'en', diff --git a/invokeai/frontend/web/eslint.config.mjs b/invokeai/frontend/web/eslint.config.mjs index f177c17b21..6449cfb627 100644 --- a/invokeai/frontend/web/eslint.config.mjs +++ b/invokeai/frontend/web/eslint.config.mjs @@ -17,8 +17,6 @@ export default [ { languageOptions: { - ecmaVersion: 'latest', - sourceType: 'module', parser: typescriptParser, parserOptions: { ecmaFeatures: { @@ -27,8 +25,9 @@ export default [ }, globals: { ...globals.browser, - ...globals.es2021, ...globals.node, + GlobalCompositeOperation: 'readonly', + RequestInit: 'readonly', }, }, @@ -41,7 +40,7 @@ export default [ import: pluginImport, 'unused-imports': pluginUnusedImports, 'simple-import-sort': pluginSimpleImportSort, - 'react-refresh': pluginReactRefresh, + 'react-refresh': pluginReactRefresh.configs.vite, path: pluginPath, i18next: pluginI18Next, storybook: pluginStorybook, @@ -71,13 +70,6 @@ export default [ 'react-hooks/exhaustive-deps': 'error', - 'react-refresh/only-export-components': [ - 'warn', - { - allowConstantExport: true, - }, - ], - curly: 'error', 'no-var': 'error', 'brace-style': 'error', @@ -143,9 +135,9 @@ export default [ '@typescript-eslint/no-import-type-side-effects': 'error', '@typescript-eslint/consistent-type-assertions': [ - 'warn', + 'error', { - assertionStyle: 'never', + assertionStyle: 'as', }, ], @@ -184,6 +176,9 @@ export default [ }, ], + // Typescript handles this for us: https://eslint.org/docs/latest/rules/no-redeclare#handled_by_typescript + 'no-redeclare': 'off', + 'no-restricted-imports': [ 'error', { @@ -241,13 +236,7 @@ export default [ '**/*.scss', 'src/services/api/schema.ts', '.prettierrc.js', + '.storybook', ], }, - - { - files: ['**/*.test.ts', '**/*.test.tsx'], - rules: { - '@typescript-eslint/consistent-type-assertions': 'off', - }, - }, ]; diff --git a/invokeai/frontend/web/src/app/components/InvokeAIUI.tsx b/invokeai/frontend/web/src/app/components/InvokeAIUI.tsx index d9c58c3368..b365faf244 100644 --- a/invokeai/frontend/web/src/app/components/InvokeAIUI.tsx +++ b/invokeai/frontend/web/src/app/components/InvokeAIUI.tsx @@ -317,7 +317,7 @@ const InvokeAIUI = ({ if (import.meta.env.MODE === 'development') { window.$store = $store; } - () => { + return () => { $store.set(undefined); if (import.meta.env.MODE === 'development') { window.$store = undefined; diff --git a/invokeai/frontend/web/src/common/util/stopPropagation.ts b/invokeai/frontend/web/src/common/util/stopPropagation.ts index 0ad2b4b98a..a4bafe68cf 100644 --- a/invokeai/frontend/web/src/common/util/stopPropagation.ts +++ b/invokeai/frontend/web/src/common/util/stopPropagation.ts @@ -1,3 +1,5 @@ -export const preventDefault = (e: React.MouseEvent) => { +import type { MouseEvent } from 'react'; + +export const preventDefault = (e: MouseEvent) => { e.preventDefault(); }; diff --git a/invokeai/frontend/web/src/common/util/typedMemo.ts b/invokeai/frontend/web/src/common/util/typedMemo.ts index a084d95c81..adf3473de0 100644 --- a/invokeai/frontend/web/src/common/util/typedMemo.ts +++ b/invokeai/frontend/web/src/common/util/typedMemo.ts @@ -1,10 +1,11 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import type React from 'react'; import { memo } from 'react'; /** * A typed version of React.memo, useful for components that take generics. */ -export const typedMemo: >( +export const typedMemo: >( component: T, propsAreEqual?: (prevProps: React.ComponentProps, nextProps: React.ComponentProps) => boolean ) => T & { displayName?: string } = memo; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageList.tsx b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageList.tsx index 84cd483e3a..b8291f9cc5 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageList.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageList.tsx @@ -126,6 +126,7 @@ const AddRefImageDropTargetAndButton = memo(() => { ); }); +AddRefImageDropTargetAndButton.displayName = 'AddRefImageDropTargetAndButton'; const BboxButton = memo(() => { const { t } = useTranslation(); @@ -145,4 +146,4 @@ const BboxButton = memo(() => { /> ); }); -AddRefImageDropTargetAndButton.displayName = 'AddRefImageDropTargetAndButton'; +BboxButton.displayName = 'BboxButton'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolChooser.tsx b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolChooser.tsx index db9fca677c..d2b35ced8a 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolChooser.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolChooser.tsx @@ -4,6 +4,7 @@ import { ToolBrushButton } from 'features/controlLayers/components/Tool/ToolBrus import { ToolColorPickerButton } from 'features/controlLayers/components/Tool/ToolColorPickerButton'; import { ToolMoveButton } from 'features/controlLayers/components/Tool/ToolMoveButton'; import { ToolRectButton } from 'features/controlLayers/components/Tool/ToolRectButton'; +import React from 'react'; import { ToolEraserButton } from './ToolEraserButton'; import { ToolViewButton } from './ToolViewButton'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityPreviewImage.tsx b/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityPreviewImage.tsx index 34e84371d0..d8a9bb1c71 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityPreviewImage.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityPreviewImage.tsx @@ -7,7 +7,7 @@ import { useEntityAdapter } from 'features/controlLayers/contexts/EntityAdapterC import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext'; import { TRANSPARENCY_CHECKERBOARD_PATTERN_DARK_DATAURL } from 'features/controlLayers/konva/patterns/transparency-checkerboard-pattern'; import { selectCanvasSlice, selectEntity } from 'features/controlLayers/store/selectors'; -import { memo, useEffect, useMemo, useRef } from 'react'; +import React, { memo, useEffect, useMemo, useRef } from 'react'; import { useSelector } from 'react-redux'; const ChakraCanvas = chakra.canvas; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts index 6472c2c89b..487d32159f 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStageModule.ts @@ -339,7 +339,9 @@ export class CanvasStageModule extends CanvasModuleBase { onStageMouseWheel = (e: KonvaEventObject) => { e.evt.preventDefault(); - this._snapTimeout && window.clearTimeout(this._snapTimeout); + if (this._snapTimeout !== null) { + window.clearTimeout(this._snapTimeout); + } if (e.evt.ctrlKey || e.evt.metaKey) { return; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/filters.ts b/invokeai/frontend/web/src/features/controlLayers/store/filters.ts index 0e7f372cbf..091905b51f 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/filters.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/filters.ts @@ -146,7 +146,7 @@ const zNoiseFilterConfig = z.object({ }); export type NoiseFilterConfig = z.infer; -const zFilterConfig = z.discriminatedUnion('type', [ +const _zFilterConfig = z.discriminatedUnion('type', [ zAdjustImageFilterConfig, zCannyEdgeDetectionFilterConfig, zColorMapFilterConfig, @@ -164,7 +164,7 @@ const zFilterConfig = z.discriminatedUnion('type', [ zBlurFilterConfig, zNoiseFilterConfig, ]); -export type FilterConfig = z.infer; +export type FilterConfig = z.infer; const zFilterType = z.enum([ 'adjust_image', diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts index 88cab7beec..661b0097ea 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts @@ -82,8 +82,8 @@ const zIPMethodV2 = z.enum(['full', 'style', 'composition', 'style_strong', 'sty export type IPMethodV2 = z.infer; export const isIPMethodV2 = (v: unknown): v is IPMethodV2 => zIPMethodV2.safeParse(v).success; -const zTool = z.enum(['brush', 'eraser', 'move', 'rect', 'view', 'bbox', 'colorPicker']); -export type Tool = z.infer; +const _zTool = z.enum(['brush', 'eraser', 'move', 'rect', 'view', 'bbox', 'colorPicker']); +export type Tool = z.infer; const zPoints = z.array(z.number()).refine((points) => points.length % 2 === 0, { message: 'Must have an even number of coordinate components', @@ -106,23 +106,23 @@ export const RGBA_BLACK: RgbaColor = { r: 0, g: 0, b: 0, a: 1 }; const zOpacity = z.number().gte(0).lte(1); -const zDimensions = z.object({ +const _zDimensions = z.object({ width: z.number().int().positive(), height: z.number().int().positive(), }); -export type Dimensions = z.infer; +export type Dimensions = z.infer; const zCoordinate = z.object({ x: z.number(), y: z.number(), }); export type Coordinate = z.infer; -const zCoordinateWithPressure = z.object({ +const _zCoordinateWithPressure = z.object({ x: z.number(), y: z.number(), pressure: z.number(), }); -export type CoordinateWithPressure = z.infer; +export type CoordinateWithPressure = z.infer; const SAM_POINT_LABELS = { background: -1, @@ -154,12 +154,12 @@ export const SAM_POINT_LABEL_STRING_TO_NUMBER: Record; +type SAMPoint = z.infer; export type SAMPointWithId = SAMPoint & { id: string }; const zRect = z.object({ @@ -170,10 +170,10 @@ const zRect = z.object({ }); export type Rect = z.infer; -const zRectWithRotation = zRect.extend({ +const _zRectWithRotation = zRect.extend({ rotation: z.number(), }); -export type RectWithRotation = z.infer; +export type RectWithRotation = z.infer; const zCanvasBrushLineState = z.object({ id: zId, @@ -402,13 +402,13 @@ export type BoundingBoxScaleMethod = z.infer; export const isBoundingBoxScaleMethod = (v: unknown): v is BoundingBoxScaleMethod => zBoundingBoxScaleMethod.safeParse(v).success; -const zCanvasEntityState = z.discriminatedUnion('type', [ +const _zCanvasEntityState = z.discriminatedUnion('type', [ zCanvasRasterLayerState, zCanvasControlLayerState, zCanvasRegionalGuidanceState, zCanvasInpaintMaskState, ]); -export type CanvasEntityState = z.infer; +export type CanvasEntityState = z.infer; const zCanvasEntityType = z.union([ zCanvasRasterLayerState.shape.type, diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx index 5b4e6236b1..721792dbd5 100644 --- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx @@ -51,7 +51,7 @@ const BoardContextMenu = ({ board, children }: Props) => { board_id: board.board_id, changes: { archived: true }, }).unwrap(); - } catch (error) { + } catch { toast({ status: 'error', title: 'Unable to archive board', diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparisonSlider.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparisonSlider.tsx index 35361ff23a..d35a90570c 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparisonSlider.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageComparisonSlider.tsx @@ -5,7 +5,7 @@ import { TRANSPARENCY_CHECKERBOARD_PATTERN_DARK_DATAURL } from 'features/control import type { Dimensions } from 'features/controlLayers/store/types'; import { ImageComparisonLabel } from 'features/gallery/components/ImageViewer/ImageComparisonLabel'; import { selectComparisonFit } from 'features/gallery/store/gallerySelectors'; -import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { PiCaretLeftBold, PiCaretRightBold } from 'react-icons/pi'; import type { ComparisonProps } from './common'; diff --git a/invokeai/frontend/web/src/features/gallery/components/NewGallery.tsx b/invokeai/frontend/web/src/features/gallery/components/NewGallery.tsx index affe18118e..fff65d3f2e 100644 --- a/invokeai/frontend/web/src/features/gallery/components/NewGallery.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/NewGallery.tsx @@ -14,7 +14,7 @@ import { imageToCompareChanged, selectionChanged } from 'features/gallery/store/ import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { useOverlayScrollbars } from 'overlayscrollbars-react'; import type { MutableRefObject, RefObject } from 'react'; -import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import type { GridComponents, GridComputeItemKey, diff --git a/invokeai/frontend/web/src/features/gallery/hooks/useCreateStylePresetFromMetadata.ts b/invokeai/frontend/web/src/features/gallery/hooks/useCreateStylePresetFromMetadata.ts index afdd8a5bda..1fc0c05c20 100644 --- a/invokeai/frontend/web/src/features/gallery/hooks/useCreateStylePresetFromMetadata.ts +++ b/invokeai/frontend/web/src/features/gallery/hooks/useCreateStylePresetFromMetadata.ts @@ -52,12 +52,12 @@ export const useCreateStylePresetFromMetadata = (imageDTO?: ImageDTO | null) => try { positivePrompt = await MetadataHandlers.PositivePrompt.parse(metadata, store); - } catch (error) { + } catch { positivePrompt = ''; } try { negativePrompt = (await MetadataHandlers.NegativePrompt.parse(metadata, store)) ?? ''; - } catch (error) { + } catch { negativePrompt = ''; } diff --git a/invokeai/frontend/web/src/features/metadata/parsing.tsx b/invokeai/frontend/web/src/features/metadata/parsing.tsx index 777b5fa173..b01ee5cc2a 100644 --- a/invokeai/frontend/web/src/features/metadata/parsing.tsx +++ b/invokeai/frontend/web/src/features/metadata/parsing.tsx @@ -990,7 +990,7 @@ const recallByHandlers = async (arg: { const value = await handler.parse(metadata, store); handler.recall(value, store); recalled.set(handler, value); - } catch (error) { + } catch { // } } @@ -1146,7 +1146,6 @@ export function useSingleMetadataDatum(metadata: unknown, handler: SingleMeta return { data, recall }; } -/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ export function useCollectionMetadataDatum(metadata: unknown, handler: CollectionMetadataHandler) { const store = useAppStore(); const [data, setData] = useState>(buildUnparsedData); diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/Fields/PredictionTypeSelect.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/Fields/PredictionTypeSelect.tsx index c75f14ce45..dcef95b424 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/Fields/PredictionTypeSelect.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/Fields/PredictionTypeSelect.tsx @@ -22,7 +22,11 @@ const PredictionTypeSelect = ({ control }: Props) => { const value = useMemo(() => options.find((o) => o.value === field.value), [field.value]); const onChange = useCallback( (v) => { - v?.value === 'none' ? field.onChange(undefined) : field.onChange(v?.value); + if (v?.value === 'none') { + field.onChange(undefined); + } else { + field.onChange(v?.value); + } }, [field] ); diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/TriggerPhrases.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/TriggerPhrases.tsx index 3f5133dedf..5931822e9e 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/TriggerPhrases.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/TriggerPhrases.tsx @@ -10,7 +10,7 @@ import { TagLabel, } from '@invoke-ai/ui-library'; import type { ChangeEvent } from 'react'; -import { memo, useCallback, useMemo, useState } from 'react'; +import React, { memo, useCallback, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { PiPlusBold } from 'react-icons/pi'; import { useUpdateModelMutation } from 'services/api/endpoints/models'; diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/context.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/context.tsx index 73aaa193ee..f5afce3719 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/context.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/context.tsx @@ -220,6 +220,7 @@ export const InvocationNodeContextProvider = memo(({ nodeId, children }: PropsWi return {children}; }); +InvocationNodeContextProvider.displayName = 'InvocationNodeContextProvider'; export const useInvocationNodeContext = () => { const context = useContext(InvocationNodeContext); diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ModelFieldCombobox.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ModelFieldCombobox.tsx index d0d1da0b5d..05e07bc7f2 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ModelFieldCombobox.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ModelFieldCombobox.tsx @@ -14,7 +14,7 @@ type Props = { groupByType?: boolean; }; -const _ModelFieldCombobox = ({ +const ModelFieldComboboxInternal = ({ value: _value, modelConfigs, isLoadingConfigs, @@ -48,4 +48,4 @@ const _ModelFieldCombobox = ({ ); }; -export const ModelFieldCombobox = typedMemo(_ModelFieldCombobox); +export const ModelFieldCombobox = typedMemo(ModelFieldComboboxInternal); diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/PublishedWorkflowPanelContent.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/PublishedWorkflowPanelContent.tsx index 0a1bbf2421..d9df276f1b 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/PublishedWorkflowPanelContent.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/PublishedWorkflowPanelContent.tsx @@ -22,7 +22,7 @@ export const PublishedWorkflowPanelContent = memo(() => { title: t('toast.workflowUnpublished'), status: 'success', }); - } catch (error) { + } catch { toast({ title: t('toast.problemUnpublishingWorkflow'), description: t('toast.problemUnpublishingWorkflowDescription'), diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/ContainerElement.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/ContainerElement.tsx index 5edf6034b3..7679939608 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/ContainerElement.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/ContainerElement.tsx @@ -34,7 +34,7 @@ import { useTranslation } from 'react-i18next'; import type { Equals } from 'tsafe'; import { assert } from 'tsafe'; -const ContainerElement = memo(({ id }: { id: string }) => { +const ContainerElementComponent = memo(({ id }: { id: string }) => { const el = useElement(id); const mode = useAppSelector(selectWorkflowMode); @@ -49,7 +49,7 @@ const ContainerElement = memo(({ id }: { id: string }) => { // mode === 'edit' return ; }); -ContainerElement.displayName = 'ContainerElementComponent'; +ContainerElementComponent.displayName = 'ContainerElementComponent'; const containerViewModeSx: SystemStyleObject = { gap: 2, @@ -301,7 +301,7 @@ const FormElementComponent = memo(({ id }: { id: string }) => { } if (isContainerElement(el)) { - return ; + return ; } if (isNodeFieldElement(el)) { diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/form-manipulation.test.ts b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/form-manipulation.test.ts index bfac0f7395..ebd3a4b6b9 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/form-manipulation.test.ts +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/form-manipulation.test.ts @@ -63,8 +63,8 @@ describe('workflow builder form manipulation', () => { }); it('should narrow the type of the element if a type guard is provided and the element matches', () => { - const element = getElement(form, form.rootElementId, isContainerElement); - assert>(); + const _element = getElement(form, form.rootElementId, isContainerElement); + assert>(); }); }); diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowThumbnail/WorkflowThumbnailEditor.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowThumbnail/WorkflowThumbnailEditor.tsx index b2694a7ae0..2a1b7073f7 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowThumbnail/WorkflowThumbnailEditor.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowThumbnail/WorkflowThumbnailEditor.tsx @@ -42,7 +42,7 @@ export const WorkflowThumbnailEditor = ({ setCanSaveChanges(false); toast({ status: 'success', title: 'Workflow thumbnail updated' }); - } catch (error) { + } catch { toast({ status: 'error', title: 'Failed to update thumbnail' }); } }, [deleteThumbnail, setThumbnail, workflowId, localThumbnailUrl]); diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowThumbnail/WorkflowThumbnailField.tsx b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowThumbnail/WorkflowThumbnailField.tsx index 6416baf41f..4e8811e40c 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowThumbnail/WorkflowThumbnailField.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/WorkflowThumbnail/WorkflowThumbnailField.tsx @@ -26,7 +26,7 @@ export const WorkflowThumbnailField = ({ const file = new File([blob], 'workflow.png', { type: 'image/png' }); setThumbnail(file); } - } catch (error) { + } catch { setThumbnail(null); } }, []); diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldErrors.ts b/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldErrors.ts index 0b3b67667d..3b8749d581 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldErrors.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldErrors.ts @@ -22,7 +22,7 @@ export const useInputFieldErrors = (fieldName: string): FieldError[] => { return EMPTY_ARRAY; } const errors = thisNodeErrors.filter((error) => { - error.type === 'field-error' && error.fieldName === fieldName; + return error.type === 'field-error' && error.fieldName === fieldName; }); if (errors.length === 0) { return EMPTY_ARRAY; diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldIsInvalid.ts b/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldIsInvalid.ts index 89e36b2420..a5739fec94 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldIsInvalid.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldIsInvalid.ts @@ -22,7 +22,7 @@ export const useInputFieldIsInvalid = (fieldName: string) => { return false; } const isFieldInvalid = thisNodeErrors.some((error) => { - error.type === 'field-error' && error.fieldName === fieldName; + return error.type === 'field-error' && error.fieldName === fieldName; }); return isFieldInvalid; }), diff --git a/invokeai/frontend/web/src/features/nodes/types/common.ts b/invokeai/frontend/web/src/features/nodes/types/common.ts index b5febc5731..e674949e44 100644 --- a/invokeai/frontend/web/src/features/nodes/types/common.ts +++ b/invokeai/frontend/web/src/features/nodes/types/common.ts @@ -138,7 +138,7 @@ export type ModelIdentifierField = z.infer; // #endregion // #region Control Adapters -const zControlField = z.object({ +const _zControlField = z.object({ image: zImageField, control_model: zModelIdentifierField, control_weight: z.union([z.number(), z.array(z.number())]).optional(), @@ -147,9 +147,9 @@ const zControlField = z.object({ control_mode: z.enum(['balanced', 'more_prompt', 'more_control', 'unbalanced']).optional(), resize_mode: z.enum(['just_resize', 'crop_resize', 'fill_resize', 'just_resize_simple']).optional(), }); -export type ControlField = z.infer; +export type ControlField = z.infer; -const zIPAdapterField = z.object({ +const _zIPAdapterField = z.object({ image: zImageField, ip_adapter_model: zModelIdentifierField, weight: z.number(), @@ -157,9 +157,9 @@ const zIPAdapterField = z.object({ begin_step_percent: z.number().optional(), end_step_percent: z.number().optional(), }); -export type IPAdapterField = z.infer; +export type IPAdapterField = z.infer; -const zT2IAdapterField = z.object({ +const _zT2IAdapterField = z.object({ image: zImageField, t2i_adapter_model: zModelIdentifierField, weight: z.union([z.number(), z.array(z.number())]).optional(), @@ -167,7 +167,7 @@ const zT2IAdapterField = z.object({ end_step_percent: z.number().optional(), resize_mode: z.enum(['just_resize', 'crop_resize', 'fill_resize', 'just_resize_simple']).optional(), }); -export type T2IAdapterField = z.infer; +export type T2IAdapterField = z.infer; // #endregion // #region ProgressImage diff --git a/invokeai/frontend/web/src/features/nodes/types/field.ts b/invokeai/frontend/web/src/features/nodes/types/field.ts index 0d2d0e7181..4021f85fbf 100644 --- a/invokeai/frontend/web/src/features/nodes/types/field.ts +++ b/invokeai/frontend/web/src/features/nodes/types/field.ts @@ -1918,8 +1918,8 @@ export const zStatefulFieldValue = z.union([ ]); export type StatefulFieldValue = z.infer; -const zFieldValue = z.union([zStatefulFieldValue, zStatelessFieldValue]); -export type FieldValue = z.infer; +const _zFieldValue = z.union([zStatefulFieldValue, zStatelessFieldValue]); +export type FieldValue = z.infer; // #endregion // #region StatefulFieldInputInstance & FieldInputInstance diff --git a/invokeai/frontend/web/src/features/nodes/types/invocation.ts b/invokeai/frontend/web/src/features/nodes/types/invocation.ts index c42f451e40..4c018fb887 100644 --- a/invokeai/frontend/web/src/features/nodes/types/invocation.ts +++ b/invokeai/frontend/web/src/features/nodes/types/invocation.ts @@ -6,7 +6,7 @@ import { zFieldInputInstance, zFieldInputTemplate, zFieldOutputTemplate } from ' import { zSemVer } from './semver'; // #region InvocationTemplate -const zInvocationTemplate = z.object({ +const _zInvocationTemplate = z.object({ type: z.string(), title: z.string(), description: z.string(), @@ -19,7 +19,7 @@ const zInvocationTemplate = z.object({ nodePack: z.string().min(1).default('invokeai'), classification: zClassification, }); -export type InvocationTemplate = z.infer; +export type InvocationTemplate = z.infer; // #endregion // #region NodeData @@ -43,7 +43,7 @@ export const zNotesNodeData = z.object({ isOpen: z.boolean(), notes: z.string(), }); -const zCurrentImageNodeData = z.object({ +const _zCurrentImageNodeData = z.object({ id: z.string().trim().min(1), type: z.literal('current_image'), label: z.string(), @@ -52,7 +52,7 @@ const zCurrentImageNodeData = z.object({ export type NotesNodeData = z.infer; export type InvocationNodeData = z.infer; -type CurrentImageNodeData = z.infer; +type CurrentImageNodeData = z.infer; export type InvocationNode = Node; export type NotesNode = Node; @@ -71,7 +71,7 @@ const zNodeError = z.object({ error_message: z.string(), error_traceback: z.string(), }); -const zNodeExecutionState = z.object({ +const _zNodeExecutionState = z.object({ nodeId: z.string().trim().min(1), status: zNodeStatus, progress: z.number().nullable(), @@ -79,14 +79,14 @@ const zNodeExecutionState = z.object({ outputs: z.array(z.any()), error: zNodeError.nullable(), }); -export type NodeExecutionState = z.infer; +export type NodeExecutionState = z.infer; // #endregion // #region Edges -const zInvocationNodeEdgeCollapsedData = z.object({ +const _zInvocationNodeEdgeCollapsedData = z.object({ count: z.number().int().min(1), }); -type InvocationNodeEdgeCollapsedData = z.infer; +type InvocationNodeEdgeCollapsedData = z.infer; export type DefaultInvocationNodeEdge = Edge, 'default'>; export type CollapsedInvocationNodeEdge = Edge; export type AnyEdge = DefaultInvocationNodeEdge | CollapsedInvocationNodeEdge; diff --git a/invokeai/frontend/web/src/features/nodes/types/v2/field.ts b/invokeai/frontend/web/src/features/nodes/types/v2/field.ts index 96715c73f1..a3085228e5 100644 --- a/invokeai/frontend/web/src/features/nodes/types/v2/field.ts +++ b/invokeai/frontend/web/src/features/nodes/types/v2/field.ts @@ -328,7 +328,7 @@ const zStatelessFieldOutputInstance = zFieldOutputInstanceBase.extend({ // #endregion -const zStatefulFieldType = z.union([ +const _zStatefulFieldType = z.union([ zIntegerFieldType, zFloatFieldType, zStringFieldType, @@ -347,7 +347,7 @@ const zStatefulFieldType = z.union([ zColorFieldType, zSchedulerFieldType, ]); -export type StatefulFieldType = z.infer; +export type StatefulFieldType = z.infer; /** * Here we define the main field unions: diff --git a/invokeai/frontend/web/src/features/nodes/util/workflow/validateWorkflow.ts b/invokeai/frontend/web/src/features/nodes/util/workflow/validateWorkflow.ts index d3220fcc42..b86870d450 100644 --- a/invokeai/frontend/web/src/features/nodes/util/workflow/validateWorkflow.ts +++ b/invokeai/frontend/web/src/features/nodes/util/workflow/validateWorkflow.ts @@ -82,7 +82,7 @@ export const validateWorkflow = async (args: ValidateWorkflowArgs): Promise // #endregion // #region LoRA Model -const zParameterLoRAModel = zModelIdentifierField; -export type ParameterLoRAModel = z.infer; +const _zParameterLoRAModel = zModelIdentifierField; +export type ParameterLoRAModel = z.infer; // #endregion // #region VAE Model diff --git a/invokeai/frontend/web/src/features/prompt/PromptExpansion/expand.ts b/invokeai/frontend/web/src/features/prompt/PromptExpansion/expand.ts index 8f949b3ebf..dbd8187b46 100644 --- a/invokeai/frontend/web/src/features/prompt/PromptExpansion/expand.ts +++ b/invokeai/frontend/web/src/features/prompt/PromptExpansion/expand.ts @@ -31,7 +31,7 @@ export const expandPrompt = async (arg: { dispatch: AppDispatch; getState: AppGe }); assert(output.type === 'string_output'); promptExpansionApi.setSuccess(output.value); - } catch (error) { + } catch { promptExpansionApi.reset(); toast({ id: 'PROMPT_EXPANSION_FAILED', diff --git a/invokeai/frontend/web/src/features/queue/components/ClearModelCacheButton.tsx b/invokeai/frontend/web/src/features/queue/components/ClearModelCacheButton.tsx index 6c11a9cdc6..26458fae6c 100644 --- a/invokeai/frontend/web/src/features/queue/components/ClearModelCacheButton.tsx +++ b/invokeai/frontend/web/src/features/queue/components/ClearModelCacheButton.tsx @@ -17,7 +17,7 @@ const ClearModelCacheButton = () => { status: 'success', title: t('modelCache.clearSucceeded'), }); - } catch (error) { + } catch { toast({ status: 'error', title: t('modelCache.clearFailed'), diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/CanvasTabImageSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/CanvasTabImageSettingsAccordion.tsx index bfedadc324..233a4c51ad 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/CanvasTabImageSettingsAccordion.tsx +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/CanvasTabImageSettingsAccordion.tsx @@ -39,7 +39,7 @@ const selectBadges = createMemoizedSelector([selectCanvasSlice, selectParamsSlic return EMPTY_ARRAY; } - badges; + return badges; }); const scalingLabelProps: FormLabelProps = { diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/GenerateTabImageSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/GenerateTabImageSettingsAccordion.tsx index 332bb56ef8..7769018e72 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/GenerateTabImageSettingsAccordion.tsx +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/ImageSettingsAccordion/GenerateTabImageSettingsAccordion.tsx @@ -36,7 +36,7 @@ const selectBadges = createMemoizedSelector( return EMPTY_ARRAY; } - badges; + return badges; } ); diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/RefinerSettingsAccordion/RefinerSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/RefinerSettingsAccordion/RefinerSettingsAccordion.tsx index 26b52dfb99..050722e3bc 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/components/RefinerSettingsAccordion/RefinerSettingsAccordion.tsx +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/RefinerSettingsAccordion/RefinerSettingsAccordion.tsx @@ -11,7 +11,7 @@ import ParamSDXLRefinerScheduler from 'features/sdxl/components/SDXLRefiner/Para import ParamSDXLRefinerStart from 'features/sdxl/components/SDXLRefiner/ParamSDXLRefinerStart'; import ParamSDXLRefinerSteps from 'features/sdxl/components/SDXLRefiner/ParamSDXLRefinerSteps'; import { useStandaloneAccordionToggle } from 'features/settingsAccordions/hooks/useStandaloneAccordionToggle'; -import { memo } from 'react'; +import React, { memo } from 'react'; import { useTranslation } from 'react-i18next'; import { useIsRefinerAvailable } from 'services/api/hooks/useIsRefinerAvailable'; diff --git a/invokeai/frontend/web/src/features/stylePresets/components/DeleteStylePresetDialog.tsx b/invokeai/frontend/web/src/features/stylePresets/components/DeleteStylePresetDialog.tsx index 1302dd17e4..5135010b5c 100644 --- a/invokeai/frontend/web/src/features/stylePresets/components/DeleteStylePresetDialog.tsx +++ b/invokeai/frontend/web/src/features/stylePresets/components/DeleteStylePresetDialog.tsx @@ -35,7 +35,7 @@ export const DeleteStylePresetDialog = memo(() => { status: 'success', title: t('stylePresets.templateDeleted'), }); - } catch (error) { + } catch { toast({ status: 'error', title: t('stylePresets.unableToDeleteTemplate'), diff --git a/invokeai/frontend/web/src/features/stylePresets/components/StylePresetExportButton.tsx b/invokeai/frontend/web/src/features/stylePresets/components/StylePresetExportButton.tsx index 3e47e9aba6..9f6fdbbc3b 100644 --- a/invokeai/frontend/web/src/features/stylePresets/components/StylePresetExportButton.tsx +++ b/invokeai/frontend/web/src/features/stylePresets/components/StylePresetExportButton.tsx @@ -27,7 +27,7 @@ export const StylePresetExportButton = () => { try { const response = await exportStylePresets().unwrap(); blob = new Blob([response], { type: 'text/csv' }); - } catch (error) { + } catch { toast({ status: 'error', title: t('stylePresets.exportFailed'), diff --git a/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetForm.tsx b/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetForm.tsx index aadc82f1fe..fcfe960508 100644 --- a/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetForm.tsx +++ b/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetForm.tsx @@ -68,7 +68,7 @@ export const StylePresetForm = ({ } else { await createStylePreset(payload).unwrap(); } - } catch (error) { + } catch { toast({ status: 'error', title: 'Failed to save style preset', diff --git a/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetModal.tsx b/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetModal.tsx index d1da39664a..bd755c0018 100644 --- a/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetModal.tsx +++ b/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetModal.tsx @@ -55,7 +55,7 @@ export const StylePresetModal = () => { if (blob) { file = new File([blob], 'style_preset.png', { type: 'image/png' }); } - } catch (error) { + } catch { // do nothing } } diff --git a/invokeai/frontend/web/src/features/ui/layouts/auto-layout-context.tsx b/invokeai/frontend/web/src/features/ui/layouts/auto-layout-context.tsx index c887176c44..1c99b38857 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/auto-layout-context.tsx +++ b/invokeai/frontend/web/src/features/ui/layouts/auto-layout-context.tsx @@ -38,6 +38,7 @@ export type RootLayoutGridviewComponents = Record | IGridviewPanelProps; export const withPanelContainer = (Component: FunctionComponent) => + /* eslint-disable-next-line react/display-name */ memo((props: PanelProps) => { return ( diff --git a/invokeai/frontend/web/src/features/ui/layouts/navigation-api.ts b/invokeai/frontend/web/src/features/ui/layouts/navigation-api.ts index a904e9172e..f15eb6caac 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/navigation-api.ts +++ b/invokeai/frontend/web/src/features/ui/layouts/navigation-api.ts @@ -340,7 +340,7 @@ export class NavigationApi { log.trace(`Focused panel ${key}`); return true; - } catch (error) { + } catch { log.error(`Failed to focus panel ${panelId} in tab ${tab}`); return false; } diff --git a/invokeai/frontend/web/src/features/workflowLibrary/hooks/useCreateNewWorkflow.ts b/invokeai/frontend/web/src/features/workflowLibrary/hooks/useCreateNewWorkflow.ts index 48fabdce78..543283c779 100644 --- a/invokeai/frontend/web/src/features/workflowLibrary/hooks/useCreateNewWorkflow.ts +++ b/invokeai/frontend/web/src/features/workflowLibrary/hooks/useCreateNewWorkflow.ts @@ -70,15 +70,15 @@ export const useCreateLibraryWorkflow = (): CreateLibraryWorkflowReturn => { // When a workflow is saved, the form field initial values are updated to the current form field values dispatch(formFieldInitialValuesChanged({ formFieldInitialValues: getFormFieldInitialValues() })); updateOpenedAt({ workflow_id: id }); - onSuccess && onSuccess(); + onSuccess?.(); toast.update(toastRef.current, { title: t('workflows.workflowSaved'), status: 'success', duration: 1000, isClosable: true, }); - } catch (e) { - onError && onError(); + } catch { + onError?.(); if (!toast.isActive(`auth-error-toast-${workflowsApi.endpoints.createWorkflow.name}`)) { toast.update(toastRef.current, { title: t('workflows.problemSavingWorkflow'), diff --git a/invokeai/frontend/web/src/features/workflowLibrary/hooks/useSaveLibraryWorkflow.ts b/invokeai/frontend/web/src/features/workflowLibrary/hooks/useSaveLibraryWorkflow.ts index 1b1379c2b2..5e699edb20 100644 --- a/invokeai/frontend/web/src/features/workflowLibrary/hooks/useSaveLibraryWorkflow.ts +++ b/invokeai/frontend/web/src/features/workflowLibrary/hooks/useSaveLibraryWorkflow.ts @@ -55,7 +55,7 @@ export const useSaveLibraryWorkflow = (): UseSaveLibraryWorkflowReturn => { duration: 1000, isClosable: true, }); - } catch (e) { + } catch { if (!toast.isActive(`auth-error-toast-${workflowsApi.endpoints.updateWorkflow.name}`)) { toast.update(toastRef.current, { title: t('workflows.problemSavingWorkflow'), diff --git a/invokeai/frontend/web/src/services/api/authToastMiddleware.ts b/invokeai/frontend/web/src/services/api/authToastMiddleware.ts index 2f9bd4776c..987efcd326 100644 --- a/invokeai/frontend/web/src/services/api/authToastMiddleware.ts +++ b/invokeai/frontend/web/src/services/api/authToastMiddleware.ts @@ -72,7 +72,7 @@ export const authToastMiddleware: Middleware = () => (next) => (action) => { description: customMessage, }); } - } catch (error) { + } catch { // no-op } } diff --git a/invokeai/frontend/web/src/services/events/onModelInstallError.tsx b/invokeai/frontend/web/src/services/events/onModelInstallError.tsx index 53bbbb91df..23089ca410 100644 --- a/invokeai/frontend/web/src/services/events/onModelInstallError.tsx +++ b/invokeai/frontend/web/src/services/events/onModelInstallError.tsx @@ -128,7 +128,6 @@ export const buildOnModelInstallError = (getState: AppGetState, dispatch: AppDis if (!install) { dispatch(api.util.invalidateTags([{ type: 'ModelInstalls' }])); } else { - install.source; dispatch( modelsApi.util.updateQueryData('listModelInstalls', undefined, (draft) => { const modelImport = draft.find((m) => m.id === data.id);