[WIP] added files from fossil to git, added multilanguage
This commit is contained in:
parent
3aaf0d7cb0
commit
5cceb33c50
|
@ -0,0 +1,23 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"alarms": {
|
||||
"defaultMessage": "Alarms"
|
||||
},
|
||||
"allInstallations": {
|
||||
"defaultMessage": "All installations"
|
||||
},
|
||||
"applyChanges": {
|
||||
"defaultMessage": "Apply changes"
|
||||
},
|
||||
"country": {
|
||||
"defaultMessage": "Country"
|
||||
},
|
||||
"customerName": {
|
||||
"defaultMessage": "Customer name"
|
||||
},
|
||||
"english": {
|
||||
"defaultMessage": "English"
|
||||
},
|
||||
"german": {
|
||||
"defaultMessage": "German"
|
||||
},
|
||||
"installation": {
|
||||
"defaultMessage": "Installation"
|
||||
},
|
||||
"location": {
|
||||
"defaultMessage": "Location"
|
||||
},
|
||||
"log": {
|
||||
"defaultMessage": "Log"
|
||||
},
|
||||
"logout": {
|
||||
"defaultMessage": "Logout"
|
||||
},
|
||||
"orderNumbers": {
|
||||
"defaultMessage": "Order number"
|
||||
},
|
||||
"region": {
|
||||
"defaultMessage": "Region"
|
||||
},
|
||||
"search": {
|
||||
"defaultMessage": "Search"
|
||||
},
|
||||
"updatedSuccessfully": {
|
||||
"defaultMessage": "Updated successfully"
|
||||
},
|
||||
"users": {
|
||||
"defaultMessage": "Users"
|
||||
}
|
||||
}
|
|
@ -32,6 +32,9 @@
|
|||
"reactflow": "^11.5.6",
|
||||
"typescript": "^4.9.5",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formatjs/cli": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@adobe/css-tools": {
|
||||
|
@ -2306,6 +2309,26 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@formatjs/cli": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/cli/-/cli-6.0.3.tgz",
|
||||
"integrity": "sha512-YPhDUw5zQwufAZRUlk054Z/J9jeZWH4LEbAVnQFrfJ8NNgOziDqn9SSTEfRB4W0w8JBGgte4x1SwwJjH/HGoRA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"formatjs": "bin/formatjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/compiler-sfc": "^3.2.34"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/compiler-sfc": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@formatjs/ecma402-abstract": {
|
||||
"version": "1.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.14.3.tgz",
|
||||
|
@ -19710,6 +19733,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@formatjs/cli": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/cli/-/cli-6.0.3.tgz",
|
||||
"integrity": "sha512-YPhDUw5zQwufAZRUlk054Z/J9jeZWH4LEbAVnQFrfJ8NNgOziDqn9SSTEfRB4W0w8JBGgte4x1SwwJjH/HGoRA==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"@formatjs/ecma402-abstract": {
|
||||
"version": "1.14.3",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.14.3.tgz",
|
||||
|
|
|
@ -32,7 +32,8 @@
|
|||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
"eject": "react-scripts eject",
|
||||
"extract": "formatjs extract"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
|
@ -51,5 +52,8 @@
|
|||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formatjs/cli": "^6.0.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,7 @@
|
|||
import useToken from "./hooks/useToken";
|
||||
import Login from "./Login";
|
||||
import { BrowserRouter, Route, Routes } from "react-router-dom";
|
||||
import {
|
||||
Box,
|
||||
Grid,
|
||||
ButtonGroup,
|
||||
Button,
|
||||
Divider,
|
||||
Select,
|
||||
MenuItem,
|
||||
} from "@mui/material";
|
||||
import { Box, Grid, Divider } from "@mui/material";
|
||||
import NestedList from "./components/NestedList";
|
||||
import BasicTable from "./components/Table";
|
||||
import BasicTabs from "./components/Tabs";
|
||||
|
@ -17,25 +9,18 @@ import Alarms from "./routes/Alarms";
|
|||
import InstallationDetail from "./routes/Installation";
|
||||
import Log from "./routes/Log";
|
||||
import routes from "./routes.json";
|
||||
import { FormattedMessage, IntlProvider } from "react-intl";
|
||||
import { IntlProvider } from "react-intl";
|
||||
import { useState } from "react";
|
||||
import en from "./lang/en.json";
|
||||
import de from "./lang/de.json";
|
||||
import NavigationButtons from "./components/NavigationButtons";
|
||||
import LanguageSelect from "./components/LanguageSelect";
|
||||
import LogoutButton from "./components/LogoutButton";
|
||||
|
||||
const App = () => {
|
||||
const { token, setToken } = useToken();
|
||||
const { token, setToken, removeToken } = useToken();
|
||||
const [language, setLanguage] = useState("en");
|
||||
|
||||
if (!token) {
|
||||
return <Login setToken={setToken} />;
|
||||
}
|
||||
|
||||
const de = {
|
||||
allInstallations: "Alle Installationen",
|
||||
};
|
||||
|
||||
const en = {
|
||||
allInstallations: "All installations",
|
||||
};
|
||||
|
||||
const getTranslations = () => {
|
||||
if (language === "de") {
|
||||
return de;
|
||||
|
@ -43,6 +28,12 @@ const App = () => {
|
|||
return en;
|
||||
};
|
||||
|
||||
if (!token) {
|
||||
return <Login setToken={setToken} />;
|
||||
}
|
||||
|
||||
console.log("app");
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<IntlProvider
|
||||
|
@ -53,36 +44,10 @@ const App = () => {
|
|||
<Box sx={{ padding: 2 }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={3}>
|
||||
<ButtonGroup
|
||||
variant="outlined"
|
||||
aria-label="outlined primary button group"
|
||||
sx={{ paddingBottom: 3 }}
|
||||
>
|
||||
<Button>
|
||||
<FormattedMessage
|
||||
id="allInstallations"
|
||||
defaultMessage="All installations"
|
||||
/>
|
||||
</Button>
|
||||
<Button>
|
||||
<FormattedMessage id="users" defaultMessage="Users" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<NavigationButtons />
|
||||
<NestedList />
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={language}
|
||||
label="Age"
|
||||
onChange={(e) => setLanguage(e.target.value)}
|
||||
>
|
||||
<MenuItem value="en">
|
||||
<FormattedMessage id="english" defaultMessage="English" />
|
||||
</MenuItem>
|
||||
<MenuItem value="de">
|
||||
<FormattedMessage id="german" defaultMessage="German" />
|
||||
</MenuItem>
|
||||
</Select>
|
||||
<LanguageSelect language={language} setLanguage={setLanguage} />
|
||||
<LogoutButton removeToken={removeToken} />
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState } from "react";
|
||||
import { Button, CircularProgress } from "@mui/material";
|
||||
import { Alert, Button, CircularProgress } from "@mui/material";
|
||||
import Container from "@mui/material/Container";
|
||||
import InnovenergyTextfield from "./components/InnovenergyTextfield";
|
||||
import { axiosConfigWithoutToken } from "./config/axiosConfig";
|
||||
|
@ -15,11 +15,16 @@ const Login = ({ setToken }: { setToken: any }) => {
|
|||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState();
|
||||
|
||||
const handleSubmit = async (e: any) => {
|
||||
const handleSubmit = (e: any) => {
|
||||
setLoading(true);
|
||||
loginUser(username, password).then((res) => {
|
||||
setToken(res.data);
|
||||
loginUser(username, password).then(({ data }) => {
|
||||
if (typeof data === "string") {
|
||||
setToken(data);
|
||||
setLoading(false);
|
||||
}
|
||||
setError(data);
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
@ -41,6 +46,7 @@ const Login = ({ setToken }: { setToken: any }) => {
|
|||
value={password}
|
||||
handleChange={(e) => setPassword(e.target.value)}
|
||||
/>
|
||||
{error && <Alert severity="error">Incorrect username or password</Alert>}
|
||||
<div>
|
||||
<Button variant="outlined" onClick={handleSubmit} sx={{ my: 1 }}>
|
||||
Login
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Button } from "@mui/material";
|
||||
import { Alert, Button, Snackbar } from "@mui/material";
|
||||
import { useFormik } from "formik";
|
||||
import { useState } from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import axiosConfig from "../config/axiosConfig";
|
||||
import { I_Installation } from "../util/installation.util";
|
||||
|
@ -13,13 +14,15 @@ const CustomerForm = (props: I_CustomerFormProps) => {
|
|||
const { values, id } = props;
|
||||
const intl = useIntl();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
name: values.name,
|
||||
region: values.region,
|
||||
location: values.location,
|
||||
country: values.country,
|
||||
orderNumber: values.orderNumber,
|
||||
orderNumbers: values.orderNumbers,
|
||||
},
|
||||
onSubmit: (formikValues) => {
|
||||
axiosConfig
|
||||
|
@ -28,11 +31,15 @@ const CustomerForm = (props: I_CustomerFormProps) => {
|
|||
id,
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
setOpen(true);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<InnovenergyTextfield
|
||||
|
@ -76,18 +83,31 @@ const CustomerForm = (props: I_CustomerFormProps) => {
|
|||
handleChange={formik.handleChange}
|
||||
/>
|
||||
<InnovenergyTextfield
|
||||
id="orderNumber-textfield"
|
||||
id="orderNumbers-textfield"
|
||||
label={intl.formatMessage({
|
||||
id: "orderNumber",
|
||||
id: "orderNumbers",
|
||||
defaultMessage: "Order number",
|
||||
})}
|
||||
name="orderNumber"
|
||||
value={formik.values.orderNumber}
|
||||
name="orderNumbers"
|
||||
value={formik.values.orderNumbers}
|
||||
handleChange={formik.handleChange}
|
||||
/>
|
||||
<Button variant="outlined" type="submit">
|
||||
<FormattedMessage id="applyChanges" defaultMessage="Apply changes" />
|
||||
</Button>
|
||||
<Snackbar
|
||||
open={open}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "right",
|
||||
}}
|
||||
autoHideDuration={6000}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<Alert onClose={handleClose} severity="success" sx={{ width: "100%" }}>
|
||||
<FormattedMessage id="updatedSuccessfully" defaultMessage="Updated successfully" />
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { MenuItem, Select } from "@mui/material";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
interface LanguageSelectProps {
|
||||
language: string;
|
||||
setLanguage: (language: string) => void;
|
||||
}
|
||||
const LanguageSelect = (props: LanguageSelectProps) => {
|
||||
return (
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={props.language}
|
||||
label="Age"
|
||||
onChange={(e) => props.setLanguage(e.target.value)}
|
||||
>
|
||||
<MenuItem value="en">
|
||||
<FormattedMessage id="english" defaultMessage="English" />
|
||||
</MenuItem>
|
||||
<MenuItem value="de">
|
||||
<FormattedMessage id="german" defaultMessage="German" />
|
||||
</MenuItem>
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
||||
export default LanguageSelect;
|
|
@ -0,0 +1,28 @@
|
|||
import { Button } from "@mui/material";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import axiosConfig from "../config/axiosConfig";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
interface LogoutButtonProps {
|
||||
removeToken: () => void;
|
||||
}
|
||||
const LogoutButton = (props: LogoutButtonProps) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
axiosConfig.post("/Logout").then(() => {
|
||||
navigate("/");
|
||||
props.removeToken();
|
||||
});
|
||||
}}
|
||||
sx={{ mx: 1 }}
|
||||
>
|
||||
<FormattedMessage id="logout" defaultMessage="Logout" />
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogoutButton;
|
|
@ -0,0 +1,24 @@
|
|||
import { Button, ButtonGroup } from "@mui/material";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
const NavigationButtons = () => {
|
||||
return (
|
||||
<ButtonGroup
|
||||
variant="outlined"
|
||||
aria-label="outlined primary button group"
|
||||
sx={{ paddingBottom: 3 }}
|
||||
>
|
||||
<Button>
|
||||
<FormattedMessage
|
||||
id="allInstallations"
|
||||
defaultMessage="All installations"
|
||||
/>
|
||||
</Button>
|
||||
<Button>
|
||||
<FormattedMessage id="users" defaultMessage="Users" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavigationButtons;
|
|
@ -5,7 +5,7 @@ import { Divider, TextField } from "@mui/material";
|
|||
import { Link } from "react-router-dom";
|
||||
import useRouteMatch from "../hooks/useRouteMatch";
|
||||
import routes from "../routes.json";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Fragment, useEffect, useState } from "react";
|
||||
import { I_Installation } from "../util/installation.util";
|
||||
import axiosConfig from "../config/axiosConfig";
|
||||
import { useIntl } from "react-intl";
|
||||
|
@ -46,11 +46,10 @@ const NestedList = () => {
|
|||
]);
|
||||
|
||||
useEffect(() => {
|
||||
axiosConfig
|
||||
.get("https://localhost:7087/api/GetAllInstallations", {})
|
||||
.then((res) => {
|
||||
setData(res.data);
|
||||
});
|
||||
console.log("useeffect");
|
||||
axiosConfig.get("/GetAllInstallations", {}).then((res) => {
|
||||
setData(res.data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
@ -72,9 +71,8 @@ const NestedList = () => {
|
|||
aria-labelledby="nested-list-subheader"
|
||||
>
|
||||
{filteredData?.map((installation) => (
|
||||
<>
|
||||
<Fragment key={installation.id}>
|
||||
<Link
|
||||
key={installation.id}
|
||||
to={getPathWithoutId(routeMatch?.pattern?.path) + installation.id}
|
||||
style={{ textDecoration: "none", color: "black" }}
|
||||
>
|
||||
|
@ -87,7 +85,7 @@ const NestedList = () => {
|
|||
</ListItemButton>
|
||||
</Link>
|
||||
<Divider />
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</List>
|
||||
</>
|
||||
|
|
|
@ -21,7 +21,10 @@ const BasicTabs = () => {
|
|||
return (
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
|
||||
<Tabs value={routeMatch?.pattern?.path} aria-label="basic tabs example">
|
||||
<Tabs
|
||||
value={routeMatch?.pattern?.path ?? routes.installationWithId}
|
||||
aria-label="basic tabs example"
|
||||
>
|
||||
<Tab
|
||||
label={intl.formatMessage({
|
||||
id: "installation",
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { useState } from "react";
|
||||
import axiosConfig from "../config/axiosConfig";
|
||||
|
||||
const useToken = () => {
|
||||
const getToken = () => {
|
||||
|
@ -11,12 +10,17 @@ const useToken = () => {
|
|||
const saveToken = (userToken: any) => {
|
||||
sessionStorage.setItem("token", JSON.stringify(userToken));
|
||||
setToken(userToken);
|
||||
axiosConfig.defaults.headers.common["auth"] = userToken;
|
||||
};
|
||||
|
||||
const removeToken = () => {
|
||||
sessionStorage.removeItem("token");
|
||||
setToken(null);
|
||||
};
|
||||
|
||||
return {
|
||||
setToken: saveToken,
|
||||
token,
|
||||
removeToken,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"alarms": "Alarme",
|
||||
"allInstallations": "Alle Installationen",
|
||||
"applyChanges": "Änderungen übernehmen",
|
||||
"country": "Land",
|
||||
"customerName": "Kundenname",
|
||||
"english": "Englisch",
|
||||
"german": "Deutsch",
|
||||
"installation": "Installation",
|
||||
"location": "Ort",
|
||||
"log": "Log",
|
||||
"orderNumbers": "Bestellnummern",
|
||||
"region": "Region",
|
||||
"search": "Suche",
|
||||
"users": "Benutzer",
|
||||
"logout": "Logout",
|
||||
"updatedSuccessfully": "Erfolgreich aktualisiert"
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"alarms": "Alarms",
|
||||
"allInstallations": "All installations",
|
||||
"applyChanges": "Apply changes",
|
||||
"country": "country",
|
||||
"customerName": "Customer name",
|
||||
"english": "English",
|
||||
"german": "German",
|
||||
"installation": "Installation",
|
||||
"location": "Location",
|
||||
"log": "Log",
|
||||
"orderNumbers": "Order numbers",
|
||||
"region": "Region",
|
||||
"search": "Search",
|
||||
"users": "Users",
|
||||
"logout": "Logout",
|
||||
"updatedSuccessfully": "Updated successfully"
|
||||
}
|
|
@ -8,7 +8,6 @@ import routes from "../routes.json";
|
|||
import InstallationDetail from "./Installation";
|
||||
|
||||
const Home = () => {
|
||||
|
||||
return (
|
||||
<Box sx={{ padding: 2, bgcolor: "orange.50" }}>
|
||||
<Grid container spacing={2}>
|
||||
|
@ -27,7 +26,7 @@ const Home = () => {
|
|||
type="search"
|
||||
fullWidth
|
||||
/>
|
||||
<NestedList />
|
||||
<NestedList />
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Box, CircularProgress } from "@mui/material";
|
||||
import { Alert, Box, CircularProgress } from "@mui/material";
|
||||
import { AxiosError } from "axios";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import CustomerForm from "../components/CustomerForm";
|
||||
|
@ -9,23 +10,36 @@ const InstallationDetail = () => {
|
|||
const { id } = useParams();
|
||||
const [values, setValues] = useState<I_Installation>();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<AxiosError>();
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
axiosConfig.get("/GetInstallationById?id=" + id).then((res) => {
|
||||
setValues(res.data);
|
||||
setLoading(false);
|
||||
});
|
||||
axiosConfig
|
||||
.get("/GetInstallationById?id=" + id)
|
||||
.then((res) => {
|
||||
setValues(res.data);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
setError(err);
|
||||
setLoading(false);
|
||||
});
|
||||
}, [id]);
|
||||
|
||||
if (values && values.id.toString() === id) {
|
||||
if (error) {
|
||||
return (
|
||||
<Alert severity="error" sx={{ mt: 1 }}>
|
||||
{error.message}
|
||||
</Alert>
|
||||
);
|
||||
} else if (values && values.id.toString() === id) {
|
||||
return (
|
||||
<Box sx={{ py: 3, width: 1 / 2 }}>
|
||||
<CustomerForm values={values} id={id} />
|
||||
</Box>
|
||||
);
|
||||
} else if (loading) {
|
||||
return <CircularProgress />;
|
||||
return <CircularProgress sx={{ m: 2 }} />;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ export interface I_Installation {
|
|||
location: string;
|
||||
region: string;
|
||||
country: string;
|
||||
orderNumber: string;
|
||||
orderNumbers: string;
|
||||
lat: number;
|
||||
long: number;
|
||||
s3Bucket: string;
|
||||
|
@ -17,5 +17,3 @@ export interface I_Installation {
|
|||
information: string;
|
||||
parentId: number;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue