mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui.git
synced 2025-10-30 02:12:33 +00:00
Merge pull request #34 from Telecominfraproject/dev-microservice
Dev microservice
This commit is contained in:
@@ -1 +1,4 @@
|
||||
/src/assets
|
||||
/src/assets
|
||||
/build
|
||||
/node_modules
|
||||
.github
|
||||
|
||||
34
.eslintrc
34
.eslintrc
@@ -1,16 +1,11 @@
|
||||
{
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"allowImportExportEverywhere": false,
|
||||
"codeFrame": false
|
||||
},
|
||||
"extends": ["airbnb", "prettier"],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"jest": true
|
||||
},
|
||||
"rules": {
|
||||
"extends": ["airbnb", "prettier"],
|
||||
"plugins": ["prettier"],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"jest": true
|
||||
},
|
||||
"rules": {
|
||||
"max-len": ["error", {"code": 150}],
|
||||
"prefer-promise-reject-errors": ["off"],
|
||||
"react/jsx-filename-extension": ["off"],
|
||||
@@ -18,13 +13,22 @@
|
||||
"no-return-assign": ["off"],
|
||||
"react/jsx-props-no-spreading": ["off"],
|
||||
"react/destructuring-assignment": ["off"],
|
||||
"no-restricted-syntax": ["error", "ForInStatement", "LabeledStatement", "WithStatement"]
|
||||
"no-restricted-syntax": ["error", "ForInStatement", "LabeledStatement", "WithStatement"],
|
||||
"react/jsx-one-expression-per-line": "off",
|
||||
"react/jsx-wrap-multilines": "off",
|
||||
"react/jsx-curly-newline": "off"
|
||||
},
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"node": {
|
||||
"paths": ["src"]
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"allowImportExportEverywhere": false,
|
||||
"codeFrame": false
|
||||
}
|
||||
}
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,4 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
4
.prettierignore
Normal file
4
.prettierignore
Normal file
@@ -0,0 +1,4 @@
|
||||
/src/assets
|
||||
build
|
||||
node_modules
|
||||
.github
|
||||
@@ -26,12 +26,12 @@ npm run build
|
||||
Once the build is done, you can move the `build` folder on your server.
|
||||
|
||||
### Configuration
|
||||
You must change the `config.json` file in `public` directory to point to your gateway URL. You may also limit the ability for users to change the default gateway. If you do not allow a gateway change, the gateway URL will not appear on the login screen.
|
||||
You must change the `config.json` file in `public` directory to point to your uCentral Security Service URL (uCentralSec). You may also limit the ability for users to change the default uCentralSec. If you do not allow a uCentralSec change, the uCentralSec URL will not appear on the login screen.
|
||||
|
||||
Here are the current default values:
|
||||
```
|
||||
{
|
||||
"DEFAULT_GATEWAY_URL": "https://ucentral.dpaas.arilia.com:16001",
|
||||
"ALLOW_GATEWAY_CHANGE": false
|
||||
"DEFAULT_UCENTRALSEC_URL": "https://ucentral.dpaas.arilia.com:16001",
|
||||
"ALLOW_UCENTRALSEC_CHANGE": false
|
||||
}
|
||||
```
|
||||
|
||||
7
babel.config.json
Normal file
7
babel.config.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react"
|
||||
],
|
||||
"plugins": ["@babel/plugin-proposal-class-properties"]
|
||||
}
|
||||
12
config/paths.js
Normal file
12
config/paths.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
// Source files
|
||||
src: path.resolve(__dirname, '../src'),
|
||||
|
||||
// Production build files
|
||||
build: path.resolve(__dirname, '../build'),
|
||||
|
||||
// Static files that get copied to build folder
|
||||
public: path.resolve(__dirname, '../public'),
|
||||
};
|
||||
76
config/webpack.common.js
Normal file
76
config/webpack.common.js
Normal file
@@ -0,0 +1,76 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable prefer-template */
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const path = require('path');
|
||||
const paths = require('./paths');
|
||||
|
||||
module.exports = {
|
||||
entry: [paths.src + '/index.js'],
|
||||
output: {
|
||||
path: paths.build,
|
||||
filename: '[name].bundle.js',
|
||||
publicPath: '/',
|
||||
},
|
||||
resolve: {
|
||||
modules: [path.resolve('./node_modules'), path.resolve('./src')],
|
||||
preferRelative: true,
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
|
||||
new MiniCssExtractPlugin({
|
||||
filename: 'styles/[name].[contenthash].css',
|
||||
chunkFilename: '[id].[contenthash].css',
|
||||
}),
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: paths.src + '/assets',
|
||||
to: 'assets',
|
||||
globOptions: {
|
||||
ignore: ['*.DS_Store'],
|
||||
},
|
||||
},
|
||||
{
|
||||
from: paths.public + '/locales',
|
||||
to: 'locales',
|
||||
globOptions: {
|
||||
ignore: ['*.DS_Store'],
|
||||
},
|
||||
},
|
||||
{
|
||||
from: paths.public + '/config.json',
|
||||
to: 'config.json',
|
||||
},
|
||||
],
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
title: 'uCentralGW',
|
||||
favicon: paths.public + '/favicon.ico',
|
||||
template: paths.public + '/index.html',
|
||||
filename: 'index.html',
|
||||
}),
|
||||
],
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /node_modules/,
|
||||
use: ['babel-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.(css|scss)$/,
|
||||
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: ['@svgr/webpack'],
|
||||
},
|
||||
{ test: /\.(?:ico|gif|png|jpg|jpeg)$/i, type: 'asset/resource' },
|
||||
],
|
||||
},
|
||||
};
|
||||
53
config/webpack.dev.js
Normal file
53
config/webpack.dev.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable prefer-template */
|
||||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||
const { merge } = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const paths = require('./paths');
|
||||
const common = require('./webpack.common');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'development',
|
||||
|
||||
target: 'web',
|
||||
|
||||
devtool: 'inline-source-map',
|
||||
|
||||
devServer: {
|
||||
historyApiFallback: true,
|
||||
contentBase: paths.build,
|
||||
open: true,
|
||||
compress: false,
|
||||
hot: true,
|
||||
port: 3000,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.[js]sx?$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
plugins: [require.resolve('react-refresh/babel')],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
modules: [
|
||||
'node_modules',
|
||||
'src',
|
||||
path.resolve(__dirname, '../', 'node_modules', 'ucentral-libs', 'src'),
|
||||
],
|
||||
alias: {
|
||||
react: path.resolve(__dirname, '../', 'node_modules', 'react'),
|
||||
'react-router-dom': path.resolve('./node_modules/react-router-dom'),
|
||||
'ucentral-libs': path.resolve(__dirname, '../', 'node_modules', 'ucentral-libs', 'src'),
|
||||
},
|
||||
},
|
||||
plugins: [new ReactRefreshWebpackPlugin()],
|
||||
});
|
||||
36
config/webpack.prod.js
Normal file
36
config/webpack.prod.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable prefer-template */
|
||||
const { merge } = require('webpack-merge');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
const paths = require('./paths');
|
||||
const common = require('./webpack.common');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'production',
|
||||
devtool: false,
|
||||
output: {
|
||||
path: paths.build,
|
||||
publicPath: '/',
|
||||
filename: 'js/[name].[contenthash].bundle.js',
|
||||
},
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: 'styles/[name].[contenthash].css',
|
||||
chunkFilename: '[contenthash].css',
|
||||
}),
|
||||
],
|
||||
module: {
|
||||
rules: [],
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [`...`, new TerserPlugin(), new CssMinimizerPlugin()],
|
||||
},
|
||||
performance: {
|
||||
hints: false,
|
||||
maxEntrypointSize: 512000,
|
||||
maxAssetSize: 512000,
|
||||
},
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/ash
|
||||
# Check if variables are set
|
||||
export DEFAULT_GATEWAY_URL="${DEFAULT_GATEWAY_URL:-https://ucentral.dpaas.arilia.com:16001}"
|
||||
export ALLOW_GATEWAY_CHANGE="${ALLOW_GATEWAY_CHANGE:-false}"
|
||||
export DEFAULT_UCENTRALSEC_URL="${DEFAULT_UCENTRALSEC_URL:-https://ucentral.dpaas.arilia.com:16001}"
|
||||
export ALLOW_UCENTRALSEC_CHANGE="${ALLOW_UCENTRALSEC_CHANGE:-false}"
|
||||
|
||||
echo '{"DEFAULT_GATEWAY_URL": "'$DEFAULT_GATEWAY_URL'","ALLOW_GATEWAY_CHANGE": '$ALLOW_GATEWAY_CHANGE'}' > /usr/share/nginx/html/config.json
|
||||
echo '{"DEFAULT_UCENTRALSEC_URL": "'$DEFAULT_UCENTRALSEC_URL'","ALLOW_UCENTRALSEC_CHANGE": '$ALLOW_UCENTRALSEC_CHANGE'}' > /usr/share/nginx/html/config.json
|
||||
|
||||
@@ -71,5 +71,5 @@ affinity: {}
|
||||
|
||||
# Application
|
||||
public_env_variables:
|
||||
DEFAULT_GATEWAY_URL: https://ucentral.dpaas.arilia.com:16001
|
||||
ALLOW_GATEWAY_CHANGE: false
|
||||
DEFAULT_UCENTRALSEC_URL: https://ucentral.dpaas.arilia.com:16001
|
||||
ALLOW_UCENTRALSEC_CHANGE: false
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
"paths": {
|
||||
"*": ["*"]
|
||||
}
|
||||
},
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
30991
package-lock.json
generated
30991
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
85
package.json
85
package.json
@@ -1,23 +1,14 @@
|
||||
{
|
||||
"name": "ucentral-client",
|
||||
"version": "0.9.5",
|
||||
"private": true,
|
||||
"version": "0.9.14",
|
||||
"dependencies": {
|
||||
"@coreui/coreui": "^3.4.0",
|
||||
"@coreui/icons": "^2.0.1",
|
||||
"@coreui/icons-react": "^1.1.0",
|
||||
"@coreui/react": "^3.4.6",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.35",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||
"@fortawesome/react-fontawesome": "^0.1.14",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^11.2.7",
|
||||
"@testing-library/user-event": "^13.1.9",
|
||||
"apexcharts": "^3.27.1",
|
||||
"axios": "^0.21.1",
|
||||
"axios-retry": "^3.1.9",
|
||||
"http": "^0.0.1-security",
|
||||
"https": "^1.0.0",
|
||||
"i18next": "^20.3.1",
|
||||
"i18next-browser-languagedetector": "^6.1.2",
|
||||
"i18next-http-backend": "^1.2.6",
|
||||
@@ -27,20 +18,18 @@
|
||||
"react-dom": "^17.0.2",
|
||||
"react-i18next": "^11.11.0",
|
||||
"react-paginate": "^7.1.3",
|
||||
"react-redux": "^7.2.4",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-select": "^4.3.1",
|
||||
"react-widgets": "^5.1.1",
|
||||
"redux": "^4.1.0",
|
||||
"sass": "^1.35.1",
|
||||
"ucentral-libs": "^0.8.7",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
"start": "webpack serve --config config/webpack.dev.js",
|
||||
"build": "webpack --config config/webpack.prod.js",
|
||||
"format": "prettier --write 'src/**/*.js'",
|
||||
"eslint-fix": "eslint --fix 'src/**/*.js'"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
@@ -51,12 +40,54 @@
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"src/**/*.{js,jsx}": [
|
||||
"*.{js,jsx}": [
|
||||
"eslint",
|
||||
"pretty-quick — staged",
|
||||
"git add"
|
||||
"prettier --write"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.6",
|
||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||
"@babel/plugin-transform-runtime": "^7.14.5",
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"@babel/preset-env": "^7.14.7",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"autoprefixer": "^10.2.6",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"copy-webpack-plugin": "^7.0.0",
|
||||
"css-loader": "^5.2.6",
|
||||
"css-minimizer-webpack-plugin": "^2.0.0",
|
||||
"dotenv-webpack": "^6.0.4",
|
||||
"eslint": "^7.29.0",
|
||||
"eslint-config-airbnb": "^18.2.1",
|
||||
"eslint-config-prettier": "^7.2.0",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-loader": "^4.0.2",
|
||||
"eslint-plugin-babel": "^5.3.1",
|
||||
"eslint-plugin-import": "^2.23.4",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-react": "^7.24.0",
|
||||
"eslint-plugin-react-hooks": "^4.2.0",
|
||||
"html-webpack-plugin": "^5.3.2",
|
||||
"husky": "^4.3.8",
|
||||
"lint-staged": "^11.0.0",
|
||||
"mini-css-extract-plugin": "^1.6.1",
|
||||
"node-sass": "^5.0.0",
|
||||
"path": "^0.12.7",
|
||||
"prettier": "^2.3.2",
|
||||
"react-refresh": "^0.9.0",
|
||||
"sass-loader": "^11.1.1",
|
||||
"style-loader": "^2.0.0",
|
||||
"terser-webpack-plugin": "^5.1.4",
|
||||
"webpack": "^5.40.0",
|
||||
"webpack-cli": "^4.7.2",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
@@ -68,17 +99,5 @@
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^7.28.0",
|
||||
"eslint-config-airbnb": "^18.2.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.23.4",
|
||||
"eslint-plugin-react": "^7.24.0",
|
||||
"husky": "^6.0.0",
|
||||
"lint-staged": "^11.0.0",
|
||||
"prettier": "^2.3.1",
|
||||
"pretty-quick": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"DEFAULT_GATEWAY_URL": "https://ucentral.dpaas.arilia.com:16001",
|
||||
"ALLOW_GATEWAY_CHANGE": false
|
||||
"DEFAULT_UCENTRALSEC_URL": "https://ucentral.dpaas.arilia.com:16001",
|
||||
"ALLOW_UCENTRALSEC_CHANGE": false
|
||||
}
|
||||
|
||||
@@ -2,42 +2,13 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<link rel="icon" href="favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>uCentralGW</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
"blink": {
|
||||
"blink": "LEDs Blinken",
|
||||
"device_leds": "LEDs",
|
||||
"execute_now": "Möchten Sie dieses Muster jetzt einstellen?",
|
||||
"pattern": "Wählen Sie das Muster, das Sie verwenden möchten:",
|
||||
"set_leds": "LEDs einstellen",
|
||||
"when_blink_leds": "Wann möchten Sie die LEDs blinken lassen?"
|
||||
},
|
||||
"commands": {
|
||||
@@ -23,6 +25,8 @@
|
||||
"title": "Gerätebefehle"
|
||||
},
|
||||
"common": {
|
||||
"add": "Hinzufügen",
|
||||
"adding_ellipsis": "Hinzufügen ...",
|
||||
"are_you_sure": "Bist du sicher?",
|
||||
"cancel": "Abbrechen",
|
||||
"certificate": "Zertifikat",
|
||||
@@ -36,7 +40,11 @@
|
||||
"connected": "Verbindung wurde hergestellt",
|
||||
"copied": "kopiert!",
|
||||
"copy_to_clipboard": "In die Zwischenablage kopieren",
|
||||
"created_by": "Erstellt von",
|
||||
"custom_date": "Benutzerdefiniertes Datum",
|
||||
"date": "Datum",
|
||||
"day": "tag",
|
||||
"days": "tage",
|
||||
"delete": "Löschen",
|
||||
"details": "Einzelheiten",
|
||||
"device_list": "Liste der Geräte",
|
||||
@@ -52,6 +60,8 @@
|
||||
"exit": "Ausgang",
|
||||
"firmware": "Firmware",
|
||||
"from": "Von",
|
||||
"hour": "stunde",
|
||||
"hours": "std",
|
||||
"id": "ID",
|
||||
"ip_address": "IP Adresse",
|
||||
"later_tonight": "Später am Abend",
|
||||
@@ -60,9 +70,12 @@
|
||||
"logout": "Ausloggen",
|
||||
"mac": "MAC-Adresse",
|
||||
"manufacturer": "Hersteller",
|
||||
"minute": "Minute",
|
||||
"minutes": "protokoll",
|
||||
"na": "(unbekannt)",
|
||||
"need_date": "Du brauchst ein Datum...",
|
||||
"no": "Nein",
|
||||
"no_items": "Keine Gegenstände",
|
||||
"not_connected": "Nicht verbunden",
|
||||
"off": "Aus",
|
||||
"on": "An",
|
||||
@@ -73,6 +86,8 @@
|
||||
"save": "Sparen",
|
||||
"saving": "Speichern ...",
|
||||
"schedule": "Zeitplan",
|
||||
"second": "zweite",
|
||||
"seconds": "sekunden",
|
||||
"seconds_elapsed": "Sekunden verstrichen",
|
||||
"serial_number": "Seriennummer",
|
||||
"start": "Start",
|
||||
@@ -92,6 +107,7 @@
|
||||
"last_configuration_change": "Letzte Konfigurationsänderung",
|
||||
"last_configuration_download": "Letzter Konfigurations-Download",
|
||||
"location": "Ort",
|
||||
"note": "Hinweis",
|
||||
"notes": "Anmerkungen",
|
||||
"owner": "Inhaber",
|
||||
"title": "Gerätekonfiguration",
|
||||
@@ -140,14 +156,16 @@
|
||||
"login": "Anmeldung",
|
||||
"login_error": "Anmeldefehler, bestätigen Sie, dass Ihr Benutzername, Ihr Passwort und Ihre Gateway-URL gültig sind",
|
||||
"password": "Passwort",
|
||||
"please_enter_gateway": "Bitte geben Sie eine Gateway-URL ein",
|
||||
"please_enter_gateway": "Bitte geben Sie eine uCentralSec-URL ein",
|
||||
"please_enter_password": "Bitte geben Sie Ihr Passwort ein",
|
||||
"please_enter_username": "Bitte geben Sie Ihren Benutzernamen ein",
|
||||
"sign_in_to_account": "Melden Sie sich bei Ihrem Konto an",
|
||||
"url": "uCentralSec-URL",
|
||||
"username": "Benutzername"
|
||||
},
|
||||
"reboot": {
|
||||
"directions": "Wann möchten Sie dieses Gerät neu starten?",
|
||||
"now": "Möchten Sie dieses Gerät jetzt neu starten?",
|
||||
"title": "Gerät neustarten"
|
||||
},
|
||||
"scan": {
|
||||
@@ -167,10 +185,23 @@
|
||||
"show_latest": "Neueste Statistiken anzeigen JSON",
|
||||
"title": "Statistiken"
|
||||
},
|
||||
"status": {
|
||||
"connection_status": "Verbindungsstatus",
|
||||
"error": "Statusdaten sind nicht verfügbar",
|
||||
"last_contact": "Letzter Kontakt",
|
||||
"load_averages": "Belastung (Durchschnitt 1 / 5 / 15 Minuten)",
|
||||
"localtime": "Ortszeit",
|
||||
"memory": "Verwendeter Speicher",
|
||||
"percentage_free": "{{percentage}}% von {{total}} kostenlos",
|
||||
"percentage_used": "{{percentage}}% von {{total}} verwendet",
|
||||
"title": "#{{serialNumber}} Status",
|
||||
"uptime": "Betriebszeit",
|
||||
"used_total_memory": "{{used}} verwendet / {{total}} insgesamt"
|
||||
},
|
||||
"trace": {
|
||||
"choose_network": "Netzwerk auswählen",
|
||||
"directions": "Starten Sie eine Tcpdump auf diesem Geräts für eine bestimmte Dauer oder eine Anzahl von Paketen",
|
||||
"download_trace": "Klicke hier zum herunterladen",
|
||||
"download_trace": "Trace-Datei herunterladen",
|
||||
"packets": "Pakete",
|
||||
"title": "Tcpdump",
|
||||
"trace": "Spur",
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
"blink": {
|
||||
"blink": "Blink",
|
||||
"device_leds": "Device LEDs",
|
||||
"pattern": "Choose the pattern you would like to use: ",
|
||||
"execute_now": "Would you like to set this pattern now?",
|
||||
"pattern": "LEDs pattern: ",
|
||||
"set_leds": "Set LEDs",
|
||||
"when_blink_leds": "When would you like to make the device LEDs blink?"
|
||||
},
|
||||
"commands": {
|
||||
@@ -23,6 +25,8 @@
|
||||
"title": "Command History"
|
||||
},
|
||||
"common": {
|
||||
"add": "Add",
|
||||
"adding_ellipsis": "Adding...",
|
||||
"are_you_sure": "Are you sure?",
|
||||
"cancel": "Cancel",
|
||||
"certificate": "Certificate",
|
||||
@@ -36,7 +40,11 @@
|
||||
"connected": "Connected",
|
||||
"copied": "Copied!",
|
||||
"copy_to_clipboard": "Copy to clipboard",
|
||||
"created_by": "Created By",
|
||||
"custom_date": "Custom Date",
|
||||
"date": "Date",
|
||||
"day": "day",
|
||||
"days": "days",
|
||||
"delete": "Delete",
|
||||
"details": "Details",
|
||||
"device_list": "List of Devices",
|
||||
@@ -52,6 +60,8 @@
|
||||
"exit": "Exit",
|
||||
"firmware": "Firmware",
|
||||
"from": "From",
|
||||
"hour": "hour",
|
||||
"hours": "hours",
|
||||
"id": "Id",
|
||||
"ip_address": "Ip Address",
|
||||
"later_tonight": "Later tonight",
|
||||
@@ -60,9 +70,12 @@
|
||||
"logout": "Logout",
|
||||
"mac": "MAC Address",
|
||||
"manufacturer": "Manufacturer",
|
||||
"minute": "minute",
|
||||
"minutes": "minutes",
|
||||
"na": "N/A",
|
||||
"need_date": "You need a date...",
|
||||
"no": "No",
|
||||
"no_items": "No Items",
|
||||
"not_connected": "Not Connected",
|
||||
"off": "Off",
|
||||
"on": "On",
|
||||
@@ -73,6 +86,8 @@
|
||||
"save": "Save",
|
||||
"saving": "Saving... ",
|
||||
"schedule": "Schedule",
|
||||
"second": "second",
|
||||
"seconds": "seconds",
|
||||
"seconds_elapsed": "Seconds elapsed",
|
||||
"serial_number": "Serial Number",
|
||||
"start": "Start",
|
||||
@@ -92,6 +107,7 @@
|
||||
"last_configuration_change": "Last Configuration Change",
|
||||
"last_configuration_download": "Last Configuration Download",
|
||||
"location": "Location",
|
||||
"note": "Note",
|
||||
"notes": "Notes",
|
||||
"owner": "Owner",
|
||||
"title": "Configuration",
|
||||
@@ -140,14 +156,16 @@
|
||||
"login": "Login",
|
||||
"login_error": "Login error, confirm that your username, password and gateway url are valid",
|
||||
"password": "Password",
|
||||
"please_enter_gateway": "Please enter a gateway URL",
|
||||
"please_enter_gateway": "Please enter a uCentralSec URL",
|
||||
"please_enter_password": "Please enter your password",
|
||||
"please_enter_username": "Please enter your username",
|
||||
"sign_in_to_account": "Sign in to your account",
|
||||
"url": "uCentralSec URL",
|
||||
"username": "Username"
|
||||
},
|
||||
"reboot": {
|
||||
"directions": "When would you like to reboot this device?",
|
||||
"now": "Would you like to reboot this device now?",
|
||||
"title": "Reboot"
|
||||
},
|
||||
"scan": {
|
||||
@@ -167,10 +185,23 @@
|
||||
"show_latest": "Show latest statistics JSON",
|
||||
"title": "Statistics"
|
||||
},
|
||||
"status": {
|
||||
"connection_status": "Connection Status",
|
||||
"error": "Status data is unavailable",
|
||||
"last_contact": "Last Contact",
|
||||
"load_averages": "Load ( 1 / 5 / 15 minute average)",
|
||||
"localtime": "Localtime",
|
||||
"memory": "Memory Used",
|
||||
"percentage_free": "{{percentage}}% of {{total}} free",
|
||||
"percentage_used": "{{percentage}}% of {{total}} used",
|
||||
"title": "#{{serialNumber}} Status",
|
||||
"uptime": "Uptime",
|
||||
"used_total_memory": "{{used}} used / {{total}} total "
|
||||
},
|
||||
"trace": {
|
||||
"choose_network": "Choose network",
|
||||
"directions": "Launch a remote trace of this device for either a specific duration or a number of packets",
|
||||
"download_trace": "Click here to download",
|
||||
"download_trace": "Download Trace File",
|
||||
"packets": "Packets",
|
||||
"title": "Trace",
|
||||
"trace": "Trace",
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
"blink": {
|
||||
"blink": "Parpadeo",
|
||||
"device_leds": "LED de dispositivo",
|
||||
"execute_now": "¿Le gustaría establecer este patrón ahora?",
|
||||
"pattern": "Elija el patrón que le gustaría usar:",
|
||||
"set_leds": "Establecer LED",
|
||||
"when_blink_leds": "¿Cuándo desea que los LED del dispositivo parpadeen?"
|
||||
},
|
||||
"commands": {
|
||||
@@ -23,6 +25,8 @@
|
||||
"title": "Historial de Comandos"
|
||||
},
|
||||
"common": {
|
||||
"add": "Añadir",
|
||||
"adding_ellipsis": "Añadiendo ...",
|
||||
"are_you_sure": "¿Estás seguro?",
|
||||
"cancel": "Cancelar",
|
||||
"certificate": "Certificado",
|
||||
@@ -36,7 +40,11 @@
|
||||
"connected": "Conectado",
|
||||
"copied": "Copiado!",
|
||||
"copy_to_clipboard": "Copiar al portapapeles",
|
||||
"created_by": "Creado por",
|
||||
"custom_date": "Fecha personalizada",
|
||||
"date": "Fecha",
|
||||
"day": "día",
|
||||
"days": "días",
|
||||
"delete": "Borrar",
|
||||
"details": "Detalles",
|
||||
"device_list": "Listado de dispositivos",
|
||||
@@ -52,6 +60,8 @@
|
||||
"exit": "salida",
|
||||
"firmware": "Firmware",
|
||||
"from": "Desde",
|
||||
"hour": "hora",
|
||||
"hours": "horas",
|
||||
"id": "Carné de identidad",
|
||||
"ip_address": "Dirección IP",
|
||||
"later_tonight": "Más tarde esta noche",
|
||||
@@ -60,9 +70,12 @@
|
||||
"logout": "Cerrar sesión",
|
||||
"mac": "Dirección MAC",
|
||||
"manufacturer": "Fabricante",
|
||||
"minute": "minuto",
|
||||
"minutes": "minutos",
|
||||
"na": "N / A",
|
||||
"need_date": "Necesitas una cita ...",
|
||||
"no": "No",
|
||||
"no_items": "No hay articulos",
|
||||
"not_connected": "No conectado",
|
||||
"off": "Apagado",
|
||||
"on": "en",
|
||||
@@ -73,6 +86,8 @@
|
||||
"save": "Salvar",
|
||||
"saving": "Ahorro...",
|
||||
"schedule": "Programar",
|
||||
"second": "segundo",
|
||||
"seconds": "segundos",
|
||||
"seconds_elapsed": "Segundos transcurridos",
|
||||
"serial_number": "Número de serie",
|
||||
"start": "comienzo",
|
||||
@@ -92,6 +107,7 @@
|
||||
"last_configuration_change": "Último cambio de configuración",
|
||||
"last_configuration_download": "Descarga de la última configuración",
|
||||
"location": "Ubicación",
|
||||
"note": "Nota",
|
||||
"notes": "Notas",
|
||||
"owner": "Propietario",
|
||||
"title": "Configuración",
|
||||
@@ -140,14 +156,16 @@
|
||||
"login": "Iniciar sesión",
|
||||
"login_error": "Error de inicio de sesión, confirme que su nombre de usuario, contraseña y URL de puerta de enlace son válidos",
|
||||
"password": "Contraseña",
|
||||
"please_enter_gateway": "Ingrese una URL de puerta de enlace",
|
||||
"please_enter_gateway": "Ingrese una URL de uCentralSec",
|
||||
"please_enter_password": "Por favor, introduzca su contraseña",
|
||||
"please_enter_username": "Por favor, ingrese su nombre de usuario",
|
||||
"sign_in_to_account": "Iniciar sesión en su cuenta",
|
||||
"url": "URL de uCentralSec",
|
||||
"username": "Nombre de usuario"
|
||||
},
|
||||
"reboot": {
|
||||
"directions": "¿Cuándo le gustaría reiniciar este dispositivo?",
|
||||
"now": "¿Le gustaría reiniciar este dispositivo ahora?",
|
||||
"title": "Reiniciar"
|
||||
},
|
||||
"scan": {
|
||||
@@ -167,10 +185,23 @@
|
||||
"show_latest": "Mostrar las últimas estadísticas JSON",
|
||||
"title": "estadística"
|
||||
},
|
||||
"status": {
|
||||
"connection_status": "Estado de conexión",
|
||||
"error": "Los datos de estado no están disponibles",
|
||||
"last_contact": "Último contacto",
|
||||
"load_averages": "Carga (promedio de 1/5/15 minutos)",
|
||||
"localtime": "Hora local",
|
||||
"memory": "Memoria usada",
|
||||
"percentage_free": "{{percentage}}% de {{total}} gratis",
|
||||
"percentage_used": "{{percentage}}% de {{total}} utilizado",
|
||||
"title": "#{{serialNumber}} Estado",
|
||||
"uptime": "Tiempo de actividad",
|
||||
"used_total_memory": "{{used}} usado / {{total}} total"
|
||||
},
|
||||
"trace": {
|
||||
"choose_network": "Elija la red",
|
||||
"directions": "Lanzar un rastreo remoto de este dispositivo por una duración específica o por una cantidad de paquetes",
|
||||
"download_trace": "Haga click aquí para descargar",
|
||||
"download_trace": "Descargar archivo de seguimiento",
|
||||
"packets": "Paquetes",
|
||||
"title": "Rastro",
|
||||
"trace": "Rastro",
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
"blink": {
|
||||
"blink": "Cligner",
|
||||
"device_leds": "LED de l'appareil",
|
||||
"execute_now": "Souhaitez-vous définir ce modèle maintenant ?",
|
||||
"pattern": "Choisissez le modèle que vous souhaitez utiliser :",
|
||||
"set_leds": "Définir les LED",
|
||||
"when_blink_leds": "Quand souhaitez-vous faire clignoter les LED de l'appareil ?"
|
||||
},
|
||||
"commands": {
|
||||
@@ -23,6 +25,8 @@
|
||||
"title": "Historique des commandes"
|
||||
},
|
||||
"common": {
|
||||
"add": "Ajouter",
|
||||
"adding_ellipsis": "Ajouter...",
|
||||
"are_you_sure": "Êtes-vous sûr?",
|
||||
"cancel": "annuler",
|
||||
"certificate": "Certificat",
|
||||
@@ -36,7 +40,11 @@
|
||||
"connected": "Connecté",
|
||||
"copied": "Copié!",
|
||||
"copy_to_clipboard": "Copier dans le presse-papier",
|
||||
"created_by": "Créé par",
|
||||
"custom_date": "Date personnalisée",
|
||||
"date": "Rendez-vous amoureux",
|
||||
"day": "journée",
|
||||
"days": "journées",
|
||||
"delete": "Effacer",
|
||||
"details": "Détails",
|
||||
"device_list": "Liste des appareils",
|
||||
@@ -52,6 +60,8 @@
|
||||
"exit": "Sortie",
|
||||
"firmware": "Micrologiciel",
|
||||
"from": "De",
|
||||
"hour": "heure",
|
||||
"hours": "heures",
|
||||
"id": "Id",
|
||||
"ip_address": "Adresse IP",
|
||||
"later_tonight": "Plus tard ce soir",
|
||||
@@ -60,9 +70,12 @@
|
||||
"logout": "Connectez - Out",
|
||||
"mac": "ADRESSE MAC",
|
||||
"manufacturer": "fabricant",
|
||||
"minute": "minute",
|
||||
"minutes": "minutes",
|
||||
"na": "N / A",
|
||||
"need_date": "Vous avez besoin d'un rendez-vous...",
|
||||
"no": "Non",
|
||||
"no_items": "Pas d'objet",
|
||||
"not_connected": "Pas connecté",
|
||||
"off": "De",
|
||||
"on": "sur",
|
||||
@@ -73,6 +86,8 @@
|
||||
"save": "Sauvegarder",
|
||||
"saving": "Économie...",
|
||||
"schedule": "Programme",
|
||||
"second": "seconde",
|
||||
"seconds": "secondes",
|
||||
"seconds_elapsed": "Secondes écoulées",
|
||||
"serial_number": "Numéro de série",
|
||||
"start": "Début",
|
||||
@@ -92,6 +107,7 @@
|
||||
"last_configuration_change": "Dernière modification de configuration",
|
||||
"last_configuration_download": "Téléchargement de la dernière configuration",
|
||||
"location": "Emplacement",
|
||||
"note": "Remarque",
|
||||
"notes": "Remarques",
|
||||
"owner": "Propriétaire",
|
||||
"title": "Configuration",
|
||||
@@ -140,14 +156,16 @@
|
||||
"login": "S'identifier",
|
||||
"login_error": "Erreur de connexion, confirmez que votre nom d'utilisateur, mot de passe et URL de passerelle sont valides",
|
||||
"password": "Mot de passe",
|
||||
"please_enter_gateway": "Veuillez saisir une URL de passerelle",
|
||||
"please_enter_gateway": "Veuillez saisir une URL uCentralSec",
|
||||
"please_enter_password": "s'il vous plait entrez votre mot de passe",
|
||||
"please_enter_username": "s'il vous plaît entrez votre nom d'utilisateur",
|
||||
"sign_in_to_account": "Connectez-vous à votre compte",
|
||||
"url": "URL uCentralSec",
|
||||
"username": "Nom d'utilisateur"
|
||||
},
|
||||
"reboot": {
|
||||
"directions": "Quand souhaitez-vous redémarrer cet appareil ?",
|
||||
"now": "Souhaitez-vous redémarrer cet appareil maintenant ?",
|
||||
"title": "Redémarrer"
|
||||
},
|
||||
"scan": {
|
||||
@@ -167,10 +185,23 @@
|
||||
"show_latest": "Afficher les dernières statistiques JSON",
|
||||
"title": "statistiques"
|
||||
},
|
||||
"status": {
|
||||
"connection_status": "Statut de connexion",
|
||||
"error": "Les données d'état ne sont pas disponibles",
|
||||
"last_contact": "Dernier contact",
|
||||
"load_averages": "Charge (moyenne 1 / 5 / 15 minutes)",
|
||||
"localtime": "heure locale",
|
||||
"memory": "Mémoire utilisée",
|
||||
"percentage_free": "{{percentage}}% de {{total}} gratuit",
|
||||
"percentage_used": "{{percentage}}% de {{total}} utilisé",
|
||||
"title": "#{{serialNumber}} état",
|
||||
"uptime": "La disponibilité",
|
||||
"used_total_memory": "{{used}} utilisé / {{total}} total"
|
||||
},
|
||||
"trace": {
|
||||
"choose_network": "Choisir le réseau",
|
||||
"directions": "Lancer une trace à distance de cet appareil pour une durée spécifique ou un nombre de paquets",
|
||||
"download_trace": "Cliquez ici pour télécharger",
|
||||
"download_trace": "Télécharger le fichier de trace",
|
||||
"packets": "Paquets",
|
||||
"title": "Trace",
|
||||
"trace": "Trace",
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
"blink": {
|
||||
"blink": "Piscar",
|
||||
"device_leds": "LEDs do dispositivo",
|
||||
"execute_now": "Você gostaria de definir este padrão agora?",
|
||||
"pattern": "Escolha o padrão que deseja usar:",
|
||||
"set_leds": "Definir LEDs",
|
||||
"when_blink_leds": "Quando você gostaria de fazer os LEDs do dispositivo piscarem?"
|
||||
},
|
||||
"commands": {
|
||||
@@ -23,6 +25,8 @@
|
||||
"title": "Histórico de Comandos"
|
||||
},
|
||||
"common": {
|
||||
"add": "Adicionar",
|
||||
"adding_ellipsis": "Adicionando ...",
|
||||
"are_you_sure": "Você tem certeza?",
|
||||
"cancel": "Cancelar",
|
||||
"certificate": "Certificado",
|
||||
@@ -36,7 +40,11 @@
|
||||
"connected": "Conectado",
|
||||
"copied": "Copiado!",
|
||||
"copy_to_clipboard": "Copiar para área de transferência",
|
||||
"created_by": "Criado Por",
|
||||
"custom_date": "Data personalizada",
|
||||
"date": "Encontro",
|
||||
"day": "dia",
|
||||
"days": "dias",
|
||||
"delete": "Excluir",
|
||||
"details": "Detalhes",
|
||||
"device_list": "Lista de Dispositivos",
|
||||
@@ -52,6 +60,8 @@
|
||||
"exit": "Saída",
|
||||
"firmware": "Firmware",
|
||||
"from": "De",
|
||||
"hour": "hora",
|
||||
"hours": "horas",
|
||||
"id": "identidade",
|
||||
"ip_address": "Endereço de IP",
|
||||
"later_tonight": "Logo à noite",
|
||||
@@ -60,9 +70,12 @@
|
||||
"logout": "Sair",
|
||||
"mac": "Endereço MAC",
|
||||
"manufacturer": "Fabricante",
|
||||
"minute": "minuto",
|
||||
"minutes": "minutos",
|
||||
"na": "N / D",
|
||||
"need_date": "Você precisa de um encontro ...",
|
||||
"no": "Não",
|
||||
"no_items": "Nenhum item",
|
||||
"not_connected": "Não conectado",
|
||||
"off": "Fora",
|
||||
"on": "em",
|
||||
@@ -73,6 +86,8 @@
|
||||
"save": "Salve",
|
||||
"saving": "Salvando ...",
|
||||
"schedule": "Cronograma",
|
||||
"second": "segundo",
|
||||
"seconds": "segundos",
|
||||
"seconds_elapsed": "Segundos decorridos",
|
||||
"serial_number": "Número de série",
|
||||
"start": "Começar",
|
||||
@@ -92,6 +107,7 @@
|
||||
"last_configuration_change": "Última Mudança de Configuração",
|
||||
"last_configuration_download": "Último download da configuração",
|
||||
"location": "Localização",
|
||||
"note": "Nota",
|
||||
"notes": "notas",
|
||||
"owner": "Proprietário",
|
||||
"title": "Configuração",
|
||||
@@ -140,14 +156,16 @@
|
||||
"login": "Entrar",
|
||||
"login_error": "Erro de login, confirme se seu nome de usuário, senha e url de gateway são válidos",
|
||||
"password": "Senha",
|
||||
"please_enter_gateway": "Insira um URL de gateway",
|
||||
"please_enter_gateway": "Insira um URL uCentralSec",
|
||||
"please_enter_password": "Por favor, insira sua senha",
|
||||
"please_enter_username": "Por favor insira seu nome de usuário",
|
||||
"sign_in_to_account": "Faça login em sua conta",
|
||||
"url": "URL uCentralSec",
|
||||
"username": "Nome de usuário"
|
||||
},
|
||||
"reboot": {
|
||||
"directions": "Quando você gostaria de reinicializar este dispositivo?",
|
||||
"now": "Você gostaria de reiniciar este dispositivo agora?",
|
||||
"title": "Reiniciar"
|
||||
},
|
||||
"scan": {
|
||||
@@ -167,10 +185,23 @@
|
||||
"show_latest": "Mostrar estatísticas mais recentes JSON",
|
||||
"title": "Estatisticas"
|
||||
},
|
||||
"status": {
|
||||
"connection_status": "Status da conexão",
|
||||
"error": "Dados de status indisponíveis",
|
||||
"last_contact": "Último contato",
|
||||
"load_averages": "Carga (1/5/15 minutos em média)",
|
||||
"localtime": "Horário local",
|
||||
"memory": "Memória Usada",
|
||||
"percentage_free": "{{percentage}}% de {{total}} grátis",
|
||||
"percentage_used": "{{percentage}}% de {{total}} usado",
|
||||
"title": "#{{serialNumber}} status",
|
||||
"uptime": "Tempo de atividade",
|
||||
"used_total_memory": "{{used}} usado / {{total}} total"
|
||||
},
|
||||
"trace": {
|
||||
"choose_network": "Escolha a rede",
|
||||
"directions": "Lançar um rastreamento remoto deste dispositivo para uma duração específica ou um número de pacotes",
|
||||
"download_trace": "Clique aqui para baixar",
|
||||
"download_trace": "Baixar arquivo de rastreamento",
|
||||
"packets": "Pacotes",
|
||||
"title": "Vestígio",
|
||||
"trace": "Vestígio",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "favicon.svg",
|
||||
"type": "image/svg",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "favicon.svg",
|
||||
"type": "image/svg",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 141.5 185.6" style="enable-background:new 0 0 141.5 185.6;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#414141;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
.st2{fill:#FED206;}
|
||||
.st3{fill:#EB6F53;}
|
||||
.st4{fill:#3BA9B6;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M120.7,183.9H21.5c-10.8,0-19.5-8.7-19.5-19.5V20.5c0-10.8,8.7-19.5,19.5-19.5h99.2
|
||||
c10.8,0,19.5,8.7,19.5,19.5v143.9C140.2,175.2,131.5,183.9,120.7,183.9z"/>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st1" d="M46.3,166.2v-3.4h-1.2v-0.6h3.1v0.6H47v3.4H46.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M49,166.2v-4h2.7v0.6h-2v1h2v0.6h-2v1.1h2v0.6H49z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M52.6,166.2v-4h0.7v3.4h1.8v0.6H52.6z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M55.7,166.2v-4h2.7v0.6h-2v1h2v0.6h-2v1.1h2v0.6H55.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M59.1,164.2c0-1.2,0.9-2.1,2.1-2.1c0.8,0,1.3,0.4,1.6,0.9l-0.6,0.3c-0.2-0.3-0.6-0.6-1-0.6
|
||||
c-0.8,0-1.4,0.6-1.4,1.4c0,0.8,0.6,1.4,1.4,1.4c0.4,0,0.8-0.3,1-0.6l0.6,0.3c-0.3,0.5-0.8,0.9-1.6,0.9
|
||||
C60,166.3,59.1,165.5,59.1,164.2z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M63.2,164.2c0-1.2,0.8-2.1,2-2.1c1.2,0,2,0.9,2,2.1c0,1.2-0.8,2.1-2,2.1C64,166.3,63.2,165.4,63.2,164.2z
|
||||
M66.5,164.2c0-0.8-0.5-1.4-1.3-1.4c-0.8,0-1.3,0.6-1.3,1.4c0,0.8,0.5,1.4,1.3,1.4C66,165.7,66.5,165,66.5,164.2z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M71.3,166.2v-3.1l-1.2,3.1h-0.3l-1.2-3.1v3.1h-0.7v-4h1l1.1,2.7l1.1-2.7h1v4H71.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M75.7,166.2v-4h0.7v4H75.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M80.4,166.2l-2.1-2.8v2.8h-0.7v-4h0.7l2,2.8v-2.8h0.7v4H80.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M82.3,166.2v-4H85v0.6h-2v1h2v0.6h-2v1.7H82.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M87.9,166.2l-0.9-1.5h-0.7v1.5h-0.7v-4h1.7c0.8,0,1.3,0.5,1.3,1.2c0,0.7-0.5,1.1-0.9,1.2l1,1.6H87.9z
|
||||
M88,163.5c0-0.4-0.3-0.6-0.7-0.6h-1v1.3h1C87.7,164.1,88,163.9,88,163.5z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M92.4,166.2l-0.3-0.8h-1.8l-0.3,0.8h-0.8l1.6-4h0.9l1.6,4H92.4z M91.2,162.9l-0.7,1.9h1.4L91.2,162.9z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M95.8,166.2v-4h1.5c0.8,0,1.2,0.5,1.2,1.2c0,0.6-0.4,1.2-1.2,1.2h-1.2v1.7H95.8z M98.2,163.4
|
||||
c0-0.5-0.3-0.9-0.9-0.9h-1.1v1.7h1.1C97.8,164.3,98.2,163.9,98.2,163.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M101.5,166.2l-1.1-1.6h-0.9v1.6h-0.3v-4h1.5c0.7,0,1.2,0.4,1.2,1.2c0,0.7-0.5,1.1-1.1,1.1l1.2,1.7H101.5z
|
||||
M101.6,163.4c0-0.5-0.4-0.9-0.9-0.9h-1.1v1.7h1.1C101.2,164.3,101.6,163.9,101.6,163.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M102.8,164.2c0-1.2,0.8-2.1,1.9-2.1c1.2,0,1.9,0.9,1.9,2.1c0,1.2-0.8,2.1-1.9,2.1
|
||||
C103.6,166.3,102.8,165.4,102.8,164.2z M106.3,164.2c0-1-0.6-1.7-1.6-1.7c-1,0-1.6,0.7-1.6,1.7c0,1,0.6,1.7,1.6,1.7
|
||||
C105.7,166,106.3,165.2,106.3,164.2z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M106.9,165.8l0.2-0.3c0.2,0.2,0.4,0.4,0.8,0.4c0.5,0,0.9-0.4,0.9-0.9v-2.8h0.3v2.8c0,0.8-0.5,1.2-1.2,1.2
|
||||
C107.5,166.3,107.2,166.1,106.9,165.8z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M110.4,166.2v-4h2.5v0.3h-2.2v1.5h2.1v0.3h-2.1v1.6h2.2v0.3H110.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M113.5,164.2c0-1.2,0.9-2.1,2-2.1c0.6,0,1.1,0.3,1.5,0.7l-0.3,0.2c-0.3-0.3-0.7-0.6-1.2-0.6
|
||||
c-0.9,0-1.7,0.7-1.7,1.7c0,1,0.7,1.7,1.7,1.7c0.5,0,0.9-0.2,1.2-0.6l0.3,0.2c-0.4,0.4-0.8,0.7-1.5,0.7
|
||||
C114.4,166.3,113.5,165.5,113.5,164.2z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M118.7,166.2v-3.7h-1.3v-0.3h2.9v0.3H119v3.7H118.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st1" points="26.3,163.8 31.6,158.5 36.9,163.8 37.7,163.8 31.6,157.6 25.5,163.8 "/>
|
||||
<polygon class="st1" points="36.9,164.7 31.6,170 26.3,164.7 25.5,164.7 31.6,170.8 37.7,164.7 "/>
|
||||
<polygon class="st1" points="31,163.8 36.3,158.5 41.6,163.8 42.5,163.8 36.3,157.6 30.2,163.8 "/>
|
||||
<polygon class="st1" points="41.6,164.7 36.3,170 31,164.7 30.2,164.7 36.3,170.8 42.5,164.7 "/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M33.2,100.7c-4.6,0-8.3,3.7-8.3,8.3s3.7,8.3,8.3,8.3s8.3-3.7,8.3-8.3S37.8,100.7,33.2,100.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st2" d="M33.2,35.2c40.7,0,73.8,33.1,73.8,73.8c0,0.7,0,1.4,0,2.1c0,1.7,0.6,3.3,1.7,4.6c1.2,1.2,2.8,1.9,4.5,2
|
||||
l0.2,0c3.5,0,6.3-2.7,6.4-6.2c0-0.8,0-1.7,0-2.5c0-47.7-38.8-86.6-86.6-86.6c-0.8,0-1.7,0-2.5,0c-1.7,0-3.3,0.8-4.5,2
|
||||
c-1.2,1.2-1.8,2.9-1.7,4.6c0.1,3.5,3,6.3,6.6,6.2C31.8,35.2,32.5,35.2,33.2,35.2z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st3" d="M33.2,60.5c26.7,0,48.5,21.7,48.5,48.5c0,0.6,0,1.3,0,2c-0.1,1.7,0.5,3.3,1.7,4.6c1.2,1.3,2.7,2,4.4,2.1
|
||||
c1.7,0.1,3.3-0.5,4.6-1.7c1.2-1.2,2-2.7,2-4.4c0-0.9,0.1-1.8,0.1-2.6c0-33.8-27.5-61.2-61.2-61.2c-0.8,0-1.6,0-2.6,0.1
|
||||
c-1.7,0.1-3.3,0.8-4.4,2.1c-1.2,1.3-1.8,2.9-1.7,4.6s0.8,3.3,2.1,4.4c1.3,1.2,2.9,1.8,4.6,1.7C31.9,60.5,32.6,60.5,33.2,60.5z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st4" d="M33.2,86.7c12.3,0,22.3,10,22.3,22.3c0,0.5,0,1.1-0.1,1.8c-0.3,3.5,2.3,6.6,5.8,6.9
|
||||
c3.5,0.3,6.6-2.3,6.9-5.8c0.1-1,0.1-1.9,0.1-2.8c0-19.3-15.7-35.1-35.1-35.1c-0.9,0-1.8,0-2.8,0.1c-1.7,0.1-3.2,0.9-4.3,2.2
|
||||
c-1.1,1.3-1.6,2.9-1.5,4.6c0.1,1.7,0.9,3.2,2.2,4.3c1.3,1.1,2.9,1.6,4.6,1.5C32.1,86.7,32.7,86.7,33.2,86.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M35.8,130.4c1.1,0.6,2.1,1.5,2.7,2.6c0.7,1.1,1,2.3,1,3.7s-0.3,2.6-1,3.7c-0.7,1.1-1.6,2-2.7,2.6
|
||||
c-1.1,0.6-2.4,1-3.8,1s-2.7-0.3-3.8-1c-1.1-0.6-2.1-1.5-2.7-2.6c-0.7-1.1-1-2.3-1-3.7c0-1.3,0.3-2.6,1-3.7c0.7-1.1,1.6-2,2.7-2.6
|
||||
c1.1-0.6,2.4-0.9,3.8-0.9C33.4,129.5,34.7,129.8,35.8,130.4z M29.9,132.9c-0.7,0.4-1.2,0.9-1.6,1.6s-0.6,1.4-0.6,2.2
|
||||
c0,0.8,0.2,1.6,0.6,2.3c0.4,0.7,0.9,1.2,1.6,1.6c0.7,0.4,1.4,0.6,2.1,0.6c0.8,0,1.5-0.2,2.1-0.6c0.6-0.4,1.2-0.9,1.5-1.6
|
||||
c0.4-0.7,0.6-1.4,0.6-2.3c0-0.8-0.2-1.6-0.6-2.2s-0.9-1.2-1.5-1.6c-0.6-0.4-1.4-0.6-2.1-0.6C31.3,132.3,30.6,132.5,29.9,132.9z"/>
|
||||
<path class="st1" d="M50.6,133.6c0.8,0.5,1.4,1.1,1.8,2c0.4,0.8,0.6,1.8,0.6,2.9c0,1.1-0.2,2-0.6,2.8c-0.4,0.8-1,1.5-1.8,1.9
|
||||
c-0.8,0.5-1.6,0.7-2.6,0.7c-0.7,0-1.4-0.1-2-0.4s-1.1-0.7-1.5-1.2v5.4h-3.1V133h3.1v1.6c0.4-0.5,0.9-1,1.4-1.2s1.2-0.4,2-0.4
|
||||
C48.9,132.9,49.8,133.1,50.6,133.6z M49.1,140.5c0.5-0.6,0.7-1.3,0.7-2.2c0-0.9-0.2-1.6-0.7-2.1c-0.5-0.6-1.1-0.8-1.9-0.8
|
||||
s-1.4,0.3-1.9,0.8c-0.5,0.6-0.8,1.3-0.8,2.1c0,0.9,0.2,1.6,0.8,2.2s1.1,0.8,1.9,0.8S48.6,141,49.1,140.5z"/>
|
||||
<path class="st1" d="M63.4,134.4c0.9,1,1.4,2.4,1.4,4.2c0,0.3,0,0.6,0,0.7H57c0.2,0.7,0.5,1.2,1,1.6c0.5,0.4,1.1,0.6,1.8,0.6
|
||||
c0.5,0,1-0.1,1.5-0.3s0.9-0.5,1.3-0.9l1.6,1.6c-0.5,0.6-1.2,1.1-2,1.4c-0.8,0.3-1.6,0.5-2.6,0.5c-1.1,0-2.1-0.2-3-0.7
|
||||
s-1.5-1.1-2-1.9c-0.5-0.8-0.7-1.8-0.7-2.9c0-1.1,0.2-2.1,0.7-2.9s1.1-1.5,2-1.9c0.8-0.5,1.8-0.7,2.9-0.7
|
||||
C61.2,132.9,62.5,133.4,63.4,134.4z M61.8,137.5c0-0.7-0.3-1.3-0.7-1.7s-1-0.6-1.7-0.6c-0.7,0-1.2,0.2-1.7,0.6
|
||||
c-0.4,0.4-0.7,1-0.9,1.7H61.8z"/>
|
||||
<path class="st1" d="M76.2,134c0.7,0.7,1.1,1.7,1.1,3v6.8h-3.1v-5.9c0-0.7-0.2-1.2-0.6-1.6s-0.9-0.6-1.5-0.6
|
||||
c-0.8,0-1.4,0.3-1.8,0.8c-0.4,0.5-0.7,1.2-0.7,2v5.3h-3.1V133h3.1v1.9c0.7-1.3,2-2,3.7-2C74.6,132.8,75.5,133.2,76.2,134z"/>
|
||||
<path class="st1" d="M96,129.7h3.3l-4.7,14h-3.3l-2.9-10.1l-3,10.1h-3.2l-4.7-14h3.4l3,10.7l3-10.7H90l3.1,10.7L96,129.7z"/>
|
||||
<path class="st1" d="M103.3,128.7c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2c-0.3,0.3-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.2-0.5
|
||||
c-0.3-0.3-0.5-0.7-0.5-1.2c0-0.5,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.5,1.2-0.5C102.6,128.2,103,128.3,103.3,128.7z M100.6,133h3.1
|
||||
v10.8h-3.1V133z"/>
|
||||
<path class="st1" d="M106.5,129.7h10.1l0,2.6h-6.9v3.4h6.3v2.6h-6.3v5.3h-3.2V129.7z"/>
|
||||
<path class="st1" d="M120.9,128.7c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2c-0.3,0.3-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.2-0.5
|
||||
c-0.3-0.3-0.5-0.7-0.5-1.2c0-0.5,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.5,1.2-0.5C120.1,128.2,120.5,128.3,120.9,128.7z M118.1,133h3.1
|
||||
v10.8h-3.1V133z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 8.0 KiB |
@@ -1,2 +0,0 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
44
src/App.js
44
src/App.js
@@ -1,7 +1,9 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { HashRouter, Route, Switch } from 'react-router-dom';
|
||||
import React from 'react';
|
||||
import { HashRouter, Switch } from 'react-router-dom';
|
||||
import 'scss/style.scss';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import Router from 'router';
|
||||
import { AuthProvider } from 'contexts/AuthProvider';
|
||||
import { checkIfJson } from 'utils/helper';
|
||||
|
||||
const loading = (
|
||||
<div className="pt-3 text-center">
|
||||
@@ -9,32 +11,22 @@ const loading = (
|
||||
</div>
|
||||
);
|
||||
|
||||
const TheLayout = React.lazy(() => import('layout'));
|
||||
const Login = React.lazy(() => import('pages/LoginPage'));
|
||||
|
||||
const App = () => {
|
||||
const isLoggedIn = useSelector((state) => state.connected);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
const token = sessionStorage.getItem('access_token');
|
||||
if (token !== undefined && token !== null) {
|
||||
dispatch({ type: 'set', connected: true });
|
||||
}
|
||||
}, [dispatch]);
|
||||
const storageToken = sessionStorage.getItem('access_token');
|
||||
const apiEndpoints = checkIfJson(sessionStorage.getItem('gateway_endpoints'))
|
||||
? JSON.parse(sessionStorage.getItem('gateway_endpoints'))
|
||||
: {};
|
||||
|
||||
return (
|
||||
<HashRouter>
|
||||
<React.Suspense fallback={loading}>
|
||||
<Switch>
|
||||
<Route
|
||||
path="/"
|
||||
name="Devices"
|
||||
render={(props) => (isLoggedIn ? <TheLayout {...props} /> : <Login {...props} />)}
|
||||
/>
|
||||
</Switch>
|
||||
</React.Suspense>
|
||||
</HashRouter>
|
||||
<AuthProvider token={storageToken ?? ''} apiEndpoints={apiEndpoints}>
|
||||
<HashRouter>
|
||||
<React.Suspense fallback={loading}>
|
||||
<Switch>
|
||||
<Router />
|
||||
</Switch>
|
||||
</React.Suspense>
|
||||
</HashRouter>
|
||||
</AuthProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
@@ -122,14 +122,11 @@ import {
|
||||
cilXCircle,
|
||||
cilWarning,
|
||||
} from '@coreui/icons';
|
||||
import { sygnet } from './sygnet';
|
||||
import { logo } from './logo';
|
||||
import { logoNegative } from './logo-negative';
|
||||
|
||||
import { logo } from './CoreuiLogo';
|
||||
|
||||
export const icons = {
|
||||
sygnet,
|
||||
logo,
|
||||
logoNegative,
|
||||
cilAlignCenter,
|
||||
cilAlignLeft,
|
||||
cilAlignRight,
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
export const logoNegative = [
|
||||
'608 134',
|
||||
`
|
||||
<title>coreui react pro logo</title>
|
||||
<g>
|
||||
<g style="fill:#80d0ff;">
|
||||
<path d="M362.0177,90.1512,353.25,69.4149a.2507.2507,0,0,0-.2559-.1914H343.01a.2263.2263,0,0,0-.2559.2559V90.0233a.5657.5657,0,0,1-.64.64h-1.2163a.5652.5652,0,0,1-.64-.64V46.5028a.5655.5655,0,0,1,.64-.64H353.442a9.9792,9.9792,0,0,1,7.7437,3.2324A12.2,12.2,0,0,1,364.13,57.64a12.4389,12.4389,0,0,1-2.24,7.584,9.37,9.37,0,0,1-6.08,3.7441c-.1709.086-.2139.1915-.128.3194l8.7041,20.6084.064.2558q0,.5127-.5757.5118h-1.1523A.703.703,0,0,1,362.0177,90.1512ZM342.754,48.3593v18.496a.2259.2259,0,0,0,.2559.2559h10.3037a7.6713,7.6713,0,0,0,6.0166-2.5918,9.8807,9.8807,0,0,0,2.3037-6.8164,10.2875,10.2875,0,0,0-2.272-6.9756,7.6033,7.6033,0,0,0-6.0483-2.624H343.01A.2263.2263,0,0,0,342.754,48.3593Z"/>
|
||||
<path d="M401.3263,48.1034H381.2945a.2262.2262,0,0,0-.2558.2559v18.496a.2259.2259,0,0,0,.2558.2559h13.8238a.5664.5664,0,0,1,.6406.64v.96a.5663.5663,0,0,1-.6406.6406H381.2945a.2263.2263,0,0,0-.2558.2559v18.56a.2258.2258,0,0,0,.2558.2558h20.0318a.5671.5671,0,0,1,.6406.6407v.96a.566.566,0,0,1-.6406.64H379.1827a.5653.5653,0,0,1-.64-.64V46.5028a.5656.5656,0,0,1,.64-.64h22.1436a.5664.5664,0,0,1,.6406.64v.96A.5663.5663,0,0,1,401.3263,48.1034Z"/>
|
||||
<path d="M439.047,90.1512l-2.4317-8.832a.2971.2971,0,0,0-.32-.1924H419.5274a.2957.2957,0,0,0-.32.1924l-2.3681,8.7676a.6577.6577,0,0,1-.7036.5762H414.919a.5385.5385,0,0,1-.5756-.7041l12.0317-43.584a.6436.6436,0,0,1,.7041-.5117h1.6a.6442.6442,0,0,1,.7041.5117l12.16,43.584.0644.1923q0,.5127-.64.5118h-1.2163A.6428.6428,0,0,1,439.047,90.1512ZM419.9435,78.9188a.3031.3031,0,0,0,.2236.0967h15.4883a.3048.3048,0,0,0,.2236-.0967c.0645-.0635.0742-.1162.0322-.1592l-7.872-28.9287c-.043-.0849-.086-.1279-.128-.1279s-.0859.043-.1279.1279L419.9112,78.76C419.8683,78.8026,419.879,78.8553,419.9435,78.9188Z"/>
|
||||
<path d="M456.6017,87.911a11.6372,11.6372,0,0,1-3.3277-8.7041V57.1913a11.4158,11.4158,0,0,1,3.36-8.5762,12.0941,12.0941,0,0,1,8.8-3.2637,12.2566,12.2566,0,0,1,8.8643,3.2315,11.3927,11.3927,0,0,1,3.36,8.6084v.64a.5663.5663,0,0,1-.6406.6407l-1.28.0634q-.6408,0-.64-.5761v-.8321a9.289,9.289,0,0,0-2.6558-6.9121,10.6734,10.6734,0,0,0-14.0161,0,9.2854,9.2854,0,0,0-2.6563,6.9121V79.3993a9.2808,9.2808,0,0,0,2.6563,6.9121,10.67,10.67,0,0,0,14.0161,0,9.2843,9.2843,0,0,0,2.6558-6.9121v-.7686q0-.5757.64-.5752l1.28.0635a.5667.5667,0,0,1,.6406.6406v.5118a11.4952,11.4952,0,0,1-3.36,8.64,13.6227,13.6227,0,0,1-17.6963,0Z"/>
|
||||
<path d="M514.4376,46.5028v.96a.5658.5658,0,0,1-.64.6406H503.046a.2263.2263,0,0,0-.2559.2559v41.664a.566.566,0,0,1-.6406.64h-1.2158a.5652.5652,0,0,1-.64-.64V48.3593a.2266.2266,0,0,0-.2558-.2559H489.8619a.5656.5656,0,0,1-.64-.6406v-.96a.5656.5656,0,0,1,.64-.64H513.798A.5658.5658,0,0,1,514.4376,46.5028Z"/>
|
||||
<path d="M522.0665,89.5116a2.8385,2.8385,0,0,1-.8-2.0488,2.9194,2.9194,0,0,1,.8-2.1114,2.7544,2.7544,0,0,1,2.08-.832,2.8465,2.8465,0,0,1,2.9438,2.9434,2.7541,2.7541,0,0,1-.832,2.08,2.9221,2.9221,0,0,1-2.1118.8008A2.754,2.754,0,0,1,522.0665,89.5116Z"/>
|
||||
<path d="M542.4054,88.0077a11.3123,11.3123,0,0,1-3.2-8.416v-5.44a.5656.5656,0,0,1,.64-.64h1.2158a.5661.5661,0,0,1,.64.64v5.5039a9.1424,9.1424,0,0,0,2.5283,6.72,8.9745,8.9745,0,0,0,6.6875,2.5605,8.7908,8.7908,0,0,0,9.28-9.28V46.5028a.5655.5655,0,0,1,.64-.64h1.2163a.566.566,0,0,1,.64.64V79.5917a11.2545,11.2545,0,0,1-3.2325,8.416,13.0618,13.0618,0,0,1-17.0556,0Z"/>
|
||||
<path d="M580.35,88.1034a10.4859,10.4859,0,0,1-3.36-8.1279v-1.792a.5663.5663,0,0,1,.64-.6407h1.0884a.5668.5668,0,0,1,.64.6407v1.6a8.5459,8.5459,0,0,0,2.752,6.6562,10.5353,10.5353,0,0,0,7.36,2.4961,9.8719,9.8719,0,0,0,6.9761-2.3681,8.2161,8.2161,0,0,0,2.56-6.336,8.4,8.4,0,0,0-1.12-4.416,11.3812,11.3812,0,0,0-3.3281-3.3926,71.6714,71.6714,0,0,0-6.1763-3.7119,71.0479,71.0479,0,0,1-6.24-3.84,12.1711,12.1711,0,0,1-3.4238-3.68,10.2614,10.2614,0,0,1-1.28-5.3438,9.8579,9.8579,0,0,1,3.0718-7.7441,12.0122,12.0122,0,0,1,8.32-2.752q5.6954,0,8.96,3.1036a10.8251,10.8251,0,0,1,3.2642,8.2246v1.6a.5658.5658,0,0,1-.64.64h-1.1519a.5652.5652,0,0,1-.64-.64V56.8075a8.8647,8.8647,0,0,0-2.624-6.6885,9.9933,9.9933,0,0,0-7.232-2.5273,9.37,9.37,0,0,0-6.5278,2.1435,7.8224,7.8224,0,0,0-2.3682,6.1123,7.8006,7.8006,0,0,0,1.0244,4.16,10.387,10.387,0,0,0,3.0078,3.0391,62.8714,62.8714,0,0,0,5.9522,3.4882,71.0575,71.0575,0,0,1,6.72,4.2559,13.4674,13.4674,0,0,1,3.648,3.9365,10.049,10.049,0,0,1,1.28,5.1836,10.7177,10.7177,0,0,1-3.2637,8.1924q-3.2637,3.0717-8.832,3.0723Q583.71,91.1757,580.35,88.1034Z"/>
|
||||
</g>
|
||||
|
||||
<g style="fill:#fff;">
|
||||
<g>
|
||||
<path d="M99.835,36.0577l-39-22.5167a12,12,0,0,0-12,0l-39,22.5166a12.0339,12.0339,0,0,0-6,10.3924V91.4833a12.0333,12.0333,0,0,0,6,10.3923l39,22.5167a12,12,0,0,0,12,0l39-22.5167a12.0331,12.0331,0,0,0,6-10.3923V46.45A12.0334,12.0334,0,0,0,99.835,36.0577Zm-2,55.4256a4,4,0,0,1-2,3.4641l-39,22.5167a4.0006,4.0006,0,0,1-4,0l-39-22.5167a4,4,0,0,1-2-3.4641V46.45a4,4,0,0,1,2-3.4642l39-22.5166a4,4,0,0,1,4,0l39,22.5166a4,4,0,0,1,2,3.4642Z"/>
|
||||
<path d="M77.8567,82.0046h-2.866a4,4,0,0,0-1.9247.4934L55.7852,91.9833,35.835,80.4648V57.4872l19.95-11.5185,17.2893,9.4549a3.9993,3.9993,0,0,0,1.9192.4906h2.8632a2,2,0,0,0,2-2V51.2024a2,2,0,0,0-1.04-1.7547L59.628,38.9521a8.0391,8.0391,0,0,0-7.8428.09L31.8346,50.56a8.0246,8.0246,0,0,0-4,6.9287v22.976a8,8,0,0,0,4,6.9283l19.95,11.5186a8.0429,8.0429,0,0,0,7.8433.0879l19.19-10.5312a2,2,0,0,0,1.0378-1.7533v-2.71A2,2,0,0,0,77.8567,82.0046Z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M172.58,45.3618a15.0166,15.0166,0,0,0-15,14.9995V77.6387a15,15,0,0,0,30,0V60.3613A15.0166,15.0166,0,0,0,172.58,45.3618Zm7,32.2769a7,7,0,0,1-14,0V60.3613a7,7,0,0,1,14,0Z"/>
|
||||
<path d="M135.9138,53.4211a7.01,7.01,0,0,1,7.8681,6.0752.9894.9894,0,0,0,.9843.865h6.03a1.0108,1.0108,0,0,0,.9987-1.0971,15.0182,15.0182,0,0,0-15.7162-13.8837,15.2881,15.2881,0,0,0-14.2441,15.4163V77.2037A15.288,15.288,0,0,0,136.0792,92.62a15.0183,15.0183,0,0,0,15.7162-13.8842,1.0107,1.0107,0,0,0-.9987-1.0971h-6.03a.9894.9894,0,0,0-.9843.865,7.01,7.01,0,0,1-7.8679,6.0757,7.1642,7.1642,0,0,1-6.0789-7.1849V60.6057A7.1638,7.1638,0,0,1,135.9138,53.4211Z"/>
|
||||
<path d="M218.7572,72.9277a12.1585,12.1585,0,0,0,7.1843-11.0771V58.1494A12.1494,12.1494,0,0,0,213.7921,46H196.835a1,1,0,0,0-1,1V91a1,1,0,0,0,1,1h6a1,1,0,0,0,1-1V74h6.6216l7.9154,17.4138a1,1,0,0,0,.91.5862h6.5911a1,1,0,0,0,.91-1.4138Zm-.8157-11.0771A4.1538,4.1538,0,0,1,213.7926,66h-9.8511V54h9.8511a4.1538,4.1538,0,0,1,4.1489,4.1494Z"/>
|
||||
<path d="M260.835,46h-26a1,1,0,0,0-1,1V91a1,1,0,0,0,1,1h26a1,1,0,0,0,1-1V85a1,1,0,0,0-1-1h-19V72h13a1,1,0,0,0,1-1V65a1,1,0,0,0-1-1h-13V54h19a1,1,0,0,0,1-1V47A1,1,0,0,0,260.835,46Z"/>
|
||||
<path d="M298.835,46h-6a1,1,0,0,0-1,1V69.6475a7.0066,7.0066,0,1,1-14,0V47a1,1,0,0,0-1-1h-6a1,1,0,0,0-1,1V69.6475a15.0031,15.0031,0,1,0,30,0V47A1,1,0,0,0,298.835,46Z"/>
|
||||
<rect x="307.835" y="46" width="8" height="38" rx="1"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
`,
|
||||
];
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.6 KiB |
@@ -1,12 +0,0 @@
|
||||
export const sygnet = [
|
||||
'160 160',
|
||||
`
|
||||
<title>coreui logo</title>
|
||||
<g>
|
||||
<g style="fill:#fff;">
|
||||
<path d="M125,47.091,86,24.5743a12,12,0,0,0-12,0L35,47.091a12.0336,12.0336,0,0,0-6,10.3923v45.0334a12.0335,12.0335,0,0,0,6,10.3923l39,22.5166a11.9993,11.9993,0,0,0,12,0l39-22.5166a12.0335,12.0335,0,0,0,6-10.3923V57.4833A12.0336,12.0336,0,0,0,125,47.091Zm-2,55.4257a4,4,0,0,1-2,3.464L82,128.4974a4,4,0,0,1-4,0L39,105.9807a4,4,0,0,1-2-3.464V57.4833a4,4,0,0,1,2-3.4641L78,31.5025a4,4,0,0,1,4,0l39,22.5167a4,4,0,0,1,2,3.4641Z"/>
|
||||
<path d="M103.0216,93.0379h-2.866a4,4,0,0,0-1.9246.4935L80.95,103.0167,61,91.4981V68.5206L80.95,57.002l17.2894,9.455a4,4,0,0,0,1.9192.4905h2.8632a2,2,0,0,0,2-2V62.2357a2,2,0,0,0-1.04-1.7547L84.793,49.9854a8.0391,8.0391,0,0,0-7.8428.09L57,61.5929A8.0243,8.0243,0,0,0,53,68.5216v22.976a8,8,0,0,0,4,6.9283l19.95,11.5185a8.0422,8.0422,0,0,0,7.8433.0879l19.19-10.5311a2,2,0,0,0,1.0378-1.7534v-2.71A2,2,0,0,0,103.0216,93.0379Z"/>
|
||||
</g>
|
||||
</g>
|
||||
`,
|
||||
];
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
CSwitch,
|
||||
CCol,
|
||||
CRow,
|
||||
CForm,
|
||||
CFormGroup,
|
||||
CInputRadio,
|
||||
CLabel,
|
||||
@@ -17,10 +16,10 @@ import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import DatePicker from 'react-widgets/DatePicker';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { dateToUnix } from 'utils/helper';
|
||||
import 'react-widgets/styles.css';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import eventBus from 'utils/eventBus';
|
||||
import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody';
|
||||
@@ -30,16 +29,17 @@ import styles from './index.module.scss';
|
||||
|
||||
const BlinkModal = ({ show, toggleModal }) => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [isNow, setIsNow] = useState(false);
|
||||
const [waiting, setWaiting] = useState(false);
|
||||
const [chosenDate, setChosenDate] = useState(new Date().toString());
|
||||
const [chosenPattern, setPattern] = useState('on');
|
||||
const [result, setResult] = useState(null);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
const toggleNow = () => {
|
||||
setIsNow(!isNow);
|
||||
}
|
||||
};
|
||||
|
||||
const setDate = (date) => {
|
||||
if (date) {
|
||||
@@ -58,12 +58,10 @@ const BlinkModal = ({ show, toggleModal }) => {
|
||||
|
||||
const doAction = () => {
|
||||
setWaiting(true);
|
||||
|
||||
const token = getToken();
|
||||
const utcDate = new Date(chosenDate);
|
||||
|
||||
const parameters = {
|
||||
serialNumber: selectedDeviceId,
|
||||
serialNumber: deviceSerialNumber,
|
||||
when: isNow ? 0 : dateToUnix(utcDate),
|
||||
pattern: chosenPattern,
|
||||
duration: 30,
|
||||
@@ -71,11 +69,15 @@ const BlinkModal = ({ show, toggleModal }) => {
|
||||
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.post(`/device/${encodeURIComponent(selectedDeviceId)}/leds`, parameters, { headers })
|
||||
.post(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(deviceSerialNumber)}/leds`,
|
||||
parameters,
|
||||
{ headers },
|
||||
)
|
||||
.then(() => {
|
||||
setResult('success');
|
||||
})
|
||||
@@ -98,50 +100,52 @@ const BlinkModal = ({ show, toggleModal }) => {
|
||||
) : (
|
||||
<div>
|
||||
<CModalBody>
|
||||
<h6>{t('blink.when_blink_leds')}</h6>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="7">{t('blink.pattern')}</CCol>
|
||||
<CCol>
|
||||
<CForm disabled={waiting}>
|
||||
<CFormGroup variant="checkbox" onClick={() => setPattern('on')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenPattern === 'on'}
|
||||
id="radio1"
|
||||
name="radios"
|
||||
value="option1"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="radio1">
|
||||
{t('common.on')}
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
<CFormGroup variant="checkbox" onClick={() => setPattern('off')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenPattern === 'off'}
|
||||
id="radio2"
|
||||
name="radios"
|
||||
value="option2"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="radio2">
|
||||
{t('common.off')}
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
<CFormGroup variant="checkbox" onClick={() => setPattern('blink')}>
|
||||
<CInputRadio
|
||||
defaultChecked={chosenPattern === 'blink'}
|
||||
id="radio3"
|
||||
name="radios"
|
||||
value="option3"
|
||||
/>
|
||||
<CLabel variant="checkbox" htmlFor="radio3">
|
||||
{t('blink.blink')}
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
</CForm>
|
||||
<CFormGroup row>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('blink.pattern')}</CLabel>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CCol>
|
||||
<CFormGroup variant="custom-radio" onClick={() => setPattern('on')} inline>
|
||||
<CInputRadio
|
||||
custom
|
||||
defaultChecked={chosenPattern === 'on'}
|
||||
id="radio1"
|
||||
name="radios"
|
||||
value="option1"
|
||||
/>
|
||||
<CLabel variant="custom-checkbox" htmlFor="radio1">
|
||||
{t('common.on')}
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
<CFormGroup variant="custom-radio" onClick={() => setPattern('off')} inline>
|
||||
<CInputRadio
|
||||
custom
|
||||
defaultChecked={chosenPattern === 'off'}
|
||||
id="radio2"
|
||||
name="radios"
|
||||
value="option2"
|
||||
/>
|
||||
<CLabel variant="custom-checkbox" htmlFor="radio2">
|
||||
{t('common.off')}
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
<CFormGroup variant="custom-radio" onClick={() => setPattern('blink')} inline>
|
||||
<CInputRadio
|
||||
custom
|
||||
defaultChecked={chosenPattern === 'blink'}
|
||||
id="radio3"
|
||||
name="radios"
|
||||
value="option3"
|
||||
/>
|
||||
<CLabel variant="custom-checkbox" htmlFor="radio3">
|
||||
{t('blink.blink')}
|
||||
</CLabel>
|
||||
</CFormGroup>
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="8">
|
||||
<p className={styles.spacedText}>{t('common.execute_now')}</p>
|
||||
<p className={styles.spacedText}>{t('blink.execute_now')}</p>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CSwitch
|
||||
@@ -156,7 +160,7 @@ const BlinkModal = ({ show, toggleModal }) => {
|
||||
</CRow>
|
||||
<CRow hidden={isNow} className={styles.spacedRow}>
|
||||
<CCol md="4" className={styles.spacedDate}>
|
||||
<p>{t('common.date')}</p>
|
||||
<p>{t('common.custom_date')}</p>
|
||||
</CCol>
|
||||
<CCol xs="12" md="8">
|
||||
<DatePicker
|
||||
@@ -173,7 +177,7 @@ const BlinkModal = ({ show, toggleModal }) => {
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<LoadingButton
|
||||
label={isNow ? t('blink.blink') : t('common.schedule')}
|
||||
label={isNow ? t('blink.set_leds') : t('common.schedule')}
|
||||
isLoadingLabel={t('common.loading_ellipsis')}
|
||||
isLoading={waiting}
|
||||
action={doAction}
|
||||
|
||||
@@ -13,13 +13,11 @@ import {
|
||||
} from '@coreui/react';
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import DatePicker from 'react-widgets/DatePicker';
|
||||
import { cilCloudDownload, cilSync } from '@coreui/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faClipboardCheck } from '@fortawesome/free-solid-svg-icons';
|
||||
import { cilCloudDownload, cilSync, cilCalendarCheck } from '@coreui/icons';
|
||||
import { prettyDate, dateToUnix } from 'utils/helper';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import eventBus from 'utils/eventBus';
|
||||
import ConfirmModal from 'components/ConfirmModal';
|
||||
import LoadingButton from 'components/LoadingButton';
|
||||
@@ -27,8 +25,10 @@ import WifiScanResultModalWidget from 'components/WifiScanResultModal';
|
||||
import DeviceCommandsCollapse from './DeviceCommandsCollapse';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
const DeviceCommands = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
// Wifiscan result related
|
||||
const [chosenWifiScan, setChosenWifiScan] = useState(null);
|
||||
const [showScanModal, setShowScanModal] = useState(false);
|
||||
@@ -92,7 +92,7 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
params: {
|
||||
limit: commandLimit,
|
||||
@@ -109,7 +109,12 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
}
|
||||
|
||||
axiosInstance
|
||||
.get(`/commands?serialNumber=${encodeURIComponent(selectedDeviceId)}${extraParams}`, options)
|
||||
.get(
|
||||
`${endpoints.ucentralgw}/api/v1/commands?serialNumber=${encodeURIComponent(
|
||||
deviceSerialNumber,
|
||||
)}${extraParams}`,
|
||||
options,
|
||||
)
|
||||
.then((response) => {
|
||||
setCommands(response.data.commands);
|
||||
})
|
||||
@@ -124,13 +129,16 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/octet-stream',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
responseType: 'arraybuffer',
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/file/${uuid}?serialNumber=${selectedDeviceId}`, options)
|
||||
.get(
|
||||
`${endpoints.ucentralgw}/api/v1/file/${uuid}?serialNumber=${deviceSerialNumber}`,
|
||||
options,
|
||||
)
|
||||
.then((response) => {
|
||||
const blob = new Blob([response.data], { type: 'application/octet-stream' });
|
||||
const link = document.createElement('a');
|
||||
@@ -147,11 +155,11 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
};
|
||||
return axiosInstance
|
||||
.delete(`/command/${uuidDelete}`, options)
|
||||
.delete(`${endpoints.ucentralgw}/api/v1/command/${uuidDelete}`, options)
|
||||
.then(() => {
|
||||
deleteCommandFromList(uuidDelete);
|
||||
setUuidDelete('');
|
||||
@@ -233,12 +241,12 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId && start !== '' && end !== '') {
|
||||
if (deviceSerialNumber && start !== '' && end !== '') {
|
||||
getCommands();
|
||||
} else if (selectedDeviceId && start === '' && end === '') {
|
||||
} else if (deviceSerialNumber && start === '' && end === '') {
|
||||
getCommands();
|
||||
}
|
||||
}, [selectedDeviceId, start, end]);
|
||||
}, [deviceSerialNumber, start, end]);
|
||||
|
||||
useEffect(() => {
|
||||
eventBus.on('actionCompleted', () => refreshCommands());
|
||||
@@ -249,7 +257,7 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId) {
|
||||
if (deviceSerialNumber) {
|
||||
setCommandLimit(25);
|
||||
setLoadingMore(false);
|
||||
setShowLoadingMore(true);
|
||||
@@ -257,7 +265,7 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
setEnd('');
|
||||
getCommands();
|
||||
}
|
||||
}, [selectedDeviceId]);
|
||||
}, [deviceSerialNumber]);
|
||||
|
||||
useEffect(() => {
|
||||
if (commandLimit !== 25) {
|
||||
@@ -313,9 +321,7 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
items={commands ?? []}
|
||||
fields={columns}
|
||||
className={styles.whiteIcon}
|
||||
columnFilter
|
||||
sorter
|
||||
sorterValue={{ column: 'submitted', desc: 'true' }}
|
||||
sorterValue={{ column: 'created', desc: 'true' }}
|
||||
scopedSlots={{
|
||||
completed: (item) => (
|
||||
<td>
|
||||
@@ -363,12 +369,7 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
{item.command === 'trace' ? (
|
||||
<CIcon content={cilCloudDownload} size="lg" />
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faClipboardCheck}
|
||||
className={[styles.customIconHeight, 'c-icon c-icon-lg'].join(
|
||||
' ',
|
||||
)}
|
||||
/>
|
||||
<CIcon content={cilCalendarCheck} size="lg" />
|
||||
)}
|
||||
</CButton>
|
||||
</CPopover>
|
||||
@@ -453,8 +454,4 @@ const DeviceCommands = ({ selectedDeviceId }) => {
|
||||
);
|
||||
};
|
||||
|
||||
DeviceCommands.propTypes = {
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default DeviceCommands;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
}
|
||||
|
||||
.scrollableBox {
|
||||
height: 400px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.whiteIcon {
|
||||
|
||||
@@ -16,9 +16,9 @@ import {
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import 'react-widgets/styles.css';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import { checkIfJson } from 'utils/helper';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import eventBus from 'utils/eventBus';
|
||||
@@ -27,6 +27,8 @@ import styles from './index.module.scss';
|
||||
|
||||
const ConfigureModal = ({ show, toggleModal }) => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [hadSuccess, setHadSuccess] = useState(false);
|
||||
const [hadFailure, setHadFailure] = useState(false);
|
||||
const [doingNow, setDoingNow] = useState(false);
|
||||
@@ -36,7 +38,7 @@ const ConfigureModal = ({ show, toggleModal }) => {
|
||||
const [checkingIfSure, setCheckingIfSure] = useState(false);
|
||||
const [errorJson, setErrorJson] = useState(false);
|
||||
const [inputKey, setInputKey] = useState(0);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
let fileReader;
|
||||
|
||||
const confirmingIfSure = () => {
|
||||
@@ -69,10 +71,8 @@ const ConfigureModal = ({ show, toggleModal }) => {
|
||||
setHadSuccess(false);
|
||||
setWaiting(true);
|
||||
|
||||
const token = getToken();
|
||||
|
||||
const parameters = {
|
||||
serialNumber: selectedDeviceId,
|
||||
serialNumber: deviceSerialNumber,
|
||||
when: 0,
|
||||
UUID: 1,
|
||||
configuration: JSON.parse(newConfig),
|
||||
@@ -80,11 +80,15 @@ const ConfigureModal = ({ show, toggleModal }) => {
|
||||
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.post(`/device/${encodeURIComponent(selectedDeviceId)}/configure`, parameters, { headers })
|
||||
.post(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(deviceSerialNumber)}/configure`,
|
||||
parameters,
|
||||
{ headers },
|
||||
)
|
||||
.then(() => {
|
||||
setHadSuccess(true);
|
||||
})
|
||||
|
||||
@@ -5,28 +5,29 @@ import { cilClone } from '@coreui/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CButton, CPopover } from '@coreui/react';
|
||||
|
||||
const CopyToClipboardButton = ({content, size}) => {
|
||||
const CopyToClipboardButton = ({ content, size }) => {
|
||||
const { t } = useTranslation();
|
||||
const [result, setResult] = useState('');
|
||||
|
||||
const copyToClipboard = () => {
|
||||
navigator.clipboard.writeText(content);
|
||||
setResult(t('common.copied'));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<CPopover content={t('common.copy_to_clipboard')}>
|
||||
<CButton onClick={copyToClipboard} size={size}>
|
||||
<CIcon content={cilClone} />
|
||||
{' '}{result || ''}
|
||||
</CButton>
|
||||
</CPopover>
|
||||
<CPopover content={t('common.copy_to_clipboard')}>
|
||||
<CButton onClick={copyToClipboard} size={size}>
|
||||
<CIcon content={cilClone} />
|
||||
{' '}
|
||||
{result || ''}
|
||||
</CButton>
|
||||
</CPopover>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
CopyToClipboardButton.propTypes = {
|
||||
content: PropTypes.string.isRequired,
|
||||
size: PropTypes.string
|
||||
size: PropTypes.string,
|
||||
};
|
||||
|
||||
CopyToClipboardButton.defaultProps = {
|
||||
|
||||
@@ -6,12 +6,15 @@ import PropTypes from 'prop-types';
|
||||
import ConfirmFooter from 'components/ConfirmFooter';
|
||||
import { dateToUnix } from 'utils/helper';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import eventBus from 'utils/eventBus';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const DeleteLogModal = ({ serialNumber, show, toggle, object }) => {
|
||||
const DeleteLogModal = ({ show, toggle, object }) => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [maxDate, setMaxDate] = useState(new Date().toString());
|
||||
|
||||
@@ -27,14 +30,14 @@ const DeleteLogModal = ({ serialNumber, show, toggle, object }) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
params: {
|
||||
endDate: dateToUnix(maxDate),
|
||||
},
|
||||
};
|
||||
return axiosInstance
|
||||
.delete(`/device/${serialNumber}/${object}`, options)
|
||||
.delete(`${endpoints.ucentralgw}/api/v1/device/${deviceSerialNumber}/${object}`, options)
|
||||
.then(() => {})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
@@ -94,7 +97,6 @@ DeleteLogModal.propTypes = {
|
||||
show: PropTypes.bool.isRequired,
|
||||
toggle: PropTypes.func.isRequired,
|
||||
object: PropTypes.string.isRequired,
|
||||
serialNumber: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default DeleteLogModal;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CButton, CCard, CCardHeader, CCardBody, CRow, CCol } from '@coreui/react';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import LoadingButton from 'components/LoadingButton';
|
||||
import RebootModal from 'components/RebootModal';
|
||||
import FirmwareUpgradeModal from 'components/FirmwareUpgradeModal';
|
||||
@@ -15,8 +15,10 @@ import FactoryResetModal from 'components/FactoryResetModal';
|
||||
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const DeviceActions = ({ selectedDeviceId }) => {
|
||||
const DeviceActions = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [showRebootModal, setShowRebootModal] = useState(false);
|
||||
const [showBlinkModal, setShowBlinkModal] = useState(false);
|
||||
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
|
||||
@@ -59,12 +61,15 @@ const DeviceActions = ({ selectedDeviceId }) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/device/${encodeURIComponent(selectedDeviceId)}/rtty`, options)
|
||||
.get(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(deviceSerialNumber)}/rtty`,
|
||||
options,
|
||||
)
|
||||
.then((response) => {
|
||||
const url = `https://${response.data.server}:${response.data.viewport}/connect/${response.data.connectionId}`;
|
||||
const newWindow = window.open(url, '_blank', 'noopener,noreferrer');
|
||||
@@ -78,7 +83,9 @@ const DeviceActions = ({ selectedDeviceId }) => {
|
||||
|
||||
return (
|
||||
<CCard>
|
||||
<CCardHeader><div className="text-value-lg">{t('actions.title')}</div></CCardHeader>
|
||||
<CCardHeader>
|
||||
<div className="text-value-lg">{t('actions.title')}</div>
|
||||
</CCardHeader>
|
||||
<CCardBody>
|
||||
<CRow>
|
||||
<CCol>
|
||||
@@ -143,8 +150,4 @@ const DeviceActions = ({ selectedDeviceId }) => {
|
||||
);
|
||||
};
|
||||
|
||||
DeviceActions.propTypes = {
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default DeviceActions;
|
||||
|
||||
@@ -4,11 +4,8 @@ import {
|
||||
CCard,
|
||||
CCardHeader,
|
||||
CCardBody,
|
||||
CFormGroup,
|
||||
CCol,
|
||||
CLabel,
|
||||
CForm,
|
||||
CInput,
|
||||
CCollapse,
|
||||
CCardFooter,
|
||||
CButton,
|
||||
@@ -16,17 +13,20 @@ import {
|
||||
CPopover,
|
||||
} from '@coreui/react';
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { cilWindowMaximize } from '@coreui/icons';
|
||||
import { prettyDate } from 'utils/helper';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import CopyToClipboardButton from 'components/CopyToClipboardButton';
|
||||
import DeviceNotes from 'components/DeviceNotes';
|
||||
import DeviceConfigurationModal from './DeviceConfigurationModal';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const DeviceConfiguration = ({ selectedDeviceId }) => {
|
||||
const DeviceConfiguration = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [collapse, setCollapse] = useState(false);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [device, setDevice] = useState(null);
|
||||
@@ -44,12 +44,15 @@ const DeviceConfiguration = ({ selectedDeviceId }) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/device/${encodeURIComponent(selectedDeviceId)}`, options)
|
||||
.get(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(deviceSerialNumber)}`,
|
||||
options,
|
||||
)
|
||||
.then((response) => {
|
||||
setDevice(response.data);
|
||||
})
|
||||
@@ -57,8 +60,8 @@ const DeviceConfiguration = ({ selectedDeviceId }) => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId) getDevice();
|
||||
}, [selectedDeviceId]);
|
||||
if (deviceSerialNumber) getDevice();
|
||||
}, [deviceSerialNumber]);
|
||||
|
||||
if (device) {
|
||||
return (
|
||||
@@ -66,7 +69,9 @@ const DeviceConfiguration = ({ selectedDeviceId }) => {
|
||||
<CCard>
|
||||
<CCardHeader>
|
||||
<CRow>
|
||||
<CCol><div className="text-value-lg">{t('configuration.title')}</div></CCol>
|
||||
<CCol>
|
||||
<div className="text-value-lg">{t('configuration.title')}</div>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<div className={styles.alignRight}>
|
||||
<CPopover content={t('configuration.view_json')}>
|
||||
@@ -79,122 +84,115 @@ const DeviceConfiguration = ({ selectedDeviceId }) => {
|
||||
</CRow>
|
||||
</CCardHeader>
|
||||
<CCardBody>
|
||||
<CForm
|
||||
action=""
|
||||
method="post"
|
||||
encType="multipart/form-data"
|
||||
className="form-horizontal"
|
||||
>
|
||||
<CFormGroup row>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('common.uuid')} : </CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.UUID}
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('common.serial_number')} : </CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.serialNumber}
|
||||
<CopyToClipboardButton size="sm" content={device.serialNumber}/>
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('configuration.type')} : </CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.deviceType}
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('configuration.last_configuration_change')} : </CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{prettyDate(device.lastConfigurationChange)}
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('common.mac')} :</CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.macAddress}
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('configuration.created')} : </CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{prettyDate(device.createdTimestamp)}
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('common.uuid')} : </CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.UUID}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('common.serial_number')} : </CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.serialNumber}
|
||||
<CopyToClipboardButton size="sm" content={device.serialNumber} />
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('configuration.type')} : </CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.deviceType}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('configuration.last_configuration_change')} : </CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{prettyDate(device.lastConfigurationChange)}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('common.mac')} :</CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.macAddress}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('configuration.created')} : </CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{prettyDate(device.createdTimestamp)}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="3" className={styles.topPadding}>
|
||||
<CLabel>{t('configuration.device_password')} : </CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.devicePassword === '' ? 'openwifi' : device.devicePassword}
|
||||
<CopyToClipboardButton
|
||||
size="sm"
|
||||
content={device?.devicePassword === '' ? 'openwifi' : device.devicePassword}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<DeviceNotes
|
||||
notes={device.notes}
|
||||
refreshNotes={getDevice}
|
||||
serialNumber={deviceSerialNumber}
|
||||
/>
|
||||
<CCollapse show={collapse}>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('configuration.last_configuration_download')} : </CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{prettyDate(device.lastConfigurationDownload)}
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CCol md="3" className={styles.topPadding}>
|
||||
<CLabel>{t('configuration.device_password')} : </CLabel>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('common.manufacturer')} :</CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.devicePassword === '' ? 'openwifi' : device.devicePassword}
|
||||
<CopyToClipboardButton size="sm" content={device?.devicePassword === '' ? 'openwifi' : device.devicePassword}/>
|
||||
{device.manufacturer}
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CCollapse show={collapse}>
|
||||
<CFormGroup row>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('common.manufacturer')} :</CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.manufacturer}
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CCol md="3">
|
||||
<CLabel htmlFor="text-input">{t('configuration.notes')} :</CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
<CInput id="text-input" name="text-input" placeholder={device.notes} />
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('configuration.owner')} :</CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.owner}
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
<CFormGroup row>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('configuration.location')} :</CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.location}
|
||||
</CCol>
|
||||
</CFormGroup>
|
||||
</CCollapse>
|
||||
<CCardFooter>
|
||||
<CButton show={collapse ? 'true' : 'false'} onClick={toggle} block>
|
||||
<CIcon
|
||||
className={styles.blackIcon}
|
||||
name={collapse ? 'cilChevronTop' : 'cilChevronBottom'}
|
||||
size="lg"
|
||||
/>
|
||||
</CButton>
|
||||
</CCardFooter>
|
||||
</CForm>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('configuration.owner')} :</CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.owner}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('configuration.location')} :</CLabel>
|
||||
</CCol>
|
||||
<CCol xs="12" md="9">
|
||||
{device.location}
|
||||
</CCol>
|
||||
</CRow>
|
||||
</CCollapse>
|
||||
<CCardFooter>
|
||||
<CButton show={collapse ? 'true' : 'false'} onClick={toggle} block>
|
||||
<CIcon
|
||||
className={styles.blackIcon}
|
||||
name={collapse ? 'cilChevronTop' : 'cilChevronBottom'}
|
||||
size="lg"
|
||||
/>
|
||||
</CButton>
|
||||
</CCardFooter>
|
||||
</CCardBody>
|
||||
</CCard>
|
||||
<DeviceConfigurationModal show={showModal} toggle={toggleModal} configuration={device} />
|
||||
@@ -210,8 +208,4 @@ const DeviceConfiguration = ({ selectedDeviceId }) => {
|
||||
);
|
||||
};
|
||||
|
||||
DeviceConfiguration.propTypes = {
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default DeviceConfiguration;
|
||||
|
||||
@@ -13,3 +13,8 @@
|
||||
.topPadding {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.spacedRow {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
@@ -15,17 +15,19 @@ import {
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import DatePicker from 'react-widgets/DatePicker';
|
||||
import PropTypes from 'prop-types';
|
||||
import { prettyDate, dateToUnix } from 'utils/helper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import eventBus from 'utils/eventBus';
|
||||
import LoadingButton from 'components/LoadingButton';
|
||||
import DeleteLogModal from 'components/DeleteLogModal';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
const DeviceHealth = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [collapse, setCollapse] = useState(false);
|
||||
const [details, setDetails] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -68,7 +70,7 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
params: {
|
||||
limit: logLimit,
|
||||
@@ -85,7 +87,12 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
}
|
||||
|
||||
axiosInstance
|
||||
.get(`/device/${encodeURIComponent(selectedDeviceId)}/healthchecks${extraParams}`, options)
|
||||
.get(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(
|
||||
deviceSerialNumber,
|
||||
)}/healthchecks${extraParams}`,
|
||||
options,
|
||||
)
|
||||
.then((response) => {
|
||||
setHealthChecks(response.data.values);
|
||||
})
|
||||
@@ -128,7 +135,7 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId) {
|
||||
if (deviceSerialNumber) {
|
||||
setLogLimit(25);
|
||||
setLoadingMore(false);
|
||||
setShowLoadingMore(true);
|
||||
@@ -136,7 +143,7 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
setEnd('');
|
||||
getDeviceHealth();
|
||||
}
|
||||
}, [selectedDeviceId]);
|
||||
}, [deviceSerialNumber]);
|
||||
|
||||
useEffect(() => {
|
||||
if (logLimit !== 25) {
|
||||
@@ -168,12 +175,12 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
}, [healthChecks]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId && start !== '' && end !== '') {
|
||||
if (deviceSerialNumber && start !== '' && end !== '') {
|
||||
getDeviceHealth();
|
||||
} else if (selectedDeviceId && start === '' && end === '') {
|
||||
} else if (deviceSerialNumber && start === '' && end === '') {
|
||||
getDeviceHealth();
|
||||
}
|
||||
}, [start, end, selectedDeviceId]);
|
||||
}, [start, end, deviceSerialNumber]);
|
||||
|
||||
useEffect(() => {
|
||||
eventBus.on('deletedHealth', () => getDeviceHealth());
|
||||
@@ -185,8 +192,8 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
|
||||
return (
|
||||
<CWidgetDropdown
|
||||
header={sanityLevel ? `${sanityLevel}%` : t('common.unknown')}
|
||||
text={t('health.title')}
|
||||
header={t('health.title')}
|
||||
text={sanityLevel ? `${sanityLevel}%` : t('common.unknown')}
|
||||
value={sanityLevel ?? 100}
|
||||
color={barColor}
|
||||
inverse="true"
|
||||
@@ -210,11 +217,13 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
</div>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol>
|
||||
{t('common.from')}:
|
||||
{t('common.from')}
|
||||
:
|
||||
<DatePicker includeTime onChange={(date) => modifyStart(date)} />
|
||||
</CCol>
|
||||
<CCol>
|
||||
{t('common.to')}:
|
||||
{t('common.to')}
|
||||
:
|
||||
<DatePicker includeTime onChange={(date) => modifyEnd(date)} />
|
||||
</CCol>
|
||||
</CRow>
|
||||
@@ -281,7 +290,7 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
/>
|
||||
</CButton>
|
||||
<DeleteLogModal
|
||||
serialNumber={selectedDeviceId}
|
||||
serialNumber={deviceSerialNumber}
|
||||
object="healthchecks"
|
||||
show={showDeleteModal}
|
||||
toggle={toggleDeleteModal}
|
||||
@@ -292,8 +301,4 @@ const DeviceHealth = ({ selectedDeviceId }) => {
|
||||
);
|
||||
};
|
||||
|
||||
DeviceHealth.propTypes = {
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default DeviceHealth;
|
||||
|
||||
@@ -10,14 +10,14 @@ import {
|
||||
CRow,
|
||||
CCol,
|
||||
CPopover,
|
||||
CSelect,
|
||||
} from '@coreui/react';
|
||||
import ReactPaginate from 'react-paginate';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Select from 'react-select';
|
||||
import PropTypes from 'prop-types';
|
||||
import { cilSync, cilInfo, cilBadge, cilBan } from '@coreui/icons';
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import { cleanBytesString } from 'utils/helper';
|
||||
import meshIcon from 'assets/icons/Mesh.png';
|
||||
@@ -29,6 +29,7 @@ import styles from './index.module.scss';
|
||||
|
||||
const DeviceList = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const [loadedSerials, setLoadedSerials] = useState(false);
|
||||
const [serialNumbers, setSerialNumbers] = useState([]);
|
||||
const [page, setPage] = useState(0);
|
||||
@@ -38,16 +39,15 @@ const DeviceList = () => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const getSerialNumbers = () => {
|
||||
const token = getToken();
|
||||
setLoading(true);
|
||||
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get('/devices?serialOnly=true', {
|
||||
.get(`${endpoints.ucentralgw}/api/v1/devices?serialOnly=true`, {
|
||||
headers,
|
||||
})
|
||||
.then((response) => {
|
||||
@@ -60,12 +60,11 @@ const DeviceList = () => {
|
||||
};
|
||||
|
||||
const getDeviceInformation = () => {
|
||||
const token = getToken();
|
||||
setLoading(true);
|
||||
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
};
|
||||
|
||||
const startIndex = page * devicesPerPage;
|
||||
@@ -76,7 +75,7 @@ const DeviceList = () => {
|
||||
.join(',');
|
||||
|
||||
axiosInstance
|
||||
.get(`/devices?deviceWithStatus=true&select=${serialsToGet}`, {
|
||||
.get(`${endpoints.ucentralgw}/api/v1/devices?deviceWithStatus=true&select=${serialsToGet}`, {
|
||||
headers,
|
||||
})
|
||||
.then((response) => {
|
||||
@@ -89,18 +88,22 @@ const DeviceList = () => {
|
||||
};
|
||||
|
||||
const refreshDevice = (serialNumber) => {
|
||||
const token = getToken();
|
||||
setLoading(true);
|
||||
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/devices?deviceWithStatus=true&select=${encodeURIComponent(serialNumber)}`, {
|
||||
headers,
|
||||
})
|
||||
.get(
|
||||
`${endpoints.ucentralgw}/api/v1/devices?deviceWithStatus=true&select=${encodeURIComponent(
|
||||
serialNumber,
|
||||
)}`,
|
||||
{
|
||||
headers,
|
||||
},
|
||||
)
|
||||
.then((response) => {
|
||||
const device = response.data.devicesWithStatus[0];
|
||||
const foundIndex = devices.findIndex((obj) => obj.serialNumber === serialNumber);
|
||||
@@ -189,12 +192,6 @@ const DeviceListDisplay = ({
|
||||
},
|
||||
];
|
||||
|
||||
const selectOptions = [
|
||||
{ value: '10', label: '10' },
|
||||
{ value: '25', label: '25' },
|
||||
{ value: '50', label: '50' },
|
||||
];
|
||||
|
||||
const getDeviceIcon = (deviceType) => {
|
||||
if (deviceType === 'AP_Default' || deviceType === 'AP') {
|
||||
return <img src={apIcon} className={styles.icon} alt="AP" />;
|
||||
@@ -281,13 +278,17 @@ const DeviceListDisplay = ({
|
||||
<CCardHeader>
|
||||
<CRow>
|
||||
<CCol />
|
||||
<CCol xs={2}>
|
||||
<Select
|
||||
isClearable={false}
|
||||
options={selectOptions}
|
||||
defaultValue={{ value: devicesPerPage, label: devicesPerPage }}
|
||||
onChange={(value) => updateDevicesPerPage(value.value)}
|
||||
/>
|
||||
<CCol xs={1}>
|
||||
<CSelect
|
||||
custom
|
||||
defaultValue={devicesPerPage}
|
||||
onChange={(e) => updateDevicesPerPage(e.target.value)}
|
||||
disabled={loading}
|
||||
>
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
</CSelect>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</CCardHeader>
|
||||
@@ -296,6 +297,7 @@ const DeviceListDisplay = ({
|
||||
items={devices ?? []}
|
||||
fields={columns}
|
||||
hover
|
||||
border
|
||||
loading={loading}
|
||||
scopedSlots={{
|
||||
serialNumber: (item) => (
|
||||
@@ -337,7 +339,9 @@ const DeviceListDisplay = ({
|
||||
content={item.firmware ? item.firmware : t('common.na')}
|
||||
placement="top"
|
||||
>
|
||||
<p style={{width: '225px'}} className="text-truncate">{item.firmware}</p>
|
||||
<p style={{ width: '225px' }} className="text-truncate">
|
||||
{item.firmware}
|
||||
</p>
|
||||
</CPopover>
|
||||
</td>
|
||||
),
|
||||
@@ -347,7 +351,9 @@ const DeviceListDisplay = ({
|
||||
content={item.compatible ? item.compatible : t('common.na')}
|
||||
placement="top"
|
||||
>
|
||||
<p style={{width: '150px'}} className="text-truncate">{item.compatible}</p>
|
||||
<p style={{ width: '150px' }} className="text-truncate">
|
||||
{item.compatible}
|
||||
</p>
|
||||
</CPopover>
|
||||
</td>
|
||||
),
|
||||
@@ -359,7 +365,9 @@ const DeviceListDisplay = ({
|
||||
content={item.ipAddress ? item.ipAddress : t('common.na')}
|
||||
placement="top"
|
||||
>
|
||||
<p style={{width: '150px'}} className="text-truncate">{item.ipAddress}</p>
|
||||
<p style={{ width: '150px' }} className="text-truncate">
|
||||
{item.ipAddress}
|
||||
</p>
|
||||
</CPopover>
|
||||
</td>
|
||||
),
|
||||
|
||||
@@ -14,17 +14,19 @@ import {
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import DatePicker from 'react-widgets/DatePicker';
|
||||
import PropTypes from 'prop-types';
|
||||
import { prettyDate, dateToUnix } from 'utils/helper';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import eventBus from 'utils/eventBus';
|
||||
import LoadingButton from 'components/LoadingButton';
|
||||
import DeleteLogModal from 'components/DeleteLogModal';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
const DeviceLogs = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [collapse, setCollapse] = useState(false);
|
||||
const [details, setDetails] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -65,7 +67,7 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
params: {
|
||||
limit: logLimit,
|
||||
@@ -82,7 +84,12 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
}
|
||||
|
||||
axiosInstance
|
||||
.get(`/device/${encodeURIComponent(selectedDeviceId)}/logs${extraParams}`, options)
|
||||
.get(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(
|
||||
deviceSerialNumber,
|
||||
)}/logs${extraParams}`,
|
||||
options,
|
||||
)
|
||||
.then((response) => {
|
||||
setLogs(response.data.values);
|
||||
})
|
||||
@@ -125,7 +132,7 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId) {
|
||||
if (deviceSerialNumber) {
|
||||
setLogLimit(25);
|
||||
setLoadingMore(false);
|
||||
setShowLoadingMore(true);
|
||||
@@ -133,7 +140,7 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
setEnd('');
|
||||
getLogs();
|
||||
}
|
||||
}, [selectedDeviceId]);
|
||||
}, [deviceSerialNumber]);
|
||||
|
||||
useEffect(() => {
|
||||
if (logLimit !== 25) {
|
||||
@@ -150,12 +157,12 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
}, [logs]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId && start !== '' && end !== '') {
|
||||
if (deviceSerialNumber && start !== '' && end !== '') {
|
||||
getLogs();
|
||||
} else if (selectedDeviceId && start === '' && end === '') {
|
||||
} else if (deviceSerialNumber && start === '' && end === '') {
|
||||
getLogs();
|
||||
}
|
||||
}, [start, end, selectedDeviceId]);
|
||||
}, [start, end, deviceSerialNumber]);
|
||||
|
||||
useEffect(() => {
|
||||
eventBus.on('deletedLogs', () => getLogs());
|
||||
@@ -258,7 +265,7 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
}
|
||||
/>
|
||||
<DeleteLogModal
|
||||
serialNumber={selectedDeviceId}
|
||||
serialNumber={deviceSerialNumber}
|
||||
object="logs"
|
||||
show={showDeleteModal}
|
||||
toggle={toggleDeleteModal}
|
||||
@@ -267,8 +274,4 @@ const DeviceLogs = ({ selectedDeviceId }) => {
|
||||
);
|
||||
};
|
||||
|
||||
DeviceLogs.propTypes = {
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default DeviceLogs;
|
||||
|
||||
111
src/components/DeviceNotes/index.js
Normal file
111
src/components/DeviceNotes/index.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { CDataTable, CRow, CCol, CLabel, CInput } from '@coreui/react';
|
||||
import PropTypes from 'prop-types';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { prettyDate } from 'utils/helper';
|
||||
import LoadingButton from 'components/LoadingButton';
|
||||
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const DeviceNotes = ({ serialNumber, notes, refreshNotes }) => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const [currentNote, setCurrentNote] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const saveNote = () => {
|
||||
setLoading(true);
|
||||
|
||||
const parameters = {
|
||||
serialNumber,
|
||||
notes: [{ note: currentNote }],
|
||||
};
|
||||
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.put(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(serialNumber)}`,
|
||||
parameters,
|
||||
{ headers },
|
||||
)
|
||||
.then(() => {
|
||||
setCurrentNote('');
|
||||
refreshNotes();
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
const columns = [
|
||||
{ key: 'created', label: t('common.date'), _style: { width: '30%' } },
|
||||
{ key: 'createdBy', label: t('common.created_by'), _style: { width: '20%' } },
|
||||
{ key: 'note', label: t('configuration.note'), _style: { width: '50%' } },
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="3">
|
||||
<CLabel>{t('configuration.notes')} :</CLabel>
|
||||
</CCol>
|
||||
<CCol xs="9" md="7">
|
||||
<CInput
|
||||
id="notes-input"
|
||||
name="text-input"
|
||||
value={currentNote}
|
||||
onChange={(e) => setCurrentNote(e.target.value)}
|
||||
/>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<LoadingButton
|
||||
label={t('common.add')}
|
||||
isLoadingLabel={t('common.adding_ellipsis')}
|
||||
isLoading={loading}
|
||||
action={saveNote}
|
||||
disabled={loading || currentNote === ''}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow>
|
||||
<CCol md="3" />
|
||||
<CCol xs="12" md="9">
|
||||
<div className={['overflow-auto', styles.scrollableBox].join(' ')}>
|
||||
<CDataTable
|
||||
striped
|
||||
responsive
|
||||
border
|
||||
loading={loading}
|
||||
fields={columns}
|
||||
className={styles.table}
|
||||
items={notes || []}
|
||||
noItemsView={{ noItems: t('common.no_items') }}
|
||||
sorterValue={{ column: 'created', desc: 'true' }}
|
||||
scopedSlots={{
|
||||
created: (item) => (
|
||||
<td>
|
||||
{item.created && item.created !== 0 ? prettyDate(item.created) : t('common.na')}
|
||||
</td>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
DeviceNotes.propTypes = {
|
||||
serialNumber: PropTypes.string.isRequired,
|
||||
notes: PropTypes.arrayOf(PropTypes.instanceOf(Object)).isRequired,
|
||||
refreshNotes: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default DeviceNotes;
|
||||
15
src/components/DeviceNotes/index.module.scss
Normal file
15
src/components/DeviceNotes/index.module.scss
Normal file
@@ -0,0 +1,15 @@
|
||||
.scrollableBox {
|
||||
height: 200px;
|
||||
border-style: solid;
|
||||
border-color: #ced2d8;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.table {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.spacedRow {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
36
src/components/DeviceStatusCard/MemoryBar.js
Normal file
36
src/components/DeviceStatusCard/MemoryBar.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import { CPopover, CProgress, CProgressBar } from '@coreui/react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { cleanBytesString } from 'utils/helper';
|
||||
|
||||
const MemoryBar = ({ usedBytes, totalBytes }) => {
|
||||
const { t } = useTranslation();
|
||||
const used = cleanBytesString(usedBytes);
|
||||
const total = cleanBytesString(totalBytes);
|
||||
const percentage = Math.floor((usedBytes / totalBytes) * 100);
|
||||
|
||||
return (
|
||||
<CPopover content={t('status.used_total_memory', { used, total })}>
|
||||
<CProgress>
|
||||
<CProgressBar value={percentage}>
|
||||
{percentage >= 25 ? t('status.percentage_used', { percentage, total }) : ''}
|
||||
</CProgressBar>
|
||||
<CProgressBar value={100 - percentage} color="transparent">
|
||||
<div style={{ color: 'black' }}>
|
||||
{percentage < 25
|
||||
? t('status.percentage_free', { percentage: 100 - percentage, total })
|
||||
: ''}
|
||||
</div>
|
||||
</CProgressBar>
|
||||
</CProgress>
|
||||
</CPopover>
|
||||
);
|
||||
};
|
||||
|
||||
MemoryBar.propTypes = {
|
||||
usedBytes: PropTypes.number.isRequired,
|
||||
totalBytes: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
export default React.memo(MemoryBar);
|
||||
197
src/components/DeviceStatusCard/index.js
Normal file
197
src/components/DeviceStatusCard/index.js
Normal file
@@ -0,0 +1,197 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
CCard,
|
||||
CCardHeader,
|
||||
CRow,
|
||||
CCol,
|
||||
CCardBody,
|
||||
CBadge,
|
||||
CModalBody,
|
||||
CAlert,
|
||||
CPopover,
|
||||
CButton,
|
||||
CSpinner,
|
||||
} from '@coreui/react';
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import { cilSync } from '@coreui/icons';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import { prettyDate, secondsToDetailed } from 'utils/helper';
|
||||
import MemoryBar from './MemoryBar';
|
||||
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const DeviceStatusCard = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [lastStats, setLastStats] = useState(null);
|
||||
const [status, setStatus] = useState(null);
|
||||
const [error, setError] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const transformLoad = (load) => {
|
||||
if (load === undefined) return t('common.na');
|
||||
return `${((load / 65536) * 100).toFixed(2)}%`;
|
||||
};
|
||||
|
||||
const getData = () => {
|
||||
setLoading(true);
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
};
|
||||
|
||||
const lastStatsRequest = axiosInstance.get(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(
|
||||
deviceSerialNumber,
|
||||
)}/statistics?lastOnly=true`,
|
||||
options,
|
||||
);
|
||||
const statusRequest = axiosInstance.get(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(deviceSerialNumber)}/status`,
|
||||
options,
|
||||
);
|
||||
|
||||
Promise.all([lastStatsRequest, statusRequest])
|
||||
.then(([newStats, newStatus]) => {
|
||||
setLastStats(newStats.data);
|
||||
setStatus(newStatus.data);
|
||||
})
|
||||
.catch(() => {
|
||||
setError(true);
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setError(false);
|
||||
if (deviceSerialNumber) getData();
|
||||
}, [deviceSerialNumber]);
|
||||
|
||||
if (!error) {
|
||||
return (
|
||||
<CCard>
|
||||
<CCardHeader>
|
||||
<CRow>
|
||||
<CCol>
|
||||
<div className="text-value-lg">
|
||||
{t('status.title', { serialNumber: deviceSerialNumber })}
|
||||
</div>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<div className={styles.alignRight}>
|
||||
<CPopover content={t('common.refresh')}>
|
||||
<CButton color="secondary" onClick={getData} size="sm">
|
||||
<CIcon content={cilSync} />
|
||||
</CButton>
|
||||
</CPopover>
|
||||
</div>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</CCardHeader>
|
||||
<CCardBody>
|
||||
{(!lastStats || !status) && loading ? (
|
||||
<div className={styles.centerContainer}>
|
||||
<CSpinner className={styles.spinner} />
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ position: 'relative' }}>
|
||||
<div className={styles.overlayContainer} hidden={!loading}>
|
||||
<CSpinner className={styles.spinner} />
|
||||
</div>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="5">{t('status.connection_status')} :</CCol>
|
||||
<CCol xs="10" md="7">
|
||||
{status?.connected ? (
|
||||
<CBadge color="success">{t('common.connected')}</CBadge>
|
||||
) : (
|
||||
<CBadge color="danger">{t('common.not_connected')}</CBadge>
|
||||
)}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="5">{t('status.uptime')} :</CCol>
|
||||
<CCol xs="10" md="7">
|
||||
{secondsToDetailed(
|
||||
lastStats?.unit?.uptime,
|
||||
t('common.day'),
|
||||
t('common.days'),
|
||||
t('common.hour'),
|
||||
t('common.hours'),
|
||||
t('common.minute'),
|
||||
t('common.minutes'),
|
||||
t('common.second'),
|
||||
t('common.seconds'),
|
||||
)}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="5">{t('status.last_contact')} :</CCol>
|
||||
<CCol xs="10" md="7">
|
||||
{prettyDate(status?.lastContact)}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="5">{t('status.localtime')} :</CCol>
|
||||
<CCol xs="10" md="7">
|
||||
{prettyDate(lastStats?.unit?.localtime)}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="5">{t('status.load_averages')} :</CCol>
|
||||
<CCol xs="10" md="7">
|
||||
{transformLoad(lastStats?.unit?.load[0])}
|
||||
{' / '}
|
||||
{transformLoad(lastStats?.unit?.load[1])}
|
||||
{' / '}
|
||||
{transformLoad(lastStats?.unit?.load[2])}
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CCol md="5">{t('status.memory')} :</CCol>
|
||||
<CCol xs="9" md="6" style={{ paddingTop: '5px' }}>
|
||||
<MemoryBar
|
||||
usedBytes={
|
||||
lastStats?.unit?.memory?.total && lastStats?.unit?.memory?.free
|
||||
? lastStats?.unit?.memory?.total - lastStats?.unit?.memory?.free
|
||||
: 0
|
||||
}
|
||||
totalBytes={lastStats?.unit?.memory?.total ?? 0}
|
||||
/>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</div>
|
||||
)}
|
||||
</CCardBody>
|
||||
</CCard>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<CCard>
|
||||
<CCardHeader>
|
||||
<CRow>
|
||||
<CCol>
|
||||
<div className="text-value-lg">
|
||||
{t('status.title', { serialNumber: deviceSerialNumber })}
|
||||
</div>
|
||||
</CCol>
|
||||
</CRow>
|
||||
</CCardHeader>
|
||||
<CModalBody>
|
||||
<CAlert hidden={!error} color="danger" className={styles.centerContainer}>
|
||||
{t('status.error')}
|
||||
</CAlert>
|
||||
</CModalBody>
|
||||
</CCard>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(DeviceStatusCard);
|
||||
29
src/components/DeviceStatusCard/index.module.scss
Normal file
29
src/components/DeviceStatusCard/index.module.scss
Normal file
@@ -0,0 +1,29 @@
|
||||
.centerContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.overlayContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.spacedRow {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.alignRight {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
@@ -14,15 +14,17 @@ import {
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import 'react-widgets/styles.css';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const ConfigureModal = ({ show, toggleModal }) => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [hadSuccess, setHadSuccess] = useState(false);
|
||||
const [hadFailure, setHadFailure] = useState(false);
|
||||
const [doingNow, setDoingNow] = useState(false);
|
||||
@@ -30,7 +32,6 @@ const ConfigureModal = ({ show, toggleModal }) => {
|
||||
const [keepRedirector, setKeepRedirector] = useState(true);
|
||||
const [responseBody, setResponseBody] = useState('');
|
||||
const [checkingIfSure, setCheckingIfSure] = useState(false);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
const toggleRedirector = () => {
|
||||
setKeepRedirector(!keepRedirector);
|
||||
@@ -54,17 +55,21 @@ const ConfigureModal = ({ show, toggleModal }) => {
|
||||
setWaiting(true);
|
||||
|
||||
const parameters = {
|
||||
serialNumber: selectedDeviceId,
|
||||
serialNumber: deviceSerialNumber,
|
||||
keepRedirector,
|
||||
};
|
||||
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.post(`/device/${encodeURIComponent(selectedDeviceId)}/factory`, parameters, { headers })
|
||||
.post(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(deviceSerialNumber)}/factory`,
|
||||
parameters,
|
||||
{ headers },
|
||||
)
|
||||
.then(() => {
|
||||
setHadSuccess(true);
|
||||
})
|
||||
|
||||
@@ -3,7 +3,16 @@ import { useTranslation } from 'react-i18next';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CButton, CSpinner, CModalFooter } from '@coreui/react';
|
||||
|
||||
const UpgradeFooter = ({ isNow, isShown, isLoading, action, color, variant, block, toggleParent }) => {
|
||||
const UpgradeFooter = ({
|
||||
isNow,
|
||||
isShown,
|
||||
isLoading,
|
||||
action,
|
||||
color,
|
||||
variant,
|
||||
block,
|
||||
toggleParent,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [askingIfSure, setAskingIfSure] = useState(false);
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@ import { useTranslation } from 'react-i18next';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CModalBody } from '@coreui/react';
|
||||
import { v4 as createUuid } from 'uuid';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
|
||||
const UpgradeWaitingBody = ({ serialNumber }) => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
const [secondsElapsed, setSecondsElapsed] = useState(0);
|
||||
const [labelsToShow, setLabelsToShow] = useState(['upgrade.command_submitted']);
|
||||
@@ -16,12 +17,15 @@ const UpgradeWaitingBody = ({ serialNumber }) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/device/${encodeURIComponent(serialNumber)}/status`, options)
|
||||
.get(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(serialNumber)}/status`,
|
||||
options,
|
||||
)
|
||||
.then((response) => response.data.connected)
|
||||
.catch(() => {});
|
||||
};
|
||||
@@ -30,12 +34,12 @@ const UpgradeWaitingBody = ({ serialNumber }) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/device/${encodeURIComponent(serialNumber)}`, options)
|
||||
.get(`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(serialNumber)}`, options)
|
||||
.then((response) => response.data.firmware)
|
||||
.catch(() => {});
|
||||
};
|
||||
@@ -80,11 +84,11 @@ const UpgradeWaitingBody = ({ serialNumber }) => {
|
||||
<div className="consoleBox">
|
||||
{labelsToShow.map((label) => (
|
||||
<p key={createUuid()}>
|
||||
{new Date().toString()}: {label}
|
||||
{new Date().toString()}:{label}
|
||||
</p>
|
||||
))}
|
||||
<p>
|
||||
{t('common.seconds_elapsed')}: {secondsElapsed}
|
||||
{t('common.seconds_elapsed')}:{secondsElapsed}
|
||||
</p>
|
||||
</div>
|
||||
</CModalBody>
|
||||
|
||||
@@ -15,10 +15,10 @@ import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import DatePicker from 'react-widgets/DatePicker';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { dateToUnix } from 'utils/helper';
|
||||
import 'react-widgets/styles.css';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import eventBus from 'utils/eventBus';
|
||||
import getDeviceConnection from 'utils/deviceHelper';
|
||||
@@ -28,6 +28,8 @@ import UpgradeWaitingBody from './UpgradeWaitingBody';
|
||||
|
||||
const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [isNow, setIsNow] = useState(true);
|
||||
const [waitForUpgrade, setWaitForUpgrade] = useState(false);
|
||||
const [date, setDate] = useState(new Date().toString());
|
||||
@@ -39,14 +41,12 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
const [waitingForUpgrade, setWaitingForUpgrade] = useState(false);
|
||||
const [showWaitingConsole, setShowWaitingConsole] = useState(false);
|
||||
const [deviceConnected, setDeviceConnected] = useState(true);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
const toggleNow = () => {
|
||||
if(isNow){
|
||||
if (isNow) {
|
||||
setWaitForUpgrade(false);
|
||||
setDisableWaiting(true);
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
setDisableWaiting(false);
|
||||
}
|
||||
|
||||
@@ -82,9 +82,13 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
}, [firmware, date]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId !== null && show) {
|
||||
if (deviceSerialNumber !== null && show) {
|
||||
const asyncGet = async () => {
|
||||
const isConnected = await getDeviceConnection(selectedDeviceId);
|
||||
const isConnected = await getDeviceConnection(
|
||||
deviceSerialNumber,
|
||||
currentToken,
|
||||
endpoints.ucentralgw,
|
||||
);
|
||||
setDisableWaiting(!isConnected);
|
||||
setDeviceConnected(isConnected);
|
||||
};
|
||||
@@ -98,24 +102,27 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
setBlockFields(true);
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
serialNumber: selectedDeviceId,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
serialNumber: deviceSerialNumber,
|
||||
};
|
||||
|
||||
const parameters = {
|
||||
serialNumber: selectedDeviceId,
|
||||
serialNumber: deviceSerialNumber,
|
||||
when: isNow ? 0 : dateToUnix(date),
|
||||
uri: firmware,
|
||||
};
|
||||
axiosInstance
|
||||
.post(`/device/${encodeURIComponent(selectedDeviceId)}/upgrade`, parameters, { headers })
|
||||
.post(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(deviceSerialNumber)}/upgrade`,
|
||||
parameters,
|
||||
{ headers },
|
||||
)
|
||||
.then(() => {
|
||||
if (waitForUpgrade) {
|
||||
setShowWaitingConsole(true);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
setBlockFields(false);
|
||||
setWaitingForUpgrade(false);
|
||||
@@ -131,7 +138,7 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
<CModalTitle>{t('upgrade.title')}</CModalTitle>
|
||||
</CModalHeader>
|
||||
<CModalBody>
|
||||
<UpgradeWaitingBody serialNumber={selectedDeviceId} />
|
||||
<UpgradeWaitingBody serialNumber={deviceSerialNumber} />
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<CButton color="secondary" onClick={toggleModal}>
|
||||
@@ -198,7 +205,10 @@ const FirmwareUpgradeModal = ({ show, toggleModal }) => {
|
||||
<CInvalidFeedback>{t('common.need_date')}</CInvalidFeedback>
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow} hidden={true || !isNow || disabledWaiting || !deviceConnected}>
|
||||
<CRow
|
||||
className={styles.spacedRow}
|
||||
hidden={true || !isNow || disabledWaiting || !deviceConnected}
|
||||
>
|
||||
<CCol md="8">
|
||||
<p className={styles.spacedText}>
|
||||
{t('upgrade.wait_for_upgrade')}
|
||||
|
||||
@@ -10,23 +10,29 @@ import {
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const LatestStatisticsModal = ({ show, toggle, serialNumber }) => {
|
||||
const LatestStatisticsModal = ({ show, toggle }) => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [latestStats, setLatestStats] = useState('');
|
||||
|
||||
const getLatestStats = () => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/device/${serialNumber}/statistics?lastOnly=true`, options)
|
||||
.get(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${deviceSerialNumber}/statistics?lastOnly=true`,
|
||||
options,
|
||||
)
|
||||
.then((response) => {
|
||||
setLatestStats(response.data);
|
||||
})
|
||||
@@ -57,7 +63,6 @@ const LatestStatisticsModal = ({ show, toggle, serialNumber }) => {
|
||||
};
|
||||
|
||||
LatestStatisticsModal.propTypes = {
|
||||
serialNumber: PropTypes.string.isRequired,
|
||||
toggle: PropTypes.func.isRequired,
|
||||
show: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import PropTypes from 'prop-types';
|
||||
import { v4 as createUuid } from 'uuid';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import { unixToTime, capitalizeFirstLetter } from 'utils/helper';
|
||||
import eventBus from 'utils/eventBus';
|
||||
import DeviceStatisticsChart from './DeviceStatisticsChart';
|
||||
|
||||
const StatisticsChartList = ({ selectedDeviceId }) => {
|
||||
const StatisticsChartList = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [statOptions, setStatOptions] = useState({
|
||||
interfaceList: [],
|
||||
settings: {},
|
||||
@@ -60,10 +62,10 @@ const StatisticsChartList = ({ selectedDeviceId }) => {
|
||||
// Looping through the interfaces of the log
|
||||
for (const inter of log.data.interfaces) {
|
||||
interfaceList[interfaceTypes[inter.name]][0].data.push(
|
||||
inter.counters?.tx_bytes? Math.floor(inter.counters.tx_bytes / 1024) : 0
|
||||
inter.counters?.tx_bytes ? Math.floor(inter.counters.tx_bytes / 1024) : 0,
|
||||
);
|
||||
interfaceList[interfaceTypes[inter.name]][1].data.push(
|
||||
inter.counters?.rx_bytes? Math.floor(inter.counters.rx_bytes / 1024) : 0
|
||||
inter.counters?.rx_bytes ? Math.floor(inter.counters.rx_bytes / 1024) : 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -74,7 +76,7 @@ const StatisticsChartList = ({ selectedDeviceId }) => {
|
||||
group: 'txrx',
|
||||
},
|
||||
stroke: {
|
||||
curve: 'smooth'
|
||||
curve: 'smooth',
|
||||
},
|
||||
xaxis: {
|
||||
title: {
|
||||
@@ -115,29 +117,32 @@ const StatisticsChartList = ({ selectedDeviceId }) => {
|
||||
};
|
||||
|
||||
const getStatistics = () => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
},
|
||||
params: {
|
||||
serialNumber: '24f5a207a130',
|
||||
},
|
||||
};
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
params: {
|
||||
serialNumber: '24f5a207a130',
|
||||
},
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/device/${selectedDeviceId}/statistics?newest=true&limit=50`, options)
|
||||
.then((response) => {
|
||||
transformIntoDataset(response.data.data);
|
||||
})
|
||||
.catch(() => {});
|
||||
axiosInstance
|
||||
.get(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${deviceSerialNumber}/statistics?newest=true&limit=50`,
|
||||
options,
|
||||
)
|
||||
.then((response) => {
|
||||
transformIntoDataset(response.data.data);
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId) {
|
||||
if (deviceSerialNumber) {
|
||||
getStatistics();
|
||||
}
|
||||
}, [selectedDeviceId]);
|
||||
}, [deviceSerialNumber]);
|
||||
|
||||
useEffect(() => {
|
||||
eventBus.on('refreshInterfaceStatistics', () => getStatistics());
|
||||
@@ -161,11 +166,11 @@ const StatisticsChartList = ({ selectedDeviceId }) => {
|
||||
fontSize: '25px',
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
return (
|
||||
<div key={createUuid()}>
|
||||
<DeviceStatisticsChart chart={ options } />
|
||||
<DeviceStatisticsChart chart={options} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -173,8 +178,4 @@ const StatisticsChartList = ({ selectedDeviceId }) => {
|
||||
);
|
||||
};
|
||||
|
||||
StatisticsChartList.propTypes = {
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default React.memo(StatisticsChartList);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
CDropdown,
|
||||
CDropdownToggle,
|
||||
@@ -19,7 +18,7 @@ import StatisticsChartList from './StatisticsChartList';
|
||||
import LatestStatisticsModal from './LatestStatisticsModal';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const DeviceStatisticsCard = ({ selectedDeviceId }) => {
|
||||
const DeviceStatisticsCard = () => {
|
||||
const { t } = useTranslation();
|
||||
const [showLatestModal, setShowLatestModal] = useState(false);
|
||||
|
||||
@@ -37,7 +36,9 @@ const DeviceStatisticsCard = ({ selectedDeviceId }) => {
|
||||
<CCardHeader>
|
||||
<CRow>
|
||||
<CCol>
|
||||
<div className={["text-value-lg", styles.cardTitle].join(" ")}>{t('statistics.title')}</div>
|
||||
<div className={['text-value-lg', styles.cardTitle].join(' ')}>
|
||||
{t('statistics.title')}
|
||||
</div>
|
||||
</CCol>
|
||||
<CCol className={styles.cardOptions}>
|
||||
<CDropdown className="m-1 btn-group">
|
||||
@@ -55,20 +56,12 @@ const DeviceStatisticsCard = ({ selectedDeviceId }) => {
|
||||
</CRow>
|
||||
</CCardHeader>
|
||||
<CCardBody className={styles.statsBody}>
|
||||
<StatisticsChartList selectedDeviceId={selectedDeviceId} />
|
||||
<StatisticsChartList />
|
||||
</CCardBody>
|
||||
</CCard>
|
||||
<LatestStatisticsModal
|
||||
show={showLatestModal}
|
||||
toggle={toggleLatestModal}
|
||||
serialNumber={selectedDeviceId}
|
||||
/>
|
||||
<LatestStatisticsModal show={showLatestModal} toggle={toggleLatestModal} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
DeviceStatisticsCard.propTypes = {
|
||||
selectedDeviceId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default DeviceStatisticsCard;
|
||||
|
||||
@@ -13,10 +13,10 @@ import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import DatePicker from 'react-widgets/DatePicker';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { dateToUnix } from 'utils/helper';
|
||||
import 'react-widgets/styles.css';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import eventBus from 'utils/eventBus';
|
||||
import LoadingButton from 'components/LoadingButton';
|
||||
@@ -25,15 +25,16 @@ import styles from './index.module.scss';
|
||||
|
||||
const ActionModal = ({ show, toggleModal }) => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [waiting, setWaiting] = useState(false);
|
||||
const [result, setResult] = useState(null);
|
||||
const [chosenDate, setChosenDate] = useState(new Date().toString());
|
||||
const [isNow, setIsNow] = useState(false);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
const toggleNow = () => {
|
||||
setIsNow(!isNow);
|
||||
}
|
||||
};
|
||||
|
||||
const setDate = (date) => {
|
||||
if (date) {
|
||||
@@ -52,21 +53,24 @@ const ActionModal = ({ show, toggleModal }) => {
|
||||
const doAction = () => {
|
||||
setWaiting(true);
|
||||
|
||||
const token = getToken();
|
||||
const utcDate = new Date(chosenDate);
|
||||
|
||||
const parameters = {
|
||||
serialNumber: selectedDeviceId,
|
||||
serialNumber: deviceSerialNumber,
|
||||
when: isNow ? 0 : dateToUnix(utcDate),
|
||||
};
|
||||
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.post(`/device/${encodeURIComponent(selectedDeviceId)}/reboot`, parameters, { headers })
|
||||
.post(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(deviceSerialNumber)}/reboot`,
|
||||
parameters,
|
||||
{ headers },
|
||||
)
|
||||
.then(() => {
|
||||
setResult('success');
|
||||
})
|
||||
@@ -89,10 +93,9 @@ const ActionModal = ({ show, toggleModal }) => {
|
||||
) : (
|
||||
<div>
|
||||
<CModalBody>
|
||||
<h6>{t('reboot.directions')}</h6>
|
||||
<CRow className={styles.spacedRow}>
|
||||
<CRow>
|
||||
<CCol md="8">
|
||||
<p className={styles.spacedText}>{t('common.execute_now')}</p>
|
||||
<p>{t('reboot.now')}</p>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CSwitch
|
||||
@@ -107,7 +110,7 @@ const ActionModal = ({ show, toggleModal }) => {
|
||||
</CRow>
|
||||
<CRow hidden={isNow} className={styles.spacedRow}>
|
||||
<CCol md="4" className={styles.spacedDate}>
|
||||
<p>{t('common.date')}</p>
|
||||
<p>{t('common.custom_date')}:</p>
|
||||
</CCol>
|
||||
<CCol xs="12" md="8">
|
||||
<DatePicker
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
}
|
||||
|
||||
.spacedDate {
|
||||
margin-top: 7px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
@@ -2,13 +2,14 @@ import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CModalBody, CButton, CSpinner, CModalFooter } from '@coreui/react';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const WaitingForTraceBody = ({serialNumber, commandUuid, toggle}) => {
|
||||
const WaitingForTraceBody = ({ serialNumber, commandUuid, toggle }) => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const [secondsElapsed, setSecondsElapsed] = useState(0);
|
||||
const [waitingForFile, setWaitingForFile] = useState(true);
|
||||
|
||||
@@ -16,31 +17,34 @@ const WaitingForTraceBody = ({serialNumber, commandUuid, toggle}) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/command/${encodeURIComponent(commandUuid)}`, options)
|
||||
.get(`${endpoints.ucentralgw}/api/v1/command/${encodeURIComponent(commandUuid)}`, options)
|
||||
.then((response) => {
|
||||
if(response.data.waitingForFile === 0){
|
||||
if (response.data.waitingForFile === 0) {
|
||||
setWaitingForFile(false);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
};
|
||||
|
||||
const downloadTrace = () => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/octet-stream',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
},
|
||||
responseType: 'arraybuffer',
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.get(`/file/${commandUuid}?serialNumber=${serialNumber}`, options)
|
||||
.get(
|
||||
`${endpoints.ucentralgw}/api/v1/file/${commandUuid}?serialNumber=${serialNumber}`,
|
||||
options,
|
||||
)
|
||||
.then((response) => {
|
||||
const blob = new Blob([response.data], { type: 'application/octet-stream' });
|
||||
const link = document.createElement('a');
|
||||
@@ -48,49 +52,48 @@ const WaitingForTraceBody = ({serialNumber, commandUuid, toggle}) => {
|
||||
link.download = `Trace_${commandUuid}.pcap`;
|
||||
link.click();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setSecondsElapsed(secondsElapsed + 1);
|
||||
}, 1000);
|
||||
if(!waitingForFile){
|
||||
if (!waitingForFile) {
|
||||
clearInterval(timer);
|
||||
}
|
||||
return () => {
|
||||
clearInterval(timer);
|
||||
}
|
||||
};
|
||||
}, [waitingForFile, secondsElapsed]);
|
||||
|
||||
useEffect(() => {
|
||||
const refreshStatus = setInterval(() => {
|
||||
getTraceResult();
|
||||
}, 5000);
|
||||
if(!waitingForFile){
|
||||
if (!waitingForFile) {
|
||||
clearInterval(refreshStatus);
|
||||
}
|
||||
return () => {
|
||||
clearInterval(refreshStatus);
|
||||
}
|
||||
};
|
||||
}, [waitingForFile]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<CModalBody>
|
||||
<h6>{t('trace.waiting_seconds', {seconds: secondsElapsed})}</h6>
|
||||
<h6>{t('trace.waiting_seconds', { seconds: secondsElapsed })}</h6>
|
||||
<p>{t('trace.waiting_directions')}</p>
|
||||
<div className={styles.centerDiv}>
|
||||
<CSpinner hidden={!waitingForFile} />
|
||||
<CButton
|
||||
hidden={waitingForFile}
|
||||
onClick={downloadTrace}
|
||||
disabled={waitingForFile}
|
||||
color="primary"
|
||||
>
|
||||
{t('trace.download_trace')}
|
||||
</CButton>
|
||||
</div>
|
||||
<CButton
|
||||
hidden={waitingForFile}
|
||||
onClick={downloadTrace}
|
||||
disabled={waitingForFile}
|
||||
color="link"
|
||||
block
|
||||
>
|
||||
{t('trace.download_trace')}
|
||||
</CButton>
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<CButton color="secondary" block onClick={toggle}>
|
||||
@@ -98,14 +101,13 @@ const WaitingForTraceBody = ({serialNumber, commandUuid, toggle}) => {
|
||||
</CButton>
|
||||
</CModalFooter>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
WaitingForTraceBody.propTypes = {
|
||||
serialNumber: PropTypes.string.isRequired,
|
||||
commandUuid: PropTypes.string.isRequired,
|
||||
toggle: PropTypes.func.isRequired
|
||||
toggle: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default WaitingForTraceBody;
|
||||
|
||||
@@ -17,9 +17,9 @@ import {
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import 'react-widgets/styles.css';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import eventBus from 'utils/eventBus';
|
||||
import getDeviceConnection from 'utils/deviceHelper';
|
||||
@@ -30,6 +30,8 @@ import styles from './index.module.scss';
|
||||
|
||||
const TraceModal = ({ show, toggleModal }) => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [hadSuccess, setHadSuccess] = useState(false);
|
||||
const [hadFailure, setHadFailure] = useState(false);
|
||||
const [blockFields, setBlockFields] = useState(false);
|
||||
@@ -43,11 +45,9 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
const [waitingForTrace, setWaitingForTrace] = useState(false);
|
||||
const [commandUuid, setCommandUuid] = useState(null);
|
||||
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
const toggleWaitForTrace = () => {
|
||||
setWaitForTrace(!waitForTrace);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setWaitForTrace(false);
|
||||
@@ -65,10 +65,8 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
setHadFailure(false);
|
||||
setHadSuccess(false);
|
||||
|
||||
const token = getToken();
|
||||
|
||||
const parameters = {
|
||||
serialNumber: selectedDeviceId,
|
||||
serialNumber: deviceSerialNumber,
|
||||
when: 0,
|
||||
network: chosenInterface,
|
||||
};
|
||||
@@ -81,14 +79,18 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.post(`/device/${encodeURIComponent(selectedDeviceId)}/trace`, parameters, { headers })
|
||||
.post(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(deviceSerialNumber)}/trace`,
|
||||
parameters,
|
||||
{ headers },
|
||||
)
|
||||
.then((response) => {
|
||||
setHadSuccess(true);
|
||||
if(waitForTrace) {
|
||||
if (waitForTrace) {
|
||||
setCommandUuid(response.data.UUID);
|
||||
setWaitingForTrace(true);
|
||||
}
|
||||
@@ -105,26 +107,31 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDeviceId !== null && show) {
|
||||
if (deviceSerialNumber !== null && show) {
|
||||
const asyncGet = async () => {
|
||||
const isConnected = await getDeviceConnection(selectedDeviceId);
|
||||
const isConnected = await getDeviceConnection(
|
||||
deviceSerialNumber,
|
||||
currentToken,
|
||||
endpoints.ucentralgw,
|
||||
);
|
||||
setIsDeviceConnected(isConnected);
|
||||
};
|
||||
asyncGet();
|
||||
}
|
||||
}, [show]);
|
||||
|
||||
|
||||
const getBody = () => {
|
||||
if(waitingForTrace){
|
||||
if (waitingForTrace) {
|
||||
return (
|
||||
<WaitingForTraceBody toggle={toggleModal} serialNumber={selectedDeviceId} commandUuid={commandUuid}/>
|
||||
<WaitingForTraceBody
|
||||
toggle={toggleModal}
|
||||
serialNumber={deviceSerialNumber}
|
||||
commandUuid={commandUuid}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if(hadSuccess){
|
||||
return(
|
||||
<SuccessfulActionModalBody toggleModal={toggleModal} />
|
||||
);
|
||||
if (hadSuccess) {
|
||||
return <SuccessfulActionModalBody toggleModal={toggleModal} />;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
@@ -158,34 +165,28 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
</CCol>
|
||||
<CCol xs="12" md="8">
|
||||
{usingDuration ? (
|
||||
<CSelect defaultValue="duration" disabled={blockFields}>
|
||||
<option value="20" onClick={() => setDuration(20)}>
|
||||
20s
|
||||
</option>
|
||||
<option value="40" onClick={() => setDuration(40)}>
|
||||
40s
|
||||
</option>
|
||||
<option value="60" onClick={() => setDuration(60)}>
|
||||
60s
|
||||
</option>
|
||||
<option value="120" onClick={() => setDuration(120)}>
|
||||
120s
|
||||
</option>
|
||||
<CSelect
|
||||
custom
|
||||
defaultValue={duration}
|
||||
disabled={blockFields}
|
||||
onChange={(e) => setDuration(e.target.value)}
|
||||
>
|
||||
<option value="20">20s</option>
|
||||
<option value="40">40s</option>
|
||||
<option value="60">60s</option>
|
||||
<option value="120">120s</option>
|
||||
</CSelect>
|
||||
) : (
|
||||
<CSelect defaultValue={packets} disabled={blockFields}>
|
||||
<option value="100" onClick={() => setPackets(100)}>
|
||||
100
|
||||
</option>
|
||||
<option value="250" onClick={() => setPackets(250)}>
|
||||
250
|
||||
</option>
|
||||
<option value="500" onClick={() => setPackets(500)}>
|
||||
500
|
||||
</option>
|
||||
<option value="1000" onClick={() => setPackets(1000)}>
|
||||
1000
|
||||
</option>
|
||||
<CSelect
|
||||
custom
|
||||
defaultValue={packets}
|
||||
disabled={blockFields}
|
||||
onChange={(e) => setPackets(e.target.value)}
|
||||
>
|
||||
<option value="100">100</option>
|
||||
<option value="250">250</option>
|
||||
<option value="500">500</option>
|
||||
<option value="1000">1000</option>
|
||||
</CSelect>
|
||||
)}
|
||||
</CCol>
|
||||
@@ -221,9 +222,7 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
</CRow>
|
||||
<CRow className={styles.spacedRow} hidden={!isDeviceConnected}>
|
||||
<CCol md="8">
|
||||
<p className={styles.spacedText}>
|
||||
{t('trace.wait_for_file')}
|
||||
</p>
|
||||
<p className={styles.spacedText}>{t('trace.wait_for_file')}</p>
|
||||
</CCol>
|
||||
<CCol>
|
||||
<CSwitch
|
||||
@@ -257,7 +256,7 @@ const TraceModal = ({ show, toggleModal }) => {
|
||||
</CModalFooter>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<CModal show={show} onClose={toggleModal}>
|
||||
|
||||
@@ -9,13 +9,13 @@ import {
|
||||
CForm,
|
||||
CSwitch,
|
||||
CCol,
|
||||
CSpinner
|
||||
CSpinner,
|
||||
} from '@coreui/react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { useDevice } from 'contexts/DeviceProvider';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import eventBus from 'utils/eventBus';
|
||||
import LoadingButton from 'components/LoadingButton';
|
||||
@@ -25,6 +25,8 @@ import styles from './index.module.scss';
|
||||
|
||||
const WifiScanModal = ({ show, toggleModal }) => {
|
||||
const { t } = useTranslation();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const { deviceSerialNumber } = useDevice();
|
||||
const [hadSuccess, setHadSuccess] = useState(false);
|
||||
const [hadFailure, setHadFailure] = useState(false);
|
||||
const [waiting, setWaiting] = useState(false);
|
||||
@@ -32,7 +34,6 @@ const WifiScanModal = ({ show, toggleModal }) => {
|
||||
const [activeScan, setActiveScan] = useState(false);
|
||||
const [hideOptions, setHideOptions] = useState(false);
|
||||
const [channelList, setChannelList] = useState([]);
|
||||
const selectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
const toggleVerbose = () => {
|
||||
setVerbose(!choseVerbose);
|
||||
@@ -88,20 +89,22 @@ const WifiScanModal = ({ show, toggleModal }) => {
|
||||
setHadSuccess(false);
|
||||
setWaiting(true);
|
||||
|
||||
const token = getToken();
|
||||
|
||||
const parameters = {
|
||||
serialNumber: selectedDeviceId,
|
||||
serialNumber: deviceSerialNumber,
|
||||
verbose: choseVerbose,
|
||||
activeScan,
|
||||
};
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
Authorization: `Bearer ${currentToken}`,
|
||||
};
|
||||
|
||||
axiosInstance
|
||||
.post(`/device/${encodeURIComponent(selectedDeviceId)}/wifiscan`, parameters, { headers })
|
||||
.post(
|
||||
`${endpoints.ucentralgw}/api/v1/device/${encodeURIComponent(deviceSerialNumber)}/wifiscan`,
|
||||
parameters,
|
||||
{ headers },
|
||||
)
|
||||
.then((response) => {
|
||||
const scanList = response?.data?.results?.status?.scan;
|
||||
|
||||
@@ -186,7 +189,7 @@ const WifiScanModal = ({ show, toggleModal }) => {
|
||||
</CModalBody>
|
||||
<CModalFooter>
|
||||
<LoadingButton
|
||||
label={(!hadSuccess && !hadFailure) ? t('scan.scan') : t('scan.re_scan')}
|
||||
label={!hadSuccess && !hadFailure ? t('scan.scan') : t('scan.re_scan')}
|
||||
isLoadingLabel={t('scan.scanning')}
|
||||
isLoading={waiting}
|
||||
action={doAction}
|
||||
@@ -195,7 +198,7 @@ const WifiScanModal = ({ show, toggleModal }) => {
|
||||
disabled={waiting}
|
||||
/>
|
||||
<CButton color="secondary" onClick={toggleModal}>
|
||||
{(!hadSuccess && !hadFailure) ? t('common.cancel') : t('common.exit')}
|
||||
{!hadSuccess && !hadFailure ? t('common.cancel') : t('common.exit')}
|
||||
</CButton>
|
||||
</CModalFooter>
|
||||
</CModal>
|
||||
|
||||
27
src/contexts/AuthProvider/index.js
Normal file
27
src/contexts/AuthProvider/index.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const AuthContext = React.createContext();
|
||||
|
||||
export const AuthProvider = ({ token, apiEndpoints, children }) => {
|
||||
const [currentToken, setCurrentToken] = useState(token);
|
||||
const [endpoints, setEndpoints] = useState(apiEndpoints);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ currentToken, setCurrentToken, endpoints, setEndpoints }}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
AuthProvider.propTypes = {
|
||||
token: PropTypes.string.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
apiEndpoints: PropTypes.instanceOf(Object),
|
||||
};
|
||||
|
||||
AuthProvider.defaultProps = {
|
||||
apiEndpoints: {},
|
||||
};
|
||||
|
||||
export const useAuth = () => React.useContext(AuthContext);
|
||||
21
src/contexts/DeviceProvider/index.js
Normal file
21
src/contexts/DeviceProvider/index.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const DeviceContext = React.createContext();
|
||||
|
||||
export const DeviceProvider = ({ serialNumber, children }) => {
|
||||
const [deviceSerialNumber, setDeviceSerialNumber] = useState(serialNumber);
|
||||
|
||||
return (
|
||||
<DeviceContext.Provider value={{ deviceSerialNumber, setDeviceSerialNumber }}>
|
||||
{children}
|
||||
</DeviceContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
DeviceProvider.propTypes = {
|
||||
serialNumber: PropTypes.string.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export const useDevice = () => React.useContext(DeviceContext);
|
||||
@@ -1,19 +1,17 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import 'index.css';
|
||||
import { Provider } from 'react-redux';
|
||||
import App from 'App';
|
||||
import store from 'store';
|
||||
import { icons } from 'assets/icons';
|
||||
import '@babel/polyfill';
|
||||
import 'i18n';
|
||||
|
||||
React.icons = icons;
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root'),
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ const TheFooter = () => (
|
||||
<Translation>
|
||||
{(t) => (
|
||||
<CFooter fixed={false}>
|
||||
<div>{t('footer.version')} 0.9.5</div>
|
||||
<div>{t('footer.version')} 0.9.13</div>
|
||||
<div className="mfs-auto">
|
||||
<span className="mr-1">{t('footer.powered_by')}</span>
|
||||
<a href="https://coreui.io/react" target="_blank" rel="noopener noreferrer">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
CHeader,
|
||||
@@ -11,26 +10,27 @@ import {
|
||||
CLink,
|
||||
CPopover,
|
||||
} from '@coreui/react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import { cilAccountLogout } from '@coreui/icons';
|
||||
import { logout } from 'utils/authHelper';
|
||||
import routes from 'routes';
|
||||
import LanguageSwitcher from 'components/LanguageSwitcher';
|
||||
import { LanguageSwitcher } from 'ucentral-libs';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
|
||||
const TheHeader = () => {
|
||||
const TheHeader = ({ showSidebar, setShowSidebar }) => {
|
||||
const { t, i18n } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const [translatedRoutes, setTranslatedRoutes] = useState(routes);
|
||||
const sidebarShow = useSelector((state) => state.sidebarShow);
|
||||
|
||||
const toggleSidebar = () => {
|
||||
const val = [true, 'responsive'].includes(sidebarShow) ? false : 'responsive';
|
||||
dispatch({ type: 'set', sidebarShow: val });
|
||||
const val = [true, 'responsive'].includes(showSidebar) ? false : 'responsive';
|
||||
setShowSidebar(val);
|
||||
};
|
||||
|
||||
const toggleSidebarMobile = () => {
|
||||
const val = [false, 'responsive'].includes(sidebarShow) ? true : 'responsive';
|
||||
dispatch({ type: 'set', sidebarShow: val });
|
||||
const val = [false, 'responsive'].includes(showSidebar) ? true : 'responsive';
|
||||
setShowSidebar(val);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -48,13 +48,18 @@ const TheHeader = () => {
|
||||
<CHeaderNav className="d-md-down-none mr-auto" />
|
||||
|
||||
<CHeaderNav className="px-3">
|
||||
<LanguageSwitcher />
|
||||
<LanguageSwitcher i18n={i18n} />
|
||||
</CHeaderNav>
|
||||
|
||||
<CHeaderNav className="px-3">
|
||||
<CPopover content={t('common.logout')}>
|
||||
<CLink className="c-subheader-nav-link">
|
||||
<CIcon name="cilAccountLogout" content={cilAccountLogout} size="2xl" onClick={logout} />
|
||||
<CIcon
|
||||
name="cilAccountLogout"
|
||||
content={cilAccountLogout}
|
||||
size="2xl"
|
||||
onClick={() => logout(currentToken, endpoints.ucentralsec)}
|
||||
/>
|
||||
</CLink>
|
||||
</CPopover>
|
||||
</CHeaderNav>
|
||||
@@ -69,4 +74,9 @@ const TheHeader = () => {
|
||||
);
|
||||
};
|
||||
|
||||
TheHeader.propTypes = {
|
||||
showSidebar: PropTypes.string.isRequired,
|
||||
setShowSidebar: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default TheHeader;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import {
|
||||
CCreateElement,
|
||||
CSidebar,
|
||||
@@ -11,14 +10,12 @@ import {
|
||||
CSidebarNavDropdown,
|
||||
CSidebarNavItem,
|
||||
} from '@coreui/react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import logoBar from 'assets/OpenWiFi_LogoLockup_WhiteColour.svg';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const TheSidebar = () => {
|
||||
const TheSidebar = ({ showSidebar, setShowSidebar }) => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const show = useSelector((state) => state.sidebarShow);
|
||||
|
||||
const navigation = [
|
||||
{
|
||||
@@ -30,16 +27,16 @@ const TheSidebar = () => {
|
||||
];
|
||||
|
||||
return (
|
||||
<CSidebar show={show} onShowChange={(val) => dispatch({ type: 'set', sidebarShow: val })}>
|
||||
<CSidebar show={showSidebar} onShowChange={(val) => setShowSidebar(val)}>
|
||||
<CSidebarBrand className="d-md-down-none" to="/devices">
|
||||
<img
|
||||
className={[styles.sidebarImgFull, 'c-sidebar-brand-full'].join(' ')}
|
||||
src={logoBar}
|
||||
src="assets/OpenWiFi_LogoLockup_WhiteColour.svg"
|
||||
alt="OpenWifi"
|
||||
/>
|
||||
<img
|
||||
className={[styles.sidebarImgMinimized, 'c-sidebar-brand-minimized'].join(' ')}
|
||||
src={logoBar}
|
||||
src="assets/OpenWiFi_LogoLockup_WhiteColour.svg"
|
||||
alt="OpenWifi"
|
||||
/>
|
||||
</CSidebarBrand>
|
||||
@@ -59,4 +56,9 @@ const TheSidebar = () => {
|
||||
);
|
||||
};
|
||||
|
||||
TheSidebar.propTypes = {
|
||||
showSidebar: PropTypes.string.isRequired,
|
||||
setShowSidebar: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default React.memo(TheSidebar);
|
||||
|
||||
@@ -1,21 +1,37 @@
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { logout } from 'utils/authHelper';
|
||||
import routes from 'routes';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { Header } from 'ucentral-libs';
|
||||
import Sidebar from './Sidebar';
|
||||
import TheContent from './Content';
|
||||
import TheSidebar from './Sidebar';
|
||||
import TheFooter from './Footer';
|
||||
import TheHeader from './Header';
|
||||
|
||||
const TheLayout = (props) => {
|
||||
const { isLoggedIn } = useSelector((state) => state.connected);
|
||||
if (isLoggedIn) {
|
||||
return <div>{props.children}</div>;
|
||||
}
|
||||
const TheLayout = () => {
|
||||
const [showSidebar, setShowSidebar] = useState('responsive');
|
||||
const { endpoints, currentToken } = useAuth();
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="c-app c-default-layout">
|
||||
<TheSidebar />
|
||||
<Sidebar
|
||||
showSidebar={showSidebar}
|
||||
setShowSidebar={setShowSidebar}
|
||||
t={t}
|
||||
logo="assets/OpenWiFi_LogoLockup_DarkGreyColour.svg"
|
||||
/>
|
||||
<div className="c-wrapper">
|
||||
<TheHeader />
|
||||
<Header
|
||||
showSidebar={showSidebar}
|
||||
setShowSidebar={setShowSidebar}
|
||||
routes={routes}
|
||||
t={t}
|
||||
i18n={i18n}
|
||||
logout={logout}
|
||||
authToken={currentToken}
|
||||
endpoints={endpoints}
|
||||
/>
|
||||
<div className="c-body">
|
||||
<TheContent />
|
||||
</div>
|
||||
@@ -25,12 +41,4 @@ const TheLayout = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
TheLayout.propTypes = {
|
||||
children: PropTypes.instanceOf(Object),
|
||||
};
|
||||
|
||||
TheLayout.defaultProps = {
|
||||
children: {},
|
||||
};
|
||||
|
||||
export default TheLayout;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import React from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { CRow, CCol } from '@coreui/react';
|
||||
import DeviceHealth from 'components/DeviceHealth';
|
||||
@@ -7,40 +6,35 @@ import DeviceConfiguration from 'components/DeviceConfiguration';
|
||||
import CommandHistory from 'components/CommandHistory';
|
||||
import DeviceLogs from 'components/DeviceLogs';
|
||||
import DeviceStatisticsCard from 'components/InterfaceStatistics';
|
||||
import DeviceActionCard from '../../components/DeviceActionCard';
|
||||
import DeviceActionCard from 'components/DeviceActionCard';
|
||||
import DeviceStatusCard from 'components/DeviceStatusCard';
|
||||
import { DeviceProvider } from 'contexts/DeviceProvider';
|
||||
|
||||
const DevicePage = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { deviceId } = useParams();
|
||||
const previouslySelectedDeviceId = useSelector((state) => state.selectedDeviceId);
|
||||
|
||||
useEffect(() => {
|
||||
if (deviceId && deviceId !== previouslySelectedDeviceId)
|
||||
dispatch({ type: 'set', selectedDeviceId: deviceId });
|
||||
}, [deviceId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="App">
|
||||
<div className="App">
|
||||
<DeviceProvider serialNumber={deviceId}>
|
||||
<CRow>
|
||||
<CCol xs="12" sm="6">
|
||||
<DeviceConfiguration selectedDeviceId={deviceId} />
|
||||
<DeviceStatusCard />
|
||||
<DeviceConfiguration />
|
||||
</CCol>
|
||||
<CCol xs="12" sm="6">
|
||||
<DeviceLogs selectedDeviceId={deviceId} />
|
||||
<DeviceHealth selectedDeviceId={deviceId} />
|
||||
<DeviceActionCard selectedDeviceId={deviceId} />
|
||||
<DeviceLogs />
|
||||
<DeviceHealth />
|
||||
<DeviceActionCard />
|
||||
</CCol>
|
||||
</CRow>
|
||||
<CRow>
|
||||
<CCol>
|
||||
<DeviceStatisticsCard selectedDeviceId={deviceId} />
|
||||
<CommandHistory selectedDeviceId={deviceId} />
|
||||
<DeviceStatisticsCard />
|
||||
<CommandHistory />
|
||||
</CCol>
|
||||
</CRow>
|
||||
</div>
|
||||
</>
|
||||
</DeviceProvider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -18,26 +18,25 @@ import {
|
||||
CInvalidFeedback,
|
||||
} from '@coreui/react';
|
||||
import CIcon from '@coreui/icons-react';
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { cilUser, cilLockLocked, cilLink } from '@coreui/icons';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
import logo from 'assets/OpenWiFi_LogoLockup_DarkGreyColour.svg';
|
||||
import LanguageSwitcher from 'components/LanguageSwitcher';
|
||||
import { LanguageSwitcher } from 'ucentral-libs';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const Login = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const { t, i18n } = useTranslation();
|
||||
const { setCurrentToken, setEndpoints } = useAuth();
|
||||
const [userId, setUsername] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [gatewayUrl, setGatewayUrl] = useState('');
|
||||
const [uCentralSecUrl, setUCentralSecUrl] = useState('');
|
||||
const [hadError, setHadError] = useState(false);
|
||||
const [emptyUsername, setEmptyUsername] = useState(false);
|
||||
const [emptyPassword, setEmptyPassword] = useState(false);
|
||||
const [emptyGateway, setEmptyGateway] = useState(false);
|
||||
const [defaultConfig, setDefaultConfig] = useState({
|
||||
DEFAULT_GATEWAY_URL: '',
|
||||
ALLOW_GATEWAY_CHANGE: true,
|
||||
DEFAULT_UCENTRALSEC_URL: '',
|
||||
ALLOW_UCENTRALSEC_CHANGE: true,
|
||||
});
|
||||
const placeholderUrl = 'Gateway URL (ex: https://your-url:port)';
|
||||
|
||||
@@ -70,7 +69,7 @@ const Login = () => {
|
||||
isSuccessful = false;
|
||||
}
|
||||
|
||||
if (gatewayUrl.trim() === '') {
|
||||
if (uCentralSecUrl.trim() === '') {
|
||||
setEmptyGateway(true);
|
||||
isSuccessful = false;
|
||||
}
|
||||
@@ -78,16 +77,33 @@ const Login = () => {
|
||||
};
|
||||
|
||||
const SignIn = (credentials) => {
|
||||
const gatewayUrlToUse = defaultConfig.ALLOW_GATEWAY_CHANGE
|
||||
? gatewayUrl
|
||||
: defaultConfig.DEFAULT_GATEWAY_URL;
|
||||
let token = '';
|
||||
const finalUCentralSecUrl = defaultConfig.ALLOW_UCENTRALSEC_CHANGE
|
||||
? uCentralSecUrl
|
||||
: defaultConfig.DEFAULT_UCENTRALSEC_URL;
|
||||
|
||||
axiosInstance
|
||||
.post(`${gatewayUrlToUse}/api/v1/oauth2`, credentials)
|
||||
.post(`${finalUCentralSecUrl}/api/v1/oauth2`, credentials)
|
||||
.then((response) => {
|
||||
sessionStorage.setItem('gw_url', `${gatewayUrlToUse}/api/v1`);
|
||||
sessionStorage.setItem('access_token', response.data.access_token);
|
||||
dispatch({ type: 'set', connected: true });
|
||||
token = response.data.access_token;
|
||||
return axiosInstance.get(`${finalUCentralSecUrl}/api/v1/systemEndpoints`, {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${response.data.access_token}`,
|
||||
},
|
||||
});
|
||||
})
|
||||
.then((response) => {
|
||||
const endpoints = {
|
||||
ucentralsec: finalUCentralSecUrl,
|
||||
};
|
||||
for (const endpoint of response.data.endpoints) {
|
||||
endpoints[endpoint.type] = endpoint.uri;
|
||||
}
|
||||
sessionStorage.setItem('gateway_endpoints', JSON.stringify(endpoints));
|
||||
setEndpoints(endpoints);
|
||||
setCurrentToken(token);
|
||||
})
|
||||
.catch(() => {
|
||||
setHadError(true);
|
||||
@@ -108,12 +124,12 @@ const Login = () => {
|
||||
}, [password]);
|
||||
useEffect(() => {
|
||||
if (emptyGateway) setEmptyGateway(false);
|
||||
}, [gatewayUrl]);
|
||||
}, [uCentralSecUrl]);
|
||||
useEffect(() => {
|
||||
getDefaultConfig();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
setGatewayUrl(defaultConfig.DEFAULT_GATEWAY_URL);
|
||||
setUCentralSecUrl(defaultConfig.DEFAULT_UCENTRALSEC_URL);
|
||||
}, [defaultConfig]);
|
||||
|
||||
return (
|
||||
@@ -123,7 +139,7 @@ const Login = () => {
|
||||
<CCol md="8">
|
||||
<img
|
||||
className={[styles.logo, 'c-sidebar-brand-full'].join(' ')}
|
||||
src={logo}
|
||||
src="assets/OpenWiFi_LogoLockup_DarkGreyColour.svg"
|
||||
alt="OpenWifi"
|
||||
/>
|
||||
<CCardGroup>
|
||||
@@ -133,7 +149,7 @@ const Login = () => {
|
||||
<h1>{t('login.login')}</h1>
|
||||
<p className="text-muted">{t('login.sign_in_to_account')}</p>
|
||||
<CInputGroup className="mb-3">
|
||||
<CPopover content="Username">
|
||||
<CPopover content={t('login.username')}>
|
||||
<CInputGroupPrepend>
|
||||
<CInputGroupText>
|
||||
<CIcon name="cilUser" content={cilUser} />
|
||||
@@ -154,7 +170,7 @@ const Login = () => {
|
||||
</CInvalidFeedback>
|
||||
</CInputGroup>
|
||||
<CInputGroup className="mb-4">
|
||||
<CPopover content="Password">
|
||||
<CPopover content={t('login.password')}>
|
||||
<CInputGroupPrepend>
|
||||
<CInputGroupText>
|
||||
<CIcon content={cilLockLocked} />
|
||||
@@ -173,8 +189,8 @@ const Login = () => {
|
||||
{t('login.please_enter_password')}
|
||||
</CInvalidFeedback>
|
||||
</CInputGroup>
|
||||
<CInputGroup className="mb-4" hidden={!defaultConfig.ALLOW_GATEWAY_CHANGE}>
|
||||
<CPopover content="Gateway URL">
|
||||
<CInputGroup className="mb-4" hidden={!defaultConfig.ALLOW_UCENTRALSEC_CHANGE}>
|
||||
<CPopover content={t('login.url')}>
|
||||
<CInputGroupPrepend>
|
||||
<CInputGroupText>
|
||||
<CIcon name="cilLink" content={cilLink} />
|
||||
@@ -186,9 +202,9 @@ const Login = () => {
|
||||
type="text"
|
||||
required
|
||||
placeholder={placeholderUrl}
|
||||
value={gatewayUrl}
|
||||
value={uCentralSecUrl}
|
||||
autoComplete="gateway-url"
|
||||
onChange={(event) => setGatewayUrl(event.target.value)}
|
||||
onChange={(event) => setUCentralSecUrl(event.target.value)}
|
||||
/>
|
||||
<CInvalidFeedback className="help-block">
|
||||
{t('login.please_enter_gateway')}
|
||||
@@ -213,7 +229,7 @@ const Login = () => {
|
||||
</CCol>
|
||||
<CCol xs="6">
|
||||
<div className={styles.languageSwitcher}>
|
||||
<LanguageSwitcher />
|
||||
<LanguageSwitcher i18n={i18n} />
|
||||
</div>
|
||||
</CCol>
|
||||
</CRow>
|
||||
|
||||
26
src/router/index.js
Normal file
26
src/router/index.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useAuth } from 'contexts/AuthProvider';
|
||||
import { Route } from 'react-router-dom';
|
||||
import React from 'react';
|
||||
|
||||
const TheLayout = React.lazy(() => import('layout'));
|
||||
const Login = React.lazy(() => import('pages/LoginPage'));
|
||||
|
||||
const Routes = () => {
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
|
||||
return (
|
||||
<Route
|
||||
path="/"
|
||||
name="Devices"
|
||||
render={(props) =>
|
||||
currentToken !== '' && Object.keys(endpoints).length !== 0 ? (
|
||||
<TheLayout {...props} />
|
||||
) : (
|
||||
<Login {...props} />
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Routes;
|
||||
@@ -3,9 +3,7 @@ import React from 'react';
|
||||
const DevicePage = React.lazy(() => import('pages/DevicePage'));
|
||||
const DeviceListPage = React.lazy(() => import('pages/DeviceListPage'));
|
||||
|
||||
const routes = [
|
||||
export default [
|
||||
{ path: '/devices', exact: true, name: 'common.devices', component: DeviceListPage },
|
||||
{ path: '/devices/:deviceId', name: 'common.device_page', component: DevicePage },
|
||||
];
|
||||
|
||||
export default routes;
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
pre.ignore {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.custom-select {
|
||||
appearance: none;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
19
src/store.js
19
src/store.js
@@ -1,19 +0,0 @@
|
||||
import { createStore } from 'redux';
|
||||
|
||||
const initialState = {
|
||||
sidebarShow: 'responsive',
|
||||
connected: false,
|
||||
selectedDeviceId: null,
|
||||
};
|
||||
|
||||
const changeState = (state = initialState, { type, ...rest }) => {
|
||||
switch (type) {
|
||||
case 'set':
|
||||
return { ...state, ...rest };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const store = createStore(changeState);
|
||||
export default store;
|
||||
@@ -1,6 +1,19 @@
|
||||
export const logout = () => {
|
||||
sessionStorage.clear();
|
||||
window.location.replace('/');
|
||||
import axiosInstance from './axiosInstance';
|
||||
|
||||
export const logout = (token, endpoint) => {
|
||||
axiosInstance
|
||||
.delete(`${endpoint}/api/v1/oauth2/${token}`, {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
})
|
||||
.then(() => {})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
sessionStorage.clear();
|
||||
window.location.replace('/');
|
||||
});
|
||||
};
|
||||
|
||||
export const getToken = () => {
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import * as axios from 'axios';
|
||||
import axiosRetry from 'axios-retry';
|
||||
import http from 'http';
|
||||
import https from 'https';
|
||||
|
||||
const httpAgent = new http.Agent({ keepAlive: true });
|
||||
const httpsAgent = new https.Agent({ keepAlive: true });
|
||||
const axiosInstance = axios.create(httpAgent, httpsAgent);
|
||||
const axiosInstance = axios.create();
|
||||
|
||||
axiosRetry(axiosInstance, {
|
||||
retries: 3,
|
||||
@@ -16,15 +12,6 @@ axiosInstance.defaults.timeout = 30000;
|
||||
axiosInstance.defaults.headers.get.Accept = 'application/json';
|
||||
axiosInstance.defaults.headers.post.Accept = 'application/json';
|
||||
|
||||
axiosInstance.interceptors.request.use((config) => {
|
||||
const newConfig = config;
|
||||
const url = sessionStorage.getItem('gw_url');
|
||||
if (url !== undefined && url !== null && !newConfig.url.includes(url)) {
|
||||
newConfig.url = url + newConfig.url;
|
||||
}
|
||||
return newConfig;
|
||||
});
|
||||
|
||||
axiosInstance.interceptors.response.use(
|
||||
// Success actions
|
||||
undefined,
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import { getToken } from 'utils/authHelper';
|
||||
import axiosInstance from 'utils/axiosInstance';
|
||||
|
||||
export default async (deviceId) => {
|
||||
export default async (deviceId, token, endpoint) => {
|
||||
const options = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
};
|
||||
|
||||
return axiosInstance
|
||||
.get(`/device/${encodeURIComponent(deviceId)}/status`, options)
|
||||
.get(`${endpoint}/api/v1/device/${encodeURIComponent(deviceId)}/status`, options)
|
||||
.then((response) => response.data.connected)
|
||||
.catch(() => false);
|
||||
};
|
||||
|
||||
@@ -66,3 +66,47 @@ export const checkIfJson = (string) => {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export const secondsToDetailed = (
|
||||
seconds,
|
||||
dayLabel,
|
||||
daysLabel,
|
||||
hourLabel,
|
||||
hoursLabel,
|
||||
minuteLabel,
|
||||
minutesLabel,
|
||||
secondLabel,
|
||||
secondsLabel,
|
||||
) => {
|
||||
if (!seconds || seconds === 0) return `0 ${secondsLabel}`;
|
||||
let secondsLeft = seconds;
|
||||
const days = Math.floor(secondsLeft / (3600 * 24));
|
||||
secondsLeft -= days * (3600 * 24);
|
||||
const hours = Math.floor(secondsLeft / 3600);
|
||||
secondsLeft -= hours * 3600;
|
||||
const minutes = Math.floor(secondsLeft / 60);
|
||||
secondsLeft -= minutes * 60;
|
||||
|
||||
let finalString = '';
|
||||
|
||||
if (days > 0)
|
||||
finalString =
|
||||
days === 1 ? `${finalString}${days} ${dayLabel}, ` : `${finalString}${days} ${daysLabel}, `;
|
||||
if (hours > 0)
|
||||
finalString =
|
||||
hours === 1
|
||||
? `${finalString}${hours} ${hourLabel}, `
|
||||
: `${finalString}${hours} ${hoursLabel}, `;
|
||||
if (minutes > 0)
|
||||
finalString =
|
||||
minutes === 1
|
||||
? `${finalString}${minutes} ${minuteLabel}, `
|
||||
: `${finalString}${minutes} ${minutesLabel}, `;
|
||||
if (secondsLeft > 0)
|
||||
finalString =
|
||||
secondsLeft === 1
|
||||
? `${finalString}${secondsLeft} ${secondLabel}`
|
||||
: `${finalString}${secondsLeft} ${secondsLabel}`;
|
||||
|
||||
return finalString;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user