diff --git a/package.json b/package.json index 51de8864..823ecadb 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@turf/line-offset": "^7.1.0", "@turf/line-slice": "^7.1.0", "@turf/simplify": "^7.1.0", + "@types/pannellum": "^2.5.0", "bootstrap": "^5.3.3", "color": "^4.2.3", "enzyme": "^3.11.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 24a0bd51..e1ed5389 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -74,6 +74,9 @@ importers: '@turf/simplify': specifier: ^7.1.0 version: 7.1.0 + '@types/pannellum': + specifier: ^2.5.0 + version: 2.5.0 bootstrap: specifier: ^5.3.3 version: 5.3.3(@popperjs/core@2.11.8) @@ -1672,6 +1675,9 @@ packages: '@types/node@22.7.9': resolution: {integrity: sha512-jrTfRC7FM6nChvU7X2KqcrgquofrWLFDeYC1hKfwNWomVvrn7JIksqf344WN2X/y8xrgqBd2dJATZV4GbatBfg==} + '@types/pannellum@2.5.0': + resolution: {integrity: sha512-iFVwMHmsTx91t74gU12bDmB1ty5lRgmfK6X+FxymQe8n0nuw3Pp/vk0nw73YdL9WqZgthrpf1KLPzQjZDUsj0g==} + '@types/pbf@3.0.5': resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==} @@ -7043,6 +7049,8 @@ snapshots: dependencies: undici-types: 6.19.8 + '@types/pannellum@2.5.0': {} + '@types/pbf@3.0.5': {} '@types/pica@9.0.4': {} diff --git a/src/components/AsyncComponent.tsx b/src/components/AsyncComponent.tsx index 3105e9e0..f609bf50 100644 --- a/src/components/AsyncComponent.tsx +++ b/src/components/AsyncComponent.tsx @@ -1,17 +1,35 @@ import { useLazy } from 'fm3/hooks/useLazy'; -import { ComponentType, ReactElement } from 'react'; +import { + ComponentType, + ReactElement, + FunctionComponent, + ComponentClass, + Attributes, +} from 'react'; -type Props = ComponentType> = - T extends ComponentType - ? { - factory: () => Promise<{ default: T }>; - } & P - : never; +type Factory = () => Promise<{ default: T }>; -export function AsyncComponent< - T extends ComponentType = ComponentType, ->({ factory, ...rest }: Props): ReactElement | null { - const Component = useLazy(factory) as any; // TODO type +// This madness has been created with help of ChatGPT: https://chatgpt.com/share/671bee06-98f0-8007-9924-8c153485614e - return Component ? : null; +/* Overload for FunctionComponent with specific props */ +export function AsyncComponent

( + props: { factory: Factory> } & P & Attributes, +): ReactElement | null; + +/* Overload for ComponentClass with specific props */ +export function AsyncComponent

( + props: { factory: Factory> } & P & Attributes, +): ReactElement | null; + +/* Implementation */ +export function AsyncComponent

( + props: { factory: Factory> } & P & Attributes, +): ReactElement | null { + const { factory, ...rest } = props; + + const Component = useLazy(factory); + + return !Component ? null : ( + + ); } diff --git a/src/components/DrawingPointsResult.tsx b/src/components/DrawingPointsResult.tsx index 099433d4..0273d2ef 100644 --- a/src/components/DrawingPointsResult.tsx +++ b/src/components/DrawingPointsResult.tsx @@ -7,11 +7,12 @@ import { selectFeature } from 'fm3/actions/mainActions'; import { colors } from 'fm3/constants'; import { useAppSelector } from 'fm3/hooks/reduxSelectHook'; import { selectingModeSelector } from 'fm3/selectors/mainSelectors'; -import { DragEndEvent } from 'leaflet'; +import { DragEndEvent, LeafletEvent } from 'leaflet'; import { ReactElement, useCallback, useMemo } from 'react'; import { Tooltip } from 'react-leaflet'; import { useDispatch } from 'react-redux'; import { RichMarker } from './RichMarker'; +import { is } from 'typia'; export function DrawingPointsResult(): ReactElement { const dispatch = useDispatch(); @@ -25,10 +26,19 @@ export function DrawingPointsResult(): ReactElement { ); const handleMove = useCallback( - // see https://github.com/PaulLeCam/react-leaflet/issues/981 - ({ latlng: { lat, lng: lon } }: any) => { - if (activeIndex !== null) { - dispatch(drawingPointChangePosition({ index: activeIndex, lat, lon })); + (e: LeafletEvent) => { + if ( + activeIndex !== null && + // see https://github.com/PaulLeCam/react-leaflet/issues/981 + is<{ latlng: { lat: number; lng: number } }>(e) + ) { + dispatch( + drawingPointChangePosition({ + index: activeIndex, + lat: e.latlng.lat, + lon: e.latlng.lng, + }), + ); dispatch(drawingMeasure({ elevation: false })); } diff --git a/src/components/DrawingPropertiesModal.tsx b/src/components/DrawingPropertiesModal.tsx index bc580973..4bc07287 100644 --- a/src/components/DrawingPropertiesModal.tsx +++ b/src/components/DrawingPropertiesModal.tsx @@ -329,7 +329,9 @@ export function DrawingEditLabelModal({ show }: Props): ReactElement { setEditedType(e.currentTarget.value as any)} + onChange={(e) => + setEditedType(e.currentTarget.value as 'polygon' | 'line') + } > diff --git a/src/components/Hotline.ts b/src/components/Hotline.ts index 6089c45f..05fd8085 100644 --- a/src/components/Hotline.ts +++ b/src/components/Hotline.ts @@ -1,8 +1,10 @@ import { createPathComponent, PathProps } from '@react-leaflet/core'; +import { LatLngExpression } from 'leaflet'; +import { Polyline } from 'leaflet'; import 'leaflet-hotline'; interface Props extends PathProps { - positions: (readonly [number, number, number])[]; + positions: LatLngExpression[]; outlineWidth: number; outlineColor?: string; palette: Record; @@ -11,17 +13,17 @@ interface Props extends PathProps { weight?: number; // TODO inherited from PathProps; should we actually extend from Path? } -export const Hotline = createPathComponent( +export const Hotline = createPathComponent( (props, context) => { return { - instance: (window['L'] as any).hotline(props.positions, props), + instance: (window.L as any).hotline(props.positions, props), context, }; }, (instance, props, prevProps) => { if (props.positions !== prevProps.positions) { - (instance as any).setLatLngs(props.positions); + instance.setLatLngs(props.positions); } }, ); diff --git a/src/components/Layers.tsx b/src/components/Layers.tsx index c79d1f7b..29f58f54 100644 --- a/src/components/Layers.tsx +++ b/src/components/Layers.tsx @@ -13,7 +13,7 @@ import { AsyncComponent } from './AsyncComponent'; const galleryLayerFactory = () => import('fm3/components/gallery/GalleryLayer'); -const maplibreLayerFactory = () => import('./MaplibreLayer') as any; +const maplibreLayerFactory = () => import('./MaplibreLayer'); export function Layers(): ReactElement | null { const overlays = useAppSelector((state) => state.map.overlays); @@ -140,7 +140,9 @@ export function Layers(): ReactElement | null { .filter(({ adminOnly }) => user?.isAdmin || !adminOnly) .map((item) => getTileLayer(item))} {customLayers - .filter(({ type }) => overlays.includes(type as any)) + .filter(({ type }) => + overlays.includes(type as (typeof overlays)[number]), + ) .map((cm) => getTileLayer(cm))} ); diff --git a/src/components/MapSettingsModal.tsx b/src/components/MapSettingsModal.tsx index 3cf523c2..0a2bd923 100644 --- a/src/components/MapSettingsModal.tsx +++ b/src/components/MapSettingsModal.tsx @@ -346,7 +346,9 @@ export function MapSettingsModal({ show }: Props): ReactElement { }} /> - {(overlayLetters.includes(selectedLayer as any) || + {(overlayLetters.includes( + selectedLayer as (typeof overlayLetters)[number], + ) || selectedLayer.charAt(0) === ':') && ( {m?.settings.overlayOpacity} diff --git a/src/components/MaplibreLayer.tsx b/src/components/MaplibreLayer.tsx index 1e2c65fb..fc1a81e9 100644 --- a/src/components/MaplibreLayer.tsx +++ b/src/components/MaplibreLayer.tsx @@ -2,6 +2,7 @@ import '@maplibre/maplibre-gl-leaflet'; import { createTileLayerComponent, LayerProps } from '@react-leaflet/core'; import 'fm3/maplibre-language'; import * as L from 'leaflet'; +import { Map } from 'maplibre-gl'; class MaplibreWithLang extends L.MaplibreGL { _language?: string | null; @@ -17,7 +18,9 @@ class MaplibreWithLang extends L.MaplibreGL { setLanguage(lang: string) { // this._language = lang; // unnnecessary - (this.getMaplibreMap() as any).setLanguage(lang); + ( + this.getMaplibreMap() as Map & { setLanguage: (lang: string) => void } + ).setLanguage(lang); } onAdd(map: L.Map) { diff --git a/src/components/RichMarker.tsx b/src/components/RichMarker.tsx index 51c8d780..0cfd700d 100644 --- a/src/components/RichMarker.tsx +++ b/src/components/RichMarker.tsx @@ -2,8 +2,9 @@ import { MarkerType } from 'fm3/actions/objectsActions'; import { colors } from 'fm3/constants'; import Leaflet, { BaseIconOptions, Icon } from 'leaflet'; import { CSSProperties, ReactElement, useEffect, useMemo, useRef } from 'react'; -import { createRoot } from 'react-dom/client'; +import { createRoot, Root } from 'react-dom/client'; import { Marker, MarkerProps } from 'react-leaflet'; +import { assertGuard } from 'typia'; const textStyle: CSSProperties = { fill: 'rgba(0, 0, 0, 0.5)', @@ -71,13 +72,19 @@ export function RichMarker({ export class MarkerLeafletIcon extends Icon< BaseIconOptions & { icon: ReactElement } > { - createIcon(oldIcon?: HTMLElement): HTMLElement { + createIcon(oldIcon?: HTMLElement & { _fm_root?: HTMLElement }): HTMLElement { const reuse = oldIcon?.tagName === 'DIV'; - const div = (reuse ? oldIcon : document.createElement('div')) as any; + const div = ( + reuse ? oldIcon : document.createElement('div') + ) as HTMLElement & { _fm_root?: Root }; if (!div._fm_root) { - (this as any)._setIconStyles(div, 'icon'); + assertGuard<{ _setIconStyles: (el: HTMLElement, str: string) => void }>( + this, + ); + + this._setIconStyles(div, 'icon'); div._fm_root = createRoot(div); @@ -90,7 +97,7 @@ export class MarkerLeafletIcon extends Icon< } createShadow(oldIcon?: HTMLElement): HTMLElement { - return oldIcon || (null as any as HTMLElement); + return oldIcon ?? document.createElement('div'); } } diff --git a/src/components/RoutePlannerMenu.tsx b/src/components/RoutePlannerMenu.tsx index 65d83e02..7e826595 100644 --- a/src/components/RoutePlannerMenu.tsx +++ b/src/components/RoutePlannerMenu.tsx @@ -27,10 +27,12 @@ import { TransportType, transportTypeDefs } from 'fm3/transportTypeDefs'; import { ChangeEvent, Children, + CSSProperties, FormEvent, forwardRef, Fragment, ReactElement, + ReactNode, SyntheticEvent, useCallback, useState, @@ -300,20 +302,28 @@ function IsochroneSettings() { ); } -const GraphopperModeMenu = forwardRef( +type Props = { children: ReactNode; style: CSSProperties; className: string }; + +const GraphopperModeMenu = forwardRef( ({ children, style, className }, ref) => { return (

{children} {Children.toArray(children) - .filter((item) => (item as any).props.active) + .filter( + (item): item is ReactElement => + item && + typeof item === 'object' && + 'props' in item && + item.props.active, + ) .map((item) => { return ( - - {(item as any).props.eventKey === 'roundtrip' ? ( + + {item.props.eventKey === 'roundtrip' ? ( - ) : (item as any).props.eventKey === 'isochrone' ? ( + ) : item.props.eventKey === 'isochrone' ? ( ) : null} @@ -379,7 +389,7 @@ export function RoutePlannerMenu(): ReactElement { break; - case 'convert-to-drawing': + case 'convert-to-drawing': { const tolerance = window.prompt(m?.general.simplifyPrompt, '50'); if (tolerance !== null) { @@ -392,6 +402,7 @@ export function RoutePlannerMenu(): ReactElement { } break; + } case 'toggle-milestones-km': dispatch(routePlannerToggleMilestones({ type: 'abs', toggle: true })); diff --git a/src/components/TrackViewerResult.tsx b/src/components/TrackViewerResult.tsx index 8bbc48f9..8970253c 100644 --- a/src/components/TrackViewerResult.tsx +++ b/src/components/TrackViewerResult.tsx @@ -15,7 +15,7 @@ import { useNumberFormat } from 'fm3/hooks/useNumberFormat'; import { useStartFinishPoints } from 'fm3/hooks/useStartFinishPoints'; import { selectingModeSelector } from 'fm3/selectors/mainSelectors'; import { Feature, FeatureCollection, LineString, Point } from 'geojson'; -import { Point as LPoint } from 'leaflet'; +import { LatLngExpression, Point as LPoint } from 'leaflet'; import { Fragment, ReactElement, useState } from 'react'; import { FaFlag, FaInfo, FaPlay, FaStop } from 'react-icons/fa'; import { Polyline, Tooltip } from 'react-leaflet'; @@ -52,9 +52,7 @@ export function TrackViewerResult({ const [infoDistanceKm] = useState(); const getFeatures: GetFeatures = (type: 'LineString' | 'Point') => - turfFlatten(trackGeojson as any).features.filter( - (f) => f.geometry?.type === type, - ) as any; + turfFlatten(trackGeojson).features.filter((f) => f.geometry?.type === type); const getColorLineDataForElevation = () => getFeatures('LineString').map((feature) => { @@ -66,10 +64,10 @@ export function TrackViewerResult({ const minEle = Math.min(...eles); - return smoothed.map((coord) => { + return smoothed.map((coord): LatLngExpression => { const color = (coord[2] - minEle) / (maxEle - minEle); - return [coord[1], coord[0], color || 0] as const; + return [coord[1], coord[0], color || 0]; }); }); @@ -79,7 +77,7 @@ export function TrackViewerResult({ let prevCoord = smoothed[0]; - return smoothed.map((coord) => { + return smoothed.map((coord): LatLngExpression => { const [lon, lat, ele] = coord; const d = distance([lon, lat], prevCoord, { units: 'meters' }); @@ -94,7 +92,7 @@ export function TrackViewerResult({ const color = angle / 0.5 + 0.5; - return [lat, lon, color || 0] as const; + return [lat, lon, color || 0]; }); }); diff --git a/src/components/WikiLayer.tsx b/src/components/WikiLayer.tsx index 0ed7cdfb..d3ea3655 100644 --- a/src/components/WikiLayer.tsx +++ b/src/components/WikiLayer.tsx @@ -13,6 +13,7 @@ import { createRoot } from 'react-dom/client'; import { FaExternalLinkAlt, FaTimes, FaWikipediaW } from 'react-icons/fa'; import { Marker, Tooltip } from 'react-leaflet'; import { useDispatch } from 'react-redux'; +import { assertGuard } from 'typia'; class WikiIcon extends Icon { static template: ChildNode | undefined; @@ -22,7 +23,11 @@ class WikiIcon extends Icon { const div = oldIcon && reuse ? oldIcon : document.createElement('div'); - (this as any)._setIconStyles(div, 'icon'); + assertGuard<{ _setIconStyles: (el: HTMLElement, str: string) => void }>( + this, + ); + + this._setIconStyles(div, 'icon'); if (WikiIcon.template) { div.appendChild(WikiIcon.template.cloneNode()); @@ -38,7 +43,7 @@ class WikiIcon extends Icon { } createShadow(oldIcon?: HTMLElement) { - return oldIcon || (null as any as HTMLElement); + return oldIcon ?? document.createElement('div'); } } diff --git a/src/components/gallery/GalleryEditForm.tsx b/src/components/gallery/GalleryEditForm.tsx index 8ea26a53..fc9a1d01 100644 --- a/src/components/gallery/GalleryEditForm.tsx +++ b/src/components/gallery/GalleryEditForm.tsx @@ -44,7 +44,7 @@ export function GalleryEditForm({ const m = useMessages(); const changeModel = useCallback( - (key: keyof PictureModel, value: any) => { + (key: keyof PictureModel, value: unknown) => { onModelChange({ ...model, [key]: value }); }, [model, onModelChange], diff --git a/src/components/gallery/GalleryViewerModal.tsx b/src/components/gallery/GalleryViewerModal.tsx index d54b6ab7..9520207a 100644 --- a/src/components/gallery/GalleryViewerModal.tsx +++ b/src/components/gallery/GalleryViewerModal.tsx @@ -172,22 +172,24 @@ export function GalleryViewerModal({ show }: Props): ReactElement { const panoRef = useRef(null); useEffect(() => { - if (p) { - const v = window.pannellum.viewer(panoRef.current, { - panorama: `${process.env['API_URL']}/gallery/pictures/${activeImageId}/image`, - type: 'equirectangular', - autoLoad: true, - showControls: false, - autoRotate: 15, - autoRotateInactivityDelay: 60000, - // compass: true, - // title: 'panorama', - }); - - return () => { - v.destroy(); - }; + if (!p || !panoRef.current) { + return; } + + const v = window.pannellum.viewer(panoRef.current, { + panorama: `${process.env['API_URL']}/gallery/pictures/${activeImageId}/image`, + type: 'equirectangular', + autoLoad: true, + showControls: false, + autoRotate: 15, + autoRotateInactivityDelay: 60000, + // compass: true, + // title: 'panorama', + }); + + return () => { + v.destroy(); + }; }, [p, activeImageId]); const handleFullscreen = useCallback(() => { diff --git a/src/components/gallery/galleryTileRenderrer.ts b/src/components/gallery/galleryTileRenderrer.ts index 78a249a7..85a4dfdb 100644 --- a/src/components/gallery/galleryTileRenderrer.ts +++ b/src/components/gallery/galleryTileRenderrer.ts @@ -52,7 +52,7 @@ export function renderGalleryTile({ pointB, pointA, }: Props): void { - const ctx = (tile as any).getContext('2d'); + const ctx = tile.getContext('2d'); if (!ctx) { throw Error('no context'); diff --git a/src/hooks/usePictureDropHandler.ts b/src/hooks/usePictureDropHandler.ts index 847364e6..0c2a200e 100644 --- a/src/hooks/usePictureDropHandler.ts +++ b/src/hooks/usePictureDropHandler.ts @@ -1,4 +1,4 @@ -import ExifReader from 'exifreader'; +import ExifReader, { Tags } from 'exifreader'; import { GalleryItem } from 'fm3/actions/galleryActions'; import { latLonToString } from 'fm3/geoutils'; import pica from 'pica'; @@ -70,14 +70,14 @@ export function usePictureDropHandler( }; reader.onload = () => { - let tags: { [key: string]: any }; + let tags: Tags; try { tags = ExifReader.load(reader.result as ArrayBuffer); } catch (e) { console.error(e); - tags = {}; + tags = {} as Tags; } const keywords: string[] = []; @@ -100,37 +100,43 @@ export function usePictureDropHandler( const description = ( tags['description']?.description || - tags['ImageDescription']?.description || + tags.ImageDescription?.description || '' ).trim(); - const takenAtRaw = tags['DateTimeOriginal'] || tags['DateTime']; + const takenAtRaw = tags.DateTimeOriginal || tags.DateTime; - const [rawLat, latRef] = adaptGpsCoordinate(tags['GPSLatitude']); + const [rawLat, latRef] = adaptGpsCoordinate( + tags.GPSLatitude as WeirdGpsCoordinate, + ); const NS: Record = { S: -1, N: 1 }; const lat = rawLat * (NS[ - ( + String( latRef || - (tags['GPSLatitudeRef'] || { value: [] }).value[0] || - '' + ((tags.GPSLatitudeRef as { value: string[] }) ?? { value: [] }) + .value[0] || + '', ).toUpperCase() ] || Number.NaN); - const [rawLon, lonRef] = adaptGpsCoordinate(tags['GPSLongitude']); + const [rawLon, lonRef] = adaptGpsCoordinate( + tags.GPSLongitude as WeirdGpsCoordinate, + ); const EW: Record = { W: -1, E: 1 }; const lon = rawLon * (EW[ - ( + String( lonRef || - (tags['GPSLongitudeRef'] || { value: [] }).value[0] || - '' + ((tags.GPSLongitudeRef as { value: string[] }) ?? { value: [] }) + .value[0] || + '', ).toUpperCase() ] || Number.NaN); @@ -147,7 +153,8 @@ export function usePictureDropHandler( '' ).trim(), description: /CAMERA|^DCIM/.test(description) ? '' : description, - takenAt: takenAtRaw && parseExifDateTime(takenAtRaw.description), + takenAt: + (takenAtRaw && parseExifDateTime(takenAtRaw.description)) ?? null, tags: keywords, errors: [], }); @@ -188,11 +195,13 @@ export function usePictureDropHandler( ); } -// adds support for Olympus and other weirdos -function adaptGpsCoordinate(x: { +type WeirdGpsCoordinate = { description: string | number; value: string; -}) { +}; + +// adds support for Olympus and other weirdos +function adaptGpsCoordinate(x: WeirdGpsCoordinate) { if (x) { if (typeof x.description === 'number') { return [x.description]; diff --git a/src/httpRequest.ts b/src/httpRequest.ts index fcfbd56e..fda5d270 100644 --- a/src/httpRequest.ts +++ b/src/httpRequest.ts @@ -107,7 +107,7 @@ export async function httpRequest({ init, ); } catch (err) { - (err as any)._fm_fetchError = true; + (err as { _fm_fetchError: boolean })._fm_fetchError = true; throw err; } diff --git a/src/locationChangeHandler.ts b/src/locationChangeHandler.ts index 4d865208..b539a23e 100644 --- a/src/locationChangeHandler.ts +++ b/src/locationChangeHandler.ts @@ -92,7 +92,7 @@ export function handleLocationChange(store: MyStore, location: Location): void { const search = (document.location.hash || document.location.search).slice(1); - const { sq } = (history.location.state as any) ?? { + const { sq } = (history.location.state as { sq: string }) ?? { sq: undefined, }; @@ -335,6 +335,7 @@ export function handleLocationChange(store: MyStore, location: Location): void { key === 'line' || key === 'polygon' ) { + // eslint-disable-next-line no-control-regex const m = /([^;\x1e]*)([;\x1e].*)?/.exec(value); if (!m) { @@ -454,7 +455,7 @@ export function handleLocationChange(store: MyStore, location: Location): void { if (newCls.length) { for (const cm of newCls) { - if ((cm as any).tileSize) { + if ('tileSize' in cm && cm.tileSize) { cm.scaleWithDpi = true; } } diff --git a/src/maplibre-language.ts b/src/maplibre-language.ts index 89299e3e..95c75c9e 100644 --- a/src/maplibre-language.ts +++ b/src/maplibre-language.ts @@ -1,6 +1,8 @@ import { Map } from 'maplibre-gl'; -(Map.prototype as any).setLanguage = function (language: string) { +( + Map.prototype as Map & { setLanguage: (language: string) => void } +).setLanguage = function (language: string) { const setLanguage = () => { const replacer = [ 'case', diff --git a/src/processors/urlProcessor.ts b/src/processors/urlProcessor.ts index 680bcb13..53e563d2 100644 --- a/src/processors/urlProcessor.ts +++ b/src/processors/urlProcessor.ts @@ -365,7 +365,7 @@ export const urlProcessor: Processor = { const urlSearch = serializeQuery(queryParts); if ( - (mapId && sq !== (history.location.state as any)?.sq) || + (mapId && sq !== (history.location.state as { sq: string })?.sq) || urlSearch !== window.location.hash.slice(1) ) { const method = diff --git a/src/reducers/galleryReducer.ts b/src/reducers/galleryReducer.ts index 650385fe..d73bbc80 100644 --- a/src/reducers/galleryReducer.ts +++ b/src/reducers/galleryReducer.ts @@ -230,7 +230,7 @@ export const galleryReducer = createReducer( return s; }) .handleAction(gallerySetItemForPositionPicking, (state, action) => { - let x: GalleryItem | undefined; + let x; return { ...state, @@ -241,7 +241,8 @@ export const galleryReducer = createReducer( ? safeParseCoordinates(state.editModel.dirtyPosition) : null : typeof action.payload === 'number' - ? (x = state.items.find(({ id }) => id === action.payload)) + ? // eslint-disable-next-line no-cond-assign + (x = state.items.find(({ id }) => id === action.payload)) ? safeParseCoordinates(x.dirtyPosition) : null : null, diff --git a/src/translations/messagesInterface.ts b/src/translations/messagesInterface.ts index 3b7eb837..6869a23d 100644 --- a/src/translations/messagesInterface.ts +++ b/src/translations/messagesInterface.ts @@ -1,3 +1,4 @@ +import { Changeset } from 'fm3/actions/changesetsActions'; import { RoutingMode, Weighting } from 'fm3/actions/routePlannerActions'; import { ElevationInfoBaseProps } from 'fm3/components/ElevationInfo'; import { HttpError } from 'fm3/httpRequest'; @@ -509,7 +510,7 @@ export type Messages = { olderThanFull: ({ days }: { days: number }) => string; notFound: string; fetchError: ({ err }: Err) => string; - detail: ({ changeset }: { changeset: any }) => JSX.Element; + detail: ({ changeset }: { changeset: Changeset }) => JSX.Element; details: { author: string; description: string; @@ -857,7 +858,7 @@ export function addError( (err.body ? ': ' + err.body : '') : !(err instanceof Error) ? String(err) - : (err as any)._fm_fetchError + : (err as Error & { _fm_fetchError: boolean })._fm_fetchError ? ((window.navigator.onLine === false ? messages.general.offline : messages.general.connectionError) ?? err.message) diff --git a/src/types/common.ts b/src/types/common.ts index 39fc3a07..adbaf9b9 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -46,8 +46,6 @@ declare global { fmHeadless?: { searchResultStyle?: PathOptions; }; - pannellum: any; - Sentry: typeof Sentry; } diff --git a/webpack.config.js b/webpack.config.js index b73b2280..b674f9fc 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -319,10 +319,11 @@ module.exports = { /intl\/locale-data\/jsonp$/, /(sk|cs|en)\.tsx/, ), - prod && - new ESLintPlugin({ - extensions: ['js', 'jsx', 'ts', 'tsx'], - threads: 4, - }), + // TODO + // prod && + // new ESLintPlugin({ + // extensions: ['js', 'jsx', 'ts', 'tsx'], + // threads: 4, + // }), ].filter(Boolean), };