mirror of
https://github.com/chirpstack/chirpstack.git
synced 2025-06-16 14:28:14 +00:00
ui: Migrate from create-react-app to vite (#459)
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
import React, { PropsWithChildren, useState, useEffect } from "react";
|
||||
import type { PropsWithChildren } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
import SessionStore from "../stores/SessionStore";
|
||||
|
||||
|
@ -36,7 +36,7 @@ function AesKeyInput(props: IProps) {
|
||||
};
|
||||
|
||||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
let v = e.target.value;
|
||||
const v = e.target.value;
|
||||
const match = v.match(/[A-Fa-f0-9]/g);
|
||||
|
||||
let value = "";
|
||||
@ -68,11 +68,11 @@ function AesKeyInput(props: IProps) {
|
||||
};
|
||||
|
||||
const generateRandom = () => {
|
||||
let cryptoObj = window.crypto || window.Crypto;
|
||||
let b = new Uint8Array(16);
|
||||
const cryptoObj = window.crypto || window.Crypto;
|
||||
const b = new Uint8Array(16);
|
||||
cryptoObj.getRandomValues(b);
|
||||
|
||||
let key = Buffer.from(b).toString("hex");
|
||||
const key = Buffer.from(b).toString("hex");
|
||||
setValue(key);
|
||||
updateField(key);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
import { Select } from "antd";
|
||||
|
||||
@ -55,7 +55,7 @@ function AutoComplete({ placeholder, className, value, getOption, getOptions, on
|
||||
});
|
||||
};
|
||||
|
||||
const onSelectFn = (value: string, option: any) => {
|
||||
const onSelectFn = (value: string, option: Option) => {
|
||||
setOption({ label: option.label, value: option.value });
|
||||
|
||||
if (onSelect !== undefined) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Form } from "antd";
|
||||
|
||||
import Autocomplete, { OptionCallbackFunc, OptionsCallbackFunc } from "./Autocomplete";
|
||||
import type { OptionCallbackFunc, OptionsCallbackFunc } from "./Autocomplete";
|
||||
import Autocomplete from "./Autocomplete";
|
||||
|
||||
interface IProps {
|
||||
label: string;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { Controlled as CodeMirror } from "react-codemirror2";
|
||||
import type { Editor, EditorChange } from "codemirror";
|
||||
|
||||
import { Form } from "antd";
|
||||
|
||||
@ -23,7 +24,7 @@ function CodeEditor(props: IProps) {
|
||||
setReloadKey(k => k + 1);
|
||||
}, [form, props]);
|
||||
|
||||
const handleChange = (editor: any, data: any, newCode: string) => {
|
||||
const handleChange = (editor: Editor, data: EditorChange, newCode: string) => {
|
||||
setValue(newCode);
|
||||
form.setFieldsValue({
|
||||
[props.name]: newCode,
|
||||
|
@ -1,18 +1,19 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
|
||||
import { Table } from "antd";
|
||||
import { ColumnsType } from "antd/es/table";
|
||||
import type { ColumnsType } from "antd/es/table";
|
||||
|
||||
import SessionStore from "../stores/SessionStore";
|
||||
|
||||
export type GetPageCallbackFunc = (totalCount: number, rows: object[]) => void;
|
||||
|
||||
interface IProps {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
columns: ColumnsType<any>;
|
||||
getPage: (limit: number, offset: number, callbackFunc: GetPageCallbackFunc) => void;
|
||||
onRowsSelectChange?: (ids: string[]) => void;
|
||||
rowKey: string;
|
||||
refreshKey?: any;
|
||||
refreshKey?: unknown;
|
||||
noPagination?: boolean;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { useState, PropsWithChildren } from "react";
|
||||
import type { PropsWithChildren } from "react";
|
||||
import { useState } from "react";
|
||||
import { Popover, Button, Typography, Space, Input } from "antd";
|
||||
|
||||
interface IProps {
|
||||
|
@ -3,7 +3,8 @@ import React, { useState, useEffect } from "react";
|
||||
import { notification, Input, Select, Button, Space, Form, Dropdown, Menu } from "antd";
|
||||
import { ReloadOutlined, CopyOutlined } from "@ant-design/icons";
|
||||
|
||||
import { GetRandomDevAddrRequest, GetRandomDevAddrResponse } from "@chirpstack/chirpstack-api-grpc-web/api/device_pb";
|
||||
import type { GetRandomDevAddrResponse } from "@chirpstack/chirpstack-api-grpc-web/api/device_pb";
|
||||
import { GetRandomDevAddrRequest } from "@chirpstack/chirpstack-api-grpc-web/api/device_pb";
|
||||
|
||||
import DeviceStore from "../stores/DeviceStore";
|
||||
|
||||
@ -39,7 +40,7 @@ function DevAddrInput(props: IProps) {
|
||||
};
|
||||
|
||||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
let v = e.target.value;
|
||||
const v = e.target.value;
|
||||
const match = v.match(/[A-Fa-f0-9]/g);
|
||||
|
||||
let value = "";
|
||||
@ -71,7 +72,7 @@ function DevAddrInput(props: IProps) {
|
||||
};
|
||||
|
||||
const generateRandom = () => {
|
||||
let req = new GetRandomDevAddrRequest();
|
||||
const req = new GetRandomDevAddrRequest();
|
||||
req.setDevEui(props.devEui);
|
||||
|
||||
DeviceStore.getRandomDevAddr(req, (resp: GetRandomDevAddrResponse) => {
|
||||
|
@ -36,7 +36,7 @@ function EuiInput(props: IProps) {
|
||||
};
|
||||
|
||||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
let v = e.target.value;
|
||||
const v = e.target.value;
|
||||
const match = v.match(/[A-Fa-f0-9]/g);
|
||||
|
||||
let value = "";
|
||||
@ -68,11 +68,11 @@ function EuiInput(props: IProps) {
|
||||
};
|
||||
|
||||
const generateRandom = () => {
|
||||
let cryptoObj = window.crypto || window.Crypto;
|
||||
let b = new Uint8Array(8);
|
||||
const cryptoObj = window.crypto || window.Crypto;
|
||||
const b = new Uint8Array(8);
|
||||
cryptoObj.getRandomValues(b);
|
||||
|
||||
let key = Buffer.from(b).toString("hex");
|
||||
const key = Buffer.from(b).toString("hex");
|
||||
setValue(key);
|
||||
updateField(key);
|
||||
};
|
||||
|
@ -1,15 +1,12 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
|
||||
import { Button, Menu, Dropdown, Input, AutoComplete } from "antd";
|
||||
import { UserOutlined, DownOutlined, QuestionOutlined } from "@ant-design/icons";
|
||||
|
||||
import { User } from "@chirpstack/chirpstack-api-grpc-web/api/user_pb";
|
||||
import {
|
||||
SettingsResponse,
|
||||
GlobalSearchRequest,
|
||||
GlobalSearchResponse,
|
||||
} from "@chirpstack/chirpstack-api-grpc-web/api/internal_pb";
|
||||
import type { User } from "@chirpstack/chirpstack-api-grpc-web/api/user_pb";
|
||||
import type { SettingsResponse, GlobalSearchResponse } from "@chirpstack/chirpstack-api-grpc-web/api/internal_pb";
|
||||
import { GlobalSearchRequest } from "@chirpstack/chirpstack-api-grpc-web/api/internal_pb";
|
||||
|
||||
import InternalStore from "../stores/InternalStore";
|
||||
import SessionStore from "../stores/SessionStore";
|
||||
@ -38,7 +35,7 @@ function Header({ user }: { user: User }) {
|
||||
return;
|
||||
}
|
||||
|
||||
let req = new GlobalSearchRequest();
|
||||
const req = new GlobalSearchRequest();
|
||||
req.setLimit(20);
|
||||
req.setSearch(search);
|
||||
|
||||
@ -52,8 +49,8 @@ function Header({ user }: { user: User }) {
|
||||
return;
|
||||
}
|
||||
|
||||
let oidc = settings.getOpenidConnect()!;
|
||||
let oAuth2 = settings.getOauth2()!;
|
||||
const oidc = settings.getOpenidConnect()!;
|
||||
const oAuth2 = settings.getOauth2()!;
|
||||
|
||||
if (oidc.getEnabled() && oidc.getLogoutUrl() !== "") {
|
||||
SessionStore.logout(false, () => {
|
||||
@ -74,8 +71,8 @@ function Header({ user }: { user: User }) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let oidcEnabled = settings!.getOpenidConnect()!.getEnabled();
|
||||
let oAuth2Enabled = settings!.getOauth2()!.getEnabled();
|
||||
const oidcEnabled = settings!.getOpenidConnect()!.getEnabled();
|
||||
const oAuth2Enabled = settings!.getOauth2()!.getEnabled();
|
||||
|
||||
const menu = (
|
||||
<Menu>
|
||||
@ -88,9 +85,9 @@ function Header({ user }: { user: User }) {
|
||||
</Menu>
|
||||
);
|
||||
|
||||
let options: {
|
||||
label: any;
|
||||
options: any[];
|
||||
const options: {
|
||||
label: JSX.Element;
|
||||
options: ReturnType<typeof renderItem>[];
|
||||
}[] = [
|
||||
{
|
||||
label: renderTitle("Tenants"),
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import { useState } from "react";
|
||||
|
||||
import moment from "moment";
|
||||
import { JSONTree as JSONTreeOriginal } from "react-json-tree";
|
||||
@ -7,7 +7,7 @@ import fileDownload from "js-file-download";
|
||||
import { Tag, Drawer, Button, Table, Spin, Space } from "antd";
|
||||
import { ZoomInOutlined } from "@ant-design/icons";
|
||||
|
||||
import { LogItem } from "@chirpstack/chirpstack-api-grpc-web/api/internal_pb";
|
||||
import type { LogItem } from "@chirpstack/chirpstack-api-grpc-web/api/internal_pb";
|
||||
|
||||
interface IProps {
|
||||
logs: LogItem[];
|
||||
@ -15,17 +15,17 @@ interface IProps {
|
||||
|
||||
function LogTable(props: IProps) {
|
||||
const [drawerOpen, setDrawerOpen] = useState<boolean>(false);
|
||||
const [body, setBody] = useState<any>(null);
|
||||
const [drawerTitle, setDrawerTitle] = useState<any>(null);
|
||||
const [body, setBody] = useState<string | null>(null);
|
||||
const [drawerTitle, setDrawerTitle] = useState<string | null>(null);
|
||||
|
||||
const onDrawerClose = () => {
|
||||
setDrawerOpen(false);
|
||||
};
|
||||
|
||||
const onDrawerOpen = (time: any, body: any) => {
|
||||
let ts = new Date(0);
|
||||
ts.setUTCSeconds(time.seconds);
|
||||
let drawerTitle = moment(ts).format("YYYY-MM-DD HH:mm:ss");
|
||||
const onDrawerOpen = (time: { seconds: number } | undefined, body: string) => {
|
||||
const ts = new Date(0);
|
||||
ts.setUTCSeconds(time!.seconds);
|
||||
const drawerTitle = moment(ts).format("YYYY-MM-DD HH:mm:ss");
|
||||
|
||||
return () => {
|
||||
setBody(body);
|
||||
@ -35,16 +35,16 @@ function LogTable(props: IProps) {
|
||||
};
|
||||
|
||||
const downloadSingleFrame = () => {
|
||||
fileDownload(JSON.stringify(JSON.parse(body), null, 4), "single-log.json", "application/json");
|
||||
fileDownload(JSON.stringify(JSON.parse(body!), null, 4), "single-log.json", "application/json");
|
||||
};
|
||||
|
||||
const downloadFrames = () => {
|
||||
let items = props.logs.map((l, i) => JSON.parse(l.getBody()));
|
||||
const items = props.logs.map((l, i) => JSON.parse(l.getBody()));
|
||||
fileDownload(JSON.stringify(items, null, 4), "log.json");
|
||||
};
|
||||
|
||||
let items = props.logs.map((l, i) => l.toObject());
|
||||
let bodyJson = JSON.parse(body);
|
||||
const items = props.logs.map((l, i) => l.toObject());
|
||||
const bodyJson = JSON.parse(body!);
|
||||
|
||||
const theme = {
|
||||
scheme: "google",
|
||||
@ -104,7 +104,7 @@ function LogTable(props: IProps) {
|
||||
key: "time",
|
||||
width: 200,
|
||||
render: (text, obj) => {
|
||||
let ts = new Date(0);
|
||||
const ts = new Date(0);
|
||||
ts.setUTCSeconds(obj.time!.seconds);
|
||||
return moment(ts).format("YYYY-MM-DD HH:mm:ss");
|
||||
},
|
||||
|
@ -1,8 +1,11 @@
|
||||
import React, { useEffect, PropsWithChildren, useState } from "react";
|
||||
import type { PropsWithChildren } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import L, { LatLngTuple, FitBoundsOptions } from "leaflet";
|
||||
import type { LatLngTuple, FitBoundsOptions } from "leaflet";
|
||||
import L from "leaflet";
|
||||
import "leaflet.awesome-markers";
|
||||
import { MarkerProps as LMarkerProps, useMap } from "react-leaflet";
|
||||
import type { MarkerProps as LMarkerProps } from "react-leaflet";
|
||||
import { useMap } from "react-leaflet";
|
||||
import { MapContainer, Marker as LMarker, TileLayer } from "react-leaflet";
|
||||
|
||||
import InternalStore from "../stores/InternalStore";
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
|
||||
import { Menu, MenuProps, Typography } from "antd";
|
||||
import type { MenuProps } from "antd";
|
||||
import { Menu, Typography } from "antd";
|
||||
import {
|
||||
CloudOutlined,
|
||||
HomeOutlined,
|
||||
@ -15,15 +16,13 @@ import {
|
||||
RadarChartOutlined,
|
||||
} from "@ant-design/icons";
|
||||
|
||||
import {
|
||||
GetTenantResponse,
|
||||
ListTenantsRequest,
|
||||
ListTenantsResponse,
|
||||
} from "@chirpstack/chirpstack-api-grpc-web/api/tenant_pb";
|
||||
import type { GetTenantResponse, ListTenantsResponse } from "@chirpstack/chirpstack-api-grpc-web/api/tenant_pb";
|
||||
import { ListTenantsRequest } from "@chirpstack/chirpstack-api-grpc-web/api/tenant_pb";
|
||||
|
||||
import { GetVersionResponse } from "@chirpstack/chirpstack-api-grpc-web/api/internal_pb";
|
||||
import type { GetVersionResponse } from "@chirpstack/chirpstack-api-grpc-web/api/internal_pb";
|
||||
|
||||
import Autocomplete, { OptionCallbackFunc, OptionsCallbackFunc } from "../components/Autocomplete";
|
||||
import type { OptionCallbackFunc, OptionsCallbackFunc } from "../components/Autocomplete";
|
||||
import Autocomplete from "../components/Autocomplete";
|
||||
import Admin from "../components/Admin";
|
||||
import TenantStore from "../stores/TenantStore";
|
||||
import SessionStore from "../stores/SessionStore";
|
||||
@ -42,7 +41,7 @@ function SideMenu() {
|
||||
};
|
||||
|
||||
const getTenantOptions = (search: string, fn: OptionsCallbackFunc) => {
|
||||
let req = new ListTenantsRequest();
|
||||
const req = new ListTenantsRequest();
|
||||
req.setSearch(search);
|
||||
req.setLimit(10);
|
||||
|
||||
@ -162,7 +161,7 @@ function SideMenu() {
|
||||
parseLocation();
|
||||
}, [location, parseLocation]);
|
||||
|
||||
let items: MenuProps["items"] = [];
|
||||
const items: MenuProps["items"] = [];
|
||||
|
||||
if (SessionStore.isAdmin()) {
|
||||
items.push({
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { Card } from "antd";
|
||||
|
||||
import { TimeUnit } from "chart.js";
|
||||
import type { TimeUnit } from "chart.js";
|
||||
import { Bar } from "react-chartjs-2";
|
||||
import moment from "moment";
|
||||
import palette from "google-palette";
|
||||
|
||||
import { Metric, Aggregation } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
|
||||
import type { Metric } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
|
||||
import { Aggregation } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
|
||||
|
||||
interface IProps {
|
||||
metric: Metric;
|
||||
@ -20,7 +21,7 @@ function MetricBar(props: IProps) {
|
||||
unit = "month";
|
||||
}
|
||||
|
||||
const animation: false = false;
|
||||
const animation = false as const;
|
||||
|
||||
const options = {
|
||||
animation: animation,
|
||||
@ -43,7 +44,7 @@ function MetricBar(props: IProps) {
|
||||
},
|
||||
};
|
||||
|
||||
let data: {
|
||||
const data: {
|
||||
labels: number[];
|
||||
datasets: {
|
||||
label: string;
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { Card } from "antd";
|
||||
|
||||
import { TimeUnit } from "chart.js";
|
||||
import type { TimeUnit } from "chart.js";
|
||||
import { Line } from "react-chartjs-2";
|
||||
import moment from "moment";
|
||||
import palette from "google-palette";
|
||||
|
||||
import { Metric, Aggregation, MetricKind } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
|
||||
import type { Metric } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
|
||||
import { Aggregation, MetricKind } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
|
||||
|
||||
interface IProps {
|
||||
metric: Metric;
|
||||
@ -27,7 +28,7 @@ function MetricChart(props: IProps) {
|
||||
tooltipFormat = "LT";
|
||||
}
|
||||
|
||||
const animation: false = false;
|
||||
const animation = false as const;
|
||||
|
||||
const options = {
|
||||
animation: animation,
|
||||
@ -52,7 +53,7 @@ function MetricChart(props: IProps) {
|
||||
};
|
||||
|
||||
let prevValue = 0;
|
||||
let data = {
|
||||
const data = {
|
||||
labels: props.metric.getTimestampsList().map(v => moment(v.toDate()).valueOf()),
|
||||
datasets: props.metric
|
||||
.getDatasetsList()
|
||||
@ -72,7 +73,7 @@ function MetricChart(props: IProps) {
|
||||
return null;
|
||||
} else {
|
||||
if (props.metric.getKind() === MetricKind.COUNTER) {
|
||||
let val = v - prevValue;
|
||||
const val = v - prevValue;
|
||||
prevValue = v;
|
||||
if (val < 0) {
|
||||
return 0;
|
||||
|
@ -1,11 +1,14 @@
|
||||
// TODO: find a way to type `ctx`
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { Card } from "antd";
|
||||
|
||||
import { color } from "chart.js/helpers";
|
||||
import { TimeUnit } from "chart.js";
|
||||
import type { TimeUnit } from "chart.js";
|
||||
import { Chart } from "react-chartjs-2";
|
||||
import moment from "moment";
|
||||
|
||||
import { Metric, Aggregation } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
|
||||
import type { Metric } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
|
||||
import { Aggregation } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
|
||||
|
||||
interface IProps {
|
||||
metric: Metric;
|
||||
@ -22,9 +25,9 @@ function MetricHeatmap(props: IProps) {
|
||||
unit = "month";
|
||||
}
|
||||
|
||||
const animation: false = false;
|
||||
const animation = false as const;
|
||||
|
||||
let options = {
|
||||
const options = {
|
||||
animation: animation,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
@ -63,13 +66,13 @@ function MetricHeatmap(props: IProps) {
|
||||
},
|
||||
};
|
||||
|
||||
let dataData: {
|
||||
const dataData: {
|
||||
x: number;
|
||||
y: string;
|
||||
v: number;
|
||||
}[] = [];
|
||||
|
||||
let data = {
|
||||
const data = {
|
||||
labels: props.metric.getDatasetsList().map(v => v.getLabel()),
|
||||
datasets: [
|
||||
{
|
||||
@ -93,8 +96,8 @@ function MetricHeatmap(props: IProps) {
|
||||
const step = value - ctx.dataset.minValue;
|
||||
const factor = (1 / steps) * step;
|
||||
|
||||
let result: [number, number, number] = ctx.dataset.fromColor.slice();
|
||||
for (var i = 0; i < 3; i++) {
|
||||
const result: [number, number, number] = ctx.dataset.fromColor.slice();
|
||||
for (let i = 0; i < 3; i++) {
|
||||
result[i] = Math.round(result[i] + factor * (ctx.dataset.toColor[i] - ctx.dataset.fromColor[i]));
|
||||
}
|
||||
|
||||
@ -117,8 +120,8 @@ function MetricHeatmap(props: IProps) {
|
||||
const dsList = props.metric.getDatasetsList();
|
||||
|
||||
for (let i = 0; i < tsList.length; i++) {
|
||||
for (let ds of dsList) {
|
||||
let v = ds.getDataList()[i];
|
||||
for (const ds of dsList) {
|
||||
const v = ds.getDataList()[i];
|
||||
if (v === 0) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import { notification, Input, Select, Button, Space, Form, Dropdown, Menu } from "antd";
|
||||
@ -37,7 +36,7 @@ function RelayIdInput(props: IProps) {
|
||||
};
|
||||
|
||||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
let v = e.target.value;
|
||||
const v = e.target.value;
|
||||
const match = v.match(/[A-Fa-f0-9]/g);
|
||||
|
||||
let value = "";
|
||||
@ -69,11 +68,11 @@ function RelayIdInput(props: IProps) {
|
||||
};
|
||||
|
||||
const generateRandom = () => {
|
||||
let cryptoObj = window.crypto || window.Crypto;
|
||||
let b = new Uint8Array(4);
|
||||
const cryptoObj = window.crypto || window.Crypto;
|
||||
const b = new Uint8Array(4);
|
||||
cryptoObj.getRandomValues(b);
|
||||
|
||||
let key = Buffer.from(b).toString("hex");
|
||||
const key = Buffer.from(b).toString("hex");
|
||||
setValue(key);
|
||||
updateField(key);
|
||||
};
|
||||
|
Reference in New Issue
Block a user