mirror of
https://github.com/Hypfer/Valetudo.git
synced 2025-10-26 11:27:27 +00:00
chore: Remove prettier
This commit is contained in:
parent
abd6345458
commit
71bd3dd6f3
5
.github/.prettierrc.yml
vendored
5
.github/.prettierrc.yml
vendored
@ -1,5 +0,0 @@
|
||||
---
|
||||
trailingComma: es5
|
||||
tabWidth: 2
|
||||
semi: true
|
||||
singleQuote: true
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
trailingComma: es5
|
||||
tabWidth: 4
|
||||
semi: true
|
||||
singleQuote: false
|
||||
@ -7,8 +7,7 @@
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:react-hooks/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"plugins": [
|
||||
"react",
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
trailingComma: es5
|
||||
tabWidth: 4
|
||||
semi: true
|
||||
singleQuote: true
|
||||
@ -65,11 +65,9 @@
|
||||
"@typescript-eslint/parser": "4.28.3",
|
||||
"cra-build-watch": "^3.4.0",
|
||||
"eslint": "7.31.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-react": "7.24.0",
|
||||
"eslint-plugin-react-hooks": "4.2.0",
|
||||
"miragejs": "0.1.41",
|
||||
"prettier": "2.3.2",
|
||||
"source-map-explorer": "2.5.2",
|
||||
"typescript": "4.2.4"
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import React from 'react';
|
||||
import {createTheme, CssBaseline, ThemeProvider,} from '@material-ui/core';
|
||||
import AdapterDateFns from '@material-ui/lab/AdapterDateFns';
|
||||
import LocalizationProvider from '@material-ui/lab/LocalizationProvider';
|
||||
import AppRouter from './AppRouter';
|
||||
import CapabilitiesProvider from './CapabilitiesProvider';
|
||||
import {SnackbarProvider} from 'notistack';
|
||||
import {QueryClient, QueryClientProvider} from 'react-query';
|
||||
import {ReactQueryDevtools} from 'react-query/devtools';
|
||||
import React from "react";
|
||||
import {createTheme, CssBaseline, ThemeProvider,} from "@material-ui/core";
|
||||
import AdapterDateFns from "@material-ui/lab/AdapterDateFns";
|
||||
import LocalizationProvider from "@material-ui/lab/LocalizationProvider";
|
||||
import AppRouter from "./AppRouter";
|
||||
import CapabilitiesProvider from "./CapabilitiesProvider";
|
||||
import {SnackbarProvider} from "notistack";
|
||||
import {QueryClient, QueryClientProvider} from "react-query";
|
||||
import {ReactQueryDevtools} from "react-query/devtools";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
@ -17,18 +17,18 @@ const App = (): JSX.Element => {
|
||||
() => {
|
||||
return createTheme({
|
||||
palette: {
|
||||
mode: /*prefersDarkMode ? */ 'dark' /*: 'light' */,
|
||||
mode: /*prefersDarkMode ? */ "dark" /*: 'light' */,
|
||||
},
|
||||
map: {
|
||||
floor: '#0076FF',
|
||||
wall: '#242424',
|
||||
segment: ['#19A1A1', '#7AC037', '#DF5618', '#F7C841', '#9966CC'],
|
||||
path: '#050505',
|
||||
noGo: {stroke: '#FF0000', fill: '#75000066'},
|
||||
noMop: {stroke: '#CC00FF', fill: '#58006E66'},
|
||||
active: {stroke: '#35911A', fill: '#6AF5424C'},
|
||||
floor: "#0076FF",
|
||||
wall: "#242424",
|
||||
segment: ["#19A1A1", "#7AC037", "#DF5618", "#F7C841", "#9966CC"],
|
||||
path: "#050505",
|
||||
noGo: {stroke: "#FF0000", fill: "#75000066"},
|
||||
noMop: {stroke: "#CC00FF", fill: "#58006E66"},
|
||||
active: {stroke: "#35911A", fill: "#6AF5424C"},
|
||||
},
|
||||
})
|
||||
});
|
||||
},
|
||||
[/*prefersDarkMode*/]
|
||||
);
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import {HashRouter, Redirect, Route, Switch} from 'react-router-dom';
|
||||
import Div100vh from 'react-div-100vh';
|
||||
import HomePage from './HomePage';
|
||||
import SettingsRouter from './settings';
|
||||
import {styled} from '@material-ui/core';
|
||||
import {HashRouter, Redirect, Route, Switch} from "react-router-dom";
|
||||
import Div100vh from "react-div-100vh";
|
||||
import HomePage from "./HomePage";
|
||||
import SettingsRouter from "./settings";
|
||||
import {styled} from "@material-ui/core";
|
||||
|
||||
const Root = styled(Div100vh)({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
});
|
||||
|
||||
const Content = styled('main')({
|
||||
flex: '1',
|
||||
display: 'flex',
|
||||
overflow: 'auto',
|
||||
const Content = styled("main")({
|
||||
flex: "1",
|
||||
display: "flex",
|
||||
overflow: "auto",
|
||||
});
|
||||
|
||||
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
import {Backdrop, Button, CircularProgress, styled, Typography,} from '@material-ui/core';
|
||||
import {SnackbarKey, useSnackbar} from 'notistack';
|
||||
import React from 'react';
|
||||
import {Capability, useCapabilitiesQuery} from './api';
|
||||
import {Backdrop, Button, CircularProgress, styled, Typography,} from "@material-ui/core";
|
||||
import {SnackbarKey, useSnackbar} from "notistack";
|
||||
import React from "react";
|
||||
import {Capability, useCapabilitiesQuery} from "./api";
|
||||
|
||||
const StyledBackdrop = styled(Backdrop)(({theme}) => {return {
|
||||
zIndex: theme.zIndex.drawer + 1,
|
||||
color: '#fff',
|
||||
display: 'flex',
|
||||
flexFlow: 'column',
|
||||
}});
|
||||
const StyledBackdrop = styled(Backdrop)(({theme}) => {
|
||||
return {
|
||||
zIndex: theme.zIndex.drawer + 1,
|
||||
color: "#fff",
|
||||
display: "flex",
|
||||
flexFlow: "column",
|
||||
};
|
||||
});
|
||||
|
||||
const Context = React.createContext<Capability[]>([]);
|
||||
|
||||
@ -38,26 +40,29 @@ const CapabilitiesProvider = (props: {
|
||||
return;
|
||||
}
|
||||
|
||||
const SnackbarAction = () => {return (
|
||||
<Button
|
||||
onClick={() => {
|
||||
refetchCapabilities({throwOnError: true}).then(() =>
|
||||
{return enqueueSnackbar('Succesfully loaded capabilities!', {
|
||||
variant: 'success',
|
||||
})}
|
||||
);
|
||||
}}
|
||||
>
|
||||
const SnackbarAction = () => {
|
||||
return (
|
||||
<Button
|
||||
onClick={() => {
|
||||
refetchCapabilities({throwOnError: true}).then(() => {
|
||||
return enqueueSnackbar("Succesfully loaded capabilities!", {
|
||||
variant: "success",
|
||||
});
|
||||
}
|
||||
);
|
||||
}}
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
)};
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
if (snackbarKey.current) {
|
||||
closeSnackbar(snackbarKey.current);
|
||||
}
|
||||
|
||||
snackbarKey.current = enqueueSnackbar('Error while loading capabilities', {
|
||||
variant: 'error',
|
||||
snackbarKey.current = enqueueSnackbar("Error while loading capabilities", {
|
||||
variant: "error",
|
||||
action: SnackbarAction,
|
||||
persist: true,
|
||||
});
|
||||
@ -68,7 +73,7 @@ const CapabilitiesProvider = (props: {
|
||||
<StyledBackdrop
|
||||
open={capabilitiesLoading}
|
||||
style={{
|
||||
transitionDelay: capabilitiesLoading ? '800ms' : '0ms',
|
||||
transitionDelay: capabilitiesLoading ? "800ms" : "0ms",
|
||||
}}
|
||||
unmountOnExit
|
||||
>
|
||||
@ -85,8 +90,9 @@ export const useCapabilitiesSupported = (
|
||||
): boolean[] => {
|
||||
const supportedCapabilities = React.useContext(Context);
|
||||
|
||||
return capabilities.map((capability) =>
|
||||
{return supportedCapabilities.includes(capability)}
|
||||
return capabilities.map((capability) => {
|
||||
return supportedCapabilities.includes(capability);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import {Box, Divider, Grid, styled} from '@material-ui/core';
|
||||
import ControlsBody from './controls';
|
||||
import ControlsBottomSheet from './controls/ControlsBottomSheet';
|
||||
import {useIsMobileView} from './hooks';
|
||||
import MapPage from './map';
|
||||
import {Box, Divider, Grid, styled} from "@material-ui/core";
|
||||
import ControlsBody from "./controls";
|
||||
import ControlsBottomSheet from "./controls/ControlsBottomSheet";
|
||||
import {useIsMobileView} from "./hooks";
|
||||
import MapPage from "./map";
|
||||
|
||||
const RootGrid = styled(Grid)({
|
||||
height: '100%',
|
||||
flexWrap: 'nowrap',
|
||||
height: "100%",
|
||||
flexWrap: "nowrap",
|
||||
});
|
||||
const ScrollableGrid = styled(Grid)({
|
||||
overflow: 'auto',
|
||||
overflow: "auto",
|
||||
});
|
||||
|
||||
const HomePage = (): JSX.Element => {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import axios from 'axios';
|
||||
import { RawMapData } from './RawMapData';
|
||||
import { PresetSelectionState, RobotAttribute } from './RawRobotState';
|
||||
import axios from "axios";
|
||||
import { RawMapData } from "./RawMapData";
|
||||
import { PresetSelectionState, RobotAttribute } from "./RawRobotState";
|
||||
import {
|
||||
Capability,
|
||||
GitHubRelease,
|
||||
@ -18,11 +18,11 @@ import {
|
||||
Zone,
|
||||
ZonePreset,
|
||||
ZoneProperties,
|
||||
} from './types';
|
||||
import { floorObject } from './utils';
|
||||
} from "./types";
|
||||
import { floorObject } from "./utils";
|
||||
|
||||
export const valetudoAPI = axios.create({
|
||||
baseURL: `../api/v2`,
|
||||
baseURL: "../api/v2",
|
||||
});
|
||||
|
||||
const SSETracker = new Map<string, () => () => void>();
|
||||
@ -203,9 +203,9 @@ export const fetchMapSegmentationProperties = async (): Promise<MapSegmentationP
|
||||
`/robot/capabilities/${Capability.MapSegmentation}/properties`
|
||||
)
|
||||
.then(({data}) => {
|
||||
return data
|
||||
return data;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const sendCleanSegmentsCommand = async (
|
||||
parameters: MapSegmentationActionRequestParameters
|
||||
@ -249,14 +249,14 @@ export const sendLocateCommand = async (): Promise<void> => {
|
||||
};
|
||||
|
||||
export const fetchRobotInformation = async (): Promise<RobotInformation> => {
|
||||
return valetudoAPI.get<RobotInformation>(`/robot`).then(({data}) => {
|
||||
return valetudoAPI.get<RobotInformation>("/robot").then(({data}) => {
|
||||
return data;
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchValetudoInformation = async (): Promise<ValetudoVersion> => {
|
||||
return valetudoAPI
|
||||
.get<ValetudoVersion>(`/valetudo/version`)
|
||||
.get<ValetudoVersion>("/valetudo/version")
|
||||
.then(({data}) => {
|
||||
return data;
|
||||
});
|
||||
@ -264,7 +264,7 @@ export const fetchValetudoInformation = async (): Promise<ValetudoVersion> => {
|
||||
|
||||
export const fetchSystemHostInfo = async (): Promise<SystemHostInfo> => {
|
||||
return valetudoAPI
|
||||
.get<SystemHostInfo>(`/system/host/info`)
|
||||
.get<SystemHostInfo>("/system/host/info")
|
||||
.then(({data}) => {
|
||||
return data;
|
||||
});
|
||||
@ -288,7 +288,7 @@ export const fetchLatestGitHubRelease = async (): Promise<GitHubRelease> => {
|
||||
};
|
||||
|
||||
export const fetchTimerInformation = async (): Promise<TimerInformation> => {
|
||||
return valetudoAPI.get<TimerInformation>(`/timers`).then(({ data }) => {
|
||||
return valetudoAPI.get<TimerInformation>("/timers").then(({ data }) => {
|
||||
return data;
|
||||
});
|
||||
};
|
||||
@ -298,9 +298,9 @@ export const deleteTimer = async (id: string): Promise<void> => {
|
||||
};
|
||||
|
||||
export const sendTimerCreation = async (timerData: Timer): Promise<void> => {
|
||||
await valetudoAPI.post(`/timers`, timerData).then(({ status }) => {
|
||||
await valetudoAPI.post("/timers", timerData).then(({ status }) => {
|
||||
if (status !== 201) {
|
||||
throw new Error('Could not create timer');
|
||||
throw new Error("Could not create timer");
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -310,14 +310,14 @@ export const sendTimerUpdate = async (timerData: Timer): Promise<void> => {
|
||||
.post(`/timers/${timerData.id}`, timerData)
|
||||
.then(({ status }) => {
|
||||
if (status !== 200) {
|
||||
throw new Error('Could not update timer');
|
||||
throw new Error("Could not update timer");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchTimerProperties = async (): Promise<TimerProperties> => {
|
||||
return valetudoAPI
|
||||
.get<TimerProperties>(`/timers/properties`)
|
||||
.get<TimerProperties>("/timers/properties")
|
||||
.then(({ data }) => {
|
||||
return data;
|
||||
});
|
||||
|
||||
@ -166,9 +166,9 @@ export const capabilityToPresetType: Record<
|
||||
Parameters<typeof usePresetSelectionMutation>[0],
|
||||
PresetSelectionState["type"]
|
||||
> = {
|
||||
[Capability.FanSpeedControl]: "fan_speed",
|
||||
[Capability.WaterUsageControl]: "water_grade",
|
||||
};
|
||||
[Capability.FanSpeedControl]: "fan_speed",
|
||||
[Capability.WaterUsageControl]: "water_grade",
|
||||
};
|
||||
export const usePresetSelectionMutation = (
|
||||
capability: Capability.FanSpeedControl | Capability.WaterUsageControl
|
||||
) => {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
export * from './hooks';
|
||||
export * from './RawMapData';
|
||||
export * from './RawRobotState';
|
||||
export * from './types';
|
||||
export * from './client';
|
||||
export * from "./hooks";
|
||||
export * from "./RawMapData";
|
||||
export * from "./RawRobotState";
|
||||
export * from "./types";
|
||||
export * from "./client";
|
||||
|
||||
@ -33,37 +33,37 @@ const RatioBar: FunctionComponent<RatioBarProps> = (props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className={styles.ratioBarBase}>
|
||||
{mappedPartitions.reverse().map((mp, i) => {
|
||||
return (
|
||||
<span
|
||||
key={"bar." + i}
|
||||
className={styles.ratioBarContent}
|
||||
style={{
|
||||
transform: `translateX(${-100 + mp.totalPercent}%)`,
|
||||
backgroundColor: mp.color,
|
||||
}}
|
||||
>
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</span>
|
||||
<span>
|
||||
{mappedPartitions.reverse().map((mp, i) => {
|
||||
return (
|
||||
<span
|
||||
key={"legend." + i}
|
||||
style={{
|
||||
paddingRight: "5px",
|
||||
fontSize: "0.75rem",
|
||||
color: "rgba(255, 255, 255, 0.7)",
|
||||
}}
|
||||
>
|
||||
<span style={{ color: mp.color }}>●</span> {mp.label}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</span>
|
||||
<span className={styles.ratioBarBase}>
|
||||
{mappedPartitions.reverse().map((mp, i) => {
|
||||
return (
|
||||
<span
|
||||
key={"bar." + i}
|
||||
className={styles.ratioBarContent}
|
||||
style={{
|
||||
transform: `translateX(${-100 + mp.totalPercent}%)`,
|
||||
backgroundColor: mp.color,
|
||||
}}
|
||||
>
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</span>
|
||||
<span>
|
||||
{mappedPartitions.reverse().map((mp, i) => {
|
||||
return (
|
||||
<span
|
||||
key={"legend." + i}
|
||||
style={{
|
||||
paddingRight: "5px",
|
||||
fontSize: "0.75rem",
|
||||
color: "rgba(255, 255, 255, 0.7)",
|
||||
}}
|
||||
>
|
||||
<span style={{ color: mp.color }}>●</span> {mp.label}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -47,7 +47,7 @@ const BasicControls = (): JSX.Element => {
|
||||
const {
|
||||
mutate: executeBasicControlCommand,
|
||||
isLoading: basicControlIsExecuting
|
||||
} = useBasicControlMutation();
|
||||
} = useBasicControlMutation();
|
||||
const [locateSupported] = useCapabilitiesSupported(Capability.Locate);
|
||||
const {
|
||||
mutate: locate,
|
||||
|
||||
@ -38,9 +38,9 @@ const Segments = (): JSX.Element => {
|
||||
isLoading: cleanSegmentsIsExecuting,
|
||||
mutate: cleanSegments
|
||||
} = useCleanSegmentsMutation({
|
||||
onSuccess() {
|
||||
setSelected({});
|
||||
},
|
||||
onSuccess() {
|
||||
setSelected({});
|
||||
},
|
||||
});
|
||||
const [selected, setSelected] = React.useState<Record<string, boolean>>({});
|
||||
const isLoading = segmentsLoading || cleanSegmentsIsExecuting;
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
import ControlsBody from './ControlsBody';
|
||||
import ControlsBody from "./ControlsBody";
|
||||
|
||||
export default ControlsBody;
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
export * from './useHTMLElement';
|
||||
export * from './useForkRef';
|
||||
export * from './useIsMobileView';
|
||||
export * from "./useHTMLElement";
|
||||
export * from "./useForkRef";
|
||||
export * from "./useIsMobileView";
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
import ReactDOM from "react-dom";
|
||||
import App from "./App";
|
||||
|
||||
ReactDOM.render(<App/>, document.getElementById('root'));
|
||||
ReactDOM.render(<App/>, document.getElementById("root"));
|
||||
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import {ThemeProvider, useTheme} from '@material-ui/core';
|
||||
import Konva from 'konva';
|
||||
import {KonvaEventObject} from 'konva/lib/Node';
|
||||
import React from 'react';
|
||||
import {Layer} from 'react-konva';
|
||||
import {useForkRef} from '../hooks';
|
||||
import MapStage, {MapStageProps, MapStageRef} from './MapStage';
|
||||
import {ChipShape, PixelsShape} from './shapes';
|
||||
import {ThemeProvider, useTheme} from "@material-ui/core";
|
||||
import Konva from "konva";
|
||||
import {KonvaEventObject} from "konva/lib/Node";
|
||||
import React from "react";
|
||||
import {Layer} from "react-konva";
|
||||
import {useForkRef} from "../hooks";
|
||||
import MapStage, {MapStageProps, MapStageRef} from "./MapStage";
|
||||
import {ChipShape, PixelsShape} from "./shapes";
|
||||
|
||||
export interface MapLayer {
|
||||
id: string;
|
||||
@ -41,25 +41,33 @@ const Map = React.forwardRef<MapStageRef | null, MapProps>(
|
||||
stageRef.current?.redraw();
|
||||
}, [entities]);
|
||||
|
||||
const stageProps = React.useMemo<Omit<MapStageProps, 'children'>>(() => {
|
||||
const stageProps = React.useMemo<Omit<MapStageProps, "children">>(() => {
|
||||
const minX = Math.min(
|
||||
...layers.map(
|
||||
({dimensions, pixelSize: scale}) => {return dimensions.x[0] * scale}
|
||||
({dimensions, pixelSize: scale}) => {
|
||||
return dimensions.x[0] * scale;
|
||||
}
|
||||
)
|
||||
);
|
||||
const maxX = Math.max(
|
||||
...layers.map(
|
||||
({dimensions, pixelSize: scale}) => {return dimensions.x[1] * scale}
|
||||
({dimensions, pixelSize: scale}) => {
|
||||
return dimensions.x[1] * scale;
|
||||
}
|
||||
)
|
||||
);
|
||||
const minY = Math.min(
|
||||
...layers.map(
|
||||
({dimensions, pixelSize: scale}) => {return dimensions.y[0] * scale}
|
||||
({dimensions, pixelSize: scale}) => {
|
||||
return dimensions.y[0] * scale;
|
||||
}
|
||||
)
|
||||
);
|
||||
const maxY = Math.max(
|
||||
...layers.map(
|
||||
({dimensions, pixelSize: scale}) => {return dimensions.y[1] * scale}
|
||||
({dimensions, pixelSize: scale}) => {
|
||||
return dimensions.y[1] * scale;
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
@ -108,21 +116,23 @@ const Map = React.forwardRef<MapStageRef | null, MapProps>(
|
||||
*/}
|
||||
<ThemeProvider theme={theme}>
|
||||
<Layer>
|
||||
{layers.map(({pixels, color, id, pixelSize}) => {return (
|
||||
<PixelsShape
|
||||
key={id}
|
||||
pixels={pixels}
|
||||
pixelSize={pixelSize}
|
||||
fill={color}
|
||||
/>
|
||||
)})}
|
||||
{layers.map(({pixels, color, id, pixelSize}) => {
|
||||
return (
|
||||
<PixelsShape
|
||||
key={id}
|
||||
pixels={pixels}
|
||||
pixelSize={pixelSize}
|
||||
fill={color}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{entities}
|
||||
{labels.map(({text, position, icon}) => {
|
||||
const [x, y] = position;
|
||||
|
||||
return (
|
||||
<ChipShape
|
||||
key={`${text}:${position.join(',')}`}
|
||||
key={`${text}:${position.join(",")}`}
|
||||
text={text}
|
||||
x={x}
|
||||
y={y}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import {Box, Button, CircularProgress, styled, Typography,} from '@material-ui/core';
|
||||
import {useRobotMapQuery} from '../api';
|
||||
import MapLayers from './layers';
|
||||
import {Box, Button, CircularProgress, styled, Typography,} from "@material-ui/core";
|
||||
import {useRobotMapQuery} from "../api";
|
||||
import MapLayers from "./layers";
|
||||
|
||||
const Container = styled(Box)({
|
||||
flex: '1',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexFlow: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flex: "1",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
flexFlow: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
});
|
||||
|
||||
const MapPage = (): JSX.Element => {
|
||||
@ -24,7 +24,9 @@ const MapPage = (): JSX.Element => {
|
||||
<Container>
|
||||
<Typography color="error">Error loading map data</Typography>
|
||||
<Box m={1}/>
|
||||
<Button color="primary" variant="contained" onClick={() => {return refetchMap()}}>
|
||||
<Button color="primary" variant="contained" onClick={() => {
|
||||
return refetchMap();
|
||||
}}>
|
||||
Retry
|
||||
</Button>
|
||||
</Container>
|
||||
|
||||
@ -1,37 +1,38 @@
|
||||
import Konva from 'konva';
|
||||
import {KonvaEventObject, Node} from 'konva/lib/Node';
|
||||
import React from 'react';
|
||||
import {Stage, StageProps} from 'react-konva';
|
||||
import {useHTMLElement} from '../hooks';
|
||||
import {bound, getCenter, getDistance, isTouchEnabled, ZeroVector,} from './utils';
|
||||
import {Box, styled, useTheme} from '@material-ui/core';
|
||||
import {Vector2d} from 'konva/lib/types';
|
||||
import Konva from "konva";
|
||||
import {KonvaEventObject, Node} from "konva/lib/Node";
|
||||
import React from "react";
|
||||
import {Stage, StageProps} from "react-konva";
|
||||
import {useHTMLElement} from "../hooks";
|
||||
import {bound, getCenter, getDistance, isTouchEnabled, ZeroVector,} from "./utils";
|
||||
import {Box, styled, useTheme} from "@material-ui/core";
|
||||
import {Vector2d} from "konva/lib/types";
|
||||
|
||||
Konva.pixelRatio = 1;
|
||||
Konva.hitOnDragEnabled = isTouchEnabled;
|
||||
const MaxScaleBound = 10;
|
||||
|
||||
const Container = styled(Box)({
|
||||
position: 'relative',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
position: "relative",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
});
|
||||
const StyledStage = styled(Stage)({
|
||||
position: 'absolute',
|
||||
position: "absolute",
|
||||
});
|
||||
|
||||
const scalePersistentNodes = (stage: Konva.Stage) => {
|
||||
stage
|
||||
.find(
|
||||
(node: Node) =>
|
||||
{return node.getAttr('minimumScale') !== undefined ||
|
||||
node.getAttr('maximumScale')}
|
||||
(node: Node) => {
|
||||
return node.getAttr("minimumScale") !== undefined ||
|
||||
node.getAttr("maximumScale");
|
||||
}
|
||||
)
|
||||
.forEach((shape) => {
|
||||
const stageScaleX = stage.scaleX();
|
||||
const stageScaleY = stage.scaleY();
|
||||
const minimumScale = shape.getAttr('minimumScale') ?? -Infinity;
|
||||
const maximumScale = shape.getAttr('maximumScale') ?? Infinity;
|
||||
const minimumScale = shape.getAttr("minimumScale") ?? -Infinity;
|
||||
const maximumScale = shape.getAttr("maximumScale") ?? Infinity;
|
||||
shape.scale({
|
||||
x: bound(stageScaleX, minimumScale, maximumScale) / stageScaleX,
|
||||
y: bound(stageScaleY, minimumScale, maximumScale) / stageScaleY,
|
||||
@ -96,10 +97,12 @@ const MapStage = React.forwardRef<MapStageRef | null, MapStageProps>(
|
||||
const [containerRef, {containerWidth, containerHeight}] = useHTMLElement(
|
||||
{containerWidth: 0, containerHeight: 0},
|
||||
React.useCallback(
|
||||
(element: HTMLDivElement) => {return {
|
||||
containerWidth: element.offsetWidth,
|
||||
containerHeight: element.offsetHeight,
|
||||
}},
|
||||
(element: HTMLDivElement) => {
|
||||
return {
|
||||
containerWidth: element.offsetWidth,
|
||||
containerHeight: element.offsetHeight,
|
||||
};
|
||||
},
|
||||
[]
|
||||
)
|
||||
);
|
||||
@ -118,18 +121,22 @@ const MapStage = React.forwardRef<MapStageRef | null, MapStageProps>(
|
||||
}
|
||||
|
||||
return {
|
||||
view: () => {return {
|
||||
width: containerWidth,
|
||||
height: containerHeight,
|
||||
position: stage.position(),
|
||||
scale: stageScale,
|
||||
}},
|
||||
map: () => {return {
|
||||
width,
|
||||
height,
|
||||
scale: stage.scaleX(),
|
||||
origin: stage.offset(),
|
||||
}},
|
||||
view: () => {
|
||||
return {
|
||||
width: containerWidth,
|
||||
height: containerHeight,
|
||||
position: stage.position(),
|
||||
scale: stageScale,
|
||||
};
|
||||
},
|
||||
map: () => {
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
scale: stage.scaleX(),
|
||||
origin: stage.offset(),
|
||||
};
|
||||
},
|
||||
redraw() {
|
||||
scalePersistentNodes(stage);
|
||||
stage.batchDraw();
|
||||
@ -209,22 +216,24 @@ const MapStage = React.forwardRef<MapStageRef | null, MapStageProps>(
|
||||
);
|
||||
|
||||
const dragBoundFunc = React.useMemo(
|
||||
() =>
|
||||
{return function (this: Konva.Node, pos: Vector2d): Vector2d {
|
||||
() => {
|
||||
return function (this: Konva.Node, pos: Vector2d): Vector2d {
|
||||
const scale = this.scaleX();
|
||||
|
||||
const boundAxis = (value: number, container: number, map: number) =>
|
||||
{return bound(
|
||||
const boundAxis = (value: number, container: number, map: number) => {
|
||||
return bound(
|
||||
value,
|
||||
-(map * stageScale) * (scale / stageScale) + padding,
|
||||
container - padding
|
||||
)};
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
x: boundAxis(pos.x, containerWidth, width),
|
||||
y: boundAxis(pos.y, containerHeight, height),
|
||||
};
|
||||
}},
|
||||
};
|
||||
},
|
||||
[containerHeight, containerWidth, height, padding, stageScale, width]
|
||||
);
|
||||
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
import MapPage from './MapPage';
|
||||
import MapPage from "./MapPage";
|
||||
|
||||
export default MapPage;
|
||||
|
||||
@ -81,13 +81,13 @@ const MapLayers = (props: Omit<MapLayersProps, "onDone">): JSX.Element => {
|
||||
const layers = React.useMemo<Layer[]>(() => {
|
||||
const layers : Array<Layer> = [
|
||||
"View"
|
||||
]
|
||||
];
|
||||
|
||||
if (goToLocation) {
|
||||
layers.push("Go");
|
||||
}
|
||||
if (mapSegmentation) {
|
||||
layers.push("Segments")
|
||||
layers.push("Segments");
|
||||
}
|
||||
if (zoneCleaning) {
|
||||
layers.push("Zones");
|
||||
@ -95,10 +95,10 @@ const MapLayers = (props: Omit<MapLayersProps, "onDone">): JSX.Element => {
|
||||
|
||||
return layers;
|
||||
|
||||
},
|
||||
[goToLocation, mapSegmentation, zoneCleaning]
|
||||
},
|
||||
[goToLocation, mapSegmentation, zoneCleaning]
|
||||
);
|
||||
const [selectedLayer, setSelectedLayer] = React.useState<Layer>('View');
|
||||
const [selectedLayer, setSelectedLayer] = React.useState<Layer>("View");
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const selectLayer = (layer: Layer) => {
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import {Box, Button, CircularProgress, Container, Fade, Grid, Typography, Zoom,} from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import {Box, Button, CircularProgress, Container, Fade, Grid, Typography, Zoom,} from "@material-ui/core";
|
||||
import React from "react";
|
||||
import {
|
||||
Capability,
|
||||
RawMapEntityType,
|
||||
useCleanSegmentsMutation,
|
||||
useMapSegmentationPropertiesQuery,
|
||||
useRobotStatusQuery,
|
||||
} from '../../api';
|
||||
import Map from '../Map';
|
||||
import {LayerActionButton, LayerActionsContainer} from './Styled';
|
||||
import {MapLayersProps} from './types';
|
||||
import {manhatten, pairWiseArray} from '../utils';
|
||||
import Color from 'color';
|
||||
import {useMapEntities, useMapLabels, useMapLayers} from './hooks';
|
||||
} from "../../api";
|
||||
import Map from "../Map";
|
||||
import {LayerActionButton, LayerActionsContainer} from "./Styled";
|
||||
import {MapLayersProps} from "./types";
|
||||
import {manhatten, pairWiseArray} from "../utils";
|
||||
import Color from "color";
|
||||
import {useMapEntities, useMapLabels, useMapLayers} from "./hooks";
|
||||
|
||||
interface SegmentsLayerOverlayProps {
|
||||
segments: string[];
|
||||
@ -34,7 +34,9 @@ const SegmentsLayerOverlay = (
|
||||
isError: mapSegmentationPropertiesLoadError,
|
||||
refetch: refetchMapSegmentationProperties,
|
||||
} = useMapSegmentationPropertiesQuery();
|
||||
const {data: status} = useRobotStatusQuery((state) => {return state.value});
|
||||
const {data: status} = useRobotStatusQuery((state) => {
|
||||
return state.value;
|
||||
});
|
||||
const {
|
||||
mutate: executeSegmentAction,
|
||||
isLoading: segmentActionExecuting
|
||||
@ -42,7 +44,7 @@ const SegmentsLayerOverlay = (
|
||||
onSuccess: onDone,
|
||||
});
|
||||
|
||||
const canClean = status === 'idle' || status === 'docked';
|
||||
const canClean = status === "idle" || status === "docked";
|
||||
const didSelectSegments = segments.length > 0;
|
||||
|
||||
const handleClick = React.useCallback(() => {
|
||||
@ -69,7 +71,9 @@ const SegmentsLayerOverlay = (
|
||||
Error loading {Capability.MapSegmentation} properties
|
||||
</Typography>
|
||||
<Box m={1}/>
|
||||
<Button color="primary" variant="contained" onClick={() => {return refetchMapSegmentationProperties()}}>
|
||||
<Button color="primary" variant="contained" onClick={() => {
|
||||
return refetchMapSegmentationProperties();
|
||||
}}>
|
||||
Retry
|
||||
</Button>
|
||||
</Container>
|
||||
@ -183,11 +187,16 @@ const SegmentsLayer = (props: MapLayersProps): JSX.Element => {
|
||||
];
|
||||
|
||||
const segment = data.layers
|
||||
.filter((layer) => {return layer.type === 'segment'})
|
||||
.find((layer) =>
|
||||
{return pairWiseArray(layer.pixels).some(
|
||||
(pixel) => {return manhatten(scaledPosition, pixel) === 0}
|
||||
)}
|
||||
.filter((layer) => {
|
||||
return layer.type === "segment";
|
||||
})
|
||||
.find((layer) => {
|
||||
return pairWiseArray(layer.pixels).some(
|
||||
(pixel) => {
|
||||
return manhatten(scaledPosition, pixel) === 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
const segmentId = segment?.metaData.segmentId;
|
||||
if (segmentId === undefined) {
|
||||
@ -196,7 +205,9 @@ const SegmentsLayer = (props: MapLayersProps): JSX.Element => {
|
||||
|
||||
setSelectedSegments((prev) => {
|
||||
if (prev.includes(segmentId)) {
|
||||
return prev.filter((v) => {return v !== segmentId});
|
||||
return prev.filter((v) => {
|
||||
return v !== segmentId;
|
||||
});
|
||||
}
|
||||
|
||||
return [...prev, segmentId];
|
||||
@ -206,12 +217,14 @@ const SegmentsLayer = (props: MapLayersProps): JSX.Element => {
|
||||
);
|
||||
|
||||
const coloredLayers = React.useMemo(
|
||||
() =>
|
||||
{return layers.map((layer) =>
|
||||
{return selectedSegments.includes(layer.id)
|
||||
? layer
|
||||
: {...layer, color: Color(layer.color).desaturate(0.7).hex()}}
|
||||
)},
|
||||
() => {
|
||||
return layers.map((layer) => {
|
||||
return selectedSegments.includes(layer.id) ?
|
||||
layer :
|
||||
{...layer, color: Color(layer.color).desaturate(0.7).hex()};
|
||||
}
|
||||
);
|
||||
},
|
||||
[layers, selectedSegments]
|
||||
);
|
||||
|
||||
|
||||
@ -1,18 +1,22 @@
|
||||
import {Box, emphasize, Fab, styled} from '@material-ui/core';
|
||||
import {Box, emphasize, Fab, styled} from "@material-ui/core";
|
||||
|
||||
export const LayerActionButton = styled(Fab)(({theme}) => {return {
|
||||
pointerEvents: 'auto',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
'&:hover': {
|
||||
backgroundColor: emphasize(theme.palette.background.paper, 0.15),
|
||||
},
|
||||
}});
|
||||
export const LayerActionButton = styled(Fab)(({theme}) => {
|
||||
return {
|
||||
pointerEvents: "auto",
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
"&:hover": {
|
||||
backgroundColor: emphasize(theme.palette.background.paper, 0.15),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export const LayerActionsContainer = styled(Box)(({theme}) => {return {
|
||||
position: 'absolute',
|
||||
pointerEvents: 'none',
|
||||
bottom: theme.spacing(2),
|
||||
left: theme.spacing(2),
|
||||
right: theme.spacing(2),
|
||||
}});
|
||||
export const LayerActionsContainer = styled(Box)(({theme}) => {
|
||||
return {
|
||||
position: "absolute",
|
||||
pointerEvents: "none",
|
||||
bottom: theme.spacing(2),
|
||||
left: theme.spacing(2),
|
||||
right: theme.spacing(2),
|
||||
};
|
||||
});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import Map from '../Map';
|
||||
import {useMapEntities, useMapLabels, useMapLayers} from './hooks';
|
||||
import {MapLayersProps} from './types';
|
||||
import Map from "../Map";
|
||||
import {useMapEntities, useMapLabels, useMapLayers} from "./hooks";
|
||||
import {MapLayersProps} from "./types";
|
||||
|
||||
const ViewLayer = (props: MapLayersProps): JSX.Element => {
|
||||
const {data, padding} = props;
|
||||
|
||||
@ -50,11 +50,11 @@ export const useMapEntities = (
|
||||
typeArray?: RawMapEntityType[]
|
||||
): JSX.Element[] => {
|
||||
return React.useMemo(() => {
|
||||
const filteredArray = typeArray
|
||||
? entities.filter(({ type }) => {
|
||||
const filteredArray = typeArray ?
|
||||
entities.filter(({ type }) => {
|
||||
return typeArray.includes(type);
|
||||
})
|
||||
: entities;
|
||||
}) :
|
||||
entities;
|
||||
|
||||
const sortedArray = [...filteredArray].sort((a, b) => {
|
||||
return (
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
import MapLayers from './MapLayers';
|
||||
import MapLayers from "./MapLayers";
|
||||
|
||||
export default MapLayers;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {RawMapData} from '../../api';
|
||||
import {RawMapData} from "../../api";
|
||||
|
||||
export interface MapLayersProps {
|
||||
data: RawMapData;
|
||||
|
||||
@ -56,7 +56,9 @@ export class FourColorTheoremSolver {
|
||||
minY: Infinity,
|
||||
maxY: -Infinity,
|
||||
};
|
||||
const filteredLayers = layers.filter((layer) => {return layer.type === "segment"});
|
||||
const filteredLayers = layers.filter((layer) => {
|
||||
return layer.type === "segment";
|
||||
});
|
||||
if (filteredLayers.length <= 0) {
|
||||
return undefined;
|
||||
}
|
||||
@ -117,7 +119,9 @@ export class FourColorTheoremSolver {
|
||||
}
|
||||
|
||||
buildGraph(mapData) {
|
||||
var vertices = mapData.segmentIds.map((i) => {return new MapAreaVertex(i)});
|
||||
var vertices = mapData.segmentIds.map((i) => {
|
||||
return new MapAreaVertex(i);
|
||||
});
|
||||
var graph = new MapAreaGraph(vertices);
|
||||
this.traverseMap(
|
||||
mapData.boundaries,
|
||||
@ -225,26 +229,36 @@ class MapAreaGraph {
|
||||
*/
|
||||
colorAllVertices() {
|
||||
this.vertices
|
||||
.sort((l, r) => {return r.adjacentVertexIds.size - l.adjacentVertexIds.size})
|
||||
.sort((l, r) => {
|
||||
return r.adjacentVertexIds.size - l.adjacentVertexIds.size;
|
||||
})
|
||||
.forEach((v) => {
|
||||
if (v.adjacentVertexIds.size <= 0) {
|
||||
v.color = 0;
|
||||
} else {
|
||||
var adjs = this.getAdjacentVertices(v);
|
||||
var existingColors = adjs
|
||||
.filter((vert) => {return vert.color !== undefined})
|
||||
.map((vert) => {return vert.color});
|
||||
.filter((vert) => {
|
||||
return vert.color !== undefined;
|
||||
})
|
||||
.map((vert) => {
|
||||
return vert.color;
|
||||
});
|
||||
v.color = this.lowestColor(existingColors);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getAdjacentVertices(vertex) {
|
||||
return Array.from(vertex.adjacentVertexIds).map((id) => {return this.getById(id)});
|
||||
return Array.from(vertex.adjacentVertexIds).map((id) => {
|
||||
return this.getById(id);
|
||||
});
|
||||
}
|
||||
|
||||
getById(id) {
|
||||
return this.vertices.find((v) => {return v.id === id});
|
||||
return this.vertices.find((v) => {
|
||||
return v.id === id;
|
||||
});
|
||||
}
|
||||
|
||||
lowestColor(colors) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import ChipShape from './ChipShape';
|
||||
import PixelsShape from './PixelsShape';
|
||||
import RawMapEntityShape from './RawMapEntityShape';
|
||||
import ChipShape from "./ChipShape";
|
||||
import PixelsShape from "./PixelsShape";
|
||||
import RawMapEntityShape from "./RawMapEntityShape";
|
||||
|
||||
export {ChipShape, PixelsShape, RawMapEntityShape};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {Vector2d} from 'konva/lib/types';
|
||||
import {Vector2d} from "konva/lib/types";
|
||||
|
||||
export const pairWise = function* <T>(arr: T[]): Generator<[T, T]> {
|
||||
for (let i = 0; i < arr.length; i = i + 2) {
|
||||
@ -6,40 +6,51 @@ export const pairWise = function* <T>(arr: T[]): Generator<[T, T]> {
|
||||
}
|
||||
};
|
||||
|
||||
export const pairWiseArray = <T>(arr: T[]): [T, T][] => {return [...pairWise(arr)]};
|
||||
export const pairWiseArray = <T>(arr: T[]): [T, T][] => {
|
||||
return [...pairWise(arr)];
|
||||
};
|
||||
|
||||
export const inside = (
|
||||
[x, y]: [x: number, y: number],
|
||||
box: { x: [min: number, max: number]; y: [min: number, max: number] }
|
||||
): boolean => {return x >= box.x[0] && x <= box.x[1] && y >= box.y[0] && y <= box.y[1]};
|
||||
): boolean => {
|
||||
return x >= box.x[0] && x <= box.x[1] && y >= box.y[0] && y <= box.y[1];
|
||||
};
|
||||
|
||||
export const bound = (value: number, min: number, max: number): number =>
|
||||
{return Math.min(max, Math.max(min, value))};
|
||||
export const bound = (value: number, min: number, max: number): number => {
|
||||
return Math.min(max, Math.max(min, value));
|
||||
};
|
||||
|
||||
export const manhatten = (p1: [number, number], p2: [number, number]): number =>
|
||||
{return Math.abs(p1[0] - p2[0]) + Math.abs(p1[1] - p2[1])};
|
||||
export const manhatten = (p1: [number, number], p2: [number, number]): number => {
|
||||
return Math.abs(p1[0] - p2[0]) + Math.abs(p1[1] - p2[1]);
|
||||
};
|
||||
|
||||
export const pointClosestTo = (
|
||||
points: [number, number][],
|
||||
target: [number, number]
|
||||
): [number, number] =>
|
||||
{return points.reduce(
|
||||
(prev, cur) =>
|
||||
{return manhatten(cur, target) < manhatten(prev, target) ? cur : prev},
|
||||
): [number, number] => {
|
||||
return points.reduce(
|
||||
(prev, cur) => {
|
||||
return manhatten(cur, target) < manhatten(prev, target) ? cur : prev;
|
||||
},
|
||||
points[0]
|
||||
)};
|
||||
);
|
||||
};
|
||||
|
||||
export const ZeroVector: Vector2d = {x: 0, y: 0};
|
||||
|
||||
export const getDistance = (p1: Vector2d, p2: Vector2d): number =>
|
||||
{return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2))};
|
||||
export const getDistance = (p1: Vector2d, p2: Vector2d): number => {
|
||||
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
|
||||
};
|
||||
|
||||
export const getCenter = (p1: Vector2d, p2: Vector2d): Vector2d => {return {
|
||||
x: (p1.x + p2.x) / 2,
|
||||
y: (p1.y + p2.y) / 2,
|
||||
}};
|
||||
export const getCenter = (p1: Vector2d, p2: Vector2d): Vector2d => {
|
||||
return {
|
||||
x: (p1.x + p2.x) / 2,
|
||||
y: (p1.y + p2.y) / 2,
|
||||
};
|
||||
};
|
||||
|
||||
export const isTouchEnabled =
|
||||
'ontouchstart' in window ||
|
||||
"ontouchstart" in window ||
|
||||
navigator.maxTouchPoints > 0 ||
|
||||
navigator.msMaxTouchPoints > 0;
|
||||
|
||||
@ -11,22 +11,24 @@ import {
|
||||
Link,
|
||||
styled,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import { withStyles } from '@material-ui/styles';
|
||||
import {Refresh as RefreshIcon} from '@material-ui/icons';
|
||||
import React from 'react';
|
||||
} from "@material-ui/core";
|
||||
import { withStyles } from "@material-ui/styles";
|
||||
import {Refresh as RefreshIcon} from "@material-ui/icons";
|
||||
import React from "react";
|
||||
import {
|
||||
useLatestGitHubReleaseLazyQuery,
|
||||
useRobotInformationQuery,
|
||||
useSystemHostInfoQuery,
|
||||
useValetudoVersionQuery,
|
||||
} from '../api';
|
||||
} from "../api";
|
||||
import RatioBar from "../compontents/RatioBar";
|
||||
import {convertSecondsToHumans} from "../utils";
|
||||
|
||||
const TopRightIconButton = styled(Button)(({theme}) => {return {
|
||||
marginTop: -theme.spacing(1),
|
||||
}});
|
||||
const TopRightIconButton = styled(Button)(({theme}) => {
|
||||
return {
|
||||
marginTop: -theme.spacing(1),
|
||||
};
|
||||
});
|
||||
|
||||
const ThickLinearProgressWithTopMargin = withStyles({
|
||||
root: {
|
||||
@ -57,7 +59,7 @@ const About = (): JSX.Element => {
|
||||
|
||||
|
||||
const systemLoading = robotInformationLoading || versionLoading || systemHostInfoLoading;
|
||||
const newerReleaseAvailable = (githubReleaseInformation?.tag_name ?? '0.0.0') > (version?.release ?? 'a');
|
||||
const newerReleaseAvailable = (githubReleaseInformation?.tag_name ?? "0.0.0") > (version?.release ?? "a");
|
||||
|
||||
const systemInformation = React.useMemo(() => {
|
||||
if (systemLoading) {
|
||||
@ -65,7 +67,7 @@ const About = (): JSX.Element => {
|
||||
<Fade
|
||||
in
|
||||
style={{
|
||||
transitionDelay: '500ms',
|
||||
transitionDelay: "500ms",
|
||||
}}
|
||||
unmountOnExit
|
||||
>
|
||||
@ -79,23 +81,25 @@ const About = (): JSX.Element => {
|
||||
}
|
||||
|
||||
const items: Array<[header: string, body: string]> = [
|
||||
['Manufacturer', robotInformation.manufacturer],
|
||||
['Model', robotInformation.modelName],
|
||||
['Valetudo Implementation', robotInformation.implementation],
|
||||
['Release', version.release],
|
||||
['Commit', version.commit],
|
||||
["Manufacturer", robotInformation.manufacturer],
|
||||
["Model", robotInformation.modelName],
|
||||
["Valetudo Implementation", robotInformation.implementation],
|
||||
["Release", version.release],
|
||||
["Commit", version.commit],
|
||||
];
|
||||
|
||||
return (
|
||||
<Grid container spacing={2}>
|
||||
{items.map(([header, body]) => {return (
|
||||
<Grid item key={header}>
|
||||
<Typography variant="caption" color="textSecondary">
|
||||
{header}
|
||||
</Typography>
|
||||
<Typography variant="body2">{body}</Typography>
|
||||
</Grid>
|
||||
)})}
|
||||
{items.map(([header, body]) => {
|
||||
return (
|
||||
<Grid item key={header}>
|
||||
<Typography variant="caption" color="textSecondary">
|
||||
{header}
|
||||
</Typography>
|
||||
<Typography variant="body2">{body}</Typography>
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
}, [robotInformation, systemLoading, version]);
|
||||
@ -106,7 +110,7 @@ const About = (): JSX.Element => {
|
||||
<Fade
|
||||
in
|
||||
style={{
|
||||
transitionDelay: '500ms',
|
||||
transitionDelay: "500ms",
|
||||
}}
|
||||
unmountOnExit
|
||||
>
|
||||
@ -161,7 +165,7 @@ const About = (): JSX.Element => {
|
||||
<Fade
|
||||
in
|
||||
style={{
|
||||
transitionDelay: '500ms',
|
||||
transitionDelay: "500ms",
|
||||
}}
|
||||
unmountOnExit
|
||||
>
|
||||
@ -274,7 +278,9 @@ const About = (): JSX.Element => {
|
||||
) : (
|
||||
<TopRightIconButton
|
||||
disabled={githubReleaseInformationLoading}
|
||||
onClick={() => {return fetchGithubReleaseInformation()}}
|
||||
onClick={() => {
|
||||
return fetchGithubReleaseInformation();
|
||||
}}
|
||||
>
|
||||
<RefreshIcon/>
|
||||
</TopRightIconButton>
|
||||
@ -303,7 +309,9 @@ const About = (): JSX.Element => {
|
||||
<Grid item>
|
||||
<TopRightIconButton
|
||||
disabled={systemHostInfoLoading}
|
||||
onClick={() => {return fetchSystemHostInfo()}}
|
||||
onClick={() => {
|
||||
return fetchSystemHostInfo();
|
||||
}}
|
||||
>
|
||||
<RefreshIcon/>
|
||||
</TopRightIconButton>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {Route, Switch} from 'react-router';
|
||||
import {useRouteMatch} from 'react-router-dom';
|
||||
import About from './About';
|
||||
import {Route, Switch} from "react-router";
|
||||
import {useRouteMatch} from "react-router-dom";
|
||||
import About from "./About";
|
||||
import Timers from "./timers";
|
||||
|
||||
const SettingsRouter = (): JSX.Element => {
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
import SettingsRouter from './SettingsRouter';
|
||||
import SettingsRouter from "./SettingsRouter";
|
||||
|
||||
export default SettingsRouter;
|
||||
|
||||
44
frontend/src/types/theme.d.ts
vendored
44
frontend/src/types/theme.d.ts
vendored
@ -1,44 +1,44 @@
|
||||
import '@material-ui/core/styles';
|
||||
import "@material-ui/core/styles";
|
||||
|
||||
declare module '@material-ui/core/styles' {
|
||||
declare module "@material-ui/core/styles" {
|
||||
interface Theme {
|
||||
map: {
|
||||
floor: NonNullable<React.CSSProperties['color']>;
|
||||
wall: NonNullable<React.CSSProperties['color']>;
|
||||
segment: NonNullable<React.CSSProperties['color']>[];
|
||||
path: NonNullable<React.CSSProperties['color']>;
|
||||
floor: NonNullable<React.CSSProperties["color"]>;
|
||||
wall: NonNullable<React.CSSProperties["color"]>;
|
||||
segment: NonNullable<React.CSSProperties["color"]>[];
|
||||
path: NonNullable<React.CSSProperties["color"]>;
|
||||
noGo: {
|
||||
stroke: NonNullable<React.CSSProperties['color']>;
|
||||
fill: NonNullable<React.CSSProperties['color']>;
|
||||
stroke: NonNullable<React.CSSProperties["color"]>;
|
||||
fill: NonNullable<React.CSSProperties["color"]>;
|
||||
};
|
||||
noMop: {
|
||||
stroke: NonNullable<React.CSSProperties['color']>;
|
||||
fill: NonNullable<React.CSSProperties['color']>;
|
||||
stroke: NonNullable<React.CSSProperties["color"]>;
|
||||
fill: NonNullable<React.CSSProperties["color"]>;
|
||||
};
|
||||
active: {
|
||||
stroke: NonNullable<React.CSSProperties['color']>;
|
||||
fill: NonNullable<React.CSSProperties['color']>;
|
||||
stroke: NonNullable<React.CSSProperties["color"]>;
|
||||
fill: NonNullable<React.CSSProperties["color"]>;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface ThemeOptions {
|
||||
map: {
|
||||
floor: NonNullable<React.CSSProperties['color']>;
|
||||
wall: NonNullable<React.CSSProperties['color']>;
|
||||
segment: NonNullable<React.CSSProperties['color']>[];
|
||||
path: NonNullable<React.CSSProperties['color']>;
|
||||
floor: NonNullable<React.CSSProperties["color"]>;
|
||||
wall: NonNullable<React.CSSProperties["color"]>;
|
||||
segment: NonNullable<React.CSSProperties["color"]>[];
|
||||
path: NonNullable<React.CSSProperties["color"]>;
|
||||
noGo: {
|
||||
stroke: NonNullable<React.CSSProperties['color']>;
|
||||
fill: NonNullable<React.CSSProperties['color']>;
|
||||
stroke: NonNullable<React.CSSProperties["color"]>;
|
||||
fill: NonNullable<React.CSSProperties["color"]>;
|
||||
};
|
||||
noMop: {
|
||||
stroke: NonNullable<React.CSSProperties['color']>;
|
||||
fill: NonNullable<React.CSSProperties['color']>;
|
||||
stroke: NonNullable<React.CSSProperties["color"]>;
|
||||
fill: NonNullable<React.CSSProperties["color"]>;
|
||||
};
|
||||
active: {
|
||||
stroke: NonNullable<React.CSSProperties['color']>;
|
||||
fill: NonNullable<React.CSSProperties['color']>;
|
||||
stroke: NonNullable<React.CSSProperties["color"]>;
|
||||
fill: NonNullable<React.CSSProperties["color"]>;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -38,10 +38,14 @@ export const deepCopy = <T>(target: T): T => {
|
||||
}
|
||||
if (target instanceof Array) {
|
||||
const cp = [] as any[];
|
||||
(target as any[]).forEach((v) => { cp.push(v); });
|
||||
return cp.map((n: any) => {return deepCopy<any>(n)}) as any;
|
||||
(target as any[]).forEach((v) => {
|
||||
cp.push(v);
|
||||
});
|
||||
return cp.map((n: any) => {
|
||||
return deepCopy<any>(n);
|
||||
}) as any;
|
||||
}
|
||||
if (typeof target === 'object' && Object.keys(target).length !== 0) {
|
||||
if (typeof target === "object" && Object.keys(target).length !== 0) {
|
||||
const cp = { ...(target as { [key: string]: any }) } as { [key: string]: any };
|
||||
Object.keys(cp).forEach(k => {
|
||||
cp[k] = deepCopy<any>(cp[k]);
|
||||
|
||||
77
package-lock.json
generated
77
package-lock.json
generated
@ -16,7 +16,6 @@
|
||||
"@typescript-eslint/eslint-plugin": "4.22.0",
|
||||
"@typescript-eslint/parser": "4.22.0",
|
||||
"eslint": "7.25.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-jsdoc": "^30.2.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-react": "7.23.2",
|
||||
@ -24,7 +23,6 @@
|
||||
"eslint-plugin-regexp": "^0.5.0",
|
||||
"eslint-plugin-sort-keys-fix": "^1.1.1",
|
||||
"eslint-plugin-sort-requires": "^2.1.0",
|
||||
"prettier": "2.2.1",
|
||||
"swagger-jsdoc": "git+https://npm@github.com/Hypfer/swagger-jsdoc.git#7.0.0-rc.6-noyaml-monorepo-fix",
|
||||
"swagger-parser": "^10.0.2",
|
||||
"typescript": "4.2.4",
|
||||
@ -326,6 +324,7 @@
|
||||
"@material-ui/lab": "5.0.0-alpha.40",
|
||||
"axios": "0.21.1",
|
||||
"color": "3.1.4",
|
||||
"date-fns": "2.23.0",
|
||||
"konva": "8.1.1",
|
||||
"notistack": "1.0.6",
|
||||
"react": "17.0.2",
|
||||
@ -354,11 +353,9 @@
|
||||
"@typescript-eslint/parser": "4.28.3",
|
||||
"cra-build-watch": "^3.4.0",
|
||||
"eslint": "7.31.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-react": "7.24.0",
|
||||
"eslint-plugin-react-hooks": "4.2.0",
|
||||
"miragejs": "0.1.41",
|
||||
"prettier": "2.3.2",
|
||||
"source-map-explorer": "2.5.2",
|
||||
"typescript": "4.2.4"
|
||||
}
|
||||
@ -920,19 +917,6 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"frontend/node_modules/prettier": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz",
|
||||
"integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"frontend/node_modules/pretty-format": {
|
||||
"version": "27.0.6",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz",
|
||||
@ -8643,6 +8627,18 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "2.23.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.23.0.tgz",
|
||||
"integrity": "sha512-5ycpauovVyAk0kXNZz6ZoB9AYMZB4DObse7P3BPWmyEjXNORTI8EJ6X0uaSAq4sCHzM1uajzrkr6HnsLQpxGXA==",
|
||||
"engines": {
|
||||
"node": ">=0.11"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/date-fns"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||
@ -9761,15 +9757,6 @@
|
||||
"node": "^10.12.0 || >=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-prettier": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz",
|
||||
"integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-react-app": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz",
|
||||
@ -19361,18 +19348,6 @@
|
||||
"route-recognizer": "^0.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
|
||||
"integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-bytes": {
|
||||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
|
||||
@ -32096,6 +32071,11 @@
|
||||
"whatwg-url": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"date-fns": {
|
||||
"version": "2.23.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.23.0.tgz",
|
||||
"integrity": "sha512-5ycpauovVyAk0kXNZz6ZoB9AYMZB4DObse7P3BPWmyEjXNORTI8EJ6X0uaSAq4sCHzM1uajzrkr6HnsLQpxGXA=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||
@ -33012,12 +32992,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-config-prettier": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz",
|
||||
"integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-config-react-app": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz",
|
||||
@ -40621,12 +40595,6 @@
|
||||
"route-recognizer": "^0.3.3"
|
||||
}
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
|
||||
"integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
|
||||
"dev": true
|
||||
},
|
||||
"pretty-bytes": {
|
||||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
|
||||
@ -44733,14 +44701,13 @@
|
||||
"axios": "0.21.1",
|
||||
"color": "3.1.4",
|
||||
"cra-build-watch": "^3.4.0",
|
||||
"date-fns": "2.23.0",
|
||||
"eslint": "7.31.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-react": "7.24.0",
|
||||
"eslint-plugin-react-hooks": "4.2.0",
|
||||
"konva": "8.1.1",
|
||||
"miragejs": "0.1.41",
|
||||
"notistack": "1.0.6",
|
||||
"prettier": "2.3.2",
|
||||
"react": "17.0.2",
|
||||
"react-div-100vh": "0.6.0",
|
||||
"react-dom": "17.0.2",
|
||||
@ -45083,12 +45050,6 @@
|
||||
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
|
||||
"dev": true
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz",
|
||||
"integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==",
|
||||
"dev": true
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "27.0.6",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz",
|
||||
|
||||
@ -23,7 +23,6 @@
|
||||
"@typescript-eslint/eslint-plugin": "4.22.0",
|
||||
"@typescript-eslint/parser": "4.22.0",
|
||||
"eslint": "7.25.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-jsdoc": "^30.2.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-react": "7.23.2",
|
||||
@ -31,7 +30,6 @@
|
||||
"eslint-plugin-regexp": "^0.5.0",
|
||||
"eslint-plugin-sort-keys-fix": "^1.1.1",
|
||||
"eslint-plugin-sort-requires": "^2.1.0",
|
||||
"prettier": "2.2.1",
|
||||
"swagger-jsdoc": "git+https://npm@github.com/Hypfer/swagger-jsdoc.git#7.0.0-rc.6-noyaml-monorepo-fix",
|
||||
"swagger-parser": "^10.0.2",
|
||||
"typescript": "4.2.4",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user