diff --git a/virtweb_frontend/eslint.config.js b/virtweb_frontend/eslint.config.js
index 1fd4d8a..56bdec9 100644
--- a/virtweb_frontend/eslint.config.js
+++ b/virtweb_frontend/eslint.config.js
@@ -1,12 +1,11 @@
import js from "@eslint/js";
-import reactDom from 'eslint-plugin-react-dom';
+import reactDom from "eslint-plugin-react-dom";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
-import reactX from 'eslint-plugin-react-x';
+import reactX from "eslint-plugin-react-x";
import globals from "globals";
import tseslint from "typescript-eslint";
-
export default tseslint.config(
{ ignores: ["dist"] },
{
@@ -38,7 +37,17 @@ export default tseslint.config(
],
...reactX.configs["recommended-typescript"].rules,
...reactDom.configs.recommended.rules,
- "@typescript-eslint/no-non-null-assertion": "off"
+ "@typescript-eslint/no-non-null-assertion": "off",
+ "@typescript-eslint/no-misused-promises": "off",
+ "@typescript-eslint/no-floating-promises": "off",
+ "@typescript-eslint/restrict-template-expressions": "off",
+ "@typescript-eslint/no-extraneous-class": "off",
+ "@typescript-eslint/no-explicit-any": "off",
+ "@typescript-eslint/no-unsafe-assignment": "off",
+ "@typescript-eslint/no-unsafe-return": "off",
+ "@typescript-eslint/no-unsafe-call": "off",
+ "@typescript-eslint/no-unsafe-argument": "off",
+ "react-refresh/only-export-components": "off",
},
}
);
diff --git a/virtweb_frontend/src/api/ApiClient.ts b/virtweb_frontend/src/api/ApiClient.ts
index 49df36b..7cb9445 100644
--- a/virtweb_frontend/src/api/ApiClient.ts
+++ b/virtweb_frontend/src/api/ApiClient.ts
@@ -26,7 +26,7 @@ export class APIClient {
* Get backend URL
*/
static backendURL(): string {
- const URL = import.meta.env.VITE_APP_BACKEND ?? "";
+ const URL = String(import.meta.env.VITE_APP_BACKEND ?? "");
if (URL.length === 0) throw new Error("Backend URL undefined!");
return URL;
}
diff --git a/virtweb_frontend/src/routes/IsoFilesRoute.tsx b/virtweb_frontend/src/routes/IsoFilesRoute.tsx
index 894ab54..c30a6fd 100644
--- a/virtweb_frontend/src/routes/IsoFilesRoute.tsx
+++ b/virtweb_frontend/src/routes/IsoFilesRoute.tsx
@@ -96,7 +96,7 @@ function UploadIsoFileCard(p: {
p.onFileUploaded();
} catch (e) {
console.error(e);
- await alert("Failed to perform file upload! " + e);
+ await alert(`Failed to perform file upload! ${e}`);
}
setUploadProgress(null);
@@ -120,7 +120,9 @@ function UploadIsoFileCard(p: {
value={value}
onChange={handleChange}
style={{ flex: 1 }}
- inputProps={{ accept: ServerApi.Config.iso_mimetypes.join(",") }}
+ slotProps={{
+ htmlInput: { accept: ServerApi.Config.iso_mimetypes.join(",") },
+ }}
/>
{value && }
@@ -166,14 +168,18 @@ function UploadIsoFileFromUrlCard(p: {
label="URL"
value={url}
style={{ flex: 3 }}
- onChange={(e) => { setURL(e.target.value); }}
+ onChange={(e) => {
+ setURL(e.target.value);
+ }}
/>
{ setFilename(e.target.value); }}
+ onChange={(e) => {
+ setFilename(e.target.value);
+ }}
/>
{url !== "" && actualFileName !== "" && (
@@ -238,7 +244,7 @@ function IsoFilesList(p: {
);
- const columns: GridColDef[] = [
+ const columns: GridColDef[] = [
{ field: "filename", headerName: "File name", flex: 3 },
{
field: "size",
@@ -303,7 +309,6 @@ function IsoFilesList(p: {
getRowId={(c) => c.filename}
rows={p.list}
columns={columns}
- autoHeight={true}
/>
>
diff --git a/virtweb_frontend/src/utils/FilesUtils.ts b/virtweb_frontend/src/utils/FilesUtils.ts
index 80e9874..c397fdc 100644
--- a/virtweb_frontend/src/utils/FilesUtils.ts
+++ b/virtweb_frontend/src/utils/FilesUtils.ts
@@ -1,4 +1,4 @@
-export async function downloadBlob(blob: Blob, filename: string) {
+export function downloadBlob(blob: Blob, filename: string) {
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
diff --git a/virtweb_frontend/src/widgets/forms/MACInput.tsx b/virtweb_frontend/src/widgets/forms/MACInput.tsx
index 6a121c0..b7c088c 100644
--- a/virtweb_frontend/src/widgets/forms/MACInput.tsx
+++ b/virtweb_frontend/src/widgets/forms/MACInput.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-condition */
import { TextInput } from "./TextInput";
export function MACInput(p: {
diff --git a/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx b/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx
index a0cedb0..3622a42 100644
--- a/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx
+++ b/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable react-x/no-array-index-key */
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward";
import DeleteIcon from "@mui/icons-material/Delete";
@@ -66,9 +67,19 @@ export function NWFilterRules(p: {
deleteRule(n);
}}
onGoDown={
- n < p.rules.length - 1 ? () => { swapRules(n, n + 1); } : undefined
+ n < p.rules.length - 1
+ ? () => {
+ swapRules(n, n + 1);
+ }
+ : undefined
+ }
+ onGoUp={
+ n > 0
+ ? () => {
+ swapRules(n, n - 1);
+ }
+ : undefined
}
- onGoUp={n > 0 ? () => { swapRules(n, n - 1); } : undefined}
{...p}
/>
))}
@@ -153,7 +164,9 @@ function NWRuleEdit(p: {
editable={p.editable}
onChange={p.onChange}
selector={s}
- onDelete={() => { deleteSelector(n); }}
+ onDelete={() => {
+ deleteSelector(n);
+ }}
/>
))}
diff --git a/virtweb_frontend/src/widgets/forms/NetDHCPHostReservations.tsx b/virtweb_frontend/src/widgets/forms/NetDHCPHostReservations.tsx
index 220cbf4..2425ffd 100644
--- a/virtweb_frontend/src/widgets/forms/NetDHCPHostReservations.tsx
+++ b/virtweb_frontend/src/widgets/forms/NetDHCPHostReservations.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable react-x/no-array-index-key */
import { mdiIp } from "@mdi/js";
import Icon from "@mdi/react";
import DeleteIcon from "@mui/icons-material/Delete";
diff --git a/virtweb_frontend/src/widgets/forms/NetNatConfiguration.tsx b/virtweb_frontend/src/widgets/forms/NetNatConfiguration.tsx
index d4b5cb4..7390dd3 100644
--- a/virtweb_frontend/src/widgets/forms/NetNatConfiguration.tsx
+++ b/virtweb_frontend/src/widgets/forms/NetNatConfiguration.tsx
@@ -54,6 +54,7 @@ export function NetNatConfiguration(p: {
<>
{p.nat.map((e, num) => (
(
void;
}): React.ReactElement {
- if (!p.attachedISOs && !p.editable) return <>>;
+ if (p.attachedISOs.length === 0 && !p.editable) return <>>;
return (
<>
@@ -27,7 +27,7 @@ export function VMSelectIsoInput(p: {
const iso = p.isoList.find((d) => d.filename === isoName);
return (
{
- return {
- label: `${i.filename} ${filesize(i.size)}`,
- value: i.filename,
- };
- })
- }
+ return {
+ label: `${i.filename} ${filesize(i.size)}`,
+ value: i.filename,
+ };
+ })}
/>
>
);
diff --git a/virtweb_frontend/src/widgets/net/NetworkDetails.tsx b/virtweb_frontend/src/widgets/net/NetworkDetails.tsx
index faf8a66..238cf90 100644
--- a/virtweb_frontend/src/widgets/net/NetworkDetails.tsx
+++ b/virtweb_frontend/src/widgets/net/NetworkDetails.tsx
@@ -25,7 +25,7 @@ interface DetailsProps {
}
export function NetworkDetails(p: DetailsProps): React.ReactElement {
- const [nicsList, setNicsList] = React.useState();
+ const [nicsList, setNicsList] = React.useState();
const load = async () => {
setNicsList(await ServerApi.GetNetworksList());
@@ -36,7 +36,7 @@ export function NetworkDetails(p: DetailsProps): React.ReactElement {
loadKey={"1"}
load={load}
errMsg="Failed to load the list of host network cards!"
- build={() => }
+ build={() => }
/>
);
}
@@ -306,7 +306,7 @@ function IPSection(p: {
p.config!.nat = [];
} else {
if (
- (p.config?.nat?.length ?? 0 > 0) &&
+ (p.config?.nat?.length ?? 0) > 0 &&
!(await confirm(
`Do you really want to disable IPv${p.version} NAT port forwarding on this network? Specific configuration will be deleted!`
))
diff --git a/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx b/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx
index d72aef9..4db0fb2 100644
--- a/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx
+++ b/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx
@@ -28,7 +28,9 @@ interface DetailsProps {
}
export function NWFilterDetails(p: DetailsProps): ReactElement {
- const [nwFiltersList, setNwFiltersList] = React.useState();
+ const [nwFiltersList, setNwFiltersList] = React.useState<
+ NWFilter[] | undefined
+ >();
const load = async () => {
setNwFiltersList(await NWFilterApi.GetList());
@@ -40,7 +42,7 @@ export function NWFilterDetails(p: DetailsProps): ReactElement {
load={load}
errMsg="Failed to load the list of network filters!"
build={() => (
-
+
)}
/>
);
@@ -116,7 +118,7 @@ function NetworkFilterDetailsTabGeneral(
p.nwfilter.name = v ?? "";
p.onChange?.();
}}
- checkValue={(v) => /^[a-zA-Z0-9\_\-]+$/.test(v)}
+ checkValue={(v) => /^[a-zA-Z0-9_-]+$/.test(v)}
size={ServerApi.Config.constraints.nwfilter_name_size}
/>
diff --git a/virtweb_frontend/src/widgets/tokens/APITokenDetails.tsx b/virtweb_frontend/src/widgets/tokens/APITokenDetails.tsx
index d3eca49..18c5a97 100644
--- a/virtweb_frontend/src/widgets/tokens/APITokenDetails.tsx
+++ b/virtweb_frontend/src/widgets/tokens/APITokenDetails.tsx
@@ -161,14 +161,14 @@ function APITokenTabGeneral(p: DetailsInnerProps): React.ReactElement {
{p.status === TokenWidgetStatus.Create && (
{
- setIpVersion(Number(v) as any);
+ setIpVersion(Number(v) as 4 | 6);
}}
label="Token IP restriction version"
/>
diff --git a/virtweb_frontend/src/widgets/tokens/TokenRawRightsEditor.tsx b/virtweb_frontend/src/widgets/tokens/TokenRawRightsEditor.tsx
index 1bcd837..e2294d1 100644
--- a/virtweb_frontend/src/widgets/tokens/TokenRawRightsEditor.tsx
+++ b/virtweb_frontend/src/widgets/tokens/TokenRawRightsEditor.tsx
@@ -63,6 +63,7 @@ export function TokenRawRightsEditor(p: {
{p.token.rights.map((r, num) => (
+ // eslint-disable-next-line react-x/no-array-index-key
{p.editable && (
- { deleteRule(num); }}>
+ {
+ deleteRule(num);
+ }}
+ >
diff --git a/virtweb_frontend/src/widgets/tokens/TokenRightsEditor.tsx b/virtweb_frontend/src/widgets/tokens/TokenRightsEditor.tsx
index a5891ee..dbb3c9a 100644
--- a/virtweb_frontend/src/widgets/tokens/TokenRightsEditor.tsx
+++ b/virtweb_frontend/src/widgets/tokens/TokenRightsEditor.tsx
@@ -85,8 +85,8 @@ export function TokenRightsEditor(p: {
{/* Per VM operations */}
- {p.vms.map((v, n) => (
-
+ {p.vms.map((v) => (
+
{v.name}
{/* Per VM operations */}
- {p.vms.map((v, n) => (
-
+ {p.vms.map((v) => (
+
{v.name}
{/* Per VM operations */}
- {p.groups.map((v, n) => (
-
+ {p.groups.map((v) => (
+
{v}
{/* Per network operations */}
- {p.networks.map((v, n) => (
-
+ {p.networks.map((v) => (
+
{v.name}
{/* Per network filter operations */}
- {p.nwFilters.map((v, n) => (
-
+ {p.nwFilters.map((v) => (
+
{v.name}
{/* Per API token operations */}
- {p.tokens.map((v, n) => (
-
+ {p.tokens.map((v) => (
+
{v.name}
{ toggle(a); }}
+ onChange={(_e, a) => {
+ toggle(a);
+ }}
/>
}
label={p.label}
@@ -814,7 +816,9 @@ function RouteRight(p: RightOpts): React.ReactElement {
{ toggle(a); }}
+ onChange={(_e, a) => {
+ toggle(a);
+ }}
/>
)}
diff --git a/virtweb_frontend/src/widgets/vms/VMDetails.tsx b/virtweb_frontend/src/widgets/vms/VMDetails.tsx
index 1b338af..912885c 100644
--- a/virtweb_frontend/src/widgets/vms/VMDetails.tsx
+++ b/virtweb_frontend/src/widgets/vms/VMDetails.tsx
@@ -35,14 +35,16 @@ interface DetailsProps {
}
export function VMDetails(p: DetailsProps): React.ReactElement {
- const [groupsList, setGroupsList] = React.useState();
- const [isoList, setIsoList] = React.useState();
+ const [groupsList, setGroupsList] = React.useState();
+ const [isoList, setIsoList] = React.useState();
const [vcpuCombinations, setVCPUCombinations] = React.useState<
- number[] | any
+ number[] | undefined
+ >();
+ const [networksList, setNetworksList] = React.useState<
+ NetworkInfo[] | undefined
>();
- const [networksList, setNetworksList] = React.useState();
const [networkFiltersList, setNetworkFiltersList] = React.useState<
- NWFilter[] | any
+ NWFilter[] | undefined
>();
const load = async () => {
@@ -60,11 +62,11 @@ export function VMDetails(p: DetailsProps): React.ReactElement {
errMsg="Failed to load the list of ISO files"
build={() => (
)}
@@ -202,7 +204,7 @@ function VMDetailsTabGeneral(p: DetailsInnerProps): React.ReactElement {
editable={p.editable}
label="Group"
onValueChange={(v) => {
- p.vm.group = v! as any;
+ p.vm.group = v!;
p.onChange?.();
}}
value={p.vm.group}
@@ -222,7 +224,11 @@ function VMDetailsTabGeneral(p: DetailsInnerProps): React.ReactElement {
: "Add a new group instead of using existing one"
}
>
- { setAddGroup(!addGroup); }}>
+ {
+ setAddGroup(!addGroup);
+ }}
+ >
{addGroup ? : }
diff --git a/virtweb_frontend/src/widgets/vms/VMScreenshot.tsx b/virtweb_frontend/src/widgets/vms/VMScreenshot.tsx
index 9974452..e043ac9 100644
--- a/virtweb_frontend/src/widgets/vms/VMScreenshot.tsx
+++ b/virtweb_frontend/src/widgets/vms/VMScreenshot.tsx
@@ -9,7 +9,7 @@ export function VMScreenshot(p: { vm: VMInfo }): React.ReactElement {
string | undefined
>();
- const int = React.useRef(undefined);
+ const int = React.useRef(undefined);
React.useEffect(() => {
const refresh = async () => {
@@ -25,7 +25,9 @@ export function VMScreenshot(p: { vm: VMInfo }): React.ReactElement {
if (int.current === undefined) {
refresh();
- int.current = setInterval(() => refresh(), 5000);
+ int.current = setInterval(() => {
+ refresh();
+ }, 5000);
}
return () => {
diff --git a/virtweb_frontend/src/widgets/vms/VMStatusWidget.tsx b/virtweb_frontend/src/widgets/vms/VMStatusWidget.tsx
index 5b4881a..015a7c3 100644
--- a/virtweb_frontend/src/widgets/vms/VMStatusWidget.tsx
+++ b/virtweb_frontend/src/widgets/vms/VMStatusWidget.tsx
@@ -31,13 +31,19 @@ export function VMStatusWidget(p: {
}
};
- const changedAction = () => { setState(undefined); };
+ const changedAction = () => {
+ setState(undefined);
+ };
React.useEffect(() => {
refresh();
- const i = setInterval(() => refresh(), 3000);
+ const i = setInterval(() => {
+ refresh();
+ }, 3000);
- return () => { clearInterval(i); };
+ return () => {
+ clearInterval(i);
+ };
});
if (state === undefined)
@@ -59,6 +65,7 @@ export function VMStatusWidget(p: {
icon={}
tooltip="Graphical remote control over the VM"
performAction={async () => navigate(p.vm.VNCURL)}
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
onExecuted={() => {}}
/>
)