diff --git a/.github/workflows/check-formatting.yml b/.github/workflows/check-formatting.yml index 010ab3d19..2b2f3012b 100644 --- a/.github/workflows/check-formatting.yml +++ b/.github/workflows/check-formatting.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: - node-versions: [16.x] + node-versions: [20.x] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/cypress_tests.yml b/.github/workflows/cypress_tests.yml index 441c0516c..fae810440 100644 --- a/.github/workflows/cypress_tests.yml +++ b/.github/workflows/cypress_tests.yml @@ -12,6 +12,10 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' - name: Cypress run uses: cypress-io/github-action@v6 with: diff --git a/.github/workflows/node_version_test.yml b/.github/workflows/node_version_test.yml index c4556acda..54df7d6e3 100644 --- a/.github/workflows/node_version_test.yml +++ b/.github/workflows/node_version_test.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - node-versions: [16.x,18.x] + node-versions: [20.x,22.x] steps: - uses: actions/checkout@v2 diff --git a/.storybook/main.js b/.storybook/main.js index 32c587fa5..4c3bd8036 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -1,7 +1,7 @@ module.exports = { - stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], - addons: [ + addons: [ 'storybook-source-link', //'@storybook/addon-storysource', '@storybook/addon-links', @@ -14,27 +14,28 @@ module.exports = { }, ], - framework: { - name: "@storybook/react-webpack5", - options: {} - }, - - webpackFinal: async (config, { configType }) => { - // split into more chunks - config.optimization = { - splitChunks: { - chunks: 'all', - minSize: 30 * 1024, // 30KB - maxSize: 1024 * 1024, // 1MB - }, - }; - - config.externals = { fs: 'fs' }; + framework: { + name: '@storybook/react-webpack5', + options: {}, + }, + webpackFinal: async (config) => { + config.module.rules.push({ + test: /\.(ts|tsx)$/, + use: [ + { + loader: require.resolve('babel-loader'), + options: { + presets: [require.resolve('@babel/preset-typescript')], + }, + }, + ], + }); + config.resolve.extensions.push('.ts', '.tsx'); return config; }, - typescript: { + typescript: { check: false, checkOptions: {}, reactDocgen: 'react-docgen-typescript', @@ -44,13 +45,13 @@ module.exports = { }, }, - docs: { - autodocs: true - }, + docs: { + autodocs: true, + }, staticDirs: [ '../public', ], features: { - buildStoriesJson: true, - } + buildStoriesJson: true, + }, }; diff --git a/.storybook/preview.js b/.storybook/preview.js index 750da5f8d..d481af620 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -4,8 +4,6 @@ import { themes } from "@storybook/theming"; import "./style.css"; -console.log('ReactDOM.render warning is from storybook still using react 17 to render the UI; The components shown are using 18 thoug. See https://github.com/storybookjs/storybook/issues/17831 for more info. The issue will eventually be resolved by upgrading storybook, once it fully supports React 18'); - export const parameters = { docs: { inlineStories: false, @@ -30,4 +28,4 @@ export const globalTypes = { ], }, }, -}; \ No newline at end of file +}; diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..5210b0c0f --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,73 @@ +import react from 'eslint-plugin-react'; +import typescriptEslint from '@typescript-eslint/eslint-plugin'; +import globals from 'globals'; +import tsParser from '@typescript-eslint/parser'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import js from '@eslint/js'; +import { FlatCompat } from '@eslint/eslintrc'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all, +}); + +export default [ + { + ignores: [ + '**/.cache', + '**/.github', + '**/.storybook', + '**/.vscode', + '**/coverage', + '**/dist', + '**/docs', + '**/docs-build', + '**/js-docs', + '**/node_modules', + '**/storybook-static', + '**/scripts', + ], + }, + ...compat.extends( + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:@typescript-eslint/recommended', + 'prettier', + 'plugin:storybook/recommended' + ), + { + plugins: { + react, + '@typescript-eslint': typescriptEslint, + }, + + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + ...globals.jest, + }, + + parser: tsParser, + ecmaVersion: 'latest', + sourceType: 'module', + }, + + settings: { + react: { + version: 'detect', + }, + }, + + rules: { + 'react/prop-types': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unsafe-declaration-merging': 'off', + }, + }, +]; diff --git a/package.json b/package.json index ee40d4b41..5b2647f23 100644 --- a/package.json +++ b/package.json @@ -23,87 +23,94 @@ "@dnd-kit/core": "^6.3.1", "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", - "@emotion/css": "^11.13.0", - "@emotion/react": "^11.13.3", - "@emotion/styled": "^11.13.0", - "@mapbox/mapbox-gl-draw": "^1.4.3", + "@emotion/css": "^11.13.5", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", + "@eslint/eslintrc": "^3.3.0", + "@eslint/js": "^9.22.0", + "@mapbox/mapbox-gl-draw": "1.4.3", "@mapbox/mapbox-gl-sync-move": "^0.3.1", - "@mui/icons-material": "^6.1.1", - "@mui/material": "^6.1.1", - "@reduxjs/toolkit": "^2.0.1", + "@mui/icons-material": "^6.4.7", + "@mui/material": "^6.4.7", + "@reduxjs/toolkit": "^2.6.1", "@rollup/plugin-json": "^6.1.0", - "@tmcw/togeojson": "^5.8.1", - "@turf/turf": "^7.1.0", + "@testing-library/dom": "^10.4.0", + "@tmcw/togeojson": "^7.0.0", + "@turf/turf": "^7.2.0", "@types/d3": "^7.4.3", - "@types/geojson": "^7946.0.14", - "@types/react-color": "^3.0.11", - "@types/topojson-client": "^3.1.4", - "@xmldom/xmldom": "^0.8.10", + "@types/geojson": "^7946.0.16", + "@types/react-color": "^3.0.13", + "@types/topojson-client": "^3.1.5", + "@xmldom/xmldom": "^0.9.8", "csv2geojson": "^5.1.2", - "d3": "^7.8.5", - "jspdf": "^2.5.1", - "maplibre-gl": "^4.5.2", - "osm2geojson-lite": "^0.9.4", + "d3": "^7.9.0", + "globals": "^16.0.0", + "jspdf": "^3.0.0", + "maplibre-gl": "5.2.0", + "osm2geojson-lite": "^1.0.2", "pako": "^2.1.0", "react-color": "^2.19.3", "react-moveable": "^0.56.0", - "react-redux": "^9.1.2", + "react-redux": "^9.2.0", "redux": "^5.0.1", "redux-thunk": "^3.1.0", - "three": "^0.161.0", + "three": "^0.174.0", "topojson-client": "^3.1.0", - "uuid": "^9.0.1", + "uuid": "^11.1.0", "wms-capabilities": "^0.6.0" }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", - "@babel/preset-react": "^7.23.3", + "@babel/preset-react": "^7.26.3", + "@babel/preset-typescript": "^7.26.0", "@bahmutov/cy-rollup": "^2.0.0", - "@cfaester/enzyme-adapter-react-18": "^0.7.1", + "@cfaester/enzyme-adapter-react-18": "^0.8.0", "@cypress/react18": "^2.0.1", "@rollup/plugin-babel": "^6.0.4", - "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-commonjs": "^28.0.3", "@rollup/plugin-url": "^8.0.2", - "@storybook/addon-actions": "^7.6.13", - "@storybook/addon-docs": "^7.6.13", - "@storybook/addon-essentials": "^7.6.13", - "@storybook/addon-links": "^7.6.13", - "@storybook/addons": "^7.6.13", - "@storybook/node-logger": "^7.6.13", - "@storybook/react": "^7.6.13", - "@storybook/react-webpack5": "^7.6.13", + "@storybook/addon-actions": "^8.6.4", + "@storybook/addon-docs": "^8.6.4", + "@storybook/addon-essentials": "^8.6.4", + "@storybook/addon-links": "^8.6.4", + "@storybook/addons": "^7.6.17", + "@storybook/node-logger": "^8.6.4", + "@storybook/react": "^8.6.4", + "@storybook/react-webpack5": "^8.6.4", + "@storybook/test": "^8.6.4", "@storybook/testing-react": "^2.0.1", - "@storybook/theming": "^7.6.13", + "@storybook/theming": "^8.6.4", "@svgr/rollup": "^8.1.0", - "@testing-library/react": "^14.2.1", + "@testing-library/react": "^16.2.0", "@types/elasticlunr": "^0.9.5", "@types/enzyme": "^3.10.18", - "@types/expect": "^24.3.0", - "@types/jest": "^29.5.12", - "@types/mapbox__mapbox-gl-draw": "^1.4.6", + "@types/expect": "^24.3.2", + "@types/jest": "^29.5.14", + "@types/mapbox__mapbox-gl-draw": "^1.4.8", "@types/mapbox__point-geometry": "^0.1.4", - "@types/mapbox__vector-tile": "^1.3.4", + "@types/mapbox__vector-tile": "^2.0.0", "@types/pako": "^2.0.3", - "@types/react": "^18.2.55", - "@types/react-dom": "^18.2.19", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", "@types/sql.js": "^1.4.9", - "@types/three": "^0.161.2", - "@types/uuid": "^9.0.8", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/parser": "^6.21.0", + "@types/three": "^0.174.0", + "@types/uuid": "^10.0.0", + "@typescript-eslint/eslint-plugin": "^8.26.1", + "@typescript-eslint/parser": "^8.26.1", "avj": "^0.0.0", "babel-jest": "^29.7.0", + "babel-loader": "^10.0.0", "babel-plugin-inline-react-svg": "^2.0.2", "babel-plugin-styled-components": "^2.1.4", - "babel-preset-react-app": "^10.0.1", - "cypress": "^13.6.4", + "babel-preset-react-app": "^10.1.0", + "cypress": "^14.2.0", "elasticlunr": "^0.9.5", "enzyme": "^3.11.0", - "eslint": "^8.56.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-storybook": "^0.6.15", - "glob": "^10.3.10", + "eslint": "^9.22.0", + "eslint-config-prettier": "^10.1.1", + "eslint-plugin-react": "^7.37.4", + "eslint-plugin-storybook": "^0.11.4", + "glob": "^11.0.1", "jest": "29.7.0", "jest-circus": "29.7.0", "jest-environment-jsdom": "^29.7.0", @@ -111,25 +118,26 @@ "jest-resolve": "29.7.0", "jest-watch-typeahead": "2.2.2", "node-fetch": "^3.3.2", - "postcss": "^8.4.35", - "prettier": "3.2.5", + "postcss": "^8.5.3", + "prettier": "3.5.3", "react": "^18.2.0", "react-app-polyfill": "^3.0.0", "react-dev-utils": "^12.0.1", "react-dom": "^18.2.0", "react-draggable": "^4.4.6", - "react-i18next": "^14.0.5", - "rollup": "^4.11.0", - "rollup-plugin-delete": "^2.0.0", - "rollup-plugin-import-css": "^3.4.0", - "rollup-plugin-node-externals": "^7.0.1", + "react-i18next": "^15.4.1", + "rollup": "^4.35.0", + "rollup-plugin-delete": "^3.0.1", + "rollup-plugin-import-css": "^3.5.8", + "rollup-plugin-node-externals": "^8.0.0", "rollup-plugin-typescript2": "^0.36.0", "showdown": "^2.1.0", - "sql.js": "^1.10.2", - "storybook": "^7.6.13", + "sql.js": "^1.12.0", + "storybook": "^8.6.4", "storybook-source-link": "^4.0.1", - "ts-jest": "^29.1.2", - "typescript": "^5.3.3" + "ts-jest": "^29.2.6", + "ts-loader": "^9.5.2", + "typescript": "^5.8.2" }, "jest": { "roots": [ @@ -215,6 +223,6 @@ ] }, "resolutions": { - "jackspeak": "2.1.1" + "jackspeak": "4.1.0" } } diff --git a/src/components/MapLibreMap/MapLibreMap.stories.tsx b/src/components/MapLibreMap/MapLibreMap.stories.tsx index 55a32e997..d7bc92153 100644 --- a/src/components/MapLibreMap/MapLibreMap.stories.tsx +++ b/src/components/MapLibreMap/MapLibreMap.stories.tsx @@ -1,5 +1,4 @@ import React, { useState } from "react"; - import MapLibreMap, { MapLibreMapProps } from './MapLibreMap'; import MlGeoJsonLayer from '../MlGeoJsonLayer/MlGeoJsonLayer'; import { Button } from '@mui/material'; @@ -7,6 +6,8 @@ import TopToolbar from '../../ui_components/TopToolbar'; import sample_geojson_1 from '../MlGeoJsonLayer/assets/sample_1.json'; import {FeatureCollection} from 'geojson'; import themeDecorator from '../../decorators/ThemeDecorator'; +import { StoryFn } from "@storybook/react"; + const storyoptions = { title: 'Core/MapLibreMap', @@ -25,7 +26,7 @@ const storyoptions = { }; export default storyoptions; -const Template = (args:MapLibreMapProps) => { +const Template: StoryFn = (args:MapLibreMapProps) => { return ; }; diff --git a/src/components/MapLibreMap/MapLibreMap.test.js b/src/components/MapLibreMap/MapLibreMap.test.js index cf8d70cce..76e97f339 100644 --- a/src/components/MapLibreMap/MapLibreMap.test.js +++ b/src/components/MapLibreMap/MapLibreMap.test.js @@ -1,6 +1,5 @@ -import React, { useContext, useEffect, useState } from "react"; -import { mount, configure } from "enzyme"; -import { waitFor } from "@testing-library/react"; +import React, { useContext, useState } from "react"; +import { mount } from "enzyme"; import MapContext, { MapComponentsProvider } from "../../contexts/MapContext"; import MapLibreMap from "./MapLibreMap"; diff --git a/src/components/MapLibreMap/MapLibreMap.tsx b/src/components/MapLibreMap/MapLibreMap.tsx index de3ea3bf8..90dfab180 100644 --- a/src/components/MapLibreMap/MapLibreMap.tsx +++ b/src/components/MapLibreMap/MapLibreMap.tsx @@ -21,6 +21,8 @@ export type MapLibreMapProps = { * css style definition passed to the map container DOM element */ style?: object; + + }; const defaultProps: MapLibreMapProps = { @@ -50,6 +52,8 @@ const defaultProps: MapLibreMapProps = { }, }; +type MapLibreMapComponent = FC & { defaultProps: MapLibreMapProps }; + /** * Creates a MapLibreGlWrapper instance and registers it in MapContext * after the MapLibre-gl load event has fired. @@ -60,9 +64,9 @@ const defaultProps: MapLibreMapProps = { * * @category Map components */ -const MapLibreMap: FC = (props: MapLibreMapProps) => { - const mapRef = useRef(); - const mapContainer = useRef(); +const MapLibreMap: MapLibreMapComponent = (props: MapLibreMapProps) => { + const mapRef = useRef(null); + const mapContainer = useRef(null); const mapContext = useContext(MapContext); @@ -79,7 +83,7 @@ const MapLibreMap: FC = (props: MapLibreMapProps) => { if (mapRef.current) { mapRef.current.map?.remove?.(); mapRef.current.cancelled = true; - mapRef.current = undefined; + mapRef.current = null; } }; }, []); @@ -100,7 +104,7 @@ const MapLibreMap: FC = (props: MapLibreMapProps) => { map.once('load', () => { if (!wrapper?.cancelled) { // add maplibre instance to window for debugging purposes - window['_map'] = map; + (window as {[key:string]: any})['_map'] = map; if (props.mapId) { mapContext.registerMap(props.mapId, wrapper); } else { diff --git a/src/components/MapLibreMap/lib/MapLibreGlWrapper.ts b/src/components/MapLibreMap/lib/MapLibreGlWrapper.ts index 009f8d2e6..0ab32e421 100644 --- a/src/components/MapLibreMap/lib/MapLibreGlWrapper.ts +++ b/src/components/MapLibreMap/lib/MapLibreGlWrapper.ts @@ -33,6 +33,7 @@ type ViewportState = { pitch: number; }; + /** * Creates a MapLibre-gl-js instance and offers all of the native MapLibre functions and properties as well as additional functionality such as element registration & cleanup and more events. * @@ -41,7 +42,7 @@ type ViewportState = { * @class */ -// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging +// @ts-ignore interface MapLibreGlWrapper extends MapType { addImage: ( id: string, @@ -104,7 +105,7 @@ export type MapLibreGlEventName = keyof MapLayerEventType | keyof MapEventType | export type MapLibreGlWrapperEventName = keyof MapLibreGlWrapperEventHandlers; -// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging + class MapLibreGlWrapper { [key: string]: any; registeredElements: { @@ -501,7 +502,7 @@ class MapLibreGlWrapper { self.registeredElements[componentId].events.push(_arguments); } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore self.map.on(..._arguments); return this; @@ -554,7 +555,7 @@ class MapLibreGlWrapper { // cleanup events self.registeredElements[componentId].events.forEach((item: EventArgArray) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore self.map.off(...item); }); diff --git a/src/components/MlClientSearch/lib/SearchForm.tsx b/src/components/MlClientSearch/lib/SearchForm.tsx index 4e310af5a..0383c63a0 100644 --- a/src/components/MlClientSearch/lib/SearchForm.tsx +++ b/src/components/MlClientSearch/lib/SearchForm.tsx @@ -50,7 +50,7 @@ export default function SearchForm() { function processObject(obj: object): string { const keys = searchContext.searchIndex.fields; const filteredKeys = Object.keys(obj).filter((key) => keys.includes(key)); - return filteredKeys.map((key) => obj[key]).join(', '); + return filteredKeys.map((key) => (obj as {[key:string]:any})[key]).join(', '); } const debouncedHandleInput = useCallback( debounce((e: React.ChangeEvent) => { diff --git a/src/components/MlClientSearch/lib/createGeojsonFeature.tsx b/src/components/MlClientSearch/lib/createGeojsonFeature.tsx index 65d300184..c4682f430 100644 --- a/src/components/MlClientSearch/lib/createGeojsonFeature.tsx +++ b/src/components/MlClientSearch/lib/createGeojsonFeature.tsx @@ -29,12 +29,12 @@ function determineFeatureType(coordinates: ExcludedGeometryCollection['coordinat ) ) { return 'LineString'; - } else if (coordinates.every((coord) => Array.isArray(coord) && Array.isArray(coord[0]))) { + } else if (coordinates.every((coord)=> Array.isArray(coord) && Array.isArray(coord[0]))) { // an array of arrays can be a multi-linestring or polygon, // if the first and last coordinate is the same, it is a polygon if ( - coordinates[0][0][0] === coordinates[0][coordinates[0].length - 1][0] && - coordinates[0][0][1] === coordinates[0][coordinates[0].length - 1][1] + (coordinates as {[key:string]:any})[0][0][0] === (coordinates as {[key:string]:any})[0][(coordinates as {[key:string]:any})[0].length - 1][0] && + (coordinates as {[key:string]:any})[0][0][1] === (coordinates as {[key:string]:any})[0][(coordinates as {[key:string]:any})[0].length - 1][1] ) { return 'Polygon'; } else { diff --git a/src/components/MlCreatePdfForm/MlCreatePdfForm.stories.tsx b/src/components/MlCreatePdfForm/MlCreatePdfForm.stories.tsx index b49735631..30a1a0a68 100644 --- a/src/components/MlCreatePdfForm/MlCreatePdfForm.stories.tsx +++ b/src/components/MlCreatePdfForm/MlCreatePdfForm.stories.tsx @@ -215,7 +215,7 @@ const additionalInfoTemplate = () => { const title = options.formData.get('title') as string; const text = options.formData.get('description') as string; const centerY = pageWidth / 2; - const fontSizes = { + const fontSizes: {[key:string]:any} = { a4: { width: 210, textSize: 10, @@ -317,7 +317,6 @@ const additionalInfoTemplate = () => { pdf.setFontSize(fontSizes[options.format].titleSize); const titleWidth = (pdf.getStringUnitWidth(title) * pdf.getFontSize()) / pdf.internal.scaleFactor; - pdf.internal.scaleFactor; const titleX = isLandscape ? centerY - titleWidth / 2 : (pageWidth - titleWidth) / 2; pdf.text(title, titleX, fontSizes[options.format].titleOffset); diff --git a/src/components/MlCreatePdfForm/lib/PdfContext.tsx b/src/components/MlCreatePdfForm/lib/PdfContext.tsx index 0712bb8bc..274082dcc 100644 --- a/src/components/MlCreatePdfForm/lib/PdfContext.tsx +++ b/src/components/MlCreatePdfForm/lib/PdfContext.tsx @@ -19,7 +19,7 @@ const PdfContextProvider = ({ children }: { children: React.ReactNode }) => { fixedScale: 0, }); - const geojsonRef = useRef(); + const geojsonRef = useRef(null); const template = useMemo(() => { if (typeof templates[format][quality] !== 'undefined') { diff --git a/src/components/MlCreatePdfForm/lib/PdfForm.tsx b/src/components/MlCreatePdfForm/lib/PdfForm.tsx index 9114504bf..ec605ce96 100644 --- a/src/components/MlCreatePdfForm/lib/PdfForm.tsx +++ b/src/components/MlCreatePdfForm/lib/PdfForm.tsx @@ -104,7 +104,6 @@ export default function PdfForm(props: PdfFormProps) { const [loading, setLoading] = useState(false); const pdfContext = useContext(PdfContext); const mapHook = useMap({ - // eslint-disable-next-line react/prop-types mapId: props.mapId, }); const mapExporter = useExportMap({ mapId: props.mapId }); @@ -138,7 +137,6 @@ export default function PdfForm(props: PdfFormProps) { res.formData = new FormData( document.getElementById('createPdfFormID') as HTMLFormElement ); - console.log('testlog'); props.onCreatePdf(res); } setLoading(false); diff --git a/src/components/MlCreatePdfForm/lib/PdfPreview.tsx b/src/components/MlCreatePdfForm/lib/PdfPreview.tsx index 537c5da03..14ab873b1 100644 --- a/src/components/MlCreatePdfForm/lib/PdfPreview.tsx +++ b/src/components/MlCreatePdfForm/lib/PdfPreview.tsx @@ -81,7 +81,7 @@ function getMapZoomScaleModifier(point: [number, number], _map: MapType) { export default function PdfPreview(props: Props) { const mapState = useMapState({ mapId: props.mapId, watch: { layers: false, viewport: true } }); const targetRef = useRef(null); - const fixedScaleRef = useRef(); + const fixedScaleRef = useRef(null); const moveableRef = useRef(null); const mapContainerRef = useRef(document.querySelector('.mapContainer')); //const [transform, setTransform] = useState('translate(452.111px, 15.6148px)'); diff --git a/src/components/MlFeatureEditor/MlFeatureEditor.stories.tsx b/src/components/MlFeatureEditor/MlFeatureEditor.stories.tsx index 0ee9e8bfc..9568b88c6 100644 --- a/src/components/MlFeatureEditor/MlFeatureEditor.stories.tsx +++ b/src/components/MlFeatureEditor/MlFeatureEditor.stories.tsx @@ -101,7 +101,7 @@ const catalogueTemplate = () => { unmovableButtons={ <> - {configTitles[selectedMode]} + {(configTitles as {[key:string]: any})[selectedMode]}