Compare commits

..

125 Commits

Author SHA1 Message Date
Dmitry Dunaev
6298d4f29a Chg: helm image in values to new release candidate 2021-11-22 15:01:16 +03:00
Charles
8f0828a394 Merge pull request #70 from stephb9959/main
Version 2.4.3
2021-11-19 16:33:04 -05:00
Charles
8cbecc20bc Offset fixes 2021-11-19 16:30:43 -05:00
Charles
e9562dcf82 Newer ucentral-libs version 2021-11-19 11:14:02 -05:00
Charles
750fa5be5e Hotfix for device table 2021-11-19 08:58:23 -05:00
Leonid Mirsky
c4cfc76b2d Update Helm values to v2.4.0-RC1
Signed-off-by: Leonid Mirsky <leonid@opsfleet.com>
2021-11-16 23:33:08 +02:00
Charles
e02f939cb8 Merge pull request #66 from stephb9959/main
Version 2.4.1
2021-11-15 17:27:26 -05:00
Charles
2deebea6c8 Merge branch 'main' of https://github.com/stephb9959/wlan-cloud-ucentralgw-ui into main 2021-11-15 17:22:42 -05:00
Charles
fc2b1bb23c Merge branch 'dev' into main 2021-11-15 17:21:17 -05:00
Charles
848d94bad1 Version 2.4.1 2021-11-15 17:20:32 -05:00
Charles
4bde6e2d1f Merge pull request #65 from stephb9959/main
Version 2.4.0
2021-11-15 16:58:40 -05:00
Charles
e7694b644f Merge pull request #99 from stephb9959/dev
Version 2.4.0
2021-11-15 16:58:18 -05:00
Charles
07b3ac967a Version 2.4.0 2021-11-15 16:49:41 -05:00
Charles
c955bd9126 Version 2.3.21 2021-11-15 10:45:12 -05:00
Charles
ee69783a66 Merge pull request #64 from stephb9959/main
Version 2.3.20
2021-11-13 07:43:45 -05:00
Charles
b43c86520f Merge branch 'main' of https://github.com/stephb9959/wlan-cloud-ucentralgw-ui into main 2021-11-13 07:31:29 -05:00
Charles
0952f62bf0 Merge branch 'dev' into main 2021-11-13 07:31:16 -05:00
Charles
44be7ec634 Closing edit user modal when 404 2021-11-13 07:30:30 -05:00
Charles
cddb0e94fa Merge pull request #63 from stephb9959/main
Version 2.3.18
2021-11-12 16:41:07 -05:00
Charles
1a9fb77361 Merge pull request #92 from stephb9959/dev
Login page changes, ucentral-libs upgrade
2021-11-12 13:52:06 -05:00
Charles
f7392461ad Login page changes, ucentral-libs upgrade 2021-11-12 12:01:42 -05:00
Charles
b567dc26f8 Merge pull request #90 from stephb9959/dev
Dashboard bugfixes, user modal fixes
2021-11-11 16:03:35 -05:00
Charles
a08f84f5b3 Dashboard bugfixes, user modal fixes 2021-11-11 15:58:59 -05:00
Charles
b1277ff2ac Merge pull request #62 from stephb9959/main
Version 2.3.16
2021-11-09 11:42:40 -05:00
Charles
aea1550a77 Merge pull request #83 from stephb9959/dev
Version 2.3.16
2021-11-09 11:34:29 -05:00
Max
262c1fe1e2 allow to set pod annotations (#61) 2021-11-09 13:29:16 +01:00
Charles
2d1e684c69 UI fixes 2021-11-08 14:25:25 -05:00
Charles
5c6fb8b9ec Merge pull request #81 from stephb9959/dev
Version 2.3.15
2021-11-08 11:55:19 -05:00
Charles
a6be8b08c3 Version 2.3.15 2021-11-08 11:44:23 -05:00
Charles
6503c1b84d Merge pull request #79 from stephb9959/dev
Version 2.3.14
2021-11-04 17:35:51 -04:00
Charles
1fc1588303 Version 2.3.14 2021-11-04 17:29:24 -04:00
Charles
ae03c5c33e Version 2.3.13 2021-11-04 17:21:04 -04:00
Charles
2d2603ff27 Merge pull request #60 from stephb9959/main
Version 2.3.12
2021-11-02 16:42:57 -04:00
Charles
55881b0c5e Merge pull request #73 from stephb9959/dev
Version 2.3.12
2021-11-02 16:42:32 -04:00
Charles
adf752db85 UI fixes 2021-11-02 11:47:45 -04:00
Charles
d211669244 Branding fix 2021-11-01 17:43:26 -04:00
Charles
99af39db69 Livinglab branding 2021-11-01 17:42:48 -04:00
Charles
e707239d12 Label 2021-11-01 17:38:24 -04:00
Charles
d349e43523 Merge pull request #59 from stephb9959/main
Version 2.3.11
2021-11-01 17:29:31 -04:00
Charles
d52df89ab3 Merge pull request #68 from stephb9959/dev
2.3.11
2021-11-01 17:29:01 -04:00
Charles
ae48518271 UI/Bugfixes, storage for device table 2021-11-01 15:31:24 -04:00
Charles
d7238881dc New labels 2021-10-29 08:31:22 -04:00
Charles
ebf2d7d5c6 Merge pull request #58 from stephb9959/main
Version 2.3.9
2021-10-28 14:27:24 -04:00
Charles
259087aa95 Merge pull request #63 from stephb9959/dev
Version 2.3.9
2021-10-28 14:24:50 -04:00
Charles
0d7e2056f0 Version 2.3.9 2021-10-28 14:21:17 -04:00
Charles
c35178bcbb Version 2.3.8 2021-10-28 14:04:31 -04:00
Charles
5da3fb6c19 Upping ucentral-libs version 2021-10-28 13:37:06 -04:00
Charles
1961aa62da UI fixes, using new notes in my profile 2021-10-28 12:08:15 -04:00
Charles
8678b454e3 User and Firmware tables now using modals 2021-10-28 10:00:19 -04:00
Charles
b26408ade2 Tables now more compact 2021-10-27 16:09:15 -04:00
Charles
e60c000aad UI fixes, my profile page rework 2021-10-27 15:49:35 -04:00
Charles
411c618be1 Merge pull request #57 from stephb9959/main
Version 2.3.2
2021-10-26 17:20:45 -04:00
Charles
04fe9e18b6 Merge pull request #58 from stephb9959/dev
Version 2.3.1
2021-10-26 17:16:05 -04:00
Charles
b5772ce7f4 Can now edit/view my profile 2021-10-26 15:56:49 -04:00
Charles
1c3a5232c7 UI fixes 2021-10-26 15:05:50 -04:00
Charles
35caed4b07 Upgrading ucentral-libs version 2021-10-26 13:27:55 -04:00
Charles
6fb6e92382 UI fixes 2021-10-26 12:10:55 -04:00
Charles
83a4493a61 Firmware and device page now using tabs 2021-10-25 16:19:50 -04:00
Charles
5cedcf1ebf Version 2.2.14 2021-10-25 16:04:18 -04:00
Charles
2ebc649fdf Device page now uses tabs 2021-10-25 15:58:24 -04:00
Charles
996e9c2e4b Device page now uses tabs 2021-10-25 15:55:02 -04:00
bourquecharles
01f27da4b2 New translations 2021-10-21 09:41:08 -04:00
Charles
6151dcb8ff Merge pull request #56 from stephb9959/main
Version 2.2.12
2021-10-20 13:55:26 -04:00
Charles
26e4dd9859 Merge pull request #53 from stephb9959/dev
Version 2.2.12
2021-10-20 13:52:44 -04:00
Charles
531b240990 Version 2.2.12 2021-10-20 13:48:03 -04:00
Charles
3e82403d41 Update index.js 2021-10-20 13:28:08 -04:00
Charles
3564abfa29 Merge pull request #55 from stephb9959/main
Version 2.2.11
2021-10-19 11:50:48 -04:00
Charles
cd87fb4500 Merge pull request #48 from stephb9959/dev
Version 2.2.11
2021-10-19 11:40:52 -04:00
Charles
65ffc7a656 WifiAnalysis fix 2021-10-19 11:11:40 -04:00
Charles
dab7aa77c9 Upgrading ucentralibs 2021-10-19 10:05:56 -04:00
Charles
6847b5180a Other checks for empty values in wifianalysis 2021-10-19 09:52:21 -04:00
Charles
e0ba4e4b20 Wifi Analysis fix for empty rssi/tx values 2021-10-19 09:51:41 -04:00
Dmitry Dunaev
955becdb46 Merge pull request #54 from Telecominfraproject/fix/wifi-4923--helm-git-readme
[WIFI-4923] Fix: helm-git link in chart README
2021-10-19 11:50:52 +03:00
Dmitry Dunaev
daba3a3f28 [WIFI-4923] Fix: helm-git link in chart README 2021-10-19 11:40:47 +03:00
Charles
33b8d1a1f5 Merge pull request #53 from stephb9959/main
Version 2.2.8
2021-10-14 14:29:45 -04:00
Charles
0a4a5b392c Merge pull request #45 from stephb9959/dev
New labels
2021-10-14 11:00:51 -04:00
Charles
4422d54b74 New labels 2021-10-14 11:00:10 -04:00
Charles
e4883bf588 Good favicon 2021-10-14 10:58:53 -04:00
Charles
961243eefd Merge pull request #42 from stephb9959/dev
Version 2.2.8
2021-10-13 16:37:34 -04:00
Charles
c9c3e003eb Upgrading ucentral-libs 2021-10-13 16:09:06 -04:00
Charles
0faa9f63d2 Fix for getting gw ui during login 2021-10-13 16:02:40 -04:00
Charles
a44932d4f8 V1 of MFA 2021-10-13 15:54:44 -04:00
Charles
5e35c23883 Merge pull request #52 from stephb9959/main
Version 2.2.5
2021-10-12 12:02:18 -04:00
Charles
550f5ad299 Logos fix 2021-10-12 11:46:06 -04:00
Charles
dd19ed8bcd New labels 2021-10-12 11:44:30 -04:00
Charles
ff34e1098c Update index.js 2021-10-12 11:42:57 -04:00
Charles
763922b349 Update config.json 2021-10-12 11:40:40 -04:00
Charles
757844d3ac Merge branch 'lindsaybb' into main 2021-10-12 11:39:42 -04:00
Charles
e5775e548f Merge branch 'joindigital' into main 2021-10-12 11:38:03 -04:00
Charles
477e686806 Merge pull request #37 from stephb9959/dev
Fix for RSSI/Noise parse
2021-10-12 11:36:49 -04:00
Charles
8d5f912adc Merge branch 'dev' of https://github.com/stephb9959/wlan-cloud-ucentralgw-ui into dev 2021-10-12 11:12:59 -04:00
Charles
45f206d947 Fix for converted/non-converted rssi values 2021-10-12 11:12:47 -04:00
Charles
2a271e9dea Merge pull request #35 from stephb9959/main
Dashboard fix when getting empty age value
2021-10-11 18:23:38 -04:00
Charles
a007903ea2 Merge pull request #34 from stephb9959/main
Dashboard fix when getting empty age value
2021-10-11 18:23:10 -04:00
Charles
bb55498285 Merge pull request #33 from stephb9959/main
Making dev up to date
2021-10-11 18:22:38 -04:00
Charles
39b482bab9 Dashboard fix when getting empty age value 2021-10-11 18:21:34 -04:00
Charles
8b91d3c7e5 JoinDigital branding 2021-10-11 15:20:15 -04:00
Charles
f56611b0e1 Merge pull request #32 from stephb9959/viasat
Branding
2021-10-11 15:18:46 -04:00
Charles
760a6f50b2 New labels 2021-10-11 15:16:52 -04:00
Charles
c5f629d761 Fix for dark logos 2021-10-07 16:38:29 -04:00
Charles
b754dfff73 New dark logo for viasat 2021-10-07 15:31:52 -04:00
Charles
3d4937144f New logo used 2021-10-06 15:08:52 -04:00
Charles
f7f01f4c90 Typo correction 2021-10-06 15:01:57 -04:00
Charles
8ce89f1621 Viasat branding 2021-10-06 14:57:13 -04:00
Charles
00cdb0bf1e Corrected host 2021-10-06 14:35:32 -04:00
Charles
3ce188333e Viasat branch creation 2021-10-06 14:28:51 -04:00
Charles
7ddf82cf1b Update index.js 2021-10-05 16:28:04 -04:00
Charles
1e17da594d Merge pull request #31 from stephb9959/main
Version 2.2.4
2021-10-05 16:09:57 -04:00
Charles
299922a38a Merge pull request #30 from stephb9959/dev
Version 2.2.4
2021-09-30 15:25:35 -04:00
Charles
8360644864 Bugfix for system page 2021-09-30 13:00:30 -04:00
Charles
d445766f01 Now using notification system for device commands 2021-09-30 10:02:14 -04:00
Charles
601c369f2d Merge pull request #51 from stephb9959/main
Version 2.2.2
2021-09-28 14:59:12 -04:00
Charles
818bdd67ba Merge pull request #29 from stephb9959/dev
Version 2.2.2
2021-09-28 14:58:45 -04:00
Charles
967ef64728 Reverting problematic change 2021-09-28 14:35:52 -04:00
Charles
6607d52539 System page now displaying certs 2021-09-28 14:26:59 -04:00
Charles
d48925f9ba Merge pull request #50 from stephb9959/main
2.2.1
2021-09-28 11:45:53 -04:00
Charles
e36c682fb1 Merge pull request #28 from stephb9959/main
Fixing device list if we receive 0 devices
2021-09-28 11:26:57 -04:00
Charles
63c7212685 Merge pull request #27 from stephb9959/dev
Fixing device list if we receive 0 devices
2021-09-28 11:26:15 -04:00
Charles
6f5d2170c2 Fixing device list if we receive 0 devices 2021-09-28 11:23:22 -04:00
Charles
a6ba03c33b Lindsay BB branding 2021-09-28 09:59:12 -04:00
Charles
b7c18bd320 Merge pull request #26 from stephb9959/main
Version 2.2
2021-09-28 09:54:24 -04:00
Charles
0ff74497ad Merge pull request #25 from Telecominfraproject/main
Backfilling changes to dev branch
2021-09-28 09:16:37 -04:00
Charles
cc658f0223 Merge pull request #49 from Telecominfraproject/dev-2.2
Version 2.2
2021-09-28 09:12:08 -04:00
Dmitry Dunaev
b256b941a6 Merge pull request #47 from Telecominfraproject/feature/wifi-4240--adapt-helm
[WIFI-4240] Chg: adapt deployment files to 2.2 renaming
2021-09-28 12:44:18 +03:00
Dmitry Dunaev
6a2501ad81 [WIFI-4240] Chg: adapt deployment files to 2.2 renaming 2021-09-28 12:40:39 +03:00
53 changed files with 2621 additions and 707 deletions

View File

@@ -27,7 +27,7 @@ jobs:
- uses: actions/checkout@v2
- name: Build Docker image
run: docker build -t wlan-cloud-ucentralgw-ui:${{ github.sha }} .
run: docker build -t owgw-ui:${{ github.sha }} .
- name: Tag Docker image
run: |
@@ -51,7 +51,7 @@ jobs:
echo "Result tags: $TAGS"
for tag in $TAGS; do
docker tag wlan-cloud-ucentralgw-ui:${{ github.sha }} ${{ env.DOCKER_REGISTRY_URL }}/ucentralgw-ui:$tag
docker tag owgw-ui:${{ github.sha }} ${{ env.DOCKER_REGISTRY_URL }}/owgw-ui:$tag
done
- name: Log into Docker registry
@@ -65,4 +65,4 @@ jobs:
- name: Push Docker images
if: startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/pull/') || github.ref == 'refs/heads/main'
run: |
docker images | grep ${{ env.DOCKER_REGISTRY_URL }}/ucentralgw-ui | awk -F ' ' '{print $1":"$2}' | xargs -I {} docker push {}
docker images | grep ${{ env.DOCKER_REGISTRY_URL }}/owgw-ui | awk -F ' ' '{print $1":"$2}' | xargs -I {} docker push {}

View File

@@ -16,4 +16,4 @@ jobs:
steps:
- run: |
export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-')
curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/ucentralgw-ui/$PR_BRANCH_TAG"
curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owgw-ui/$PR_BRANCH_TAG"

View File

@@ -1,6 +1,6 @@
#!/bin/ash
# Check if variables are set
export DEFAULT_UCENTRALSEC_URL="${DEFAULT_UCENTRALSEC_URL:-https://ucentral.dpaas.arilia.com:16001}"
export ALLOW_UCENTRALSEC_CHANGE="${ALLOW_UCENTRALSEC_CHANGE:-false}"
export DEFAULT_OWSEC_URL="${DEFAULT_OWSEC_URL:-https://ucentral.dpaas.arilia.com:16001}"
export ALLOW_OWSEC_CHANGE="${ALLOW_OWSEC_CHANGE:-false}"
echo '{"DEFAULT_UCENTRALSEC_URL": "'$DEFAULT_UCENTRALSEC_URL'","ALLOW_UCENTRALSEC_CHANGE": '$ALLOW_UCENTRALSEC_CHANGE'}' > /usr/share/nginx/html/config.json

View File

@@ -1,5 +1,5 @@
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: ucentralgwui
name: owgwui
version: 0.1.0

View File

@@ -1,6 +1,6 @@
# ucentralgwui
# owgwui
This Helm chart helps to deploy uCentralGW-UI to the Kubernetes clusters. It is mainly used in [assembly chart](https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart) as uCentralGW-UI requires other services as dependencies that are considered in that Helm chart. This chart is purposed to define deployment logic close to the application code itself and define default values that could be overriden during deployment.
This Helm chart helps to deploy OpenWIFI Web UI (further on refered as __Web UI__) to the Kubernetes clusters. It is mainly used in [assembly chart](https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart) as Web UI requires other services as dependencies that are considered in that Helm chart. This chart is purposed to define deployment logic close to the application code itself and define default values that could be overriden during deployment.
## TL;DR;
@@ -11,7 +11,7 @@ $ helm install .
## Introduction
This chart bootstraps an ucentralgwui on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
This chart bootstraps the Web UI on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
## Installing the Chart
@@ -20,10 +20,10 @@ Currently this chart is not assembled in charts archives, so [helm-git](https://
To install the chart with the release name `my-release`:
```bash
$ helm install --name my-release git+https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui@helm?ref=main
$ helm install --name my-release git+https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui@helm/owgwui-0.1.0.tgz?ref=main
```
The command deploys ucentralgwui on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation.
The command deploys the Web UI on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation.
> **Tip**: List all releases using `helm list`
@@ -46,21 +46,21 @@ The following table lists the configurable parameters of the chart and their def
| replicaCount | number | Amount of replicas to be deployed | `1` |
| nameOverride | string | Override to be used for application deployment | |
| fullnameOverride | string | Override to be used for application deployment (has priority over nameOverride) | |
| images.ucentralgwui.repository | string | Docker image repository | |
| images.ucentralgwui.tag | string | Docker image tag | `'master'` |
| images.ucentralgwui.pullPolicy | string | Docker image pull policy | `'Always'` |
| services.ucentralgwui.type | string | uCentralGW-UI service type | `'ClusterIP'` |
| services.ucentralgwui.ports.http.servicePort | number | Websocket endpoint port to be exposed on service | `80` |
| services.ucentralgwui.ports.http.targetPort | number | Websocket endpoint port to be targeted by service | `80` |
| services.ucentralgwui.ports.http.protocol | string | Websocket endpoint protocol | `'TCP'` |
| checks.ucentralgwui.liveness.httpGet.path | string | Liveness check path to be used | `'/'` |
| checks.ucentralgwui.liveness.httpGet.port | number | Liveness check port to be used (should be pointint to ALB endpoint) | `http` |
| checks.ucentralgwui.readiness.httpGet.path | string | Readiness check path to be used | `'/'` |
| checks.ucentralgwui.readiness.httpGet.port | number | Readiness check port to be used | `http` |
| ingresses.default.enabled | boolean | Defines if uCentralGW-UI should be exposed via Ingress controller | `False` |
| ingresses.default.hosts | array | List of hosts for exposed uCentralGW-UI | |
| ingresses.default.paths | array | List of paths to be exposed for uCentralGW-UI | |
| public_env_variables | hash | Defines list of environment variables to be passed to uCentralGW-UI (required for application configuration) | |
| images.owgwui.repository | string | Docker image repository | |
| images.owgwui.tag | string | Docker image tag | `'master'` |
| images.owgwui.pullPolicy | string | Docker image pull policy | `'Always'` |
| services.owgwui.type | string | OpenWIFI Web UI service type | `'ClusterIP'` |
| services.owgwui.ports.http.servicePort | number | Websocket endpoint port to be exposed on service | `80` |
| services.owgwui.ports.http.targetPort | number | Websocket endpoint port to be targeted by service | `80` |
| services.owgwui.ports.http.protocol | string | Websocket endpoint protocol | `'TCP'` |
| checks.owgwui.liveness.httpGet.path | string | Liveness check path to be used | `'/'` |
| checks.owgwui.liveness.httpGet.port | number | Liveness check port to be used (should be pointint to ALB endpoint) | `http` |
| checks.owgwui.readiness.httpGet.path | string | Readiness check path to be used | `'/'` |
| checks.owgwui.readiness.httpGet.port | number | Readiness check port to be used | `http` |
| ingresses.default.enabled | boolean | Defines if the Web UI should be exposed via Ingress controller | `False` |
| ingresses.default.hosts | array | List of hosts for the exposed Web UI | |
| ingresses.default.paths | array | List of paths to be exposed for the Web UI | |
| public_env_variables | hash | Defines list of environment variables to be passed to the Web UI (required for application configuration) | |
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,

View File

@@ -2,7 +2,7 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "ucentralgwui.name" -}}
{{- define "owgwui.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
@@ -11,7 +11,7 @@ Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "ucentralgwui.fullname" -}}
{{- define "owgwui.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
@@ -27,6 +27,6 @@ If release name contains chart name it will be used as a full name.
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "ucentralgwui.chart" -}}
{{- define "owgwui.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

View File

@@ -3,36 +3,42 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "ucentralgwui.fullname" . }}
name: {{ include "owgwui.fullname" . }}
labels:
app.kubernetes.io/name: {{ include "ucentralgwui.name" . }}
helm.sh/chart: {{ include "ucentralgwui.chart" . }}
app.kubernetes.io/name: {{ include "owgwui.name" . }}
helm.sh/chart: {{ include "owgwui.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "ucentralgwui.name" . }}
app.kubernetes.io/name: {{ include "owgwui.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- with .Values.services.ucentralgwui.labels }}
{{- with .Values.services.owgwui.labels }}
{{- toYaml . | nindent 6 }}
{{- end }}
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "ucentralgwui.name" . }}
app.kubernetes.io/name: {{ include "owgwui.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- with .Values.services.ucentralgwui.labels }}
{{- with .Values.services.owgwui.labels }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.podAnnotations }}
annotations:
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
spec:
containers:
- name: ucentralgwui
image: "{{ .Values.images.ucentralgwui.repository }}:{{ .Values.images.ucentralgwui.tag }}"
imagePullPolicy: {{ .Values.images.ucentralgwui.pullPolicy }}
- name: owgwui
image: "{{ .Values.images.owgwui.repository }}:{{ .Values.images.owgwui.tag }}"
imagePullPolicy: {{ .Values.images.owgwui.pullPolicy }}
env:
- name: KUBERNETES_DEPLOYED
@@ -43,19 +49,19 @@ spec:
{{- end }}
ports:
{{- range $key, $value := .Values.services.ucentralgwui.ports }}
{{- range $key, $value := .Values.services.owgwui.ports }}
- name: {{ $key }}
containerPort: {{ $value.targetPort }}
protocol: {{ $value.protocol }}
{{- end }}
{{- if .Values.checks.ucentralgwui.liveness }}
{{- if .Values.checks.owgwui.liveness }}
livenessProbe:
{{- toYaml .Values.checks.ucentralgwui.liveness | nindent 12 }}
{{- toYaml .Values.checks.owgwui.liveness | nindent 12 }}
{{- end }}
{{- if .Values.checks.ucentralgwui.readiness }}
{{- if .Values.checks.owgwui.readiness }}
readinessProbe:
{{- toYaml .Values.checks.ucentralgwui.readiness | nindent 12 }}
{{- toYaml .Values.checks.owgwui.readiness | nindent 12 }}
{{- end }}
{{- with .Values.resources }}
@@ -66,7 +72,7 @@ spec:
imagePullSecrets:
{{- range $image, $imageValue := .Values.images }}
{{- if $imageValue.regcred }}
- name: {{ include "ucentralgwui.fullname" $root }}-{{ $image }}-regcred
- name: {{ include "owgwui.fullname" $root }}-{{ $image }}-regcred
{{- end }}
{{- end }}

View File

@@ -5,10 +5,10 @@
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ include "ucentralgwui.fullname" $root }}-{{ $ingress }}
name: {{ include "owgwui.fullname" $root }}-{{ $ingress }}
labels:
app.kubernetes.io/name: {{ include "ucentralgwui.name" $root }}
helm.sh/chart: {{ include "ucentralgwui.chart" $root }}
app.kubernetes.io/name: {{ include "owgwui.name" $root }}
helm.sh/chart: {{ include "owgwui.chart" $root }}
app.kubernetes.io/instance: {{ $root.Release.Name }}
app.kubernetes.io/managed-by: {{ $root.Release.Service }}
{{- with $ingressValue.annotations }}
@@ -37,7 +37,7 @@ spec:
{{- range $ingressValue.paths }}
- path: {{ .path }}
backend:
serviceName: {{ include "ucentralgwui.fullname" $root }}-{{ .serviceName }}
serviceName: {{ include "owgwui.fullname" $root }}-{{ .serviceName }}
servicePort: {{ .servicePort }}
{{- end }}
{{- end }}

View File

@@ -10,11 +10,11 @@ kind: Secret
type: kubernetes.io/dockerconfigjson
metadata:
labels:
app.kuberentes.io/name: {{ include "ucentralgwui.name" $root }}
helm.sh/chart: {{ include "ucentralgwui.chart" $root }}
app.kuberentes.io/name: {{ include "owgwui.name" $root }}
helm.sh/chart: {{ include "owgwui.chart" $root }}
app.kubernetes.io/instance: {{ $root.Release.Name }}
app.kubernetes.io/managed-by: {{ $root.Release.Service }}
name: {{ include "ucentralgwui.fullname" $root }}-{{ $image }}-regcred
name: {{ include "owgwui.fullname" $root }}-{{ $image }}-regcred
data:
.dockerconfigjson: {{ template "imagePullSecret" $imageValue.regcred }}
{{- end }}

View File

@@ -4,14 +4,14 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "ucentralgwui.fullname" $root }}-{{ $service }}
name: {{ include "owgwui.fullname" $root }}-{{ $service }}
{{- with $serviceValue.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
labels:
app.kubernetes.io/name: {{ include "ucentralgwui.name" $root }}
helm.sh/chart: {{ include "ucentralgwui.chart" $root }}
app.kubernetes.io/name: {{ include "owgwui.name" $root }}
helm.sh/chart: {{ include "owgwui.chart" $root }}
app.kubernetes.io/instance: {{ $root.Release.Name }}
app.kubernetes.io/managed-by: {{ $root.Release.Service }}
@@ -39,7 +39,7 @@ spec:
{{- end }}
{{- end }}
selector:
app.kubernetes.io/name: {{ include "ucentralgwui.name" $root }}
app.kubernetes.io/name: {{ include "owgwui.name" $root }}
app.kubernetes.io/instance: {{ $root.Release.Name }}
{{- with $serviceValue.labels }}
{{- toYaml . | nindent 4 }}

View File

@@ -5,13 +5,13 @@ nameOverride: ""
fullnameOverride: ""
images:
ucentralgwui:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/ucentralgw-ui
tag: main
owgwui:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw-ui
tag: v2.4.0-RC2
pullPolicy: Always
services:
ucentralgwui:
owgwui:
type: ClusterIP
ports:
http:
@@ -20,7 +20,7 @@ services:
protocol: TCP
checks:
ucentralgwui:
owgwui:
liveness:
httpGet:
path: /
@@ -37,7 +37,7 @@ ingresses:
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
# tls:
# - secretName: '{{ include "ucentralgwui.fullname" . }}-default-tls' # template may be used
# - secretName: '{{ include "owgwui.fullname" . }}-default-tls' # template may be used
# cert: |
# CERT_HERE_IN_PEM
# key: |
@@ -48,7 +48,7 @@ ingresses:
- chart-example.local
paths:
- path: /
serviceName: ucentralgwui
serviceName: owgwui
servicePort: http
resources: {}
@@ -69,6 +69,8 @@ tolerations: []
affinity: {}
podAnnotations: {}
# Application
public_env_variables:
DEFAULT_UCENTRALSEC_URL: https://ucentral.dpaas.arilia.com:16001

174
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "ucentral-client",
"version": "2.2.0",
"version": "2.4.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ucentral-client",
"version": "2.2.0",
"version": "2.4.3",
"dependencies": {
"@coreui/coreui": "^3.4.0",
"@coreui/icons": "^2.0.1",
@@ -32,7 +32,7 @@
"react-tooltip": "^4.2.21",
"react-widgets": "^5.1.1",
"sass": "^1.35.1",
"ucentral-libs": "^0.9.39",
"ucentral-libs": "^1.0.37",
"uuid": "^8.3.2"
},
"devDependencies": {
@@ -76,7 +76,7 @@
"terser-webpack-plugin": "^5.1.4",
"webpack": "^5.40.0",
"webpack-bundle-analyzer": "^4.4.2",
"webpack-cli": "^4.7.2",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^3.11.2",
"webpack-merge": "^5.8.0"
}
@@ -2955,9 +2955,9 @@
}
},
"node_modules/@webpack-cli/configtest": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.4.tgz",
"integrity": "sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz",
"integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==",
"dev": true,
"peerDependencies": {
"webpack": "4.x.x || 5.x.x",
@@ -2965,9 +2965,9 @@
}
},
"node_modules/@webpack-cli/info": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.3.0.tgz",
"integrity": "sha512-ASiVB3t9LOKHs5DyVUcxpraBXDOKubYu/ihHhU+t1UPpxsivg6Od2E2qU4gJCekfEddzRBzHhzA/Acyw/mlK/w==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz",
"integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==",
"dev": true,
"dependencies": {
"envinfo": "^7.7.3"
@@ -2977,9 +2977,9 @@
}
},
"node_modules/@webpack-cli/serve": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.2.tgz",
"integrity": "sha512-vgJ5OLWadI8aKjDlOH3rb+dYyPd2GTZuQC/Tihjct6F9GpXGZINo3Y/IVuZVTM1eDQB+/AOsjPUWH/WySDaXvw==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz",
"integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==",
"dev": true,
"peerDependencies": {
"webpack-cli": "4.x.x"
@@ -9279,6 +9279,11 @@
"node": ">= 0.8.0"
}
},
"node_modules/libphonenumber-js": {
"version": "1.9.37",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.37.tgz",
"integrity": "sha512-RnUR4XwiVhMLnT7uFSdnmLeprspquuDtaShAgKTA+g/ms9/S4hQU3/QpFdh3iXPHtxD52QscXLm2W2+QBmvYAg=="
},
"node_modules/lilconfig": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.3.tgz",
@@ -9518,14 +9523,12 @@
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
"dev": true
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
},
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
"dev": true
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="
},
"node_modules/lodash.merge": {
"version": "4.6.2",
@@ -9533,6 +9536,16 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
"node_modules/lodash.reduce": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
"integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs="
},
"node_modules/lodash.startswith": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/lodash.startswith/-/lodash.startswith-4.2.1.tgz",
"integrity": "sha1-xZjErc4YiiflMUVzHNxsDnF3YAw="
},
"node_modules/lodash.truncate": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
@@ -12189,6 +12202,23 @@
"react": "^16.0.0 || ^17.0.0"
}
},
"node_modules/react-phone-input-2": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/react-phone-input-2/-/react-phone-input-2-2.14.0.tgz",
"integrity": "sha512-gOY3jUpwO7ulryXPEdqzH7L6DPqI9RQxKfBxZbgqAwXyALGsmwLWFyi2RQwXlBLWN/EPPT4Nv6I9TESVY2YBcg==",
"dependencies": {
"classnames": "^2.2.6",
"lodash.debounce": "^4.0.8",
"lodash.memoize": "^4.1.2",
"lodash.reduce": "^4.6.0",
"lodash.startswith": "^4.2.1",
"prop-types": "^15.7.2"
},
"peerDependencies": {
"react": "^16.12.0 || ^17.0.0",
"react-dom": "^16.12.0 || ^17.0.0"
}
},
"node_modules/react-redux": {
"version": "7.2.4",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz",
@@ -14812,18 +14842,20 @@
}
},
"node_modules/ucentral-libs": {
"version": "0.9.39",
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-0.9.39.tgz",
"integrity": "sha512-BGsT0tdOyJUNNIjD6y1gWATcyShhR/2Qik77FqF9m9efiLEbz7MiH+8IOxnup8X6gFt6nyTNqPZIzbXYuw48og==",
"version": "1.0.37",
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-1.0.37.tgz",
"integrity": "sha512-ALQobos6DIvXEydPotUixP7AZaDlUm2qUFkvR8F0EsdeSAW1UeYEg7Gp5r6RtxUqxp6DKpPCxOQ9bcqcl5556g==",
"dependencies": {
"@coreui/coreui": "^3.4.0",
"@coreui/icons": "^2.0.1",
"@coreui/icons-react": "^1.1.0",
"@coreui/react": "^3.4.6",
"@coreui/react-chartjs": "^1.1.0",
"libphonenumber-js": "^1.9.37",
"lodash": "^4.17.21",
"react-flow-renderer": "^9.6.6",
"react-paginate": "^7.1.3",
"react-phone-input-2": "^2.14.0",
"react-router-dom": "^5.2.0",
"react-select": "^4.3.1",
"react-tooltip": "^4.2.21",
@@ -15393,23 +15425,22 @@
}
},
"node_modules/webpack-cli": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.8.0.tgz",
"integrity": "sha512-+iBSWsX16uVna5aAYN6/wjhJy1q/GKk4KjKvfg90/6hykCTSgozbfz5iRgDTSJt/LgSbYxdBX3KBHeobIs+ZEw==",
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.1.tgz",
"integrity": "sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ==",
"dev": true,
"dependencies": {
"@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/configtest": "^1.0.4",
"@webpack-cli/info": "^1.3.0",
"@webpack-cli/serve": "^1.5.2",
"colorette": "^1.2.1",
"@webpack-cli/configtest": "^1.1.0",
"@webpack-cli/info": "^1.4.0",
"@webpack-cli/serve": "^1.6.0",
"colorette": "^2.0.14",
"commander": "^7.0.0",
"execa": "^5.0.0",
"fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2",
"interpret": "^2.2.0",
"rechoir": "^0.7.0",
"v8-compile-cache": "^2.2.0",
"webpack-merge": "^5.7.3"
},
"bin": {
@@ -15436,6 +15467,12 @@
}
}
},
"node_modules/webpack-cli/node_modules/colorette": {
"version": "2.0.16",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz",
"integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==",
"dev": true
},
"node_modules/webpack-cli/node_modules/commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
@@ -18558,25 +18595,25 @@
}
},
"@webpack-cli/configtest": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.4.tgz",
"integrity": "sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz",
"integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==",
"dev": true,
"requires": {}
},
"@webpack-cli/info": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.3.0.tgz",
"integrity": "sha512-ASiVB3t9LOKHs5DyVUcxpraBXDOKubYu/ihHhU+t1UPpxsivg6Od2E2qU4gJCekfEddzRBzHhzA/Acyw/mlK/w==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz",
"integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==",
"dev": true,
"requires": {
"envinfo": "^7.7.3"
}
},
"@webpack-cli/serve": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.2.tgz",
"integrity": "sha512-vgJ5OLWadI8aKjDlOH3rb+dYyPd2GTZuQC/Tihjct6F9GpXGZINo3Y/IVuZVTM1eDQB+/AOsjPUWH/WySDaXvw==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz",
"integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==",
"dev": true,
"requires": {}
},
@@ -23416,6 +23453,11 @@
"type-check": "~0.4.0"
}
},
"libphonenumber-js": {
"version": "1.9.37",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.37.tgz",
"integrity": "sha512-RnUR4XwiVhMLnT7uFSdnmLeprspquuDtaShAgKTA+g/ms9/S4hQU3/QpFdh3iXPHtxD52QscXLm2W2+QBmvYAg=="
},
"lilconfig": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.3.tgz",
@@ -23598,14 +23640,12 @@
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
"dev": true
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
},
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
"dev": true
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="
},
"lodash.merge": {
"version": "4.6.2",
@@ -23613,6 +23653,16 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
"lodash.reduce": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
"integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs="
},
"lodash.startswith": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/lodash.startswith/-/lodash.startswith-4.2.1.tgz",
"integrity": "sha1-xZjErc4YiiflMUVzHNxsDnF3YAw="
},
"lodash.truncate": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
@@ -25559,6 +25609,19 @@
"prop-types": "^15.6.1"
}
},
"react-phone-input-2": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/react-phone-input-2/-/react-phone-input-2-2.14.0.tgz",
"integrity": "sha512-gOY3jUpwO7ulryXPEdqzH7L6DPqI9RQxKfBxZbgqAwXyALGsmwLWFyi2RQwXlBLWN/EPPT4Nv6I9TESVY2YBcg==",
"requires": {
"classnames": "^2.2.6",
"lodash.debounce": "^4.0.8",
"lodash.memoize": "^4.1.2",
"lodash.reduce": "^4.6.0",
"lodash.startswith": "^4.2.1",
"prop-types": "^15.7.2"
}
},
"react-redux": {
"version": "7.2.4",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz",
@@ -27653,18 +27716,20 @@
}
},
"ucentral-libs": {
"version": "0.9.39",
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-0.9.39.tgz",
"integrity": "sha512-BGsT0tdOyJUNNIjD6y1gWATcyShhR/2Qik77FqF9m9efiLEbz7MiH+8IOxnup8X6gFt6nyTNqPZIzbXYuw48og==",
"version": "1.0.37",
"resolved": "https://registry.npmjs.org/ucentral-libs/-/ucentral-libs-1.0.37.tgz",
"integrity": "sha512-ALQobos6DIvXEydPotUixP7AZaDlUm2qUFkvR8F0EsdeSAW1UeYEg7Gp5r6RtxUqxp6DKpPCxOQ9bcqcl5556g==",
"requires": {
"@coreui/coreui": "^3.4.0",
"@coreui/icons": "^2.0.1",
"@coreui/icons-react": "^1.1.0",
"@coreui/react": "^3.4.6",
"@coreui/react-chartjs": "^1.1.0",
"libphonenumber-js": "^1.9.37",
"lodash": "^4.17.21",
"react-flow-renderer": "^9.6.6",
"react-paginate": "^7.1.3",
"react-phone-input-2": "^2.14.0",
"react-router-dom": "^5.2.0",
"react-select": "^4.3.1",
"react-tooltip": "^4.2.21",
@@ -28140,26 +28205,31 @@
}
},
"webpack-cli": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.8.0.tgz",
"integrity": "sha512-+iBSWsX16uVna5aAYN6/wjhJy1q/GKk4KjKvfg90/6hykCTSgozbfz5iRgDTSJt/LgSbYxdBX3KBHeobIs+ZEw==",
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.1.tgz",
"integrity": "sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ==",
"dev": true,
"requires": {
"@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/configtest": "^1.0.4",
"@webpack-cli/info": "^1.3.0",
"@webpack-cli/serve": "^1.5.2",
"colorette": "^1.2.1",
"@webpack-cli/configtest": "^1.1.0",
"@webpack-cli/info": "^1.4.0",
"@webpack-cli/serve": "^1.6.0",
"colorette": "^2.0.14",
"commander": "^7.0.0",
"execa": "^5.0.0",
"fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2",
"interpret": "^2.2.0",
"rechoir": "^0.7.0",
"v8-compile-cache": "^2.2.0",
"webpack-merge": "^5.7.3"
},
"dependencies": {
"colorette": {
"version": "2.0.16",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz",
"integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==",
"dev": true
},
"commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "ucentral-client",
"version": "2.2.0",
"version": "2.4.3",
"dependencies": {
"@coreui/coreui": "^3.4.0",
"@coreui/icons": "^2.0.1",
@@ -26,7 +26,7 @@
"react-tooltip": "^4.2.21",
"react-widgets": "^5.1.1",
"sass": "^1.35.1",
"ucentral-libs": "^0.9.39",
"ucentral-libs": "^1.0.37",
"uuid": "^8.3.2"
},
"main": "index.js",
@@ -91,7 +91,7 @@
"terser-webpack-plugin": "^5.1.4",
"webpack": "^5.40.0",
"webpack-bundle-analyzer": "^4.4.2",
"webpack-cli": "^4.7.2",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^3.11.2",
"webpack-merge": "^5.8.0"
},

View File

@@ -5,7 +5,7 @@
<link rel="icon" href="favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>uCentralGW</title>
<title>Gateway</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View File

@@ -22,6 +22,7 @@
"when_blink_leds": "Wann möchten Sie die LEDs blinken lassen?"
},
"commands": {
"command_success": "Befehl erfolgreich übermittelt",
"error": "Fehler beim Senden des Befehls!",
"error_delete_log": "Fehler beim Versuch zu löschen: {{error}}",
"event_queue": "Ereigniswarteschlange",
@@ -32,6 +33,9 @@
"common": {
"access_policy": "Zugangsrichtlinien",
"add": "Hinzufügen",
"add_items": "Füge Artikel hinzu",
"add_note": "Notiz hinzufügen",
"add_note_explanation": "Schreiben Sie unten Ihre neue Notiz und klicken Sie auf die Schaltfläche \"+\", wo Sie fertig sind",
"adding_ellipsis": "Hinzufügen ...",
"are_you_sure": "Bist du sicher?",
"back_to_login": "Zurück zur Anmeldung",
@@ -42,13 +46,16 @@
"certificates": "Zertifikate",
"clear": "Löschen",
"close": "Schließen",
"code": "Code",
"command": "Befehl",
"commands": "Befehle",
"commands_executed": "Ausgeführte Befehle",
"compatible": "kompatibel",
"completed": "Abgeschlossen",
"concurrent_devices": "Gleichzeitige Geräte",
"config_id": "Konfigurations ID",
"confirm": "Bestätigen",
"confirm_stop_editing": "Möchten Sie die Bearbeitung wirklich beenden? Dadurch werden alle nicht gespeicherten Änderungen, die Sie vorgenommen haben, verworfen.",
"connected": "Verbindung wurde hergestellt",
"copied": "kopiert!",
"copy_to_clipboard": "In die Zwischenablage kopieren",
@@ -66,7 +73,7 @@
"details": "Einzelheiten",
"device": "Gerät #{{serialNumber}}",
"device_dashboard": "Geräte-Dashboard",
"device_delete": "Gerät Nr.{{serialNumber}}löschen",
"device_delete": "#{{serialNumber}}löschen",
"device_deleted": "Gerät erfolgreich gelöscht",
"device_health": "Gerätezustand",
"device_list": "Liste der Geräte",
@@ -86,6 +93,7 @@
"endpoints": "Endpunkte",
"error": "Fehler",
"error_adding_note": "Fehler beim Hinzufügen einer Notiz",
"error_code": "Fehlercode",
"execute_now": "Möchten Sie diesen Befehl jetzt ausführen?",
"executed": "Ausgeführt",
"exit": "Ausgang",
@@ -96,12 +104,21 @@
"forgot_password_title": "Passwort vergessen",
"from": "Von",
"general_error": "API-Fehler, wenden Sie sich bitte an Ihren Administrator",
"go_back": "Geh zurück",
"hide": "verbergen",
"hour": "stunde",
"hours": "std",
"id": "ID",
"invalid_credentials": "Ungültiger Benutzername und / oder Passwort",
"invalid_file": "Die ausgewählte Datei war ungültig, bitte lesen Sie die Anweisungen und passen Sie Ihre Datei entsprechend an",
"invalid_password": "Dieses Passwort entspricht nicht den grundlegenden Passwortregeln. Bitte besuchen Sie unsere Seite Passwortrichtlinien, um mehr zu erfahren",
"invalid_pem": "Ihre PEM-Datei ist ungültig. Es sollte mit '-----BEGIN CERTIFICATE-----' ODER '-----BEGIN PRIVATE KEY-----' beginnen und mit '-----END CERTIFICATE--- enden. --' ODER '-----END PRIVATSCHLÜSSEL-----'",
"ip_address": "IP Adresse",
"ips": "IPs",
"item": "Artikel",
"items": "Artikel",
"items_per_page": "Objekte pro Seite:",
"key": "Schlüssel",
"last_dashboard_refresh": "Letzte Dashboard-Aktualisierung",
"later_tonight": "Später am Abend",
"latest": "Neueste",
@@ -110,14 +127,17 @@
"loading_more_ellipsis": "Mehr laden ...",
"logout": "Ausloggen",
"mac": "MAC-Adresse",
"main": "Main",
"manufacturer": "Hersteller",
"memory_used": "Verwendeter Speicher",
"min_max": "Min: {{min}}, Max: {{max}}",
"minute": "Minute",
"minutes": "protokoll",
"modified": "Geändert",
"na": "(unbekannt)",
"need_date": "Du brauchst ein Datum...",
"no": "Nein",
"no_addresses_found": "Keine Adressen gefunden",
"no_devices_found": "Keine Geräte gefunden",
"no_items": "Keine Gegenstände",
"none": "Keiner",
@@ -129,6 +149,7 @@
"overall_health": "Allgemeine Gesundheit",
"password_policy": "Kennwortrichtlinie",
"preview": "Vorschau",
"program": "Programm",
"recorded": "Verzeichnet",
"refresh": "Aktualisierung",
"refresh_device": "Gerät aktualisieren",
@@ -142,6 +163,9 @@
"second": "zweite",
"seconds": "sekunden",
"seconds_elapsed": "Sekunden verstrichen",
"see_details": "Siehe Einzelheiten",
"select": "wählen",
"serial_num": "Seriennummer",
"serial_number": "Seriennummer",
"show_all": "Zeige alles",
"socket_connection_closed": "Verbindung geschlossen!",
@@ -162,6 +186,7 @@
"unknown": "unbekannte",
"up_to_date": "Aktuelle Geräte",
"uptimes": "Betriebszeiten",
"use_file": "Datei verwenden",
"uuid": "UUID",
"vendors": "Anbieter",
"view_more": "Mehr anzeigen",
@@ -170,7 +195,11 @@
"configuration": {
"add_configuration": "Konfiguration hinzufügen",
"add_new_block": "Neuen Konfigurationsblock hinzufügen",
"add_or_link": "Verlinken oder hinzufügen",
"add_radio": "Radio hinzufügen",
"ca_cert_explanation": "Bitte verwenden Sie eine .pem-Datei, die mit \"-----BEGIN CERTIFICATE-----\" beginnt und mit \"-----END CERTIFICATE-----\" endet. Das Ergebnis wird im Feld darunter angezeigt. Sie können das Zertifikat, das Sie verwenden möchten, auch direkt kopieren und einfügen.",
"cannot_delete": "Diese Konfiguration kann nicht gelöscht werden, da sie von mindestens einer Entität, einem Veranstaltungsort oder einem Gerät verwendet wird",
"choose_radio_band": "Welche Radioband möchten Sie gründen?",
"choose_section": "Welchen Abschnitt soll dieser Block enthalten?",
"configuration_browser": "Konfigurationsbrowser",
"configurations": "Konfigurationen",
@@ -186,12 +215,14 @@
"device_password": "Passwort",
"device_type": "Gerätetyp",
"device_types": "Gerätetypen",
"devices_affected": "Von dieser Konfiguration betroffene Geräte:",
"edit_configuration": "Konfiguration bearbeiten",
"error_delete": "Fehler beim Versuch zu löschen: {{error}}",
"error_fetching_config": "Fehler beim Abrufen der Konfiguration",
"error_trying_delete": "Fehler beim Versuch zu löschen: {{error}}",
"error_update": "Fehler: {{error}}",
"explanation": "Erläuterung",
"key_pem_explanation": "Bitte .pem-Datei auswählen",
"last_configuration_change": "Konfigurationsänderung",
"last_configuration_download": "Letzter Konfigurations-Download",
"location": "Ort",
@@ -212,6 +243,8 @@
"used_by": "Benutzt von",
"used_by_details": "{{entities}} Entitäten, {{venues}} Veranstaltungsorte und {{devices}} Geräte",
"uuid": "Konfigurations-ID",
"view_affected_devices": "Betroffene Geräte anzeigen",
"view_config": "Konfiguration anzeigen",
"view_in_use": "In Verwendung anzeigen",
"view_json": "Rohe Konfiguration anzeigen"
},
@@ -225,6 +258,37 @@
"connect": {
"error_trying_to_connect": "Fehler beim Versuch, eine Verbindung zum Gerät herzustellen: {{error}}"
},
"contact": {
"access_pin": "Zugangs-PIN",
"add_contact": "Kontakt hinzufügen",
"create_contact": "Kontakt erstellen",
"currently_selected_contact": "Aktuell ausgewählter Kontakt: {{contact}}",
"delete": "Kontakt löschen?",
"error_assign": "Fehler beim Versuch, Kontakt zuzuweisen: {{error}}",
"error_creation": "Fehler beim Versuch, einen Kontakt zu erstellen: {{error}}",
"error_delete": "Fehler beim Versuch, den Kontakt zu löschen: {{error}}",
"error_fetching_list": "Fehler beim Abrufen der Kontakte",
"error_fetching_single": "Fehler beim Abrufen des Kontakts: {{error}}",
"error_unassign": "Fehler beim Versuch, die Zuweisung des Kontakts aufzuheben: {{error}}",
"first_name": "Vorname",
"identifier": "Identifikator",
"initials": "Initialen",
"last_name": "Nachname",
"no_associated_contact": "Kein zugehöriger Kontakt",
"primary_email": "Erste Email",
"salutation": "Anrede",
"secondary_email": "Alternative Email",
"successful_assign": "Kontakt erfolgreich zugewiesen!",
"successful_creation": "Kontakt Erstellt!",
"successful_delete": "Kontakt erfolgreich gelöscht!",
"successful_unassign": "Erfolgreich nicht zugewiesener Kontakt",
"successful_update": "Kontakt erfolgreich aktualisiert",
"title": "Kontakte",
"type": "Art",
"update_error": "Fehler beim Aktualisieren des Kontakts: {{error}}",
"user_title": "Titel",
"visual": "Korrespondenzname"
},
"delete_command": {
"explanation": "Möchten Sie diesen Befehl wirklich löschen? Diese Aktion ist nicht umkehrbar.",
"title": "Befehl löschen"
@@ -236,8 +300,12 @@
"healthchecks_title": "Healthchecks löschen"
},
"device": {
"certificate_explanation": "Zertifikate der angeschlossenen Geräte",
"error_fetching_device": "Fehler beim Abrufen der Geräteinformationen: {{error}}",
"error_fetching_devices": "Fehler beim Abrufen von Geräten: {{error}}"
"error_fetching_devices": "Fehler beim Abrufen von Geräten: {{error}}",
"health_explanation": "Zustand der angeschlossenen Geräte",
"memory_explanation": "Von angeschlossenen Geräten belegter Speicher",
"uptimes_explanation": "Zeit, zu der verbundene Geräte aktiv und verbunden waren"
},
"device_logs": {
"log": "Protokoll",
@@ -247,6 +315,7 @@
"entity": {
"add_child": "Untergeordnete Entität zu {{entityName}}hinzufügen",
"add_failure": "Fehler, der Server hat zurückgegeben: {{error}}",
"add_ips": "IPs verwalten",
"add_root": "Root-Entität hinzufügen",
"add_success": "Entität erfolgreich erstellt!",
"assigned_inventory": "Zugewiesenes Inventar",
@@ -256,13 +325,26 @@
"delete_success": "Entität erfolgreich gelöscht",
"delete_warning": "Achtung: Dieser Vorgang kann nicht rückgängig gemacht werden",
"edit_failure": "Aktualisierung fehlgeschlagen : {{error}}",
"enter_here": "Geben Sie hier die IP(s) ein, die Sie hinzufügen möchten",
"entire_tree": "Seitenverzeichnis",
"entities": "Entitäten",
"entity": "Entität",
"error_fetch_entity": "Fehler beim Abrufen von Entitätsinformationen",
"error_fetching": "Fehler beim Abrufen von Entitäten",
"error_fetching_map": "Fehler beim Abrufen der Karte: {{error}}",
"error_saving": "Fehler beim Speichern der Entität",
"higher_priority": "Stellen Sie eine höhere Priorität ein",
"ip_detection": "IP-Erkennung",
"ip_formats": "Sie können IPv4- oder IPv6-Adressen in den folgenden Formaten hinzufügen:",
"lower_priority": "Niedrigere Priorität setzen",
"need_select_entity": "sSie müssen eine Entität aus der folgenden Tabelle auswählen",
"no_ips": "Keine IPs ausgewählt",
"not_assigned": "Nicht zugeordnet",
"only_unassigned": "Nur nicht zugewiesen",
"select_entity": "Wählen Sie diese Entität aus",
"selected_entity": "Ausgewählte Einheit",
"selected_map": "Ausgewählte Karte",
"update_failure_error": "Fehler beim Versuch, die Entität zu aktualisieren: {{error}}",
"valid_serial": "Muss eine gültige Seriennummer sein (12 HEX-Zeichen)",
"venues": "Veranstaltungsorte"
},
@@ -274,6 +356,7 @@
"warning": "Achtung: Nach dem Absenden kann dies nicht rückgängig gemacht werden"
},
"firmware": {
"age_explanation": "Durchschnittliche Anzahl der Tage für alle Geräte, von denen wir diesen Wert erhalten können",
"average_age": "Durchschnittliches Firmware-Alter",
"choose_custom": "Wählen",
"details_title": "Bild #{{image}} Details",
@@ -286,9 +369,11 @@
"image": "Bild",
"image_date": "Bilddatum",
"installed_firmware": "Installierte Firmware",
"latest_explanation": "Geräte, auf denen erkannte Firmware in der neuesten Version ausgeführt wird",
"latest_version_installed": "Neueste Version installiert Version",
"newer_firmware_available": "Neuere Versionen verfügbar",
"reinstall_latest": "Neu installieren",
"release": "Veröffentlichung",
"revision": "Revision",
"show_dev": "Dev-Releases anzeigen",
"size": "Größe",
@@ -317,6 +402,7 @@
"add_tag": "Tag erstellen",
"add_tag_to": "Neues Gerät zu {{name}}hinzufügen",
"add_venue": "Veranstaltungsort hinzufügen",
"assign_ent_ven": "Zu Entität oder Veranstaltungsort zuweisen",
"assign_entity_instructions": "Sie können die Entität, der dieses Tag zugewiesen werden soll, entweder über das Menü unten finden oder die UUID der Entität manuell in das Feld oben einfügen.",
"assign_error": "Fehler beim Versuch, Tag zuzuweisen",
"assign_to_entity": "Zu Entität zuweisen",
@@ -348,6 +434,7 @@
"error_create_venue": "Fehler beim Erstellen des Veranstaltungsortes",
"error_delete_tag": "Fehler beim Löschen des Inventar-Tags",
"error_get_venue": "Fehler beim Abrufen von Veranstaltungsorten",
"error_pushing_config": "Fehler beim Versuch, die Konfiguration auf das Gerät zu übertragen: {{error}}",
"error_retrieving": "Beim Abrufen von Inventar-Tags ist ein Fehler aufgetreten",
"error_unassign": "Fehler beim Aufheben der Zuweisung",
"error_update_venue": "Fehler beim Aktualisieren des Veranstaltungsorts",
@@ -393,15 +480,46 @@
"unassigned_deleted_devices": "{{number}} Geräte gelöscht und nicht zugewiesen",
"unassigned_tags": "Nicht zugewiesene Tags",
"validating_import_file": "Importdatei und -daten werden validiert...",
"venue": "Tagungsort"
"venue": "Tagungsort",
"view_in_gateway": "Im Gateway anzeigen"
},
"location": {
"add": "Ort hinzufügen",
"building_name": "Gebäudename",
"city": "Stadt",
"country": "Land",
"create": "Standort erstellen",
"currently_selected": "Aktuell ausgewählter Standort: {{location}}",
"delete": "Ort löschen?",
"error_assign": "Fehler beim Versuch, den Standort zuzuweisen: {{error}}",
"error_creation": "Fehler beim Versuch, Standorte zu erstellen: {{error}}",
"error_delete": "Fehler beim Löschen des Standorts: {{error}}",
"error_fetching_single": "Fehler beim Versuch, den Standort abzurufen: {{error}}",
"geocode": "GeoCode",
"mobiles": "MOBILES",
"no_associated": "Kein zugeordneter Standort",
"phones": "Telefone",
"postal": "Postleitzahl",
"search": "Suchen Sie nach Standorten, um die Felder unten automatisch auszufüllen",
"state": "Zustand",
"street_address": "Adresse",
"successful_creation": "Standort erfolgreich erstellt!",
"successful_delete": "Standort erfolgreich gelöscht!",
"successful_update": "Standort erfolgreich aktualisiert!",
"successfully_assigned": "Standort erfolgreich zugewiesen!",
"title": "Standorte",
"update_error": "Fehler beim Aktualisieren des Standorts: {{error}}"
},
"login": {
"account_verification": "Bestätigung des Kontos",
"authentication_expired": "Authentifizierung abgelaufen, bitte starten Sie den Anmeldevorgang erneut",
"change_password": "Ändere das Passwort",
"change_password_error": "Fehler beim Ändern des Passworts. Stellen Sie sicher, dass das neue Passwort gültig ist, indem Sie die Seite \"Passwortrichtlinie\" besuchen",
"change_password_instructions": "Geben Sie Ihr neues Passwort ein und bestätigen Sie es",
"changing_password": "Passwort ändern...",
"confirm_new_password": "Bestätige neues Passwort",
"different_passwords": "Sie müssen das gleiche Passwort zweimal eingeben",
"email_code_validation": "Bitte überprüfen Sie Ihr E-Mail-Postfach und geben Sie den Bestätigungscode, den wir Ihnen gerade gesendet haben, in das Feld unten ein",
"forgot_password_error": "Fehler beim Versuch, eine E-Mail mit vergessenem Passwort zu senden. Stellen Sie sicher, dass diese Benutzer-ID mit einem Konto verknüpft ist.",
"forgot_password_explanation": "Geben Sie Ihren Benutzernamen ein, um eine E-Mail mit Anweisungen zum Zurücksetzen Ihres Passworts zu erhalten",
"forgot_password_success": "Sie sollten in Kürze eine E-Mail mit Anweisungen zum Zurücksetzen Ihres Passworts erhalten. Bitte überprüfen Sie Ihren Spam, wenn Sie die E-Mail nicht finden können",
@@ -410,6 +528,7 @@
"login_error": "Anmeldefehler, stellen Sie sicher, dass die von Ihnen angegebenen Informationen gültig sind",
"new_password": "Neues Kennwort",
"password": "Passwort",
"phone_validation_explanation": "Bitte überprüfen Sie Ihr Mobilgerät und geben Sie den Bestätigungscode, den wir Ihnen gerade gesendet haben, in das Feld unten 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",
@@ -418,7 +537,9 @@
"sending_ellipsis": "Senden…",
"sign_in_to_account": "Melden Sie sich bei Ihrem Konto an",
"url": "uCentralSec-URL",
"username": "Benutzername"
"username": "Benutzername",
"verification_code": "Geben Sie hier Ihre Bestätigung ein",
"wrong_code": "Der eingegebene Bestätigungscode ist ungültig."
},
"reboot": {
"directions": "Wann möchten Sie dieses Gerät neu starten?",
@@ -439,6 +560,59 @@
"settings": {
"title": "die Einstellungen"
},
"simulation": {
"add": "Simulation hinzufügen",
"cancel": "Stornieren",
"cancel_success": "Simulationslauf erfolgreich abgebrochen!",
"check_ongoing_sims": "Folge laufender Sim",
"client_interval": "Kundenintervall",
"delete_simulation": "Sim löschen. {{name}}",
"end": "Endete",
"error_creating": "Fehler beim Erstellen der Simulation: {{error}}",
"error_delete": "Fehler beim Löschen der Simulation: {{error}}",
"error_devices": "Fehler Geräte",
"error_edit": "Fehler beim Versuch, die Simulation zu speichern: {{error}}",
"error_edit_run": "Fehler beim Versuch, den Ausführungsstatus zu ändern: {{error}}",
"error_fetching_simulations": "Fehler beim Abrufen der Simulationen: {{error}}",
"error_start_run": "Fehler beim Versuch, einen Simulationslauf zu starten: {{error}}",
"gateway": "Tor",
"healtcheck_interval": "Healthcheck-Intervall",
"keep_alive": "Bleib am Leben",
"last_refresh": "Letzte Aktualisierung",
"length": "Länge",
"live_devices": "Live-Geräte",
"mac_prefix": "MAC-Präfix",
"max_associations": "max. Verbände",
"max_clients": "Max. Kunden",
"messages_transmitted": "Gesendete Nachrichten",
"min_associations": "Mindest. Verbände",
"min_clients": "Mindest. Kunden",
"pause": "Pause",
"pause_success": "Lauf pausiert!",
"prefix_length": "Erforderlich, muss eine Länge von 6 Zeichen haben",
"previous_runs": "Vorherige Läufe",
"received": "empfangen",
"received_messages": "Erhaltene Nachrichten",
"reconnect_interval": "Wiederverbindungsintervall",
"resume": "Fortsetzen",
"resume_success": "Lauf wieder aufgenommen!",
"run": "Simulationslauf",
"run_simulation": "Simulation ausführen",
"started": "gestartet",
"state_interval": "Zustandsintervall",
"stop": "Halt",
"stop_success": "Lauf gestoppt!",
"success_creating": "Simulation erfolgreich erstellt!",
"success_run_start": "Erfolgreich gestarteter Lauf!",
"successful_delete": "Simulation erfolgreich gelöscht!",
"successful_edit": "Erfolgreich bearbeitete Simulation!",
"threads": "Themen",
"time_full_devices": "Zeit für volle Geräte",
"title": "Simulationen",
"transmitted": "Übertragen",
"valid_cert": "Gültiges Zertifikat",
"valid_key": "Gültiger Schlüssel"
},
"statistics": {
"data": "Daten (KB)",
"latest_statistics": "Neueste Statistiken",
@@ -467,7 +641,7 @@
"os": "Betriebssystem",
"processors": "Prozessoren",
"reload": "Neu laden",
"reload_subsystems": "Subsysteme neu laden",
"reload_subsystems": "Subsysteme",
"subsystems": "Subsysteme",
"success_reload": "Reload-Befehl erfolgreich gesendet!"
},
@@ -506,10 +680,13 @@
"waiting_for_device": "Warten, bis das Gerät wieder verbunden ist"
},
"user": {
"add_phone_number": "Telefonnummer hinzufügen",
"avatar": "Dein Avatar",
"avatar_file": "Dein Avatar (max. 2 MB)",
"check_phone": "Bitte überprüfen Sie Ihr Telefon auf Ihren Validierungscode",
"confirm_new_password": "Bestätige neues Passwort",
"create": "Benutzer erstellen",
"create_failure": "Fehler beim Erstellen des Benutzers. Bitte stellen Sie sicher, dass diese E-Mail-Adresse nicht bereits mit einem Konto verknüpft ist.",
"create_failure": "Fehler beim Erstellen des Benutzers: {{error}}",
"create_success": "Benutzer erfolgreich erstellt",
"creating": "Benutzer erstellen ...",
"delete_avatar": "Avatar löschen",
@@ -521,29 +698,40 @@
"description": "Beschreibung",
"edit": "Benutzer bearbeiten",
"email_address": "E-Mail-Addresse",
"enter_new_phone": "Geben Sie Ihre neue Telefonnummer ein:",
"error_fetching_users": "Fehler beim Abrufen der Nutzer: {{error}}",
"error_retrieving": "Fehler beim Abrufen des Benutzers",
"error_sending_code": "Fehler beim Versuch, den Validierungscode zu senden. Bitte bestätigen Sie, dass Ihre Telefonnummer gültig ist.",
"force_password_change": "Passwortänderung bei der Anmeldung erzwingen",
"id": "Benutzeridentifikation.",
"last_login": "Letzte Anmeldung",
"login_id": "Anmelde-ID.",
"make_sure_same_password": "Stellen Sie sicher, dass beide Passwörter gleich und gültig sind",
"my_profile": "Mein Profil",
"name": "Name",
"new_code_sent": "Neuer Code gesendet!",
"nickname": "Spitzname",
"nickname_explanation": "Spitzname (optional)",
"not_validated": "Nicht validiert",
"note": "Hinweis",
"password": "Passwort",
"phone_number": "Telefonnummer",
"provide_email": "Bitte geben Sie eine gültige E-Mail Adresse an",
"provide_password": "Bitte geben Sie ein gültiges Passwort ein",
"save_avatar": "Avatar speichern",
"send_code": "Code senden",
"send_code_again": "Code nochmal senden",
"show_hide_password": "Passwort anzeigen/verbergen",
"successful_validation": "Telefonnummer bestätigt! Klicken Sie auf die Schaltfläche Speichern, um es mit Ihrem Profil zu verknüpfen",
"update_failure": "Fehler beim Aktualisieren: {{error}}",
"update_failure_title": "Update fehlgeschlagen",
"update_success": "Benutzer erfolgreich aktualisiert",
"update_success_title": "Erfolg",
"user_role": "Rolle",
"users": "Benutzer",
"validated": "Bestätigt"
"validate_phone": "Bestätigen",
"validated": "Bestätigt",
"wrong_validation_code": "Sie haben keinen gültigen Code eingegeben. Bitte versuchen Sie es erneut und vergewissern Sie sich, dass Sie die richtige Telefonnummer eingegeben haben"
},
"wifi_analysis": {
"association": "Verband",

View File

@@ -22,6 +22,7 @@
"when_blink_leds": "When would you like to make the device LEDs blink?"
},
"commands": {
"command_success": "Command Submitted Successfully",
"error": "Error while submitting command!",
"error_delete_log": "Error while trying to delete: {{error}}",
"event_queue": "Event Queue",
@@ -32,6 +33,9 @@
"common": {
"access_policy": "Access Policy",
"add": "Add",
"add_items": "Add Items",
"add_note": "Add Note",
"add_note_explanation": "Write your new note below and click the '+' button where you are done",
"adding_ellipsis": "Adding...",
"are_you_sure": "Are you sure?",
"back_to_login": "Back to Login",
@@ -42,13 +46,16 @@
"certificates": "Certificates",
"clear": "Clear",
"close": "Close",
"code": "Code",
"command": "Command",
"commands": "Commands",
"commands_executed": "Commands Executed",
"compatible": "Compatible",
"completed": "Completed",
"concurrent_devices": "Concurrent Devices",
"config_id": "Config. Id",
"confirm": "Confirm",
"confirm_stop_editing": "Are you sure you want to stop editing? This will cancel any unsaved changes you have made.",
"connected": "Connected",
"copied": "Copied!",
"copy_to_clipboard": "Copy to clipboard",
@@ -66,7 +73,7 @@
"details": "Details",
"device": "Device #{{serialNumber}}",
"device_dashboard": "Device Dashboard",
"device_delete": "Delete Device #{{serialNumber}}",
"device_delete": "Delete #{{serialNumber}}",
"device_deleted": "Device Successfully Deleted",
"device_health": "Device Health",
"device_list": "List of Devices",
@@ -86,6 +93,7 @@
"endpoints": "Endpoints",
"error": "Error",
"error_adding_note": "Error while adding note",
"error_code": "Error Code",
"execute_now": "Would you like to execute this command now?",
"executed": "Executed",
"exit": "Exit",
@@ -96,12 +104,21 @@
"forgot_password_title": "Forgot Password",
"from": "From",
"general_error": "API Error, please consult your administrator",
"go_back": "Go Back",
"hide": "Hide",
"hour": "hour",
"hours": "hours",
"id": "Id",
"invalid_credentials": "Invalid username and/or password",
"invalid_file": "The chosen file was invalid, please read the instructions and adjust your file accordingly",
"invalid_password": "This password does not confirm to basic password rules. Please visit our Password Policy page to learn more",
"invalid_pem": "Your .pem file is invalid. It should start with '-----BEGIN CERTIFICATE-----' OR '-----BEGIN PRIVATE KEY-----' and it should end with '-----END CERTIFICATE-----' OR '-----END PRIVATE KEY-----'",
"ip_address": "IP Address",
"ips": "IPs",
"item": "Item",
"items": "Items",
"items_per_page": "Items per page: ",
"key": "Key",
"last_dashboard_refresh": "Last Dashboard Refresh",
"later_tonight": "Later tonight",
"latest": "Latest",
@@ -110,14 +127,17 @@
"loading_more_ellipsis": "Loading more...",
"logout": "Logout",
"mac": "MAC Address",
"main": "Main",
"manufacturer": "Manufacturer",
"memory_used": "Memory Used",
"min_max": "Min: {{min}}, Max: {{max}}",
"minute": "minute",
"minutes": "minutes",
"modified": "Modified",
"na": "N/A",
"need_date": "You need a date...",
"no": "No",
"no_addresses_found": "No Addresses Found",
"no_devices_found": "No Devices Found",
"no_items": "No Items",
"none": "None",
@@ -129,6 +149,7 @@
"overall_health": "Overall Health",
"password_policy": "Password Policy",
"preview": "Preview",
"program": "Program",
"recorded": "Recorded",
"refresh": "Refresh",
"refresh_device": "Refresh Device",
@@ -142,6 +163,9 @@
"second": "second",
"seconds": "seconds",
"seconds_elapsed": "Seconds elapsed",
"see_details": "See Details",
"select": "Select",
"serial_num": "Serial #",
"serial_number": "Serial Number",
"show_all": "Show All",
"socket_connection_closed": "Connection closed!",
@@ -162,6 +186,7 @@
"unknown": "Unknown",
"up_to_date": "Up to Date Devices",
"uptimes": "Uptimes",
"use_file": "Use File",
"uuid": "UUID",
"vendors": "Vendors",
"view_more": "View more",
@@ -170,7 +195,11 @@
"configuration": {
"add_configuration": "Add Configuration",
"add_new_block": "Add new Configuration Block",
"add_or_link": "Link or Add",
"add_radio": "Add Radio",
"ca_cert_explanation": "Please use a .pem file that starts with \"-----BEGIN CERTIFICATE-----\" and ends with \"-----END CERTIFICATE-----\". The result will be shown in the field below. You can also copy and paste the certificate you would like to use directly.",
"cannot_delete": "This configuration cannot be deleted because it is being used by at least one entity, venue or device",
"choose_radio_band": "What radio band you would like to create?",
"choose_section": "Which section you would like this block to contain?",
"configuration_browser": "Configuration Browser",
"configurations": "Configurations",
@@ -186,13 +215,15 @@
"device_password": "Password",
"device_type": "Device Type",
"device_types": "Device Types",
"devices_affected": "Devices affected by this configuration: ",
"edit_configuration": "Edit Configuration",
"error_delete": "Error while trying to delete: {{error}}",
"error_fetching_config": "Error while fetching configuration",
"error_trying_delete": "Error while trying to delete: {{error}}",
"error_update": "Error: {{error}}",
"explanation": "Explanation",
"last_configuration_change": "Config Change",
"key_pem_explanation": "Please select .pem file",
"last_configuration_change": "Configuration Change",
"last_configuration_download": "Last Configuration Download",
"location": "Location",
"need_device_type": "Every configuration needs to support at least one device type",
@@ -212,6 +243,8 @@
"used_by": "Used By",
"used_by_details": "{{entities}} Entities, {{venues}} Venues and {{devices}} Devices",
"uuid": "Config ID",
"view_affected_devices": "View Affected Devices",
"view_config": "View Configuration",
"view_in_use": "View In Use",
"view_json": "View raw JSON"
},
@@ -225,6 +258,37 @@
"connect": {
"error_trying_to_connect": "Error while trying to connect to device: {{error}}"
},
"contact": {
"access_pin": "Access PIN",
"add_contact": "Add Contact",
"create_contact": "Create Contact",
"currently_selected_contact": "Currently Selected Contact: {{contact}}",
"delete": "Delete Contact?",
"error_assign": "Error while trying to assign contact: {{error}}",
"error_creation": "Error while trying to create contact: {{error}}",
"error_delete": "Error trying to delete contact: {{error}}",
"error_fetching_list": "Error fetching contacts",
"error_fetching_single": "Error fetching contact: {{error}}",
"error_unassign": "Error while trying to unassign contact: {{error}}",
"first_name": "First Name",
"identifier": "Identifier",
"initials": "Initials",
"last_name": "Last Name",
"no_associated_contact": "No Associated Contact",
"primary_email": "Primary Email",
"salutation": "Salutation",
"secondary_email": "Secondary Email",
"successful_assign": "Successfully assigned contact!",
"successful_creation": "Contact Created!",
"successful_delete": "Successfully Deleted Contact!",
"successful_unassign": "Successfully Unassigned Contact",
"successful_update": "Successfully Updated Contact",
"title": "Contacts",
"type": "Type",
"update_error": "Error updating contact: {{error}}",
"user_title": "Title",
"visual": "Correspondence Name"
},
"delete_command": {
"explanation": "Are you sure you want to delete this command? This action is not reversible.",
"title": "Delete Command"
@@ -236,8 +300,12 @@
"healthchecks_title": "Delete Healthchecks"
},
"device": {
"certificate_explanation": "Certificates of connected devices",
"error_fetching_device": "Error fetching device information: {{error}}",
"error_fetching_devices": "Error while fetching devices: {{error}}"
"error_fetching_devices": "Error while fetching devices: {{error}}",
"health_explanation": "Health of connected devices",
"memory_explanation": "Memory used by connected devices",
"uptimes_explanation": "Time connected devices have been up and connected"
},
"device_logs": {
"log": "Log",
@@ -247,6 +315,7 @@
"entity": {
"add_child": "Add Child Entity to {{entityName}}",
"add_failure": "Error, the server returned : {{error}}",
"add_ips": "Manage IPs",
"add_root": "Add Root Entity",
"add_success": "Entity Successfully Created!",
"assigned_inventory": "Assigned Inventory",
@@ -256,13 +325,26 @@
"delete_success": "Entity Successfully Deleted",
"delete_warning": "Warning: this operation cannot be reverted",
"edit_failure": "Update unsuccessful : {{error}}",
"enter_here": "Enter the IP(s) you'd like to add here",
"entire_tree": "Site Map",
"entities": "Entities",
"entity": "Entity",
"error_fetch_entity": "Error while fetching entity information",
"error_fetching": "Error while fetching entities",
"error_fetching_map": "Error fetching map: {{error}}",
"error_saving": "Error while saving entity",
"higher_priority": "Make Higher Priority",
"ip_detection": "IP Detection",
"ip_formats": "You can add IPv4 or IPv6 addresses in the following formats:",
"lower_priority": "Make Lower Priority",
"need_select_entity": "You need to select an entity from the table below",
"no_ips": "No IPs selected",
"not_assigned": "Not Assigned",
"only_unassigned": "Only Unassigned",
"select_entity": "Select this Entity",
"selected_entity": "Selected Entity",
"selected_map": "Selected Map",
"update_failure_error": "Error while trying to update entity: {{error}}",
"valid_serial": "Needs to be a valid serial number (12 HEX characters)",
"venues": "Venues"
},
@@ -274,6 +356,7 @@
"warning": "Warning: Once you submit this cannot be reverted"
},
"firmware": {
"age_explanation": "Average number of days for all devices from which we can obtain that value",
"average_age": "Average Firmware Age",
"choose_custom": "Choose",
"details_title": "Image #{{image}} Details",
@@ -286,9 +369,11 @@
"image": "Image",
"image_date": "Image Date",
"installed_firmware": "Installed Firmware",
"latest_explanation": "Devices running recognized firmware at its latest version",
"latest_version_installed": "Latest Version Installed",
"newer_firmware_available": "Newer Revisions Available",
"reinstall_latest": "Reinstall ",
"release": "Release",
"revision": "Revision",
"show_dev": "Show Dev Releases",
"size": "Size",
@@ -317,6 +402,7 @@
"add_tag": "Create Tag",
"add_tag_to": "Add New Device to {{name}}",
"add_venue": "Add Venue",
"assign_ent_ven": "Assign to Entity or Venue",
"assign_entity_instructions": "You can either find the entity you want this tag to be assigned to by using the menu below, or you can manually paste the entity's UUID in the field above.",
"assign_error": "Error while trying to assign tag",
"assign_to_entity": "Assign to Entity",
@@ -348,6 +434,7 @@
"error_create_venue": "Error while creating venue",
"error_delete_tag": "Error while deleting inventory tag",
"error_get_venue": "Error while retrieving venues",
"error_pushing_config": "Error while trying to push configuration to device: {{error}}",
"error_retrieving": "Error occurred while retrieving inventory tags",
"error_unassign": "Error during unassign operation",
"error_update_venue": "Error while updating venue",
@@ -393,15 +480,46 @@
"unassigned_deleted_devices": "{{number}} Devices Deleted and Unassigned",
"unassigned_tags": "Unassigned tags",
"validating_import_file": "Validating import file and data...",
"venue": "Venue"
"venue": "Venue",
"view_in_gateway": "Details in Gateway"
},
"location": {
"add": "Add Location",
"building_name": "Building Name",
"city": "City",
"country": "Country",
"create": "Create Location",
"currently_selected": "Currently Selected Location: {{location}}",
"delete": "Delete Location?",
"error_assign": "Error while trying to assign location: {{error}}",
"error_creation": "Error while trying to create locations: {{error}}",
"error_delete": "Error while deleting location: {{error}}",
"error_fetching_single": "Error while trying to fetch location: {{error}}",
"geocode": "GeoCode",
"mobiles": "Mobiles",
"no_associated": "No Associated Location",
"phones": "Phones",
"postal": "ZIP/Postal Code",
"search": "Search locations to auto fill the fields below",
"state": "State",
"street_address": "Street Address",
"successful_creation": "Location Successfully Created!",
"successful_delete": "Successfully Deleted Location!",
"successful_update": "Successfully updated location!",
"successfully_assigned": "Location Successfully Assigned!",
"title": "Locations",
"update_error": "Error updating location: {{error}}"
},
"login": {
"account_verification": "Account Verification",
"authentication_expired": "Authentication expired, please start the login process again",
"change_password": "Change Password",
"change_password_error": "Error while changing password. Make sure the new password is valid by visiting the 'Password Policy' page",
"change_password_instructions": "Enter and confirm your new password",
"changing_password": "Changing Password... ",
"confirm_new_password": "Confirm New Password",
"different_passwords": "You need to enter the same password twice",
"email_code_validation": "Please check your email box and enter the verification code we have just sent you in the box below",
"forgot_password_error": "Error while trying to send Forgot Password email. Please make sure this userId is associated to an account.",
"forgot_password_explanation": "Enter your username to receive an email containing the instructions to reset your password",
"forgot_password_success": "You should soon receive an email containing the instructions to reset your password. Please make sure to check your spam if you can't find the email",
@@ -410,6 +528,7 @@
"login_error": "Login error, make sure the information you are providing is valid",
"new_password": "New Password",
"password": "Password",
"phone_validation_explanation": "Please check your mobile device and enter the verification code we have just sent you in the box below",
"please_enter_gateway": "Please enter a uCentralSec URL",
"please_enter_password": "Please enter your password",
"please_enter_username": "Please enter your username",
@@ -418,7 +537,9 @@
"sending_ellipsis": "Sending... ",
"sign_in_to_account": "Sign in to your account",
"url": "uCentralSec URL",
"username": "Username"
"username": "Username",
"verification_code": "Enter your verification here",
"wrong_code": "The verification code that was entered is not valid. "
},
"reboot": {
"directions": "When would you like to reboot this device?",
@@ -439,6 +560,59 @@
"settings": {
"title": "Settings"
},
"simulation": {
"add": "Add Simulation",
"cancel": "Cancel",
"cancel_success": "Simulation Run Successfully Cancelled!",
"check_ongoing_sims": "Follow Ongoing Sim",
"client_interval": "Client Interval",
"delete_simulation": "Delete Sim. {{name}}",
"end": "Ended",
"error_creating": "Error creating simulation: {{error}}",
"error_delete": "Error while deleting simulation: {{error}}",
"error_devices": "Error Devices",
"error_edit": "Error while trying to save simulation: {{error}}",
"error_edit_run": "Error while trying to change run state: {{error}}",
"error_fetching_simulations": "Error fetching simulations: {{error}}",
"error_start_run": "Error while trying to start a simulation run: {{error}}",
"gateway": "Gateway",
"healtcheck_interval": "Healthcheck Interval",
"keep_alive": "Keep Alive",
"last_refresh": "Last Refresh",
"length": "Length",
"live_devices": "Live Devices",
"mac_prefix": "MAC Prefix",
"max_associations": "Max. Associations",
"max_clients": "Max. Clients",
"messages_transmitted": "Messages Transmitted",
"min_associations": "Min. Associations",
"min_clients": "Min. Clients",
"pause": "Pause",
"pause_success": "Run Paused!",
"prefix_length": "Required, needs to be of a length of 6 characters",
"previous_runs": "Previous Runs",
"received": "Received",
"received_messages": "Messages Received",
"reconnect_interval": "Reconnect Interval",
"resume": "Resume",
"resume_success": "Run Resumed!",
"run": "Simulation Run",
"run_simulation": "Run Simulation",
"started": "Started",
"state_interval": "State Interval",
"stop": "Stop",
"stop_success": "Run Stopped!",
"success_creating": "Simulation Successfully Created!",
"success_run_start": "Successfully Started Run!",
"successful_delete": "Successfully Deleted Simulation!",
"successful_edit": "Successfully Edited Simulation!",
"threads": "Threads",
"time_full_devices": "Time to Full Devices",
"title": "Simulations",
"transmitted": "Transmitted",
"valid_cert": "Valid Certificate",
"valid_key": "Valid Key"
},
"statistics": {
"data": "Data (KB)",
"latest_statistics": "Latest Statistics",
@@ -467,7 +641,7 @@
"os": "Operation System",
"processors": "Processors",
"reload": "Reload",
"reload_subsystems": "Reload Subsystems",
"reload_subsystems": "Reload",
"subsystems": "Subsystems",
"success_reload": "Reload command successfully submitted!"
},
@@ -506,10 +680,13 @@
"waiting_for_device": "Waiting for device to reconnect"
},
"user": {
"add_phone_number": "Add Phone Number",
"avatar": "Your Avatar",
"avatar_file": "Your Avatar (max. of 2 MB)",
"check_phone": "Please check your phone for your validation code",
"confirm_new_password": "Confirm New Password",
"create": "Create User",
"create_failure": "Error while creating user. Please make sure this email address is not already linked to an account.",
"create_failure": "Error while creating user: {{error}}",
"create_success": "User Created Successfully",
"creating": "Creating User...",
"delete_avatar": "Delete Avatar",
@@ -521,29 +698,40 @@
"description": "Description",
"edit": "Edit User",
"email_address": "Email Address",
"enter_new_phone": "Enter your new phone number: ",
"error_fetching_users": "Error fetching users: {{error}}",
"error_retrieving": "Error retrieving user",
"error_sending_code": "Error while trying to send validation code. Please confirm that your phone number is valid.",
"force_password_change": "Force Password Change on Login",
"id": "User Id.",
"last_login": "Last Login",
"login_id": "Login Id.",
"make_sure_same_password": "Make sure both passwords are the same and are valid",
"my_profile": "My Profile",
"name": "Name",
"new_code_sent": "New Code Sent!",
"nickname": "Nickname",
"nickname_explanation": "Nickname (optional)",
"not_validated": "Not Validated",
"note": "Note",
"password": "Password",
"phone_number": "Phone Number",
"provide_email": "Please provide a valid email address",
"provide_password": "Please provide a valid password",
"save_avatar": "Save Avatar",
"send_code": "Send Code",
"send_code_again": "Send Code Again",
"show_hide_password": "Show/Hide Password",
"successful_validation": "Phone Number Validated! Click the save button to link it to your profile",
"update_failure": "Error while trying to update: {{error}}",
"update_failure_title": "Update Failed",
"update_success": "User Updated Successfully",
"update_success_title": "Success",
"user_role": "Role",
"users": "Users",
"validated": "Validated"
"validate_phone": "Validate",
"validated": "Validated",
"wrong_validation_code": "You have not entered a valid code. Please try again and make sure you have entered the right phone number"
},
"wifi_analysis": {
"association": "Association",

View File

@@ -22,6 +22,7 @@
"when_blink_leds": "¿Cuándo desea que los LED del dispositivo parpadeen?"
},
"commands": {
"command_success": "Comando enviado con éxito",
"error": "¡Error al enviar el comando!",
"error_delete_log": "Error al intentar eliminar: {{error}}",
"event_queue": "Cola de eventos",
@@ -32,6 +33,9 @@
"common": {
"access_policy": "Política de acceso",
"add": "Añadir",
"add_items": "Agregar articulos",
"add_note": "Añadir la nota",
"add_note_explanation": "Escriba su nueva nota a continuación y haga clic en el botón '+' donde haya terminado",
"adding_ellipsis": "Añadiendo ...",
"are_you_sure": "¿Estás seguro?",
"back_to_login": "Atrás para iniciar sesión",
@@ -42,13 +46,16 @@
"certificates": "Certificados",
"clear": "Claro",
"close": "Cerrar",
"code": "Código",
"command": "Mando",
"commands": "comandos",
"commands_executed": "Comandos ejecutados",
"compatible": "Compatible",
"completed": "terminado",
"concurrent_devices": "Dispositivos concurrentes",
"config_id": "Config. Identificación",
"confirm": "Confirmar",
"confirm_stop_editing": "¿Estás seguro de que quieres dejar de editar? Esto cancelará cualquier cambio no guardado que haya realizado.",
"connected": "Conectado",
"copied": "Copiado!",
"copy_to_clipboard": "Copiar al portapapeles",
@@ -66,7 +73,7 @@
"details": "Detalles",
"device": "Dispositivo n.º{{serialNumber}}",
"device_dashboard": "Panel de control del dispositivo",
"device_delete": "Eliminar dispositivo n.º{{serialNumber}}",
"device_delete": "Eliminar #{{serialNumber}}",
"device_deleted": "Dispositivo eliminado correctamente",
"device_health": "Salud del dispositivo",
"device_list": "Listado de dispositivos",
@@ -86,6 +93,7 @@
"endpoints": "Puntos finales",
"error": "Error",
"error_adding_note": "Error al agregar una nota",
"error_code": "código de error",
"execute_now": "¿Le gustaría ejecutar este comando ahora?",
"executed": "ejecutado",
"exit": "salida",
@@ -96,12 +104,21 @@
"forgot_password_title": "Se te olvidó tu contraseña",
"from": "Desde",
"general_error": "Error de API, consulte a su administrador",
"go_back": "Regresa",
"hide": "Esconder",
"hour": "hora",
"hours": "horas",
"id": "Carné de identidad",
"invalid_credentials": "Nombre de usuario y / o contraseña inválido",
"invalid_file": "El archivo elegido no es válido, lea las instrucciones y ajuste su archivo en consecuencia",
"invalid_password": "Esta contraseña no confirma las reglas básicas de contraseña. Visite nuestra página de Política de contraseñas para obtener más información.",
"invalid_pem": "Su archivo .pem no es válido. Debe comenzar con '----- BEGIN CERTIFICATE -----' O '----- BEGIN PRIVATE KEY -----' y debe terminar con '----- END CERTIFICATE --- - 'O' ----- FIN DE CLAVE PRIVADA ----- '",
"ip_address": "Dirección IP",
"ips": "IPs",
"item": "ít",
"items": "artículos",
"items_per_page": "Artículos por página:",
"key": "Llave",
"last_dashboard_refresh": "Última actualización del panel",
"later_tonight": "Más tarde esta noche",
"latest": "último",
@@ -110,14 +127,17 @@
"loading_more_ellipsis": "Cargando más ...",
"logout": "Cerrar sesión",
"mac": "Dirección MAC",
"main": "Principal",
"manufacturer": "Fabricante",
"memory_used": "Memoria usada",
"min_max": "Mín .: {{min}}, Máx .: {{max}}",
"minute": "minuto",
"minutes": "minutos",
"modified": "Modificado",
"na": "N / A",
"need_date": "Necesitas una cita ...",
"no": "No",
"no_addresses_found": "No se encontraron direcciones",
"no_devices_found": "No se encontraron dispositivos",
"no_items": "No hay articulos",
"none": "Ninguna",
@@ -129,6 +149,7 @@
"overall_health": "Salud en general",
"password_policy": "Política de contraseñas",
"preview": "Avance",
"program": "Programa",
"recorded": "Grabado",
"refresh": "Refrescar",
"refresh_device": "Actualizar dispositivo",
@@ -142,6 +163,9 @@
"second": "segundo",
"seconds": "segundos",
"seconds_elapsed": "Segundos transcurridos",
"see_details": "Ver detalles",
"select": "Seleccionar",
"serial_num": "Número de serie",
"serial_number": "Número de serie",
"show_all": "Mostrar todo",
"socket_connection_closed": "¡Conexión cerrada!",
@@ -162,6 +186,7 @@
"unknown": "Desconocido",
"up_to_date": "Dispositivos actualizados",
"uptimes": "Tiempos de actividad",
"use_file": "Usar archivo",
"uuid": "UUID",
"vendors": "Vendedores",
"view_more": "Ver más",
@@ -170,7 +195,11 @@
"configuration": {
"add_configuration": "Agregar configuración",
"add_new_block": "Agregar nuevo bloque de configuración",
"add_or_link": "Vincular o agregar",
"add_radio": "Agregar radio",
"ca_cert_explanation": "Utilice un archivo .pem que comience con \"----- BEGIN CERTIFICATE -----\" y termine con \"----- END CERTIFICATE -----\". El resultado se mostrará en el campo siguiente. También puede copiar y pegar el certificado que le gustaría usar directamente.",
"cannot_delete": "Esta configuración no se puede eliminar porque está siendo utilizada por al menos una entidad, lugar o dispositivo",
"choose_radio_band": "¿Qué banda de radio te gustaría crear?",
"choose_section": "Qué sección le gustaría que contenga este bloque?",
"configuration_browser": "Navegador de configuración",
"configurations": "Configuraciones",
@@ -186,12 +215,14 @@
"device_password": "Contraseña",
"device_type": "Tipo de dispositivo",
"device_types": "Tipos de dispositivos",
"devices_affected": "Dispositivos afectados por esta configuración:",
"edit_configuration": "Editar configuración",
"error_delete": "Error al intentar eliminar: {{error}}",
"error_fetching_config": "Error al obtener la configuración",
"error_trying_delete": "Error al intentar eliminar: {{error}}",
"error_update": "Error: {{error}}",
"explanation": "Explicación",
"key_pem_explanation": "Seleccione el archivo .pem",
"last_configuration_change": "CAMBIO DE CONFIGURACIÓN",
"last_configuration_download": "Descarga de la última configuración",
"location": "Ubicación",
@@ -212,6 +243,8 @@
"used_by": "Usado por",
"used_by_details": "{{entities}} Entidades, {{venues}} lugares y {{devices}} dispositivos",
"uuid": "ID de configuración",
"view_affected_devices": "Ver dispositivos afectados",
"view_config": "Ver configuración",
"view_in_use": "Ver en uso",
"view_json": "Ver JSON sin procesar"
},
@@ -225,6 +258,37 @@
"connect": {
"error_trying_to_connect": "Error al intentar conectarse al dispositivo: {{error}}"
},
"contact": {
"access_pin": "PIN de acceso",
"add_contact": "Agregar contacto",
"create_contact": "Crear contacto",
"currently_selected_contact": "Contacto seleccionado actualmente: {{contact}}",
"delete": "¿Borrar contacto?",
"error_assign": "Error al intentar asignar el contacto: {{error}}",
"error_creation": "Error al intentar crear contacto: {{error}}",
"error_delete": "Error al intentar eliminar el contacto: {{error}}",
"error_fetching_list": "Error al obtener los contactos",
"error_fetching_single": "Error al obtener el contacto: {{error}}",
"error_unassign": "Error al intentar anular la asignación del contacto: {{error}}",
"first_name": "Nombre de pila",
"identifier": "Identificador",
"initials": "Iniciales",
"last_name": "Apellido",
"no_associated_contact": "Sin contacto asociado",
"primary_email": "Correo electrónico principal",
"salutation": "saludo",
"secondary_email": "Email secundario",
"successful_assign": "¡Contacto asignado correctamente!",
"successful_creation": "Contacto Creado!",
"successful_delete": "¡Contacto eliminado con éxito!",
"successful_unassign": "Contacto no asignado correctamente",
"successful_update": "Contacto actualizado con éxito",
"title": "Contactos",
"type": "Tipo",
"update_error": "Error al actualizar el contacto: {{error}}",
"user_title": "Título",
"visual": "Nombre de correspondencia"
},
"delete_command": {
"explanation": "¿Está seguro de que desea eliminar este comando? Esta acción no es reversible.",
"title": "Eliminar comando"
@@ -236,8 +300,12 @@
"healthchecks_title": "Eliminar comprobaciones de estado"
},
"device": {
"certificate_explanation": "Certificados de dispositivos conectados",
"error_fetching_device": "Error al obtener la información del dispositivo: {{error}}",
"error_fetching_devices": "Error al recuperar dispositivos: {{error}}"
"error_fetching_devices": "Error al recuperar dispositivos: {{error}}",
"health_explanation": "Salud de los dispositivos conectados",
"memory_explanation": "Memoria utilizada por dispositivos conectados",
"uptimes_explanation": "Tiempo que los dispositivos conectados han estado en funcionamiento y conectados"
},
"device_logs": {
"log": "Iniciar sesión",
@@ -247,6 +315,7 @@
"entity": {
"add_child": "Agregar entidad secundaria a {{entityName}}",
"add_failure": "Error, el servidor devolvió: {{error}}",
"add_ips": "Administrar direcciones IP",
"add_root": "Agregar entidad raíz",
"add_success": "¡Entidad creada con éxito!",
"assigned_inventory": "Inventario asignado",
@@ -256,13 +325,26 @@
"delete_success": "Entidad eliminada correctamente",
"delete_warning": "Advertencia: esta operación no se puede revertir",
"edit_failure": "Actualización fallida: {{error}}",
"enter_here": "Ingrese las IP que desea agregar aquí",
"entire_tree": "Site MAp",
"entities": "entidades",
"entity": "Entidad",
"error_fetch_entity": "Error al obtener la información de la entidad",
"error_fetching": "Error al recuperar entidades",
"error_fetching_map": "Error al obtener el mapa: {{error}}",
"error_saving": "Error al guardar la entidad",
"higher_priority": "Dar mayor prioridad",
"ip_detection": "Detección de IP",
"ip_formats": "Puede agregar direcciones IPv4 o IPv6 en los siguientes formatos:",
"lower_priority": "Hacer una prioridad más baja",
"need_select_entity": "Debe seleccionar una entidad de la siguiente tabla",
"no_ips": "No se seleccionaron direcciones IP",
"not_assigned": "No asignado",
"only_unassigned": "Solo sin asignar",
"select_entity": "Seleccione esta entidad",
"selected_entity": "Entidad seleccionada",
"selected_map": "Mapa seleccionado",
"update_failure_error": "Error al intentar actualizar la entidad: {{error}}",
"valid_serial": "Debe ser un número de serie válido (12 caracteres HEX)",
"venues": "Sedes"
},
@@ -274,6 +356,7 @@
"warning": "Advertencia: una vez que envíe, esto no se podrá revertir"
},
"firmware": {
"age_explanation": "Número medio de días para todos los dispositivos de los que podemos obtener ese valor",
"average_age": "Edad promedio del firmware",
"choose_custom": "Escoger",
"details_title": "Detalles de la imagen n. °{{image}} ",
@@ -286,9 +369,11 @@
"image": "Imagen",
"image_date": "Fecha de la imagen",
"installed_firmware": "Firmware instalado",
"latest_explanation": "Dispositivos que ejecutan firmware reconocido en su última versión",
"latest_version_installed": "Última versión instalada",
"newer_firmware_available": "Nuevas revisiones disponibles",
"reinstall_latest": "Reinstalar",
"release": "Lanzamiento",
"revision": "Revisión",
"show_dev": "Mostrar lanzamientos para desarrolladores",
"size": "Tamaño",
@@ -317,6 +402,7 @@
"add_tag": "Crear etiqueta",
"add_tag_to": "Agregar nuevo dispositivo a {{name}}",
"add_venue": "Agregar lugar",
"assign_ent_ven": "Asignar a entidad o lugar",
"assign_entity_instructions": "Puede encontrar la entidad a la que desea que se asigne esta etiqueta utilizando el menú a continuación, o puede pegar manualmente el UUID de la entidad en el campo de arriba.",
"assign_error": "Error al intentar asignar la etiqueta",
"assign_to_entity": "Asignar a entidad",
@@ -348,6 +434,7 @@
"error_create_venue": "Error al crear el lugar",
"error_delete_tag": "Error al eliminar la etiqueta de inventario",
"error_get_venue": "Error al recuperar lugares",
"error_pushing_config": "Error al intentar enviar la configuración al dispositivo: {{error}}",
"error_retrieving": "Se produjo un error al recuperar las etiquetas de inventario",
"error_unassign": "Error durante la operación de anulación de asignación",
"error_update_venue": "Error al actualizar el lugar",
@@ -393,15 +480,46 @@
"unassigned_deleted_devices": "{{number}} Dispositivos eliminados y sin asignar",
"unassigned_tags": "Etiquetas sin asignar",
"validating_import_file": "Validando archivo y datos de importación ...",
"venue": "Lugar de encuentro"
"venue": "Lugar de encuentro",
"view_in_gateway": "Ver en Gateway"
},
"location": {
"add": "Añade una ubicación",
"building_name": "Nombre del edificio",
"city": "ciudad",
"country": "País",
"create": "Crear ubicación",
"currently_selected": "Ubicación seleccionada actualmente: {{location}}",
"delete": "¿Eliminar ubicación?",
"error_assign": "Error al intentar asignar la ubicación: {{error}}",
"error_creation": "Error al intentar crear ubicaciones: {{error}}",
"error_delete": "Error al eliminar la ubicación: {{error}}",
"error_fetching_single": "Error al intentar obtener la ubicación: {{error}}",
"geocode": "Geocode",
"mobiles": "MOBILES",
"no_associated": "Sin ubicación asociada",
"phones": "Los telefonos",
"postal": "código postal",
"search": "Busque ubicaciones para completar automáticamente los campos a continuación",
"state": "Estado",
"street_address": "Dirección",
"successful_creation": "¡Ubicación creada con éxito!",
"successful_delete": "¡Ubicación eliminada con éxito!",
"successful_update": "¡Ubicación actualizada con éxito!",
"successfully_assigned": "¡Ubicación asignada correctamente!",
"title": "Ubicaciones",
"update_error": "Error al actualizar la ubicación: {{error}}"
},
"login": {
"account_verification": "Verificación de la cuenta",
"authentication_expired": "Autenticación caducada, vuelva a iniciar el proceso de inicio de sesión",
"change_password": "Cambia la contraseña",
"change_password_error": "Error al cambiar la contraseña. Asegúrese de que la nueva contraseña sea válida visitando la página 'Política de contraseñas'",
"change_password_instructions": "Ingrese y confirme su nueva contraseña",
"changing_password": "Cambio de contraseña ...",
"confirm_new_password": "confirmar nueva contraseña",
"different_passwords": "Debes ingresar la misma contraseña dos veces",
"email_code_validation": "Por favor, marque su casilla de correo electrónico e ingrese el código de verificación que le acabamos de enviar en la casilla a continuación.",
"forgot_password_error": "Error al intentar enviar el correo electrónico de Olvidé mi contraseña. Asegúrese de que este ID de usuario esté asociado a una cuenta.",
"forgot_password_explanation": "Ingrese su nombre de usuario para recibir un correo electrónico con las instrucciones para restablecer su contraseña",
"forgot_password_success": "Pronto debería recibir un correo electrónico con las instrucciones para restablecer su contraseña. Asegúrese de verificar su correo no deseado si no puede encontrar el correo electrónico",
@@ -410,6 +528,7 @@
"login_error": "Error de inicio de sesión, asegúrese de que la información que proporciona sea válida",
"new_password": "Nueva contraseña",
"password": "Contraseña",
"phone_validation_explanation": "Verifique su dispositivo móvil e ingrese el código de verificación que le acabamos de enviar en el cuadro a continuación",
"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",
@@ -418,7 +537,9 @@
"sending_ellipsis": "Enviando...",
"sign_in_to_account": "Iniciar sesión en su cuenta",
"url": "URL de uCentralSec",
"username": "Nombre de usuario"
"username": "Nombre de usuario",
"verification_code": "Ingrese su verificación aquí",
"wrong_code": "El código de verificación que se ingresó no es válido."
},
"reboot": {
"directions": "¿Cuándo le gustaría reiniciar este dispositivo?",
@@ -439,6 +560,59 @@
"settings": {
"title": "Ajustes"
},
"simulation": {
"add": "Agregar simulación",
"cancel": "Cancelar",
"cancel_success": "¡La ejecución de la simulación se canceló con éxito!",
"check_ongoing_sims": "Seguir Sim en curso",
"client_interval": "Intervalo de cliente",
"delete_simulation": "Eliminar Sim. {{name}}",
"end": "Término",
"error_creating": "Error al crear la simulación: {{error}}",
"error_delete": "Error al eliminar la simulación: {{error}}",
"error_devices": "Dispositivos de error",
"error_edit": "Error al intentar guardar la simulación: {{error}}",
"error_edit_run": "Error al intentar cambiar el estado de ejecución: {{error}}",
"error_fetching_simulations": "Error al obtener simulaciones: {{error}}",
"error_start_run": "Error al intentar iniciar una ejecución de simulación: {{error}}",
"gateway": "Puerta",
"healtcheck_interval": "Intervalo de comprobación de estado",
"keep_alive": "Mantener viva",
"last_refresh": "Última actualización",
"length": "Longitud",
"live_devices": "Dispositivos en vivo",
"mac_prefix": "Prefijo MAC",
"max_associations": "Max. Asociaciones",
"max_clients": "Max. Clientela",
"messages_transmitted": "Mensajes transmitidos",
"min_associations": "Min. Asociaciones",
"min_clients": "Min. Clientela",
"pause": "pausa",
"pause_success": "¡Ejecutar en pausa!",
"prefix_length": "Obligatorio, debe tener una longitud de 6 caracteres",
"previous_runs": "Ejecuciones anteriores",
"received": "recibido",
"received_messages": "Mensajes recibidos",
"reconnect_interval": "Intervalo de reconexión",
"resume": "Currículum",
"resume_success": "¡Ejecutar reanudado!",
"run": "Ejecución de simulación",
"run_simulation": "Ejecutar simulación",
"started": "Empezado",
"state_interval": "Intervalo de estado",
"stop": "Detener",
"stop_success": "¡Corre, detenido!",
"success_creating": "¡Simulación creada con éxito!",
"success_run_start": "¡Ejecución iniciada con éxito!",
"successful_delete": "¡Simulación eliminada con éxito!",
"successful_edit": "¡Simulación editada con éxito!",
"threads": "Trapos",
"time_full_devices": "Tiempo para dispositivos completos",
"title": "Simulaciones",
"transmitted": "Transmitido",
"valid_cert": "Certificado válido",
"valid_key": "Clave válida"
},
"statistics": {
"data": "Datos (KB)",
"latest_statistics": "Últimas estadísticas",
@@ -467,7 +641,7 @@
"os": "sistema operativo",
"processors": "Procesadores",
"reload": "Recargar",
"reload_subsystems": "Recargar subsistemas",
"reload_subsystems": "Recargar",
"subsystems": "Subsistemas",
"success_reload": "¡El comando de recarga se envió correctamente!"
},
@@ -506,10 +680,13 @@
"waiting_for_device": "Esperando que el dispositivo se vuelva a conectar"
},
"user": {
"add_phone_number": "Agregar el número de teléfono",
"avatar": "Tu avatar",
"avatar_file": "Tu avatar (máx. De 2 MB)",
"check_phone": "Por favor revise su teléfono para su código de validación",
"confirm_new_password": "confirmar nueva contraseña",
"create": "Crear usuario",
"create_failure": "Error al crear usuario. Asegúrese de que esta dirección de correo electrónico no esté vinculada a una cuenta.",
"create_failure": "Error al crear el usuario: {{error}}",
"create_success": "Usuario creado con éxito",
"creating": "Creando usuario ...",
"delete_avatar": "Eliminar avatar",
@@ -521,29 +698,40 @@
"description": "Descripción",
"edit": "editar usuario",
"email_address": "Dirección de correo electrónico",
"enter_new_phone": "Ingrese su nuevo número de teléfono:",
"error_fetching_users": "Error al obtener usuarios: {{error}}",
"error_retrieving": "Error al recuperar usuario",
"error_sending_code": "Error al intentar enviar el código de validación. Confirma que tu número de teléfono es válido.",
"force_password_change": "Forzar cambio de contraseña al iniciar sesión",
"id": "Id. De usuario",
"last_login": "Último acceso",
"login_id": "Ingresar identificación.",
"make_sure_same_password": "Asegúrese de que ambas contraseñas sean iguales y válidas",
"my_profile": "Mi perfil",
"name": "Nombre",
"new_code_sent": "¡Nuevo código enviado!",
"nickname": "Apodo",
"nickname_explanation": "Apodo (opcional)",
"not_validated": "No validado",
"note": "Nota",
"password": "Contraseña",
"phone_number": "Número de teléfono",
"provide_email": "Por favor ingrese su dirección de correo electrónico válida",
"provide_password": "Proporcione una contraseña válida",
"save_avatar": "Guardar avatar",
"send_code": "Enviar código",
"send_code_again": "Enviar Código De nuevo",
"show_hide_password": "Mostrar / Ocultar contraseña",
"successful_validation": "¡Número de teléfono validado! Haga clic en el botón guardar para vincularlo a su perfil",
"update_failure": "Error al intentar actualizar: {{error}}",
"update_failure_title": "Actualización fallida",
"update_success": "Usuario actualizado con éxito",
"update_success_title": "Éxito",
"user_role": "papel",
"users": "Usuarios",
"validated": "Validado"
"validate_phone": "validar",
"validated": "Validado",
"wrong_validation_code": "No ha introducido un código válido. Vuelve a intentarlo y asegúrate de haber ingresado el número de teléfono correcto."
},
"wifi_analysis": {
"association": "Asociación",

View File

@@ -22,6 +22,7 @@
"when_blink_leds": "Quand souhaitez-vous faire clignoter les LED de l'appareil ?"
},
"commands": {
"command_success": "Commande soumise avec succès",
"error": "Erreur lors de la soumission de la commande !",
"error_delete_log": "Erreur lors de la tentative de suppression : {{error}}",
"event_queue": "File d'attente d'événements",
@@ -32,6 +33,9 @@
"common": {
"access_policy": "Politique d'accès",
"add": "Ajouter",
"add_items": "Ajouter des articles",
"add_note": "Ajouter une note",
"add_note_explanation": "Écrivez votre nouvelle note ci-dessous et cliquez sur le bouton '+' où vous avez terminé",
"adding_ellipsis": "Ajouter...",
"are_you_sure": "Êtes-vous sûr?",
"back_to_login": "Retour connexion",
@@ -42,13 +46,16 @@
"certificates": "Certificats",
"clear": "Clair",
"close": "Fermer",
"code": "Code",
"command": "Commander",
"commands": "Les commandes",
"commands_executed": "commandes exécutées",
"compatible": "Compatible",
"completed": "Terminé",
"concurrent_devices": "Périphériques simultanés",
"config_id": "Config. Identifiant",
"confirm": "Confirmer",
"confirm_stop_editing": "Voulez-vous vraiment arrêter la modification ? Cela annulera toutes les modifications non enregistrées que vous avez apportées.",
"connected": "Connecté",
"copied": "Copié!",
"copy_to_clipboard": "Copier dans le presse-papier",
@@ -66,7 +73,7 @@
"details": "Détails",
"device": "N° d'appareil{{serialNumber}}",
"device_dashboard": "Tableau de bord de l'appareil",
"device_delete": "Supprimer l'appareil n°{{serialNumber}}",
"device_delete": "Supprimer #{{serialNumber}}",
"device_deleted": "Appareil supprimé avec succès",
"device_health": "Santé de l'appareil",
"device_list": "Liste des appareils",
@@ -86,6 +93,7 @@
"endpoints": "Points de terminaison",
"error": "Erreur",
"error_adding_note": "Erreur lors de l'ajout de la note",
"error_code": "Code d'erreur",
"execute_now": "Souhaitez-vous exécuter cette commande maintenant ?",
"executed": "réalisé",
"exit": "Sortie",
@@ -96,12 +104,21 @@
"forgot_password_title": "Mot de passe oublié",
"from": "De",
"general_error": "Erreur API, veuillez consulter votre administrateur",
"go_back": "Retourner",
"hide": "Cacher",
"hour": "heure",
"hours": "heures",
"id": "Id",
"invalid_credentials": "Nom d'utilisateur et / ou mot de passe incorrect",
"invalid_file": "Le fichier choisi n'était pas valide, veuillez lire les instructions et ajuster votre fichier en conséquence",
"invalid_password": "Ce mot de passe ne confirme pas les règles de base des mots de passe. Veuillez visiter notre page Politique de mot de passe pour en savoir plus",
"invalid_pem": "Votre fichier .pem n'est pas valide. Il doit commencer par '-----BEGIN CERTIFICATE-----' OU '-----BEGIN PRIVATE KEY-----' et il doit se terminer par '-----END CERTIFICATE--- --' OU '-----FIN CLÉ PRIVÉE-----'",
"ip_address": "Adresse IP",
"ips": "IPS",
"item": "article",
"items": "Articles",
"items_per_page": "Objets par page:",
"key": "Clé",
"last_dashboard_refresh": "Dernière actualisation du tableau de bord",
"later_tonight": "Plus tard ce soir",
"latest": "Dernier",
@@ -110,14 +127,17 @@
"loading_more_ellipsis": "Chargement plus ...",
"logout": "Connectez - Out",
"mac": "ADRESSE MAC",
"main": "Principale",
"manufacturer": "fabricant",
"memory_used": "Mémoire utilisée",
"min_max": "Min : {{min}}, Max : {{max}}",
"minute": "minute",
"minutes": "minutes",
"modified": "Modifié",
"na": "N / A",
"need_date": "Vous avez besoin d'un rendez-vous...",
"no": "Non",
"no_addresses_found": "Aucune adresse trouvée",
"no_devices_found": "Aucun périphérique trouvé",
"no_items": "Pas d'objet",
"none": "Aucun",
@@ -129,6 +149,7 @@
"overall_health": "Santé globale",
"password_policy": "Politique de mot de passe",
"preview": "Aperçu",
"program": "Programme",
"recorded": "Enregistré",
"refresh": "Rafraîchir",
"refresh_device": "Actualiser l'appareil",
@@ -142,6 +163,9 @@
"second": "seconde",
"seconds": "secondes",
"seconds_elapsed": "Secondes écoulées",
"see_details": "Voir les détails",
"select": "sélectionner",
"serial_num": "Numéro de série",
"serial_number": "Numéro de série",
"show_all": "Montre tout",
"socket_connection_closed": "Connexion fermée !",
@@ -162,6 +186,7 @@
"unknown": "Inconnu",
"up_to_date": "Appareils à jour",
"uptimes": "Disponibilités",
"use_file": "Utiliser le fichier",
"uuid": "UUID",
"vendors": "Vendeurs",
"view_more": "Afficher plus",
@@ -170,7 +195,11 @@
"configuration": {
"add_configuration": "Ajouter une configuration",
"add_new_block": "Ajouter un nouveau bloc de configuration",
"add_or_link": "Lier ou ajouter",
"add_radio": "Ajouter une radio",
"ca_cert_explanation": "Veuillez utiliser un fichier .pem qui commence par \"-----BEGIN CERTIFICATE-----\" et se termine par \"-----END CERTIFICATE-----\". Le résultat sera affiché dans le champ ci-dessous. Vous pouvez également copier et coller le certificat que vous souhaitez utiliser directement.",
"cannot_delete": "Cette configuration ne peut pas être supprimée car elle est utilisée par au moins une entité, un lieu ou un appareil",
"choose_radio_band": "Quelle bande de radio voudriez-vous créer ?",
"choose_section": "Quelle section souhaitez-vous que ce bloc contienne?",
"configuration_browser": "Navigateur de configuration",
"configurations": "Les configurations",
@@ -186,12 +215,14 @@
"device_password": "Mot de passe",
"device_type": "Type d'appareil",
"device_types": "Types d'appareils",
"devices_affected": "Appareils concernés par cette configuration :",
"edit_configuration": "Modifier la configuration",
"error_delete": "Erreur lors de la tentative de suppression : {{error}}",
"error_fetching_config": "Erreur lors de la récupération de la configuration",
"error_trying_delete": "Erreur lors de la tentative de suppression : {{error}}",
"error_update": "Erreur: {{error}}",
"explanation": "Explication",
"key_pem_explanation": "Veuillez sélectionner le fichier .pem",
"last_configuration_change": "Changement de configuration",
"last_configuration_download": "Téléchargement de la dernière configuration",
"location": "Emplacement",
@@ -212,6 +243,8 @@
"used_by": "Utilisé par",
"used_by_details": "{{entities}} Entités, {{venues}} Lieux et {{devices}} Appareils",
"uuid": "Identifiant de configuration",
"view_affected_devices": "Afficher les appareils concernés",
"view_config": "Afficher la configuration",
"view_in_use": "Afficher en cours d'utilisation",
"view_json": "Afficher le JSON brut"
},
@@ -225,6 +258,37 @@
"connect": {
"error_trying_to_connect": "Erreur lors de la tentative de connexion à l'appareil : {{error}}"
},
"contact": {
"access_pin": "NIP d'accès",
"add_contact": "Ajouter le contact",
"create_contact": "Créer un contact",
"currently_selected_contact": "Contact actuellement sélectionné : {{contact}}",
"delete": "Effacer le contact?",
"error_assign": "Erreur lors de la tentative d'attribution du contact : {{error}}",
"error_creation": "Erreur lors de la tentative de création du contact : {{error}}",
"error_delete": "Erreur lors de la tentative de suppression du contact : {{error}}",
"error_fetching_list": "Erreur lors de la récupération des contacts",
"error_fetching_single": "Erreur lors de la récupération du contact : {{error}}",
"error_unassign": "Erreur lors de la tentative de désattribution du contact : {{error}}",
"first_name": "Prénom",
"identifier": "Identifiant",
"initials": "Initiales",
"last_name": "Nom de famille",
"no_associated_contact": "Aucun contact associé",
"primary_email": "Email primaire",
"salutation": "salutation",
"secondary_email": "Email secondaire",
"successful_assign": "Contact attribué avec succès !",
"successful_creation": "Contact créé!",
"successful_delete": "Contact supprimé avec succès !",
"successful_unassign": "Contact non attribué avec succès",
"successful_update": "Contact mis à jour avec succès",
"title": "Contacts",
"type": "Type",
"update_error": "Erreur lors de la mise à jour du contact : {{error}}",
"user_title": "Titre",
"visual": "Nom de la correspondance"
},
"delete_command": {
"explanation": "Êtes-vous sûr de vouloir supprimer cette commande ? Cette action n'est pas réversible.",
"title": "Supprimer la commande"
@@ -236,8 +300,12 @@
"healthchecks_title": "Supprimer les vérifications d'état"
},
"device": {
"certificate_explanation": "Certificats des appareils connectés",
"error_fetching_device": "Erreur lors de la récupération des informations sur l'appareil : {{error}}",
"error_fetching_devices": "Erreur lors de la récupération des appareils : {{error}}"
"error_fetching_devices": "Erreur lors de la récupération des appareils : {{error}}",
"health_explanation": "Santé des appareils connectés",
"memory_explanation": "Mémoire utilisée par les appareils connectés",
"uptimes_explanation": "Heure à laquelle les appareils connectés ont été activés et connectés"
},
"device_logs": {
"log": "Bûche",
@@ -247,6 +315,7 @@
"entity": {
"add_child": "Ajouter une entité enfant à {{entityName}}",
"add_failure": "Erreur, le serveur a renvoyé : {{error}}",
"add_ips": "Gérer les IP",
"add_root": "Ajouter une entité racine",
"add_success": "Entité créée avec succès !",
"assigned_inventory": "Inventaire assigné",
@@ -256,13 +325,26 @@
"delete_success": "Entité supprimée avec succès",
"delete_warning": "Attention : cette opération ne peut pas être annulée",
"edit_failure": "Échec de la mise à jour : {{error}}",
"enter_here": "Entrez les IP que vous souhaitez ajouter ici",
"entire_tree": "Site MAp",
"entities": "Entités",
"entity": "Entité",
"error_fetch_entity": "Erreur lors de la récupération des informations sur l'entité",
"error_fetching": "Erreur lors de la récupération des entités",
"error_fetching_map": "Erreur lors de la récupération de la carte : {{error}}",
"error_saving": "Erreur lors de l'enregistrement de l'entité",
"higher_priority": "Faire une priorité plus élevée",
"ip_detection": "Détection IP",
"ip_formats": "Vous pouvez ajouter des adresses IPv4 ou IPv6 aux formats suivants :",
"lower_priority": "Faire une priorité inférieure",
"need_select_entity": "Vous devez sélectionner une entité dans le tableau ci-dessous",
"no_ips": "Aucune adresse IP sélectionnée",
"not_assigned": "Non attribué",
"only_unassigned": "Uniquement non attribué",
"select_entity": "Sélectionnez cette entité",
"selected_entity": "Entité sélectionnée",
"selected_map": "Carte sélectionnée",
"update_failure_error": "Erreur lors de la tentative de mise à jour de l'entité : {{error}}",
"valid_serial": "Doit être un numéro de série valide (12 caractères HEX)",
"venues": "Les lieux"
},
@@ -274,6 +356,7 @@
"warning": "Avertissement : Une fois que vous avez soumis, cela ne peut pas être annulé"
},
"firmware": {
"age_explanation": "Nombre moyen de jours pour tous les appareils à partir desquels nous pouvons obtenir cette valeur",
"average_age": "Âge moyen du micrologiciel",
"choose_custom": "Choisir",
"details_title": "Image #{{image}} Détails",
@@ -286,9 +369,11 @@
"image": "Image",
"image_date": "Date de l'image",
"installed_firmware": "Micrologiciel installé",
"latest_explanation": "Appareils exécutant un firmware reconnu dans sa dernière version",
"latest_version_installed": "Dernière version installée",
"newer_firmware_available": "Révisions plus récentes disponibles",
"reinstall_latest": "Réinstaller",
"release": "libération",
"revision": "Révision",
"show_dev": "Afficher les versions des développeurs",
"size": "Taille",
@@ -317,6 +402,7 @@
"add_tag": "Créer un tag",
"add_tag_to": "Ajouter un nouvel appareil à {{name}}",
"add_venue": "Ajouter un lieu",
"assign_ent_ven": "Attribuer à une entité ou à un lieu",
"assign_entity_instructions": "Vous pouvez soit trouver l'entité à laquelle vous souhaitez que cette balise soit attribuée en utilisant le menu ci-dessous, soit coller manuellement l'UUID de l'entité dans le champ ci-dessus.",
"assign_error": "Erreur lors de la tentative d'attribution de balise",
"assign_to_entity": "Affecter à l'entité",
@@ -348,6 +434,7 @@
"error_create_venue": "Erreur lors de la création du lieu",
"error_delete_tag": "Erreur lors de la suppression de la balise d'inventaire",
"error_get_venue": "Erreur lors de la récupération des lieux",
"error_pushing_config": "Erreur lors de la tentative d'envoi de la configuration sur l'appareil : {{error}}",
"error_retrieving": "Une erreur s'est produite lors de la récupération des balises d'inventaire",
"error_unassign": "Erreur lors de l'opération de désaffectation",
"error_update_venue": "Erreur lors de la mise à jour du lieu",
@@ -393,15 +480,46 @@
"unassigned_deleted_devices": "{{number}} appareils supprimés et non attribués",
"unassigned_tags": "Balises non attribuées",
"validating_import_file": "Validation du fichier d'importation et des données...",
"venue": "Lieu"
"venue": "Lieu",
"view_in_gateway": "Afficher dans la passerelle"
},
"location": {
"add": "Ajouter un emplacement",
"building_name": "Nom du bâtiment",
"city": "Ville",
"country": "Pays",
"create": "Créer un lieu",
"currently_selected": "Emplacement actuellement sélectionné : {{location}}",
"delete": "Supprimer le lieu?",
"error_assign": "Erreur lors de la tentative d'attribution de l'emplacement : {{error}}",
"error_creation": "Erreur lors de la tentative de création d'établissements : {{error}}",
"error_delete": "Erreur lors de la suppression de l'emplacement : {{error}}",
"error_fetching_single": "Erreur lors de la tentative de récupération de l'emplacement : {{error}}",
"geocode": "Géocode",
"mobiles": "MOBILES",
"no_associated": "Aucun emplacement associé",
"phones": "Téléphones",
"postal": "Zip / code postal",
"search": "Recherchez des emplacements pour remplir automatiquement les champs ci-dessous",
"state": "Etat",
"street_address": "Adresse de rue",
"successful_creation": "Emplacement créé avec succès !",
"successful_delete": "Emplacement supprimé avec succès !",
"successful_update": "Emplacement mis à jour avec succès !",
"successfully_assigned": "Emplacement attribué avec succès !",
"title": "Emplacements",
"update_error": "Erreur lors de la mise à jour de l'emplacement : {{error}}"
},
"login": {
"account_verification": "Vérification de compte",
"authentication_expired": "Authentification expirée, veuillez recommencer le processus de connexion",
"change_password": "Changer le mot de passe",
"change_password_error": "Erreur lors du changement de mot de passe. Assurez-vous que le nouveau mot de passe est valide en visitant la page « Politique de mot de passe »",
"change_password_instructions": "Saisissez et confirmez votre nouveau mot de passe",
"changing_password": "Modification du mot de passe...",
"confirm_new_password": "Confirmer le nouveau mot de passe",
"different_passwords": "Vous devez saisir deux fois le même mot de passe",
"email_code_validation": "Veuillez vérifier votre boîte e-mail et entrer le code de vérification que nous venons de vous envoyer dans la case ci-dessous",
"forgot_password_error": "Erreur lors de la tentative d'envoi de l'e-mail Mot de passe oublié. Veuillez vous assurer que cet identifiant est associé à un compte.",
"forgot_password_explanation": "Entrez votre nom d'utilisateur pour recevoir un e-mail contenant les instructions pour réinitialiser votre mot de passe",
"forgot_password_success": "Vous devriez bientôt recevoir un e-mail contenant les instructions pour réinitialiser votre mot de passe. S'il vous plaît assurez-vous de vérifier vos spams si vous ne trouvez pas l'e-mail",
@@ -410,6 +528,7 @@
"login_error": "Erreur de connexion, assurez-vous que les informations que vous fournissez sont valides",
"new_password": "Nouveau mot de passe",
"password": "Mot de passe",
"phone_validation_explanation": "Veuillez vérifier votre appareil mobile et entrer le code de vérification que nous venons de vous envoyer dans la case ci-dessous",
"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",
@@ -418,7 +537,9 @@
"sending_ellipsis": "Envoi...",
"sign_in_to_account": "Connectez-vous à votre compte",
"url": "URL uCentralSec",
"username": "Nom d'utilisateur"
"username": "Nom d'utilisateur",
"verification_code": "Entrez votre vérification ici",
"wrong_code": "Le code de vérification saisi n'est pas valide."
},
"reboot": {
"directions": "Quand souhaitez-vous redémarrer cet appareil ?",
@@ -439,6 +560,59 @@
"settings": {
"title": "Réglages"
},
"simulation": {
"add": "Ajouter une simulation",
"cancel": "annuler",
"cancel_success": "Exécution de la simulation annulée avec succès !",
"check_ongoing_sims": "Suivre le Sim en cours",
"client_interval": "Intervalle client",
"delete_simulation": "Supprimer Sim. {{name}}",
"end": "Terminé",
"error_creating": "Erreur lors de la création de la simulation : {{error}}",
"error_delete": "Erreur lors de la suppression de la simulation : {{error}}",
"error_devices": "Périphériques d'erreur",
"error_edit": "Erreur lors de la tentative d'enregistrement de la simulation : {{error}}",
"error_edit_run": "Erreur lors de la tentative de modification de l'état d'exécution : {{error}}",
"error_fetching_simulations": "Erreur lors de la récupération des simulations : {{error}}",
"error_start_run": "Erreur lors de la tentative de démarrage d'une simulation : {{error}}",
"gateway": "passerelle",
"healtcheck_interval": "Intervalle de vérification de l'état",
"keep_alive": "Rester en vie",
"last_refresh": "Dernier rafraîchissement",
"length": "Longueur",
"live_devices": "Appareils en direct",
"mac_prefix": "Préfixe MAC",
"max_associations": "Max. Les associations",
"max_clients": "Max. Clients",
"messages_transmitted": "Messages transmis",
"min_associations": "Min. Les associations",
"min_clients": "Min. Clients",
"pause": "Pause",
"pause_success": "Exécuter en pause !",
"prefix_length": "Obligatoire, doit être d'une longueur de 6 caractères",
"previous_runs": "Courses précédentes",
"received": "reçu",
"received_messages": "Messages reçus",
"reconnect_interval": "Intervalle de reconnexion",
"resume": "CV",
"resume_success": "Exécution reprise !",
"run": "Exécution de simulation",
"run_simulation": "Exécuter la simulation",
"started": "commencé",
"state_interval": "Intervalle d'état",
"stop": "Arrêtez",
"stop_success": "Exécution arrêtée !",
"success_creating": "Simulation créée avec succès !",
"success_run_start": "Exécution démarrée avec succès !",
"successful_delete": "Simulation supprimée avec succès !",
"successful_edit": "Simulation éditée avec succès !",
"threads": "Fils",
"time_full_devices": "Temps pour les appareils pleins",
"title": "Simulations",
"transmitted": "Transmis",
"valid_cert": "Certificat valide",
"valid_key": "Clé valide"
},
"statistics": {
"data": "Données (Ko)",
"latest_statistics": "Dernières statistiques",
@@ -467,7 +641,7 @@
"os": "le système d'exploitation",
"processors": "Processeurs",
"reload": "Recharger",
"reload_subsystems": "Recharger les sous-systèmes",
"reload_subsystems": "Recharger",
"subsystems": "Sous-systèmes",
"success_reload": "Recharger la commande soumise avec succès !"
},
@@ -506,10 +680,13 @@
"waiting_for_device": "En attente de la reconnexion de l'appareil"
},
"user": {
"add_phone_number": "Ajouter un numéro de téléphone",
"avatar": "Votre avatar",
"avatar_file": "Votre Avatar (max. de 2 Mo)",
"check_phone": "Veuillez vérifier votre téléphone pour votre code de validation",
"confirm_new_password": "Confirmer le nouveau mot de passe",
"create": "Créer un utilisateur",
"create_failure": "Erreur lors de la création de l'utilisateur. Veuillez vous assurer que cette adresse e-mail n'est pas déjà liée à un compte.",
"create_failure": "Erreur lors de la création de l'utilisateur : {{error}}",
"create_success": "L'utilisateur a été créé avec succès",
"creating": "Création de l'utilisateur...",
"delete_avatar": "Supprimer l'avatar",
@@ -521,29 +698,40 @@
"description": "La description",
"edit": "Modifier l'utilisateur",
"email_address": "Adresse électronique",
"enter_new_phone": "Saisissez votre nouveau numéro de téléphone :",
"error_fetching_users": "Erreur lors de la récupération des utilisateurs : {{error}}",
"error_retrieving": "Erreur lors de la récupération de l'utilisateur",
"error_sending_code": "Erreur lors de la tentative d'envoi du code de validation. Veuillez confirmer que votre numéro de téléphone est valide.",
"force_password_change": "Forcer le changement de mot de passe lors de la connexion",
"id": "Identifiant d'utilisateur.",
"last_login": "Dernière connexion",
"login_id": "Identifiant de connexion.",
"make_sure_same_password": "Assurez-vous que les deux mots de passe sont identiques et valides",
"my_profile": "Mon profil",
"name": "Prénom",
"new_code_sent": "Nouveau code envoyé !",
"nickname": "Surnom",
"nickname_explanation": "Surnom (optionnel)",
"not_validated": "Pas valide",
"note": "Remarque",
"password": "Mot de passe",
"phone_number": "Numéro de téléphone",
"provide_email": "Veuillez fournir une adresse email valide",
"provide_password": "Veuillez fournir un mot de passe valide",
"save_avatar": "Enregistrer l'avatar",
"send_code": "Envoyer le code",
"send_code_again": "Envoyer code à nouveau",
"show_hide_password": "Afficher/Masquer le mot de passe",
"successful_validation": "Numéro de téléphone validé ! Cliquez sur le bouton Enregistrer pour le lier à votre profil",
"update_failure": "Erreur lors de la tentative de mise à jour : {{error}}",
"update_failure_title": "mise à jour a échoué",
"update_success": "L'utilisateur a bien été mis à jour",
"update_success_title": "Succès",
"user_role": "Rôle",
"users": "Utilisateurs",
"validated": "Validé"
"validate_phone": "Valider",
"validated": "Validé",
"wrong_validation_code": "Vous n'avez pas entré de code valide. Veuillez réessayer et assurez-vous d'avoir entré le bon numéro de téléphone"
},
"wifi_analysis": {
"association": "Association",

View File

@@ -22,6 +22,7 @@
"when_blink_leds": "Quando você gostaria de fazer os LEDs do dispositivo piscarem?"
},
"commands": {
"command_success": "Comando enviado com sucesso",
"error": "Erro ao enviar comando!",
"error_delete_log": "Erro ao tentar excluir: {{error}}",
"event_queue": "Fila de Eventos",
@@ -32,6 +33,9 @@
"common": {
"access_policy": "Política de Acesso",
"add": "Adicionar",
"add_items": "Adicionar itens",
"add_note": "Adicionar nota",
"add_note_explanation": "Escreva sua nova nota abaixo e clique no botão '+' quando terminar",
"adding_ellipsis": "Adicionando ...",
"are_you_sure": "Você tem certeza?",
"back_to_login": "Volte ao login",
@@ -42,13 +46,16 @@
"certificates": "Certificados",
"clear": "Claro",
"close": "Perto",
"code": "Código",
"command": "Comando",
"commands": "comandos",
"commands_executed": "Comandos Executados",
"compatible": "Compatível",
"completed": "Concluído",
"concurrent_devices": "Dispositivos Simultâneos",
"config_id": "Config. Identidade",
"confirm": "confirme",
"confirm_stop_editing": "Tem certeza que deseja parar de editar? Isso cancelará todas as alterações não salvas que você fez.",
"connected": "Conectado",
"copied": "Copiado!",
"copy_to_clipboard": "Copiar para área de transferência",
@@ -66,7 +73,7 @@
"details": "Detalhes",
"device": "Dispositivo nº{{serialNumber}}",
"device_dashboard": "Painel do dispositivo",
"device_delete": "Excluir dispositivo nº{{serialNumber}}",
"device_delete": "Excluir #{{serialNumber}}",
"device_deleted": "Dispositivo excluído com sucesso",
"device_health": "Saúde do Dispositivo",
"device_list": "Lista de Dispositivos",
@@ -86,6 +93,7 @@
"endpoints": "Pontos finais",
"error": "Erro",
"error_adding_note": "Erro ao adicionar nota",
"error_code": "Erro de código",
"execute_now": "Você gostaria de executar este comando agora?",
"executed": "Executado",
"exit": "Saída",
@@ -96,12 +104,21 @@
"forgot_password_title": "Esqueceu a senha",
"from": "De",
"general_error": "Erro de API, consulte o seu administrador",
"go_back": "Volte",
"hide": "Ocultar",
"hour": "hora",
"hours": "horas",
"id": "identidade",
"invalid_credentials": "Nome de usuário e / ou senha inválidos",
"invalid_file": "O arquivo escolhido era inválido, por favor, leia as instruções e ajuste seu arquivo de acordo",
"invalid_password": "Esta senha não está de acordo com as regras básicas de senha. Visite nossa página de Política de Senha para saber mais",
"invalid_pem": "Seu arquivo .pem é inválido. Deve começar com '----- BEGIN CERTIFICATE -----' OU '----- BEGIN PRIVATE KEY -----' e deve terminar com '----- END CERTIFICATE --- - 'OU' ----- END PRIVATE KEY ----- '",
"ip_address": "Endereço de IP",
"ips": "IPs",
"item": "Item",
"items": "Unid",
"items_per_page": "Itens por página:",
"key": "Chave",
"last_dashboard_refresh": "Última atualização do painel",
"later_tonight": "Logo à noite",
"latest": "Mais recentes",
@@ -110,14 +127,17 @@
"loading_more_ellipsis": "Carregando mais ...",
"logout": "Sair",
"mac": "Endereço MAC",
"main": "a Principal",
"manufacturer": "Fabricante",
"memory_used": "Memória Usada",
"min_max": "Mín: {{min}}, Máx: {{max}}",
"minute": "minuto",
"minutes": "minutos",
"modified": "Modificado",
"na": "N / D",
"need_date": "Você precisa de um encontro ...",
"no": "Não",
"no_addresses_found": "Nenhum endereço encontrado",
"no_devices_found": "Nenhum dispositivo encontrado",
"no_items": "Nenhum item",
"none": "Nenhum",
@@ -129,6 +149,7 @@
"overall_health": "Saúde geral",
"password_policy": "Política de Senha",
"preview": "Visualizar",
"program": "Programa",
"recorded": "Gravado",
"refresh": "REFRESH",
"refresh_device": "Atualizar dispositivo",
@@ -142,6 +163,9 @@
"second": "segundo",
"seconds": "segundos",
"seconds_elapsed": "Segundos decorridos",
"see_details": "Veja detalhes",
"select": "Selecione",
"serial_num": "Nº de série",
"serial_number": "Número de série",
"show_all": "mostre tudo",
"socket_connection_closed": "Conexão fechada!",
@@ -162,6 +186,7 @@
"unknown": "Desconhecido",
"up_to_date": "Dispositivos atualizados",
"uptimes": "Uptimes",
"use_file": "Usar arquivo",
"uuid": "UUID",
"vendors": "Vendedores",
"view_more": "Veja mais",
@@ -170,7 +195,11 @@
"configuration": {
"add_configuration": "Adicionar configuração",
"add_new_block": "Adicionar novo bloco de configuração",
"add_or_link": "Link ou adicionar",
"add_radio": "Adicionar rádio",
"ca_cert_explanation": "Use um arquivo .pem que comece com \"----- BEGIN CERTIFICATE -----\" e termine com \"----- END CERTIFICATE -----\". O resultado será mostrado no campo abaixo. Você também pode copiar e colar o certificado que deseja usar diretamente.",
"cannot_delete": "Esta configuração não pode ser excluída porque está sendo usada por pelo menos uma entidade, local ou dispositivo",
"choose_radio_band": "Que banda de rádio você gostaria de criar?",
"choose_section": "Qual seção você gostaria que este bloco contivesse?",
"configuration_browser": "Navegador de configuração",
"configurations": "configurações",
@@ -186,12 +215,14 @@
"device_password": "Senha",
"device_type": "Tipo de dispositivo",
"device_types": "Tipos de dispositivos",
"devices_affected": "Dispositivos afetados por esta configuração:",
"edit_configuration": "Editar configuração",
"error_delete": "Erro ao tentar excluir: {{error}}",
"error_fetching_config": "Erro ao buscar configuração",
"error_trying_delete": "Erro ao tentar excluir: {{error}}",
"error_update": "Erro: {{error}}",
"explanation": "Explicação",
"key_pem_explanation": "Selecione o arquivo .pem",
"last_configuration_change": "Mudança de configuração",
"last_configuration_download": "Último download da configuração",
"location": "Localização",
@@ -212,6 +243,8 @@
"used_by": "Usado por",
"used_by_details": "{{entities}} Entidades, {{venues}} Locais e {{devices}} Dispositivos",
"uuid": "ID de configuração",
"view_affected_devices": "Exibir dispositivos afetados",
"view_config": "Ver configuração",
"view_in_use": "Visualização em uso",
"view_json": "Exibir JSON bruto"
},
@@ -225,6 +258,37 @@
"connect": {
"error_trying_to_connect": "Erro ao tentar conectar ao dispositivo: {{error}}"
},
"contact": {
"access_pin": "PIN de acesso",
"add_contact": "Adicionar contato",
"create_contact": "Criar Contato",
"currently_selected_contact": "Contato atualmente selecionado: {{contact}}",
"delete": "Excluir contato?",
"error_assign": "Erro ao tentar atribuir contato: {{error}}",
"error_creation": "Erro ao tentar criar contato: {{error}}",
"error_delete": "Erro ao tentar excluir contato: {{error}}",
"error_fetching_list": "Erro ao buscar contatos",
"error_fetching_single": "Erro ao buscar contato: {{error}}",
"error_unassign": "Erro ao tentar cancelar a atribuição do contato: {{error}}",
"first_name": "Primeiro nome",
"identifier": "Identificador",
"initials": "Iniciais",
"last_name": "Último nome",
"no_associated_contact": "Nenhum contato associado",
"primary_email": "e-mail primário",
"salutation": "Saudação",
"secondary_email": "Email secundário",
"successful_assign": "Contato atribuído com sucesso!",
"successful_creation": "Contato criado!",
"successful_delete": "Contato excluído com sucesso!",
"successful_unassign": "Contato não atribuído com sucesso",
"successful_update": "Contato atualizado com sucesso",
"title": "Contatos",
"type": "Tipo",
"update_error": "Erro ao atualizar contato: {{error}}",
"user_title": "Título",
"visual": "Nome para Correspondência"
},
"delete_command": {
"explanation": "Tem certeza de que deseja excluir este comando? esta ação não é reversível.",
"title": "Apagar Comando"
@@ -236,8 +300,12 @@
"healthchecks_title": "Excluir verificações de saúde"
},
"device": {
"certificate_explanation": "Certificados de dispositivos conectados",
"error_fetching_device": "Erro ao buscar informações do dispositivo: {{error}}",
"error_fetching_devices": "Erro ao buscar dispositivos: {{error}}"
"error_fetching_devices": "Erro ao buscar dispositivos: {{error}}",
"health_explanation": "Saúde de dispositivos conectados",
"memory_explanation": "Memória usada por dispositivos conectados",
"uptimes_explanation": "Há tempo em que os dispositivos conectados estão ativados e conectados"
},
"device_logs": {
"log": "Registro",
@@ -247,6 +315,7 @@
"entity": {
"add_child": "Adicionar Entidade Filha a {{entityName}}",
"add_failure": "Erro, o servidor retornou: {{error}}",
"add_ips": "Gerenciar IPs",
"add_root": "Adicionar Entidade Raiz",
"add_success": "Entidade criada com sucesso!",
"assigned_inventory": "Estoque Atribuído",
@@ -256,13 +325,26 @@
"delete_success": "Entidade excluída com sucesso",
"delete_warning": "Aviso: esta operação não pode ser revertida",
"edit_failure": "Atualização malsucedida: {{error}}",
"enter_here": "Digite o (s) IP (s) que deseja adicionar aqui",
"entire_tree": "Mapa do Site",
"entities": "Entidades",
"entity": "Entidade",
"error_fetch_entity": "Erro ao buscar informações da entidade",
"error_fetching": "Erro ao buscar entidades",
"error_fetching_map": "Erro ao buscar mapa: {{error}}",
"error_saving": "Erro ao salvar entidade",
"higher_priority": "Dê maior prioridade",
"ip_detection": "Detecção de IP",
"ip_formats": "Você pode adicionar endereços IPv4 ou IPv6 nos seguintes formatos:",
"lower_priority": "Faça menor prioridade",
"need_select_entity": "Você precisa selecionar uma entidade da tabela abaixo",
"no_ips": "Nenhum IP selecionado",
"not_assigned": "Não atribuído",
"only_unassigned": "Apenas não atribuídos",
"select_entity": "Selecione esta Entidade",
"selected_entity": "Entidade Selecionada",
"selected_map": "Mapa Selecionado",
"update_failure_error": "Erro ao tentar atualizar a entidade: {{error}}",
"valid_serial": "Precisa ser um número de série válido (12 caracteres HEX)",
"venues": "Locais"
},
@@ -274,6 +356,7 @@
"warning": "Aviso: depois de enviar, isso não pode ser revertido"
},
"firmware": {
"age_explanation": "Número médio de dias para todos os dispositivos dos quais podemos obter esse valor",
"average_age": "Idade Média do Firmware",
"choose_custom": "Escolher",
"details_title": "Detalhes da imagem #{{image}} ",
@@ -286,9 +369,11 @@
"image": "Imagem",
"image_date": "Data da Imagem",
"installed_firmware": "Firmware Instalado",
"latest_explanation": "Dispositivos executando firmware reconhecido em sua versão mais recente",
"latest_version_installed": "Última versão instalada",
"newer_firmware_available": "Novas revisões disponíveis",
"reinstall_latest": "Reinstalar",
"release": "LANÇAMENTO",
"revision": "Revisão",
"show_dev": "Mostrar lançamentos de desenvolvimento",
"size": "Tamanho",
@@ -317,6 +402,7 @@
"add_tag": "Criar tag",
"add_tag_to": "Adicionar novo dispositivo a {{name}}",
"add_venue": "Adicionar Local",
"assign_ent_ven": "Atribuir à Entidade ou Local",
"assign_entity_instructions": "Você pode encontrar a entidade à qual deseja que esta tag seja atribuída usando o menu abaixo ou pode colar manualmente o UUID da entidade no campo acima.",
"assign_error": "Erro ao tentar atribuir tag",
"assign_to_entity": "Atribuir à Entidade",
@@ -348,6 +434,7 @@
"error_create_venue": "Erro ao criar local",
"error_delete_tag": "Erro ao excluir tag de inventário",
"error_get_venue": "Erro ao recuperar locais",
"error_pushing_config": "Erro ao tentar enviar a configuração para o dispositivo: {{error}}",
"error_retrieving": "Ocorreu um erro ao recuperar as tags de inventário",
"error_unassign": "Erro durante operação de cancelamento de atribuição",
"error_update_venue": "Erro ao atualizar o local",
@@ -393,15 +480,46 @@
"unassigned_deleted_devices": "{{number}} Dispositivos excluídos e não atribuídos",
"unassigned_tags": "Tags não atribuídas",
"validating_import_file": "Validando arquivo de importação e dados ...",
"venue": "Local"
"venue": "Local",
"view_in_gateway": "Ver no Gateway"
},
"location": {
"add": "Adicionar Local",
"building_name": "nome do edifício",
"city": "Cidade",
"country": "País",
"create": "Criar local",
"currently_selected": "Local selecionado atualmente: {{location}}",
"delete": "Excluir localização?",
"error_assign": "Erro ao tentar atribuir local: {{error}}",
"error_creation": "Erro ao tentar criar locais: {{error}}",
"error_delete": "Erro ao excluir localização: {{error}}",
"error_fetching_single": "Erro ao tentar buscar localização: {{error}}",
"geocode": "GeoCode",
"mobiles": "Móbiles",
"no_associated": "Sem localização associada",
"phones": "Telefones",
"postal": "CEP / Código Postal",
"search": "Pesquise locais para preencher automaticamente os campos abaixo",
"state": "Estado",
"street_address": "Endereço",
"successful_creation": "Local criado com sucesso!",
"successful_delete": "Local excluído com sucesso!",
"successful_update": "Local atualizado com sucesso!",
"successfully_assigned": "Local atribuído com sucesso!",
"title": "Localizações",
"update_error": "Erro ao atualizar local: {{error}}"
},
"login": {
"account_verification": "Verificação de conta",
"authentication_expired": "Autenticação expirada, reinicie o processo de login",
"change_password": "Mudar senha",
"change_password_error": "Erro ao alterar a senha. Certifique-se de que a nova senha é válida visitando a página 'Política de senha'",
"change_password_instructions": "Digite e confirme sua nova senha",
"changing_password": "Alterando senha ...",
"confirm_new_password": "confirme a nova senha",
"different_passwords": "Você precisa inserir a mesma senha duas vezes",
"email_code_validation": "Verifique sua caixa de e-mail e insira o código de verificação que acabamos de enviar na caixa abaixo",
"forgot_password_error": "Erro ao tentar enviar e-mail Esqueci a senha. Certifique-se de que este userId esteja associado a uma conta.",
"forgot_password_explanation": "Digite seu nome de usuário para receber um e-mail contendo as instruções para redefinir sua senha",
"forgot_password_success": "Em breve, você receberá um e-mail com as instruções para redefinir sua senha. Certifique-se de verificar o seu spam se você não conseguir encontrar o e-mail",
@@ -410,6 +528,7 @@
"login_error": "Erro de login, certifique-se de que as informações que você está fornecendo são válidas",
"new_password": "Nova senha",
"password": "Senha",
"phone_validation_explanation": "Verifique seu dispositivo móvel e insira o código de verificação que acabamos de enviar na caixa abaixo",
"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",
@@ -418,7 +537,9 @@
"sending_ellipsis": "Enviando ...",
"sign_in_to_account": "Faça login em sua conta",
"url": "URL uCentralSec",
"username": "Nome de usuário"
"username": "Nome de usuário",
"verification_code": "Insira sua verificação aqui",
"wrong_code": "O código de verificação inserido não é válido."
},
"reboot": {
"directions": "Quando você gostaria de reinicializar este dispositivo?",
@@ -439,6 +560,59 @@
"settings": {
"title": "Definições"
},
"simulation": {
"add": "Adicionar Simulação",
"cancel": "Cancelar",
"cancel_success": "Simulação cancelada com sucesso!",
"check_ongoing_sims": "Seguir Sim em Curso",
"client_interval": "Intervalo do Cliente",
"delete_simulation": "Excluir Sim. {{name}}",
"end": "Terminado",
"error_creating": "Erro ao criar simulação: {{error}}",
"error_delete": "Erro ao excluir simulação: {{error}}",
"error_devices": "Dispositivos de Erro",
"error_edit": "Erro ao tentar salvar a simulação: {{error}}",
"error_edit_run": "Erro ao tentar alterar o estado de execução: {{error}}",
"error_fetching_simulations": "Erro ao buscar simulações: {{error}}",
"error_start_run": "Erro ao tentar iniciar uma simulação: {{error}}",
"gateway": "Gateway",
"healtcheck_interval": "Intervalo de verificação de saúde",
"keep_alive": "Mantenha vivo",
"last_refresh": "Última atualização",
"length": "Comprimento",
"live_devices": "Dispositivos Live",
"mac_prefix": "Prefixo MAC",
"max_associations": "Máx. Associações",
"max_clients": "Máx. Clientes",
"messages_transmitted": "Mensagens Transmitidas",
"min_associations": "Min. Associações",
"min_clients": "Min. Clientes",
"pause": "pausa",
"pause_success": "Executar em pausa!",
"prefix_length": "Obrigatório, deve ter 6 caracteres",
"previous_runs": "Execuções anteriores",
"received": "recebido",
"received_messages": "Mensagens recebidas",
"reconnect_interval": "Intervalo de reconexão",
"resume": "Currículo",
"resume_success": "Executar retomado!",
"run": "Simulação Rodada",
"run_simulation": "Executar Simulação",
"started": "Começado",
"state_interval": "Intervalo de estado",
"stop": "Pare",
"stop_success": "Run Stopped!",
"success_creating": "Simulação criada com sucesso!",
"success_run_start": "Execução iniciada com sucesso!",
"successful_delete": "Simulação excluída com sucesso!",
"successful_edit": "Simulação editada com sucesso!",
"threads": "Tópicos",
"time_full_devices": "Tempo para dispositivos completos",
"title": "Simulações",
"transmitted": "Transmitido",
"valid_cert": "Certificado Válido",
"valid_key": "Chave Válida"
},
"statistics": {
"data": "Dados (KB)",
"latest_statistics": "Estatísticas mais recentes",
@@ -467,7 +641,7 @@
"os": "Sistema Operacional",
"processors": "Processadores",
"reload": "Recarregar",
"reload_subsystems": "Recarregar subsistemas",
"reload_subsystems": "Recarregar",
"subsystems": "Subsistemas",
"success_reload": "Comando de recarregamento enviado com sucesso!"
},
@@ -506,10 +680,13 @@
"waiting_for_device": "Esperando que o dispositivo se reconecte"
},
"user": {
"add_phone_number": "ADICIONAR NÚMERO DE TELEFONE",
"avatar": "Seu avatar",
"avatar_file": "Seu avatar (máx. De 2 MB)",
"check_phone": "Por favor, verifique o seu telefone para o seu código de validação",
"confirm_new_password": "confirme a nova senha",
"create": "Criar usuário",
"create_failure": "Erro ao criar usuário. Certifique-se de que este endereço de e-mail ainda não esteja vinculado a uma conta.",
"create_failure": "Erro ao criar usuário: {{error}}",
"create_success": "Usuário criado com sucesso",
"creating": "Criando usuário ...",
"delete_avatar": "Apagar Avatar",
@@ -521,29 +698,40 @@
"description": "Descrição",
"edit": "Editar usuário",
"email_address": "Endereço de e-mail",
"enter_new_phone": "Insira seu novo número de telefone:",
"error_fetching_users": "Erro ao buscar usuários: {{error}}",
"error_retrieving": "Erro ao recuperar usuário",
"error_sending_code": "Erro ao tentar enviar o código de validação. Por favor, confirme se o seu número de telefone é válido.",
"force_password_change": "Forçar mudança de senha no login",
"id": "ID do usuário.",
"last_login": "Último login",
"login_id": "Identificação de usuário.",
"make_sure_same_password": "Certifique-se de que ambas as senhas são iguais e válidas",
"my_profile": "Meu perfil",
"name": "Nome",
"new_code_sent": "Novo código enviado!",
"nickname": "Apelido",
"nickname_explanation": "Apelido (opcional)",
"not_validated": "Não validado",
"note": "Nota",
"password": "Senha",
"phone_number": "Número de telefone",
"provide_email": "Por favor, forneça um endereço de e-mail válido",
"provide_password": "Forneça uma senha válida",
"save_avatar": "Salvar Avatar",
"send_code": "Enviar código",
"send_code_again": "Envie o Código Novamente",
"show_hide_password": "Mostrar / ocultar senha",
"successful_validation": "Número de telefone validado! Clique no botão Salvar para vinculá-lo ao seu perfil",
"update_failure": "Erro ao tentar atualizar: {{error}}",
"update_failure_title": "Atualização falhou",
"update_success": "Usuário atualizado com sucesso",
"update_success_title": "Sucesso",
"user_role": "Função",
"users": "Comercial",
"validated": "Validado"
"validate_phone": "validar",
"validated": "Validado",
"wrong_validation_code": "Você não digitou um código válido. Por favor, tente novamente e certifique-se de ter inserido o número de telefone correto"
},
"wifi_analysis": {
"association": "Associação",

View File

@@ -5,6 +5,7 @@ import Router from 'router';
import { AuthProvider } from 'ucentral-libs';
import { checkIfJson } from 'utils/helper';
import axiosInstance from 'utils/axiosInstance';
import { getItem } from 'utils/localStorageHelper';
const loading = (
<div className="pt-3 text-center">
@@ -13,9 +14,9 @@ const loading = (
);
const App = () => {
const storageToken = sessionStorage.getItem('access_token');
const apiEndpoints = checkIfJson(sessionStorage.getItem('gateway_endpoints'))
? JSON.parse(sessionStorage.getItem('gateway_endpoints'))
const storageToken = getItem('access_token');
const apiEndpoints = checkIfJson(getItem('gateway_endpoints'))
? JSON.parse(getItem('gateway_endpoints'))
: {};
return (

View File

@@ -24,12 +24,13 @@ import 'react-widgets/styles.css';
import axiosInstance from 'utils/axiosInstance';
import eventBus from 'utils/eventBus';
import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody';
import { LoadingButton, useAuth, useDevice } from 'ucentral-libs';
import { LoadingButton, useAuth, useDevice, useToast } from 'ucentral-libs';
const BlinkModal = ({ show, toggleModal }) => {
const { t } = useTranslation();
const { currentToken, endpoints } = useAuth();
const { deviceSerialNumber } = useDevice();
const { addToast } = useToast();
const [isNow, setIsNow] = useState(false);
const [waiting, setWaiting] = useState(false);
const [chosenDate, setChosenDate] = useState(new Date().toString());
@@ -78,7 +79,13 @@ const BlinkModal = ({ show, toggleModal }) => {
{ headers },
)
.then(() => {
setResult('success');
addToast({
title: t('common.success'),
body: t('commands.command_success'),
color: 'success',
autohide: true,
});
toggleModal();
})
.catch(() => {
setResult('error');

View File

@@ -17,7 +17,7 @@ const DetailsModal = ({ t, show, toggle, details, commandUuid }) => (
</div>
</CModalHeader>
<CModalBody>
<pre className="ignore">{JSON.stringify(details, null, 4)}</pre>
<pre className="ignore">{JSON.stringify(details, null, 2)}</pre>
</CModalBody>
</CModal>
);

View File

@@ -14,11 +14,11 @@ import {
import CIcon from '@coreui/icons-react';
import DatePicker from 'react-widgets/DatePicker';
import { cilCloudDownload, cilSync, cilCalendarCheck } from '@coreui/icons';
import { prettyDate, dateToUnix } from 'utils/helper';
import { dateToUnix } from 'utils/helper';
import axiosInstance from 'utils/axiosInstance';
import eventBus from 'utils/eventBus';
import ConfirmModal from 'components/ConfirmModal';
import { LoadingButton, useAuth, useDevice } from 'ucentral-libs';
import { LoadingButton, useAuth, useDevice, FormattedDate } from 'ucentral-libs';
import WifiScanResultModalWidget from 'components/WifiScanResultModal';
import DetailsModal from './DetailsModal';
@@ -188,9 +188,11 @@ const DeviceCommands = () => {
};
const columns = [
{ key: 'command', label: t('common.command'), _style: { width: '15%' } },
{ key: 'completed', label: t('common.completed'), filter: false, _style: { width: '20%' } },
{ key: 'submitted', label: t('common.submitted'), filter: false, _style: { width: '20%' } },
{ key: 'command', label: t('common.command'), _style: { width: '15%' } },
{ key: 'executed', label: t('common.executed'), filter: false, _style: { width: '16%' } },
{ key: 'completed', label: t('common.completed'), filter: false, _style: { width: '16%' } },
{ key: 'errorCode', label: t('common.error_code'), filter: false, _style: { width: '8%' } },
{
key: 'show_buttons',
label: '',
@@ -244,6 +246,7 @@ const DeviceCommands = () => {
return (
<div>
<CWidgetDropdown
className="m-0"
inverse="true"
color="gradient-primary"
header={t('commands.title')}
@@ -262,6 +265,7 @@ const DeviceCommands = () => {
<CCard>
<div className="overflow-auto" style={{ height: '200px' }}>
<CDataTable
addTableClasses="ignore-overflow table-sm"
border
loading={loading}
items={commands ?? []}
@@ -269,26 +273,41 @@ const DeviceCommands = () => {
className="text-white"
sorterValue={{ column: 'created', desc: 'true' }}
scopedSlots={{
command: (item) => <td className="align-middle">{item.command}</td>,
completed: (item) => (
<td>
{item.completed && item.completed !== 0
? prettyDate(item.completed)
: 'Pending'}
<td className="align-middle">
{item.completed && item.completed !== 0 ? (
<FormattedDate date={item.completed} />
) : (
'Pending'
)}
</td>
),
executed: (item) => (
<td className="align-middle">
{item.executed && item.executed !== 0 ? (
<FormattedDate date={item.executed} />
) : (
'Pending'
)}
</td>
),
submitted: (item) => (
<td>
{item.submitted && item.submitted !== ''
? prettyDate(item.submitted)
: 'Pending'}
<td className="align-middle">
{item.submitted && item.submitted !== '' ? (
<FormattedDate date={item.submitted} />
) : (
'Pending'
)}
</td>
),
errorCode: (item) => <td className="align-middle">{item.errorCode}</td>,
show_buttons: (item, index) => (
<td>
<td className="align-middle">
<CButtonToolbar
role="group"
className="justify-content-flex-end"
style={{ width: '170px' }}
style={{ width: '160px' }}
>
<CPopover
content={
@@ -309,13 +328,13 @@ const DeviceCommands = () => {
<CIcon
name="cil-cloud-download"
content={cilCloudDownload}
size="lg"
size="md"
/>
) : (
<CIcon
name="cil-calendar-check"
content={cilCalendarCheck}
size="lg"
size="md"
/>
)}
</CButton>
@@ -331,7 +350,7 @@ const DeviceCommands = () => {
toggleResponse(item);
}}
>
<CIcon name="cilList" size="lg" />
<CIcon name="cilList" size="md" />
</CButton>
</CPopover>
<CPopover content={t('common.delete')}>
@@ -345,7 +364,7 @@ const DeviceCommands = () => {
toggleConfirmModal(item.UUID, index);
}}
>
<CIcon name="cilTrash" size="lg" />
<CIcon name="cilTrash" size="mdå" />
</CButton>
</CPopover>
</CButtonToolbar>

View File

@@ -0,0 +1,64 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
CRow,
CCol,
CCard,
CCardBody,
CCardHeader,
CLabel,
CPopover,
CButton,
} from '@coreui/react';
import CIcon from '@coreui/icons-react';
import { cilSync } from '@coreui/icons';
import { prettyDate } from 'utils/helper';
import { useTranslation } from 'react-i18next';
import { CopyToClipboardButton } from 'ucentral-libs';
const ConfigurationDisplay = ({ getData, deviceConfig }) => {
const { t } = useTranslation();
return (
<CCard className="m-0">
<CCardHeader className="dark-header">
<div className="d-flex flex-row-reverse align-items-center">
<div className="text-right">
<CPopover content={t('common.refresh')}>
<CButton size="sm" color="info" onClick={getData}>
<CIcon content={cilSync} />
</CButton>
</CPopover>
</div>
</div>
</CCardHeader>
<CCardBody>
<h5>
{t('configuration.title')}
<CopyToClipboardButton
t={t}
size="sm"
content={JSON.stringify(deviceConfig?.configuration ?? {})}
/>
</h5>
<CRow>
<CCol md="2" xl="2" xxl="1">
<CLabel>{t('configuration.last_configuration_change')}: </CLabel>
</CCol>
<CCol>{prettyDate(deviceConfig?.lastConfigurationChange)}</CCol>
</CRow>
<pre className="ignore">{JSON.stringify(deviceConfig?.configuration ?? {}, null, 4)}</pre>
</CCardBody>
</CCard>
);
};
ConfigurationDisplay.propTypes = {
getData: PropTypes.func.isRequired,
deviceConfig: PropTypes.instanceOf(Object),
};
ConfigurationDisplay.defaultProps = {
deviceConfig: null,
};
export default ConfigurationDisplay;

View File

@@ -27,7 +27,7 @@ const initialState = {
error: false,
},
userRole: {
value: 'admin',
value: 'accounting',
error: false,
},
notes: {
@@ -42,16 +42,11 @@ const initialState = {
},
};
const CreateUserModal = ({ show, toggle, getUsers }) => {
const CreateUserModal = ({ show, toggle, getUsers, policies }) => {
const { t } = useTranslation();
const { currentToken, endpoints } = useAuth();
const { addToast } = useToast();
const [loading, setLoading] = useState(false);
const [policies, setPolicies] = useState({
passwordPolicy: '',
passwordPattern: '',
accessPolicy: '',
});
const [formFields, updateFieldWithId, updateField, setFormFields] = useFormFields(initialState);
const toggleChange = () => {
@@ -107,10 +102,10 @@ const CreateUserModal = ({ show, toggle, getUsers }) => {
});
toggle();
})
.catch(() => {
.catch((e) => {
addToast({
title: t('common.error'),
body: t('user.create_failure'),
body: t('user.create_failure', { error: e.response?.data?.ErrorDescription }),
color: 'danger',
autohide: true,
});
@@ -122,23 +117,6 @@ const CreateUserModal = ({ show, toggle, getUsers }) => {
setLoading(false);
}
};
const getPasswordPolicy = () => {
axiosInstance
.post(`${endpoints.owsec}/api/v1/oauth2?requirements=true`, {})
.then((response) => {
const newPolicies = response.data;
newPolicies.accessPolicy = `${endpoints.owsec}${newPolicies.accessPolicy}`;
newPolicies.passwordPolicy = `${endpoints.owsec}${newPolicies.passwordPolicy}`;
setPolicies(response.data);
})
.catch(() => {});
};
useEffect(() => {
if (policies.passwordPattern.length === 0) getPasswordPolicy();
}, []);
useEffect(() => {
setFormFields(initialState);
}, [show]);
@@ -177,6 +155,7 @@ CreateUserModal.propTypes = {
show: PropTypes.bool.isRequired,
toggle: PropTypes.func.isRequired,
getUsers: PropTypes.func.isRequired,
policies: PropTypes.instanceOf(Object).isRequired,
};
export default React.memo(CreateUserModal);

View File

@@ -122,7 +122,7 @@ const DeviceActions = () => {
return (
<CCard>
<CCardHeader>
<CCardHeader className="dark-header">
<div className="text-value-lg">{t('actions.title')}</div>
</CCardHeader>
<CCardBody>
@@ -138,7 +138,7 @@ const DeviceActions = () => {
</CButton>
</CCol>
</CRow>
<CRow className="mt-4">
<CRow className="my-1">
<CCol>
<CButton block color="primary" onClick={toggleUpgradeModal}>
{t('actions.firmware_upgrade')}
@@ -150,7 +150,7 @@ const DeviceActions = () => {
</CButton>
</CCol>
</CRow>
<CRow className="mt-4">
<CRow className="my-1">
<CCol>
<CButton block color="primary" onClick={toggleScanModal}>
{t('actions.wifi_scan')}
@@ -162,7 +162,7 @@ const DeviceActions = () => {
</CButton>
</CCol>
</CRow>
<CRow className="mt-4">
<CRow className="my-1">
<CCol>
<LoadingButton
isLoading={connectLoading}
@@ -177,7 +177,7 @@ const DeviceActions = () => {
</CButton>
</CCol>
</CRow>
<CRow className="mt-4">
<CRow className="my-1">
<CCol>
<CButton block color="primary" onClick={toggleQueueModal}>
{t('commands.event_queue')}

View File

@@ -19,7 +19,7 @@ const DeviceConfigurationModal = ({ show, toggle, configuration }) => (
<CModalTitle className="text-dark">{t('configuration.title')}</CModalTitle>
</CModalHeader>
<CModalBody>
<pre className="ignore">{JSON.stringify(configuration, null, 4)}</pre>
<pre className="ignore">{JSON.stringify(configuration, null, 2)}</pre>
</CModalBody>
<CModalFooter>
<CButton color="secondary" onClick={toggle}>

View File

@@ -48,7 +48,7 @@ const DeviceFirmwareModal = ({
const allFirmwares = [];
let continueFirmware = true;
let i = 1;
let i = 0;
while (continueFirmware) {
const newFirmwares = await getPartialFirmware(i);
if (newFirmwares === null || newFirmwares.length === 0) continueFirmware = false;

View File

@@ -2,11 +2,9 @@
import React, { useState, useEffect } from 'react';
import {
CWidgetDropdown,
CCollapse,
CButton,
CDataTable,
CCard,
CCardBody,
CRow,
CCol,
CProgress,
@@ -16,17 +14,16 @@ import CIcon from '@coreui/icons-react';
import { cilTrash } from '@coreui/icons';
import { useTranslation } from 'react-i18next';
import DatePicker from 'react-widgets/DatePicker';
import { prettyDate, dateToUnix } from 'utils/helper';
import { dateToUnix } from 'utils/helper';
import axiosInstance from 'utils/axiosInstance';
import eventBus from 'utils/eventBus';
import { LoadingButton, useAuth, useDevice } from 'ucentral-libs';
import { LoadingButton, useAuth, useDevice, FormattedDate } from 'ucentral-libs';
import DeleteLogModal from 'components/DeleteLogModal';
const DeviceHealth = () => {
const { t } = useTranslation();
const { currentToken, endpoints } = useAuth();
const { deviceSerialNumber } = useDevice();
const [details, setDetails] = useState([]);
const [loading, setLoading] = useState(false);
const [healthChecks, setHealthChecks] = useState([]);
const [start, setStart] = useState('');
@@ -95,35 +92,11 @@ const DeviceHealth = () => {
});
};
const toggleDetails = (index) => {
const position = details.indexOf(index);
let newDetails = details.slice();
if (position !== -1) {
newDetails.splice(position, 1);
} else {
newDetails = [...details, index];
}
setDetails(newDetails);
};
const getDetails = (index, healthCheckDetails) => {
if (details.includes(index))
return <pre className="ignore">{JSON.stringify(healthCheckDetails, null, 4)}</pre>;
return <pre className="ignore" />;
};
const columns = [
{ key: 'UUID', label: t('common.config_id') },
{ key: 'recorded', label: t('common.recorded') },
{ key: 'sanity', label: t('health.sanity') },
{
key: 'show_details',
label: '',
_style: { width: '1%' },
sorter: false,
filter: false,
},
{ key: 'recorded', label: t('common.recorded'), _style: { width: '15%' } },
{ key: 'UUID', label: t('common.config_id'), _style: { width: '10%' } },
{ key: 'sanity', label: t('health.sanity'), _style: { width: '5%' } },
{ key: 'checkDetails', label: t('common.details'), _style: { width: '65%' } },
];
useEffect(() => {
@@ -184,6 +157,7 @@ const DeviceHealth = () => {
return (
<CWidgetDropdown
className="m-0"
header={t('health.title')}
text={sanityLevel ? `${sanityLevel}%` : t('common.unknown')}
value={sanityLevel ?? 100}
@@ -207,6 +181,7 @@ const DeviceHealth = () => {
<CCard className="p-0">
<div className="overflow-auto" style={{ height: '200px' }}>
<CDataTable
addTableClasses="ignore-overflow table-sm"
border
items={healthChecks ?? []}
fields={columns}
@@ -215,30 +190,16 @@ const DeviceHealth = () => {
sorterValue={{ column: 'recorded', desc: 'true' }}
scopedSlots={{
UUID: (item) => <td className="align-middle">{item.UUID}</td>,
recorded: (item) => <td className="align-middle">{prettyDate(item.recorded)}</td>,
sanity: (item) => <td className="align-middle">{`${item.sanity}%`}</td>,
show_details: (item, index) => (
recorded: (item) => (
<td className="align-middle">
<CButton
color="primary"
variant={details.includes(index) ? '' : 'outline'}
shape="square"
size="sm"
onClick={() => {
toggleDetails(index);
}}
>
<CIcon name="cilList" size="lg" />
</CButton>
<FormattedDate date={item.recorded} />
</td>
),
details: (item, index) => (
<CCollapse show={details.includes(index)}>
<CCardBody>
<h5>{t('common.details')}</h5>
<div>{getDetails(index, item.values)}</div>
</CCardBody>
</CCollapse>
sanity: (item) => <td className="align-middle">{`${item.sanity}%`}</td>,
checkDetails: (item) => (
<td>
<pre className="my-0">{JSON.stringify(item.values)}</pre>
</td>
),
}}
/>

View File

@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory, useLocation } from 'react-router-dom';
import { useHistory } from 'react-router-dom';
import axiosInstance from 'utils/axiosInstance';
import { getItem, setItem } from 'utils/localStorageHelper';
import DeviceSearchBar from 'components/DeviceSearchBar';
@@ -16,8 +16,7 @@ const DeviceList = () => {
const { t } = useTranslation();
const { addToast } = useToast();
const history = useHistory();
const { search } = useLocation();
const page = new URLSearchParams(search).get('page');
const [page, setPage] = useState(parseInt(sessionStorage.getItem('deviceTable') ?? 0, 10));
const { currentToken, endpoints } = useAuth();
const [upgradeStatus, setUpgradeStatus] = useState({
loading: false,
@@ -69,7 +68,7 @@ const DeviceList = () => {
axiosInstance
.get(
`${endpoints.owgw}/api/v1/devices?deviceWithStatus=true&limit=${devicePerPage}&offset=${
devicePerPage * selectedPage + 1
devicePerPage * selectedPage
}`,
options,
)
@@ -77,25 +76,30 @@ const DeviceList = () => {
fullDevices = response.data.devicesWithStatus;
const serialsToGet = fullDevices.map((device) => device.serialNumber);
if (serialsToGet.length === 0) {
return null;
}
return axiosInstance.get(
`${endpoints.owfms}/api/v1/firmwareAge?select=${serialsToGet}`,
options,
);
})
.then((response) => {
fullDevices = fullDevices.map((device, index) => {
const foundAgeDate = response.data.ages[index].age !== undefined;
if (foundAgeDate) {
return {
...device,
firmwareInfo: {
age: response.data.ages[index].age,
latest: response.data.ages[index].latest,
},
};
}
return device;
});
if (response !== null) {
fullDevices = fullDevices.map((device, index) => {
const foundAgeDate = response.data.ages[index].age !== undefined;
if (foundAgeDate) {
return {
...device,
firmwareInfo: {
age: response.data.ages[index].age,
latest: response.data.ages[index].latest,
},
};
}
return device;
});
}
setDevices(fullDevices);
setLoading(false);
})
@@ -220,13 +224,15 @@ const DeviceList = () => {
};
const updatePageCount = ({ selected: selectedPage }) => {
history.push(`/devices?page=${selectedPage}`);
sessionStorage.setItem('deviceTable', selectedPage);
setPage(selectedPage);
getDeviceInformation(selectedPage);
};
const upgradeToLatest = (device) => {
setUpgradeStatus({
loading: true,
serialNumber: device.serialNumber,
});
const options = {
@@ -349,9 +355,6 @@ const DeviceList = () => {
};
useEffect(() => {
if (page === undefined || page === null || Number.isNaN(page)) {
history.push(`/devices?page=0`);
}
getCount();
}, []);

View File

@@ -15,10 +15,10 @@ import CIcon from '@coreui/icons-react';
import { cilTrash } from '@coreui/icons';
import { useTranslation } from 'react-i18next';
import DatePicker from 'react-widgets/DatePicker';
import { prettyDate, dateToUnix } from 'utils/helper';
import { dateToUnix } from 'utils/helper';
import axiosInstance from 'utils/axiosInstance';
import eventBus from 'utils/eventBus';
import { LoadingButton, useAuth, useDevice } from 'ucentral-libs';
import { LoadingButton, useAuth, useDevice, FormattedDate } from 'ucentral-libs';
import DeleteLogModal from 'components/DeleteLogModal';
const DeviceLogs = () => {
@@ -106,14 +106,15 @@ const DeviceLogs = () => {
const getDetails = (index, logDetails) => {
if (details.includes(index))
return <pre className="ignore">{JSON.stringify(logDetails, null, 4)}</pre>;
return <pre className="ignore">{JSON.stringify(logDetails, null, 2)}</pre>;
return <pre className="ignore" />;
};
const columns = [
{ key: 'recorded', label: t('common.recorded'), _style: { width: '15%' } },
{ key: 'UUID', label: t('common.config_id'), _style: { width: '10%' } },
{ key: 'severity', label: t('device_logs.severity'), _style: { width: '5%' } },
{ key: 'log', label: t('device_logs.log') },
{ key: 'severity', label: t('device_logs.severity') },
{ key: 'recorded', label: t('common.recorded') },
{
key: 'show_details',
label: '',
@@ -167,6 +168,7 @@ const DeviceLogs = () => {
return (
<div>
<CWidgetDropdown
className="m-0"
inverse="true"
color="gradient-info"
header={t('device_logs.title')}
@@ -185,15 +187,24 @@ const DeviceLogs = () => {
<CCard>
<div className="overflow-auto" style={{ height: '250px' }}>
<CDataTable
addTableClasses="ignore-overflow table-sm"
border
items={logs ?? []}
fields={columns}
loading={loading}
className="text-white"
sorterValue={{ column: 'recorded', desc: 'true' }}
scopedSlots={{
recorded: (item) => <td>{prettyDate(item.recorded)}</td>,
recorded: (item) => (
<td className="align-middle">
<FormattedDate date={item.recorded} />
</td>
),
UUID: (item) => <td className="align-middle">{item.UUID}</td>,
severity: (item) => <td className="align-middle">{item.severity}</td>,
log: (item) => <td className="align-middle">{item.log}</td>,
show_details: (item, index) => (
<td className="py-2">
<td className="align-middle">
<CButton
color="primary"
variant={details.includes(index) ? '' : 'outline'}
@@ -203,7 +214,7 @@ const DeviceLogs = () => {
toggleDetails(index);
}}
>
<CIcon name="cilList" size="lg" />
<CIcon name="cilList" size="md" />
</CButton>
</td>
),

View File

@@ -0,0 +1,272 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import {
CButton,
CModal,
CModalBody,
CModalHeader,
CModalTitle,
CPopover,
CNav,
CNavLink,
CTabPane,
CTabContent,
} from '@coreui/react';
import CIcon from '@coreui/icons-react';
import { cilPencil, cilSave, cilX } from '@coreui/icons';
import axiosInstance from 'utils/axiosInstance';
import {
useFormFields,
useAuth,
useToast,
FirmwareDetailsForm,
DetailedNotesTable,
} from 'ucentral-libs';
const initialState = {
created: {
value: '',
error: false,
editable: false,
},
release: {
value: false,
error: false,
editable: false,
},
image: {
value: '',
error: false,
editable: true,
},
imageDate: {
value: '',
error: false,
editable: true,
},
size: {
value: '',
error: false,
editable: true,
},
revision: {
value: '',
error: false,
editable: false,
},
uri: {
value: '',
error: false,
editable: true,
},
description: {
value: '',
error: false,
editable: true,
},
notes: {
value: [],
editable: false,
},
};
const EditFirmwareModal = ({ show, toggle, firmwareId, refreshTable }) => {
const { t } = useTranslation();
const { currentToken, endpoints } = useAuth();
const { addToast } = useToast();
const [loading, setLoading] = useState(false);
const [editing, setEditing] = useState(false);
const [index, setIndex] = useState(0);
const [firmware, updateWithId, updateWithKey, setFirmware] = useFormFields(initialState);
const getFirmware = () => {
const options = {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${currentToken}`,
},
};
axiosInstance
.get(`${endpoints.owfms}/api/v1/firmware/${firmwareId}`, options)
.then((response) => {
const newFirmware = {};
for (const key of Object.keys(response.data)) {
if (key in initialState && key !== 'currentPassword') {
newFirmware[key] = {
...initialState[key],
value: response.data[key],
};
}
}
setFirmware({ ...initialState, ...newFirmware });
})
.catch(() => {});
};
const toggleEditing = () => {
if (editing) {
getFirmware();
}
setEditing(!editing);
};
const toggleModal = () => {
toggleEditing();
toggle();
};
const updateFirmware = () => {
setLoading(true);
const parameters = {
id: firmwareId,
description: firmware.description.value,
};
const newNotes = [];
for (let i = 0; i < firmware.notes.value.length; i += 1) {
if (firmware.notes.value[i].new) newNotes.push({ note: firmware.notes.value[i].note });
}
parameters.notes = newNotes;
const options = {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${currentToken}`,
},
};
axiosInstance
.put(`${endpoints.owfms}/api/v1/firmware/${firmwareId}`, parameters, options)
.then(() => {
addToast({
title: t('firmware.update_success_title'),
body: t('firmware.update_success'),
color: 'success',
autohide: true,
});
refreshTable();
toggle();
})
.catch((e) => {
addToast({
title: t('firmware.update_failure_title'),
body: t('firmware.update_failure', { error: e.response?.data?.ErrorDescription }),
color: 'danger',
autohide: true,
});
getFirmware();
})
.finally(() => {
setLoading(false);
});
};
const addNote = (currentNote) => {
const newNotes = [...firmware.notes.value];
newNotes.unshift({
note: currentNote,
new: true,
created: new Date().getTime() / 1000,
createdBy: '',
});
updateWithKey('notes', { value: newNotes });
};
useEffect(() => {
if (show) {
getFirmware();
setEditing(false);
setIndex(0);
}
}, [show]);
return (
<CModal show={show} onClose={toggle} size="xl">
<CModalHeader className="p-1">
<CModalTitle className="pl-1 pt-1">
{t('firmware.details_title', { image: firmware.image.value })}
</CModalTitle>
<div className="text-right">
<CPopover content={t('common.save')}>
<CButton color="primary" variant="outline" onClick={updateFirmware} disabled={loading}>
<CIcon content={cilSave} />
</CButton>
</CPopover>
<CPopover content={t('common.edit')}>
<CButton
disabled={editing}
color="primary"
variant="outline"
onClick={toggleEditing}
className="ml-2"
>
<CIcon name="cil-pencil" content={cilPencil} />
</CButton>
</CPopover>
<CPopover content={t('common.close')}>
<CButton color="primary" variant="outline" className="ml-2" onClick={toggleModal}>
<CIcon content={cilX} />
</CButton>
</CPopover>
</div>
</CModalHeader>
<CModalBody className="px-3 pt-0">
<CNav variant="tabs" className="mb-0 p-0">
<CNavLink
className="font-weight-bold"
href="#"
active={index === 0}
onClick={() => setIndex(0)}
>
{t('common.main')}
</CNavLink>
<CNavLink
className="font-weight-bold"
href="#"
active={index === 1}
onClick={() => setIndex(1)}
>
{t('configuration.notes')}
</CNavLink>
</CNav>
<CTabContent>
<CTabPane active={index === 0} className="pt-2">
{index === 0 ? (
<FirmwareDetailsForm
t={t}
fields={firmware}
updateFieldsWithId={updateWithId}
editing={editing}
/>
) : null}
</CTabPane>
<CTabPane active={index === 1}>
{index === 1 ? (
<DetailedNotesTable
t={t}
notes={firmware.notes.value}
addNote={addNote}
loading={loading}
editable={editing}
/>
) : null}
</CTabPane>
</CTabContent>
</CModalBody>
</CModal>
);
};
EditFirmwareModal.propTypes = {
firmwareId: PropTypes.string.isRequired,
show: PropTypes.bool.isRequired,
toggle: PropTypes.func.isRequired,
refreshTable: PropTypes.func.isRequired,
};
export default React.memo(EditFirmwareModal);

View File

@@ -13,7 +13,7 @@ const initialState = {
changePassword: {
value: false,
error: false,
editable: false,
editable: true,
},
currentPassword: {
value: '',
@@ -36,7 +36,7 @@ const initialState = {
editable: true,
},
userRole: {
value: '',
value: 'accounting',
error: false,
editable: true,
},
@@ -46,30 +46,14 @@ const initialState = {
},
};
const EditUserModal = ({ show, toggle, userId, getUsers }) => {
const EditUserModal = ({ show, toggle, userId, getUsers, policies }) => {
const { t } = useTranslation();
const { currentToken, endpoints } = useAuth();
const { addToast } = useToast();
const [loading, setLoading] = useState(false);
const [initialUser, setInitialUser] = useState({});
const [editing, setEditing] = useState(false);
const [user, updateWithId, updateWithKey, setUser] = useUser(initialState);
const [policies, setPolicies] = useState({
passwordPolicy: '',
passwordPattern: '',
accessPolicy: '',
});
const getPasswordPolicy = () => {
axiosInstance
.post(`${endpoints.owsec}/api/v1/oauth2?requirements=true`, {})
.then((response) => {
const newPolicies = response.data;
newPolicies.accessPolicy = `${endpoints.owsec}${newPolicies.accessPolicy}`;
newPolicies.passwordPolicy = `${endpoints.owsec}${newPolicies.passwordPolicy}`;
setPolicies(response.data);
})
.catch(() => {});
};
const getUser = () => {
const options = {
@@ -95,7 +79,22 @@ const EditUserModal = ({ show, toggle, userId, getUsers }) => {
setInitialUser({ ...initialState, ...newUser });
setUser({ ...initialState, ...newUser });
})
.catch(() => {});
.catch(() => {
addToast({
title: t('common.error'),
body: t('user.error_retrieving'),
color: 'danger',
autohide: true,
});
toggle();
});
};
const toggleEditing = () => {
if (editing) {
getUser();
}
setEditing(!editing);
};
const updateUser = () => {
@@ -125,7 +124,15 @@ const EditUserModal = ({ show, toggle, userId, getUsers }) => {
}
}
if (newData) {
const newNotes = [];
for (let i = 0; i < user.notes.value.length; i += 1) {
if (user.notes.value[i].new) newNotes.push({ note: user.notes.value[i].note });
}
parameters.notes = newNotes;
if (newData || newNotes.length > 0) {
const options = {
headers: {
Accept: 'application/json',
@@ -171,40 +178,29 @@ const EditUserModal = ({ show, toggle, userId, getUsers }) => {
};
const addNote = (currentNote) => {
setLoading(true);
const parameters = {
id: userId,
notes: [{ note: currentNote }],
};
const options = {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${currentToken}`,
},
};
axiosInstance
.put(`${endpoints.owsec}/api/v1/user/${userId}`, parameters, options)
.then(() => {
getUser();
})
.catch(() => {})
.finally(() => {
setLoading(false);
});
const newNotes = [...user.notes.value];
newNotes.unshift({
note: currentNote,
new: true,
created: new Date().getTime() / 1000,
createdBy: '',
});
updateWithKey('notes', { value: newNotes });
};
useEffect(() => {
if (userId) {
getUser();
}
if (policies.passwordPattern.length === 0) {
getPasswordPolicy();
}
}, [userId]);
useEffect(() => {
if (show) {
getUser();
setEditing(false);
}
}, [show]);
return (
<Modal
t={t}
@@ -215,6 +211,8 @@ const EditUserModal = ({ show, toggle, userId, getUsers }) => {
policies={policies}
show={show}
toggle={toggle}
editing={editing}
toggleEditing={toggleEditing}
addNote={addNote}
/>
);
@@ -225,6 +223,7 @@ EditUserModal.propTypes = {
show: PropTypes.bool.isRequired,
toggle: PropTypes.func.isRequired,
getUsers: PropTypes.func.isRequired,
policies: PropTypes.instanceOf(Object).isRequired,
};
export default React.memo(EditUserModal);

View File

@@ -134,7 +134,7 @@ const FirmwareDashboard = () => {
if (
parsedData.numberOfDevices === undefined ||
Number.isNaN(parsedData.numberOfDevices) ||
parsedData === 0
parsedData.numberOfDevices === 0
) {
parsedData.latestSoftwareRate = '-';
} else {
@@ -150,10 +150,19 @@ const FirmwareDashboard = () => {
? parsedData.unknownFirmwares.reduce((acc, firmware) => acc + firmware.value, 0)
: 0;
const devicesForAverage = parsedData.numberOfDevices - usingUnknownFirmwareFromArray;
parsedData.averageFirmwareAge =
parsedData.totalSecondsOld[0].value /
(devicesForAverage > 0 ? devicesForAverage : 1) /
(24 * 60 * 60);
if (devicesForAverage !== 0 && parsedData.totalSecondsOld.length > 0) {
parsedData.averageFirmwareAge = Math.round(
parsedData.totalSecondsOld[0].value /
(devicesForAverage > 0 ? devicesForAverage : 1) /
(24 * 60 * 60),
);
parsedData.averageFirmwareAge = `${parsedData.averageFirmwareAge} ${
Math.round(parsedData.averageFirmwareAge) > 0 ? t('common.days') : t('common.day')
}`;
} else {
parsedData.averageFirmwareAge = '-';
}
// Latest firmware distribution
const latestDs = [];

View File

@@ -51,7 +51,7 @@ const LatestStatisticsModal = ({ show, toggle }) => {
</div>
</CModalHeader>
<CModalBody>
<pre className="ignore">{JSON.stringify(latestStats, null, 4)}</pre>
<pre className="ignore">{JSON.stringify(latestStats, null, 2)}</pre>
</CModalBody>
</CModal>
);

View File

@@ -1,6 +1,5 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory, useParams } from 'react-router-dom';
import { CCard, CCardHeader, CCardBody, CPopover, CButton } from '@coreui/react';
import { cilSync } from '@coreui/icons';
import CIcon from '@coreui/icons-react';
@@ -10,8 +9,6 @@ import StatisticsChartList from './StatisticsChartList';
import LatestStatisticsmodal from './LatestStatisticsModal';
const DeviceStatisticsCard = () => {
const history = useHistory();
const { deviceId } = useParams();
const { t } = useTranslation();
const [showLatestModal, setShowLatestModal] = useState(false);
const [showLifetimeModal, setShowLifetimeModal] = useState(false);
@@ -24,45 +21,35 @@ const DeviceStatisticsCard = () => {
setShowLifetimeModal(!showLifetimeModal);
};
const goToAnalysis = () => {
history.push(`/devices/${deviceId}/wifianalysis`);
};
const refresh = () => {
eventBus.dispatch('refreshInterfaceStatistics', { message: 'Refresh interface statistics' });
};
return (
<div>
<CCard>
<CCardHeader>
<CCard className="m-0">
<CCardHeader className="dark-header">
<div className="d-flex flex-row-reverse align-items-center">
<div className="pl-2">
<CPopover content={t('common.refresh')}>
<CButton color="primary" variant="outline" onClick={refresh}>
<CButton size="sm" color="info" onClick={refresh}>
<CIcon content={cilSync} />
</CButton>
</CPopover>
</div>
<div className="pl-2">
<CButton color="primary" variant="outline" onClick={toggleLifetimeModal}>
<CButton size="sm" color="info" onClick={toggleLifetimeModal}>
Lifetime Statistics
</CButton>
</div>
<div className="pl-2">
<CButton color="primary" variant="outline" onClick={toggleLatestModal}>
<CButton size="sm" color="info" onClick={toggleLatestModal}>
{t('statistics.show_latest')}
</CButton>
</div>
<div>
<CButton color="primary" variant="outline" onClick={goToAnalysis}>
{t('wifi_analysis.title')}
</CButton>
</div>
<div className="text-value-lg mr-auto">{t('statistics.title')}</div>
</div>
</CCardHeader>
<CCardBody className="p-5">
<CCardBody className="p-1">
<StatisticsChartList />
</CCardBody>
</CCard>

View File

@@ -20,17 +20,18 @@ import { dateToUnix } from 'utils/helper';
import 'react-widgets/styles.css';
import axiosInstance from 'utils/axiosInstance';
import eventBus from 'utils/eventBus';
import { LoadingButton, useAuth, useDevice } from 'ucentral-libs';
import { LoadingButton, useAuth, useDevice, useToast } from 'ucentral-libs';
import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody';
const ActionModal = ({ show, toggleModal }) => {
const { t } = useTranslation();
const { currentToken, endpoints } = useAuth();
const { deviceSerialNumber } = useDevice();
const { addToast } = useToast();
const [waiting, setWaiting] = useState(false);
const [result, setResult] = useState(null);
const [chosenDate, setChosenDate] = useState(new Date().toString());
const [isNow, setIsNow] = useState(false);
const [isNow, setIsNow] = useState(true);
const toggleNow = () => {
setIsNow(!isNow);
@@ -47,6 +48,7 @@ const ActionModal = ({ show, toggleModal }) => {
setResult(null);
setWaiting(false);
setChosenDate(new Date().toString());
setIsNow(true);
}
}, [show]);
@@ -72,7 +74,13 @@ const ActionModal = ({ show, toggleModal }) => {
{ headers },
)
.then(() => {
setResult('success');
addToast({
title: t('common.success'),
body: t('commands.command_success'),
color: 'success',
autohide: true,
});
toggleModal();
})
.catch(() => {
setResult('error');

View File

@@ -24,6 +24,7 @@ import { checkIfJson } from 'utils/helper';
const typeOptions = [
{ value: 'wifi-frames', label: 'wifi-frames' },
{ value: 'dhcp-snooping', label: 'dhcp-snooping' },
{ value: 'state', label: 'state' },
];
const TelemetryModal = ({ show, toggle }) => {
@@ -192,7 +193,7 @@ const TelemetryModal = ({ show, toggle }) => {
</CRow>
<CRow>
<CCol>
<pre>{JSON.stringify(lastMessage, null, '\t')}</pre>
<pre>{JSON.stringify(lastMessage, null, 2)}</pre>
</CCol>
</CRow>
<CRow>

View File

@@ -21,7 +21,13 @@ import {
import CIcon from '@coreui/icons-react';
import { cilX } from '@coreui/icons';
const WifiAnalysisPage = () => {
const parseDbm = (value) => {
if (!value) return '-';
if (value > -150 && value < 100) return value;
return (4294967295 - value) * -1;
};
const WifiAnalysis = () => {
const { t } = useTranslation();
const { deviceId } = useParams();
const { currentToken, endpoints } = useAuth();
@@ -60,7 +66,6 @@ const WifiAnalysisPage = () => {
};
const parseAssociationStats = (json) => {
const dbmNumber = 4294967295;
const newParsedAssociationStats = [];
const newParsedRadioStats = [];
@@ -77,8 +82,8 @@ const WifiAnalysisPage = () => {
radio: i,
channel: radio.channel,
channelWidth: radio.channel_width,
noise: radio.noise ? (dbmNumber - radio.noise) * -1 : '-',
txPower: radio.tx_power,
noise: radio.noise ? parseDbm(radio.noise) : '-',
txPower: radio.tx_power ?? '-',
activeMs: secondsToLabel(radio?.active_ms ? Math.floor(radio.active_ms / 1000) : 0),
busyMs: secondsToLabel(radio?.busy_ms ? Math.floor(radio.busy_ms / 1000) : 0),
receiveMs: secondsToLabel(radio?.receive_ms ? Math.floor(radio.receive_ms / 1000) : 0),
@@ -121,16 +126,16 @@ const WifiAnalysisPage = () => {
...extractIp(stat.data, association.bssid),
bssid: association.bssid,
ssid: ssid.ssid,
rssi: association.rssi ? (dbmNumber - association.rssi) * -1 : '-',
rssi: association.rssi ? parseDbm(association.rssi) : '-',
mode: ssid.mode,
rxBytes: cleanBytesString(association.rx_bytes, 0),
rxRate: association.rx_rate.bitrate,
rxMcs: association.rx_rate.mcs ?? '-',
rxNss: association.rx_rate.nss ?? '-',
txBytes: cleanBytesString(association.tx_bytes, 0),
txMcs: association.tx_rate.mcs,
txNss: association.tx_rate.nss,
txRate: association.tx_rate.bitrate,
txMcs: association.tx_rate.mcs ?? '-',
txNss: association.tx_rate.nss ?? '-',
txRate: association.tx_rate.bitrate ?? '-',
timeStamp,
};
associations.push(data);
@@ -196,19 +201,16 @@ const WifiAnalysisPage = () => {
return (
<div>
<CCard>
<CCardHeader>
<CCardHeader className="dark-header">
<CRow>
<CCol>
<h5 className="mb-0">{t('common.device', { serialNumber: deviceId })}</h5>
</CCol>
<CCol className="text-right">
<CButton color="primary" variant="outline" onClick={toggleModal}>
<CButton color="info" size="sm" onClick={toggleModal}>
{t('wifi_analysis.network_diagram')}
</CButton>
</CCol>
</CRow>
</CCardHeader>
<CCardBody className="overflow-auto" style={{ height: 'calc(100vh - 300px)' }}>
<CCardBody>
<CRow className="mb-4">
<CCol className="text-center">
<input
@@ -227,15 +229,17 @@ const WifiAnalysisPage = () => {
</h5>
</CCol>
</CRow>
<h5 className="pb-3 text-center">{t('wifi_analysis.radios')}</h5>
<RadioAnalysisTable data={selectedRadioStats ?? []} loading={loading} range={range} />
<h5 className="pt-5 pb-3 text-center">{t('wifi_analysis.associations')}</h5>
<WifiAnalysisTable
t={t}
data={selectedAssociationStats ?? []}
loading={loading}
range={range}
/>
<div className="overflow-auto" style={{ height: 'calc(100vh - 300px)' }}>
<h5 className="pb-3 text-center">{t('wifi_analysis.radios')}</h5>
<RadioAnalysisTable data={selectedRadioStats ?? []} loading={loading} range={range} />
<h5 className="pt-5 pb-3 text-center">{t('wifi_analysis.associations')}</h5>
<WifiAnalysisTable
t={t}
data={selectedAssociationStats ?? []}
loading={loading}
range={range}
/>
</div>
</CCardBody>
</CCard>
<CModal size="xl" show={showModal} onClose={toggleModal}>
@@ -265,4 +269,4 @@ const WifiAnalysisPage = () => {
);
};
export default WifiAnalysisPage;
export default WifiAnalysis;

View File

@@ -4,6 +4,12 @@ import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types';
import 'react-widgets/styles.css';
const parseDbm = (value) => {
if (!value) return '-';
if (value > -150 && value < 100) return value;
return 4294967295 + value;
};
const WifiChannelCard = ({ channel }) => {
const { t } = useTranslation();
const columns = [{ key: 'SSID', _style: { width: '70%' } }, { key: 'Signal' }];
@@ -17,7 +23,15 @@ const WifiChannelCard = ({ channel }) => {
</CCardHeader>
<CCardBody>
<div className="overflow-auto" style={{ height: '250px' }}>
<CDataTable items={channel.devices} fields={columns} className="text-white" />
<CDataTable
addTableClasses="ignore-overflow table-sm"
items={channel.devices}
fields={columns}
className="text-white"
scopedSlots={{
Signal: (item) => <td>{parseDbm(item.Signal)}</td>,
}}
/>
</div>
</CCardBody>
</CCard>

View File

@@ -10,42 +10,16 @@ const TheLayout = () => {
const navigation = [
{
_tag: 'CSidebarNavDropdown',
_tag: 'CSidebarNavItem',
name: t('common.devices'),
icon: 'cilRouter',
_children: [
{
addLinkClass: 'c-sidebar-nav-link ml-2',
_tag: 'CSidebarNavItem',
name: t('common.dashboard'),
to: '/devicedashboard',
},
{
addLinkClass: 'c-sidebar-nav-link ml-2',
_tag: 'CSidebarNavItem',
name: t('common.table'),
to: '/devices',
},
],
to: '/devices',
},
{
_tag: 'CSidebarNavDropdown',
_tag: 'CSidebarNavItem',
name: t('firmware.title'),
icon: 'cilSave',
_children: [
{
addLinkClass: 'c-sidebar-nav-link ml-2',
_tag: 'CSidebarNavItem',
name: t('common.dashboard'),
to: '/firmwaredashboard',
},
{
addLinkClass: 'c-sidebar-nav-link ml-2',
_tag: 'CSidebarNavItem',
name: t('common.table'),
to: '/firmware',
},
],
to: '/firmware',
},
{
_tag: 'CSidebarNavItem',
@@ -83,6 +57,7 @@ const TheLayout = () => {
endpoints={endpoints}
user={user}
avatar={avatar}
hideBreadcrumb
/>
<div className="c-body">
<ToastProvider>

View File

@@ -1,10 +1,67 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import DeviceList from 'components/DeviceListTable';
import DeviceDashboard from 'components/DeviceDashboard';
import {
CCard,
CCardBody,
CNav,
CNavLink,
CTabPane,
CTabContent,
CCardHeader,
} from '@coreui/react';
import { useTranslation } from 'react-i18next';
const DeviceListPage = () => (
<div className="App">
<DeviceList />
</div>
);
const DeviceListPage = () => {
const { t } = useTranslation();
const [index, setIndex] = useState(0);
const updateNav = (target) => {
sessionStorage.setItem('devicePage', target);
setIndex(target);
};
useEffect(() => {
const target = sessionStorage.getItem('devicePage');
if (target !== null) setIndex(parseInt(target, 10));
}, []);
return (
<CCard>
<CCardHeader className="dark-header">
<div className="text-value-lg mr-auto">{t('common.devices')}</div>
</CCardHeader>
<CCardBody className="p-0">
<CNav variant="tabs">
<CNavLink
className="font-weight-bold"
href="#"
active={index === 0}
onClick={() => updateNav(0)}
>
{t('common.dashboard')}
</CNavLink>
<CNavLink
className="font-weight-bold"
href="#"
active={index === 1}
onClick={() => updateNav(1)}
>
{t('common.table')}
</CNavLink>
</CNav>
<CTabContent>
<CTabPane active={index === 0}>
<DeviceDashboard />
</CTabPane>
<CTabPane active={index === 1}>
<DeviceList />
</CTabPane>
</CTabContent>
</CCardBody>
</CCard>
);
};
export default DeviceListPage;

View File

@@ -1,41 +1,225 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { CRow, CCol } from '@coreui/react';
import { CRow, CCol, CCard, CCardBody, CNav, CNavLink, CTabPane, CTabContent } from '@coreui/react';
import DeviceHealth from 'components/DeviceHealth';
import DeviceStatusCard from 'components/DeviceStatusCard';
import CommandHistory from 'components/CommandHistory';
import DeviceLogs from 'components/DeviceLogs';
import DeviceStatisticsCard from 'components/InterfaceStatistics';
import DeviceActionCard from 'components/DeviceActionCard';
import axiosInstance from 'utils/axiosInstance';
import { DeviceProvider } from 'ucentral-libs';
import { DeviceProvider, DeviceStatusCard, DeviceDetails, useAuth, useToast } from 'ucentral-libs';
import { useTranslation } from 'react-i18next';
import ConfigurationDisplay from 'components/ConfigurationDisplay';
import WifiAnalysis from 'components/WifiAnalysis';
const DevicePage = () => {
const { t } = useTranslation();
const { deviceId } = useParams();
const [index, setIndex] = useState(0);
const { currentToken, endpoints } = useAuth();
const { addToast } = useToast();
const [lastStats, setLastStats] = useState(null);
const [status, setStatus] = useState(null);
const [deviceConfig, setDeviceConfig] = useState(null);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);
const getDevice = () => {
const options = {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${currentToken}`,
},
};
let deviceInfo = null;
axiosInstance
.get(`${endpoints.owgw}/api/v1/device/${encodeURIComponent(deviceId)}`, options)
.then((response) => {
deviceInfo = response.data;
if (response.data.venue !== '' || (response.data.owner !== '' && endpoints.owprov)) {
return axiosInstance.get(
`${endpoints.owprov}/api/v1/inventory/${encodeURIComponent(
deviceId,
)}?withExtendedInfo=true`,
options,
);
}
setDeviceConfig(deviceInfo);
return null;
})
.then((response) => {
if (response) setDeviceConfig({ ...deviceInfo, extendedInfo: response.data.extendedInfo });
})
.catch((e) => {
addToast({
title: t('common.error'),
body: t('device.error_fetching_device', { error: e.response?.data?.ErrorDescription }),
color: 'danger',
autohide: true,
});
});
};
const getData = () => {
setLoading(true);
const options = {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${currentToken}`,
},
};
const lastStatsRequest = axiosInstance.get(
`${endpoints.owgw}/api/v1/device/${encodeURIComponent(deviceId)}/statistics?lastOnly=true`,
options,
);
const statusRequest = axiosInstance.get(
`${endpoints.owgw}/api/v1/device/${encodeURIComponent(deviceId)}/status`,
options,
);
Promise.all([lastStatsRequest, statusRequest])
.then(([newStats, newStatus]) => {
setLastStats(newStats.data);
setStatus(newStatus.data);
})
.catch(() => {
setError(true);
})
.finally(() => {
setLoading(false);
});
};
const refresh = () => {
getData();
getDevice();
};
useEffect(() => {
setError(false);
if (deviceId) {
getDevice();
getData();
}
}, [deviceId]);
return (
<div className="App">
<DeviceProvider axiosInstance={axiosInstance} serialNumber={deviceId}>
<CRow>
<CCol>
<DeviceStatusCard />
</CCol>
</CRow>
<CRow>
<CCol lg="12" xl="6">
<CommandHistory />
<DeviceStatusCard
t={t}
loading={loading}
error={error}
deviceSerialNumber={deviceId}
getData={refresh}
deviceConfig={deviceConfig}
status={status}
lastStats={lastStats}
/>
</CCol>
<CCol lg="12" xl="6">
<DeviceActionCard />
</CCol>
</CRow>
<CRow>
<CCol lg="12" xl="6">
<DeviceStatisticsCard />
</CCol>
<CCol lg="12" xl="6">
<DeviceHealth />
<DeviceLogs />
<CCol>
<CCard>
<CCardBody className="p-0">
<CNav variant="tabs">
<CNavLink
className="font-weight-bold"
href="#"
active={index === 0}
onClick={() => setIndex(0)}
>
{t('statistics.title')}
</CNavLink>
<CNavLink
className="font-weight-bold"
href="#"
active={index === 1}
onClick={() => setIndex(1)}
>
{t('common.details')}
</CNavLink>
<CNavLink
className="font-weight-bold"
href="#"
active={index === 5}
onClick={() => setIndex(5)}
>
{t('configuration.title')}
</CNavLink>
<CNavLink
className="font-weight-bold"
href="#"
active={index === 6}
onClick={() => setIndex(6)}
>
{t('wifi_analysis.title')}
</CNavLink>
<CNavLink
className="font-weight-bold"
href="#"
active={index === 2}
onClick={() => setIndex(2)}
>
{t('commands.title')}
</CNavLink>
<CNavLink
className="font-weight-bold"
href="#"
active={index === 3}
onClick={() => setIndex(3)}
>
{t('health.title')}
</CNavLink>
<CNavLink
className="font-weight-bold"
href="#"
active={index === 4}
onClick={() => setIndex(4)}
>
{t('device_logs.title')}
</CNavLink>
</CNav>
<CTabContent>
<CTabPane active={index === 0}>
{index === 0 ? <DeviceStatisticsCard /> : null}
</CTabPane>
<CTabPane active={index === 1}>
{index === 1 ? (
<DeviceDetails
t={t}
loading={loading}
getData={refresh}
deviceConfig={deviceConfig}
status={status}
lastStats={lastStats}
/>
) : null}
</CTabPane>
<CTabPane active={index === 5}>
{index === 5 ? (
<ConfigurationDisplay deviceConfig={deviceConfig} getData={refresh} />
) : null}
</CTabPane>
<CTabPane active={index === 6}>{index === 6 ? <WifiAnalysis /> : null}</CTabPane>
<CTabPane active={index === 2}>
{index === 2 ? <CommandHistory /> : null}
</CTabPane>
<CTabPane active={index === 3}>{index === 3 ? <DeviceHealth /> : null}</CTabPane>
<CTabPane active={index === 4}>{index === 4 ? <DeviceLogs /> : null}</CTabPane>
</CTabContent>
</CCardBody>
</CCard>
</CCol>
</CRow>
</DeviceProvider>

View File

@@ -2,12 +2,24 @@
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import axiosInstance from 'utils/axiosInstance';
import {
CCard,
CCardBody,
CNav,
CNavLink,
CTabPane,
CTabContent,
CCardHeader,
} from '@coreui/react';
import { FirmwareList, useAuth, useToast } from 'ucentral-libs';
import FirmwareDashboard from 'components/FirmwareDashboard';
import EditFirmwareModal from 'components/EditFirmwareModal';
const FirmwareListPage = () => {
const { t } = useTranslation();
const { currentToken, endpoints } = useAuth();
const { addToast } = useToast();
const [index, setIndex] = useState(0);
const [page, setPage] = useState({ selected: 0 });
const [pageCount, setPageCount] = useState(0);
const [firmwarePerPage, setFirmwarePerPage] = useState('10');
@@ -17,9 +29,14 @@ const FirmwareListPage = () => {
const [filteredFirmware, setFilteredFirmware] = useState([]);
const [displayedFirmware, setDisplayedFirmware] = useState([]);
const [displayDev, setDisplayDev] = useState(false);
const [addNoteLoading, setAddNoteLoading] = useState(false);
const [updateDescriptionLoading, setUpdateDescriptionLoading] = useState(false);
const [loading, setLoading] = useState(false);
const [showEditModal, setShowEditModal] = useState(false);
const [firmwareToEdit, setFirmwareToEdit] = useState('');
const toggleEditModal = (id) => {
if (id) setFirmwareToEdit(id);
setShowEditModal(!showEditModal);
};
const displayFirmware = (currentPage, perPage, firmwareToDisplay) => {
setLoading(true);
@@ -79,7 +96,7 @@ const FirmwareListPage = () => {
const allFirmwares = [];
let continueFirmware = true;
let i = 1;
let i = 0;
while (continueFirmware) {
const newFirmwares = await getPartialFirmware(deviceType ?? selectedDeviceType, i);
if (newFirmwares === null || newFirmwares.length === 0) continueFirmware = false;
@@ -146,94 +163,65 @@ const FirmwareListPage = () => {
getFirmware(value);
};
const addNote = (value, id) => {
setAddNoteLoading(true);
const parameters = {
id,
notes: [{ note: value }],
};
const options = {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${currentToken}`,
},
};
axiosInstance
.put(`${endpoints.owfms}/api/v1/firmware/${id}`, parameters, options)
.then(() => {
getFirmware();
setAddNoteLoading(false);
})
.catch(() => {
setAddNoteLoading(false);
addToast({
title: t('common.error'),
body: t('common.general_error'),
color: 'danger',
autohide: true,
});
});
};
const updateDescription = (value, id) => {
setUpdateDescriptionLoading(true);
const parameters = {
id,
description: value,
};
const options = {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${currentToken}`,
},
};
axiosInstance
.put(`${endpoints.owfms}/api/v1/firmware/${id}`, parameters, options)
.then(() => {
getFirmware();
setUpdateDescriptionLoading(false);
})
.catch(() => {
setUpdateDescriptionLoading(false);
addToast({
title: t('common.error'),
body: t('common.general_error'),
color: 'danger',
autohide: true,
});
});
};
useEffect(() => {
if (selectedDeviceType === '' && !loading) getDeviceTypes();
}, []);
return (
<FirmwareList
t={t}
loading={loading}
page={page}
pageCount={pageCount}
setPage={updatePage}
data={displayedFirmware}
firmwarePerPage={firmwarePerPage}
setFirmwarePerPage={updateFirmwarePerPage}
selectedDeviceType={selectedDeviceType}
deviceTypes={deviceTypes}
setSelectedDeviceType={updateSelectedType}
addNote={addNote}
addNoteLoading={addNoteLoading}
updateDescription={updateDescription}
updateDescriptionLoading={updateDescriptionLoading}
displayDev={displayDev}
toggleDevDisplay={toggleDevDisplay}
/>
<CCard>
<CCardHeader className="dark-header">
<div className="text-value-lg mr-auto">{t('common.firmware')}</div>
</CCardHeader>
<CCardBody className="p-0">
<CNav variant="tabs">
<CNavLink
className="font-weight-bold"
href="#"
active={index === 0}
onClick={() => setIndex(0)}
>
{t('common.dashboard')}
</CNavLink>
<CNavLink
className="font-weight-bold"
href="#"
active={index === 1}
onClick={() => setIndex(1)}
>
{t('common.table')}
</CNavLink>
</CNav>
<CTabContent>
<CTabPane active={index === 0}>
<FirmwareDashboard />
</CTabPane>
<CTabPane active={index === 1}>
<FirmwareList
t={t}
loading={loading}
page={page}
pageCount={pageCount}
setPage={updatePage}
data={displayedFirmware}
firmwarePerPage={firmwarePerPage}
toggleEditModal={toggleEditModal}
setFirmwarePerPage={updateFirmwarePerPage}
selectedDeviceType={selectedDeviceType}
deviceTypes={deviceTypes}
setSelectedDeviceType={updateSelectedType}
displayDev={displayDev}
toggleDevDisplay={toggleDevDisplay}
/>
<EditFirmwareModal
firmwareId={firmwareToEdit}
show={showEditModal}
toggle={toggleEditModal}
refreshTable={getFirmware}
/>
</CTabPane>
</CTabContent>
</CCardBody>
</CCard>
);
};

View File

@@ -1,7 +1,8 @@
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import * as axios from 'axios';
import { LoginPage, useFormFields, useAuth } from 'ucentral-libs';
import { LoginPage, useFormFields, useAuth, useToast } from 'ucentral-libs';
import { setItem } from 'utils/localStorageHelper';
const initialFormState = {
username: {
@@ -46,6 +47,7 @@ const initialResponseState = {
const Login = () => {
const { t, i18n } = useTranslation();
const { setCurrentToken, setEndpoints } = useAuth();
const { addToast } = useToast();
const [defaultConfig, setDefaultConfig] = useState({
value: '',
error: false,
@@ -61,8 +63,7 @@ const Login = () => {
passwordPattern: '',
accessPolicy: '',
});
const [isLogin, setIsLogin] = useState(true);
const [isPasswordChange, setIsChangePassword] = useState(false);
const [formType, setFormType] = useState('login');
const [fields, updateFieldWithId, updateField, setFormFields] = useFormFields(initialFormState);
const axiosInstance = axios.create();
axiosInstance.defaults.timeout = 5000;
@@ -76,7 +77,8 @@ const Login = () => {
});
setLoginResponse(initialResponseState);
setForgotResponse(initialResponseState);
setIsLogin(!isLogin);
if (formType === 'login') setFormType('forgot-password');
else setFormType('login');
};
const cancelPasswordChange = () => {
@@ -88,8 +90,7 @@ const Login = () => {
});
setLoginResponse(initialResponseState);
setForgotResponse(initialResponseState);
setIsLogin(true);
setIsChangePassword(false);
setFormType('login');
};
const signInValidation = () => {
@@ -106,7 +107,10 @@ const Login = () => {
updateField('username', { error: true });
valid = false;
}
if (isPasswordChange && fields.newpassword.value !== fields.confirmpassword.value) {
if (
formType === 'change-password' &&
fields.newpassword.value !== fields.confirmpassword.value
) {
updateField('confirmpassword', { error: true });
valid = false;
}
@@ -129,7 +133,7 @@ const Login = () => {
const onKeyDown = (event, action) => {
if (event.code === 'Enter') {
action();
action(event);
}
};
@@ -172,6 +176,34 @@ const Login = () => {
.catch();
};
const getGatewayUIUrl = (token, gwUrl) => {
axiosInstance
.get(`${gwUrl}/api/v1/system?command=info`, {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`,
},
})
.then((response) => {
if (response.data.UI) setItem('owgw-ui', response.data.UI);
})
.catch(() => {});
};
const getProvUIUrl = (token, provUrl) => {
axiosInstance
.get(`${provUrl}/api/v1/system?command=info`, {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`,
},
})
.then((response) => {
if (response.data.UI) setItem('owprov-ui', response.data.UI);
})
.catch(() => {});
};
const SignIn = () => {
setLoginResponse(initialResponseState);
if (signInValidation()) {
@@ -183,18 +215,23 @@ const Login = () => {
password: fields.password.value,
};
if (isPasswordChange) {
if (formType === 'change-password') {
parameters.newPassword = fields.newpassword.value;
}
axiosInstance
.post(`${fields.ucentralsecurl.value}/api/v1/oauth2`, parameters)
.then((response) => {
if (response.data.userMustChangePassword) {
setIsChangePassword(true);
// If there's MFA to do
if (response.data.method && response.data.created) {
setFormType(`validation-${response.data.method}-${response.data.uuid}`);
return null;
}
sessionStorage.setItem('access_token', response.data.access_token);
if (response.data.userMustChangePassword) {
setFormType('change-password');
return null;
}
setItem('access_token', response.data.access_token);
token = response.data.access_token;
return axiosInstance.get(`${fields.ucentralsecurl.value}/api/v1/systemEndpoints`, {
headers: {
@@ -211,33 +248,55 @@ const Login = () => {
for (const endpoint of response.data.endpoints) {
endpoints[endpoint.type] = endpoint.uri;
}
sessionStorage.setItem('gateway_endpoints', JSON.stringify(endpoints));
if (endpoints.owgw) getGatewayUIUrl(token, endpoints.owgw);
if (endpoints.owprov) getProvUIUrl(token, endpoints.owprov);
setItem('gateway_endpoints', JSON.stringify(endpoints));
setEndpoints(endpoints);
setCurrentToken(token);
}
})
.catch((error) => {
if (!isPasswordChange) {
if (
error.response.status === 403 &&
error.response?.data?.ErrorDescription === 'Password change expected.'
) {
setIsChangePassword(true);
if (formType === 'change-password') {
if (error.response?.data?.ErrorCode === 3) {
setChangeResponse({
text: t('login.previously_used'),
error: true,
tried: true,
});
} else if (error.response?.data?.ErrorCode === 5) {
setChangeResponse({
text: t('common.invalid_password'),
error: true,
tried: true,
});
} else {
setChangeResponse({
text: t('login.change_password_error'),
error: true,
tried: true,
});
}
} else if (error.response.status === 403) {
if (error.response?.data?.ErrorCode === 1) setFormType('change-password');
else if (error.response?.data?.ErrorCode === 2) {
setLoginResponse({
text: t('common.invalid_credentials'),
error: true,
tried: true,
});
} else {
setLoginResponse({
text: t('login.login_error'),
error: true,
tried: true,
});
}
} else {
setLoginResponse({
text: t('login.login_error'),
error: true,
tried: true,
});
} else {
setChangeResponse({
text:
fields.newpassword.value === fields.password.value
? t('login.previously_used')
: t('login.change_password_error'),
error: true,
tried: true,
});
}
})
.finally(() => {
@@ -246,6 +305,107 @@ const Login = () => {
}
};
const submitForm = (event) => {
event.preventDefault();
setLoginResponse(initialResponseState);
setLoading(true);
let token = '';
const parameters = {
userId: event.target?.username?.value,
password: event.target?.password?.value,
};
if (formType === 'change-password') {
parameters.newPassword = fields.newpassword.value;
}
axiosInstance
.post(`${fields.ucentralsecurl.value}/api/v1/oauth2`, parameters)
.then((response) => {
// If there's MFA to do
if (response.data.method && response.data.created) {
setFormType(`validation-${response.data.method}-${response.data.uuid}`);
return null;
}
if (response.data.userMustChangePassword) {
setFormType('change-password');
return null;
}
setItem('access_token', response.data.access_token);
token = response.data.access_token;
return axiosInstance.get(`${fields.ucentralsecurl.value}/api/v1/systemEndpoints`, {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${response.data.access_token}`,
},
});
})
.then((response) => {
if (response) {
const endpoints = {
owsec: fields.ucentralsecurl.value,
};
for (const endpoint of response.data.endpoints) {
endpoints[endpoint.type] = endpoint.uri;
}
if (endpoints.owgw) getGatewayUIUrl(token, endpoints.owgw);
if (endpoints.owprov) getProvUIUrl(token, endpoints.owprov);
setItem('gateway_endpoints', JSON.stringify(endpoints));
setEndpoints(endpoints);
setCurrentToken(token);
}
})
.catch((error) => {
if (formType === 'change-password') {
if (error.response?.data?.ErrorCode === 3) {
setChangeResponse({
text: t('login.previously_used'),
error: true,
tried: true,
});
} else if (error.response?.data?.ErrorCode === 5) {
setChangeResponse({
text: t('common.invalid_password'),
error: true,
tried: true,
});
} else {
setChangeResponse({
text: t('login.change_password_error'),
error: true,
tried: true,
});
}
} else if (error.response.status === 403) {
if (error.response?.data?.ErrorCode === 1) setFormType('change-password');
else if (error.response?.data?.ErrorCode === 2) {
setLoginResponse({
text: t('common.invalid_credentials'),
error: true,
tried: true,
});
} else {
setLoginResponse({
text: t('login.login_error'),
error: true,
tried: true,
});
}
} else {
setLoginResponse({
text: t('login.login_error'),
error: true,
tried: true,
});
}
})
.finally(() => {
setLoading(false);
});
};
const sendForgotPasswordEmail = () => {
setForgotResponse(initialResponseState);
@@ -279,6 +439,96 @@ const Login = () => {
}
};
const validateCode = (code) => {
const options = {
headers: {
Accept: 'application/json',
},
};
const parameters = {
uuid: formType.split('-').slice(2).join('-'),
answer: code,
};
let token = '';
return axiosInstance
.post(
`${fields.ucentralsecurl.value}/api/v1/oauth2?completeMFAChallenge=true`,
parameters,
options,
)
.then((response) => {
if (response.data.userMustChangePassword) {
setFormType('change-password');
return null;
}
setItem('access_token', response.data.access_token);
token = response.data.access_token;
return axiosInstance.get(`${fields.ucentralsecurl.value}/api/v1/systemEndpoints`, {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${response.data.access_token}`,
},
});
})
.then((response) => {
if (response) {
const endpoints = {
owsec: fields.ucentralsecurl.value,
};
for (const endpoint of response.data.endpoints) {
endpoints[endpoint.type] = endpoint.uri;
}
if (endpoints.owgw) getGatewayUIUrl(token, endpoints.owgw);
if (endpoints.owprov) getProvUIUrl(token, endpoints.owprov);
setItem('gateway_endpoints', JSON.stringify(endpoints));
setEndpoints(endpoints);
setCurrentToken(token);
}
})
.catch(() => false)
.finally(() => {
setLoading(false);
return true;
});
};
const resendValidationCode = () => {
const options = {
headers: {
Accept: 'application/json',
},
};
const parameters = {
uuid: formType.split('-').slice(2).join('-'),
};
return axiosInstance
.post(`${fields.ucentralsecurl.value}/api/v1/oauth2?resendMFACode=true`, parameters, options)
.then(() => {
addToast({
title: t('common.success'),
body: t('user.new_code_sent'),
color: 'success',
autohide: true,
});
return true;
})
.catch((e) => {
addToast({
title: t('common.error'),
body: t('login.authentication_expired'),
color: 'danger',
autohide: true,
});
if (e.response?.data?.ErrorCode === 403) setFormType('login');
return false;
});
};
useEffect(() => {
getDefaultConfig();
}, []);
@@ -287,21 +537,23 @@ const Login = () => {
<LoginPage
t={t}
i18n={i18n}
logo="assets/OpenWiFi_LogoLockup_DarkGreyColour.svg"
signIn={SignIn}
loading={loading}
logo="assets/OpenWiFi_LogoLockup_DarkGreyColour.svg"
loginResponse={loginResponse}
forgotResponse={forgotResponse}
fields={fields}
updateField={updateFieldWithId}
toggleForgotPassword={toggleForgotPassword}
isLogin={isLogin}
isPasswordChange={isPasswordChange}
formType={formType}
onKeyDown={onKeyDown}
submitForm={submitForm}
sendForgotPasswordEmail={sendForgotPasswordEmail}
changePasswordResponse={changePasswordResponse}
cancelPasswordChange={cancelPasswordChange}
policies={policies}
validateCode={validateCode}
resendValidationCode={resendValidationCode}
/>
);
};

View File

@@ -1,8 +1,8 @@
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { CCard, CCardBody, CCardHeader, CButton, CPopover } from '@coreui/react';
import { CCard, CCardBody, CCardHeader, CButton, CPopover, CButtonToolbar } from '@coreui/react';
import { cilPencil, cilSave, cilSync, cilX } from '@coreui/icons';
import CIcon from '@coreui/icons-react';
import { cilSave } from '@coreui/icons';
import axiosInstance from 'utils/axiosInstance';
import { testRegex } from 'utils/helper';
import { useUser, EditMyProfile, useAuth, useToast } from 'ucentral-libs';
@@ -13,10 +13,17 @@ const initialState = {
error: false,
editable: false,
},
currentPassword: {
newPassword: {
value: '',
error: false,
editable: true,
ignore: true,
},
confirmNewPassword: {
value: '',
error: false,
editable: true,
ignore: true,
},
email: {
value: '',
@@ -33,26 +40,30 @@ const initialState = {
error: false,
editable: true,
},
userRole: {
value: '',
error: false,
editable: true,
},
notes: {
value: [],
editable: false,
},
userTypeProprietaryInfo: {
value: {},
error: false,
},
mfaMethod: {
value: '',
error: false,
},
};
const ProfilePage = () => {
const { t } = useTranslation();
const { currentToken, endpoints, user, getAvatar, avatar } = useAuth();
const { addToast } = useToast();
const [editing, setEditing] = useState(false);
const [loading, setLoading] = useState(false);
const [initialUser, setInitialUser] = useState({});
const [userForm, updateWithId, updateWithKey, setUser] = useUser(initialState);
const [newAvatar, setNewAvatar] = useState('');
const [newAvatarFile, setNewAvatarFile] = useState(null);
const [avatarDeleted, setAvatarDeleted] = useState(false);
const [fileInputKey, setFileInputKey] = useState(0);
const [policies, setPolicies] = useState({
passwordPolicy: '',
@@ -93,10 +104,24 @@ const ProfilePage = () => {
};
}
}
setInitialUser({ ...initialState, ...newUser });
newUser.mfaMethod = {
value: response.data.userTypeProprietaryInfo.mfa.enabled
? response.data.userTypeProprietaryInfo.mfa.method
: '',
error: false,
};
setUser({ ...initialState, ...newUser });
})
.catch(() => {});
.catch((e) => {
addToast({
title: t('common.error'),
body: t('user.error_fetching_users', { error: e }),
color: 'danger',
autohide: true,
});
});
};
const uploadAvatar = () => {
@@ -124,10 +149,10 @@ const ProfilePage = () => {
setNewAvatarFile(null);
setFileInputKey(fileInputKey + 1);
})
.catch((e) => {
.catch(() => {
addToast({
title: t('user.update_failure_title'),
body: t('user.update_failure', { error: e.response?.data?.ErrorDescription }),
body: t('user.update_failure'),
color: 'danger',
autohide: true,
});
@@ -137,34 +162,53 @@ const ProfilePage = () => {
const updateUser = () => {
setLoading(true);
const parameters = {
id: user.Id,
};
let newData = true;
for (const key of Object.keys(userForm)) {
if (userForm[key].editable && userForm[key].value !== initialUser[key].value) {
if (
key === 'currentPassword' &&
!testRegex(userForm[key].value, policies.passwordPattern)
) {
updateWithKey('currentPassword', {
error: true,
});
newData = false;
break;
} else {
parameters[key] = userForm[key].value;
}
}
}
if (newAvatarFile !== null) {
if (newAvatar !== '' && newAvatarFile !== null) {
uploadAvatar();
} else if (avatarDeleted) {
const options = {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${currentToken}`,
},
};
axiosInstance
.delete(`${endpoints.owsec}/api/v1/avatar/${user.Id}`, options)
.then(() => {
getAvatar();
})
.catch(() => {});
}
if (newData) {
if (
userForm.newPassword.value !== '' &&
(!testRegex(userForm.newPassword.value, policies.passwordPattern) ||
userForm.newPassword.value !== userForm.confirmNewPassword.value)
) {
updateWithKey('newPassword', {
error: true,
});
setLoading(false);
} else {
const newNotes = [];
for (let i = 0; i < userForm.notes.value.length; i += 1) {
if (userForm.notes.value[i].new) newNotes.push({ note: userForm.notes.value[i].note });
}
const propInfo = { ...userForm.userTypeProprietaryInfo.value };
propInfo.mfa.method = userForm.mfaMethod.value === '' ? undefined : userForm.mfaMethod.value;
propInfo.mfa.enabled = userForm.mfaMethod.value !== '';
const parameters = {
id: user.Id,
description: userForm.description.value,
name: userForm.name.value,
notes: newNotes,
userTypeProprietaryInfo: propInfo,
currentPassword: userForm.newPassword.value !== '' ? userForm.newPassword.value : undefined,
};
const options = {
headers: {
Accept: 'application/json',
@@ -181,6 +225,8 @@ const ProfilePage = () => {
color: 'success',
autohide: true,
});
// eslint-disable-next-line no-use-before-define
toggleEditing();
})
.catch((e) => {
addToast({
@@ -194,62 +240,90 @@ const ProfilePage = () => {
getUser();
setLoading(false);
});
} else {
setLoading(false);
}
};
const addNote = (currentNote) => {
setLoading(true);
const parameters = {
id: user.Id,
notes: [{ note: currentNote }],
};
const options = {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${currentToken}`,
},
};
axiosInstance
.put(`${endpoints.owsec}/api/v1/user/${user.Id}`, parameters, options)
.then(() => {
getUser();
})
.catch(() => {})
.finally(() => {
setLoading(false);
});
const newNotes = [...userForm.notes.value];
newNotes.unshift({
note: currentNote,
new: true,
created: new Date().getTime() / 1000,
createdBy: '',
});
updateWithKey('notes', { value: newNotes });
};
const showPreview = (e) => {
setAvatarDeleted(false);
const imageFile = e.target.files[0];
setNewAvatar(URL.createObjectURL(imageFile));
setNewAvatarFile(imageFile);
};
const deleteAvatar = () => {
setLoading(true);
setNewAvatar('');
setAvatarDeleted(true);
};
const sendPhoneNumberTest = async (phoneNumber) => {
const options = {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${currentToken}`,
},
};
return axiosInstance
.delete(`${endpoints.owsec}/api/v1/avatar/${user.Id}`, options)
.then(() => {
getAvatar();
})
.catch(() => {})
.finally(() => {
setLoading(false);
.post(`${endpoints.owsec}/api/v1/sms?validateNumber=true`, { to: phoneNumber }, options)
.then(() => true)
.catch(() => {
addToast({
title: t('common.error'),
body: t('user.error_sending_code'),
color: 'danger',
autohide: true,
});
return false;
});
};
const testVerificationCode = async (phoneNumber, code) => {
const options = {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${currentToken}`,
},
};
return axiosInstance
.post(
`${endpoints.owsec}/api/v1/sms?completeValidation=true&validationCode=${code}`,
{ to: phoneNumber },
options,
)
.then(() => true)
.catch(() => {
addToast({
title: t('common.error'),
body: t('user.wrong_validation_code'),
color: 'danger',
autohide: true,
});
return false;
});
};
const toggleEditing = () => {
if (editing) {
setAvatarDeleted(false);
setNewAvatar('');
getUser();
getAvatar();
}
setEditing(!editing);
};
useEffect(() => {
if (user.Id) {
getAvatar();
@@ -261,14 +335,34 @@ const ProfilePage = () => {
}, [user.Id]);
return (
<CCard>
<CCardHeader>
<div className="text-right">
<CPopover content={t('common.save')}>
<CButton onClick={updateUser} color="primary" variant="outline" disabled={loading}>
<CIcon content={cilSave} />
</CButton>
</CPopover>
<CCard className="my-0 py-0">
<CCardHeader className="dark-header">
<div style={{ fontWeight: '600' }} className=" text-value-lg float-left">
{t('user.my_profile')}
</div>
<div className="text-right float-right">
<CButtonToolbar role="group" className="justify-content-end">
<CPopover content={t('common.save')}>
<CButton disabled={!editing} color="info" onClick={updateUser} className="mx-1">
<CIcon name="cil-save" content={cilSave} />
</CButton>
</CPopover>
<CPopover content={t('common.edit')}>
<CButton disabled={editing} color="dark" onClick={toggleEditing} className="mx-1">
<CIcon name="cil-pencil" content={cilPencil} />
</CButton>
</CPopover>
<CPopover content={t('common.stop_editing')}>
<CButton disabled={!editing} color="dark" onClick={toggleEditing} className="mx-1">
<CIcon name="cil-x" content={cilX} />
</CButton>
</CPopover>
<CPopover content={t('common.refresh')}>
<CButton disabled={editing} color="info" onClick={getUser} className="mx-1">
<CIcon content={cilSync} />
</CButton>
</CPopover>
</CButtonToolbar>
</div>
</CCardHeader>
<CCardBody>
@@ -276,6 +370,7 @@ const ProfilePage = () => {
t={t}
user={userForm}
updateUserWithId={updateWithId}
updateWithKey={updateWithKey}
loading={loading}
policies={policies}
addNote={addNote}
@@ -284,6 +379,10 @@ const ProfilePage = () => {
showPreview={showPreview}
deleteAvatar={deleteAvatar}
fileInputKey={fileInputKey}
sendPhoneNumberTest={sendPhoneNumberTest}
testVerificationCode={testVerificationCode}
editing={editing}
avatarDeleted={avatarDeleted}
/>
</CCardBody>
</CCard>

View File

@@ -4,7 +4,7 @@ import { ApiStatusCard, useAuth, useToast } from 'ucentral-libs';
import { v4 as createUuid } from 'uuid';
import axiosInstance from 'utils/axiosInstance';
import { CRow, CCol } from '@coreui/react';
import { prettyDate, secondsToDetailed } from 'utils/helper';
import { secondsToDetailed } from 'utils/helper';
const SystemPage = () => {
const { t } = useTranslation();
@@ -21,7 +21,7 @@ const SystemPage = () => {
processors: t('common.unknown'),
uptime: t('common.unknown'),
version: t('common.unknown'),
start: t('common.unknown'),
certificates: [],
subsystems: [],
};
@@ -41,7 +41,9 @@ const SystemPage = () => {
return Promise.all([getInfo, getSubsystems])
.then(([newInfo, newSubs]) => {
systemInfo.uptime = secondsToDetailed(
let newSystem = { ...systemInfo };
newSystem = { ...newSystem, ...newInfo.data, ...newSubs.data };
newSystem.uptime = secondsToDetailed(
newInfo.data.uptime,
t('common.day'),
t('common.days'),
@@ -52,17 +54,14 @@ const SystemPage = () => {
t('common.second'),
t('common.seconds'),
);
systemInfo.hostname = newInfo.data.hostname;
systemInfo.os = newInfo.data.os;
systemInfo.processors = newInfo.data.processors;
systemInfo.version = newInfo.data.version;
systemInfo.start = prettyDate(newInfo.data.start);
systemInfo.subsystems = newSubs.data.list.sort((a, b) => {
newSystem.start = newInfo.data.start;
newSystem.subsystems = newSubs.data.list.sort((a, b) => {
if (a < b) return -1;
if (a > b) return 1;
return 0;
});
return systemInfo;
return newSystem;
})
.catch(() => systemInfo);
};
@@ -120,37 +119,17 @@ const SystemPage = () => {
}
};
const getColumn = (index) => {
const rows = [];
for (let i = index; i < endpointsInfo.length; i += 3) {
rows.push(endpointsInfo[i]);
}
return rows;
};
useEffect(() => {
getAllInfo();
}, []);
return (
<CRow>
<CCol md="12" lg="6" xxl="4">
{getColumn(0).map((info) => (
<ApiStatusCard key={createUuid()} t={t} info={info} reload={reload} />
))}
</CCol>
<CCol md="12" lg="6" xxl="4">
{getColumn(1).map((info) => (
<ApiStatusCard key={createUuid()} t={t} info={info} reload={reload} />
))}
</CCol>
<CCol md="12" lg="6" xxl="4">
{getColumn(2).map((info) => (
<ApiStatusCard key={createUuid()} t={t} info={info} reload={reload} />
))}
</CCol>
{endpointsInfo.map((info) => (
<CCol sm="12" lg="6" xxl="4" key={createUuid()}>
<ApiStatusCard t={t} info={info} reload={reload} />
</CCol>
))}
</CRow>
);
};

View File

@@ -20,6 +20,23 @@ const UserListPage = () => {
const [loading, setLoading] = useState(true);
const [deleteLoading, setDeleteLoading] = useState(false);
const [usersPerPage, setUsersPerPage] = useState(getItem('devicesPerPage') || '10');
const [policies, setPolicies] = useState({
passwordPolicy: '',
passwordPattern: '',
accessPolicy: '',
});
const getPasswordPolicy = () => {
axiosInstance
.post(`${endpoints.owsec}/api/v1/oauth2?requirements=true`, {})
.then((response) => {
const newPolicies = response.data;
newPolicies.accessPolicy = `${endpoints.owsec}${newPolicies.accessPolicy}`;
newPolicies.passwordPolicy = `${endpoints.owsec}${newPolicies.passwordPolicy}`;
setPolicies(response.data);
})
.catch(() => {});
};
const toggleCreateModal = () => {
setShowCreateModal(!showCreateModal);
@@ -180,6 +197,7 @@ const UserListPage = () => {
useEffect(() => {
getUsers();
getPasswordPolicy();
}, []);
useEffect(() => {
@@ -193,7 +211,7 @@ const UserListPage = () => {
<div>
<UserListTable
t={t}
users={usersToDisplay}
users={usersToDisplay.sort((a, b) => a.email > b.email)}
loading={loading}
usersPerPage={usersPerPage}
setUsersPerPage={updateUsersPerPage}
@@ -206,12 +224,18 @@ const UserListPage = () => {
toggleEdit={toggleEditModal}
refreshUsers={getUsers}
/>
<CreateUserModal show={showCreateModal} toggle={toggleCreateModal} getUsers={getUsers} />
<CreateUserModal
show={showCreateModal}
toggle={toggleCreateModal}
getUsers={getUsers}
policies={policies}
/>
<EditUserModal
show={showEditModal}
toggle={toggleEditModal}
userId={userToEdit}
getUsers={getUsers}
policies={policies}
/>
</div>
);

View File

@@ -1,4 +1,4 @@
import { useAuth } from 'ucentral-libs';
import { useAuth, ToastProvider } from 'ucentral-libs';
import { Route } from 'react-router-dom';
import React from 'react';
@@ -16,7 +16,9 @@ const Routes = () => {
currentToken !== '' && Object.keys(endpoints).length !== 0 ? (
<TheLayout {...props} />
) : (
<Login {...props} />
<ToastProvider>
<Login {...props} />
</ToastProvider>
)
}
/>

View File

@@ -1,36 +1,16 @@
import React from 'react';
const DevicePage = React.lazy(() => import('pages/DevicePage'));
const DeviceDashboard = React.lazy(() => import('pages/DeviceDashboard'));
const DeviceListPage = React.lazy(() => import('pages/DeviceListPage'));
const UserListPage = React.lazy(() => import('pages/UserListPage'));
const ProfilePage = React.lazy(() => import('pages/ProfilePage'));
const WifiAnalysisPage = React.lazy(() => import('pages/WifiAnalysisPage'));
const SystemPage = React.lazy(() => import('pages/SystemPage'));
const FirmwareListPage = React.lazy(() => import('pages/FirmwareListPage'));
const FirmwareDashboard = React.lazy(() => import('pages/FirmwareDashboard'));
export default [
{
path: '/devicedashboard',
exact: true,
name: 'common.device_dashboard',
component: DeviceDashboard,
},
{ path: '/devices', exact: true, name: 'common.devices', component: DeviceListPage },
{
path: '/devices/:deviceId/wifianalysis',
name: 'wifi_analysis.title',
component: WifiAnalysisPage,
},
{ path: '/devices/:deviceId', name: 'common.device_page', component: DevicePage },
{ path: '/firmware', name: 'firmware.title', component: FirmwareListPage },
{
path: '/firmwaredashboard',
exact: true,
name: 'common.firmware_dashboard',
component: FirmwareDashboard,
},
{ path: '/users', exact: true, name: 'user.users', component: UserListPage },
{ path: '/myprofile', exact: true, name: 'user.my_profile', component: ProfilePage },
{ path: '/system', exact: true, name: 'common.system', component: SystemPage },

View File

@@ -30,3 +30,16 @@ pre.ignore {
.tooltipRight { &::after { left: 75% !important; } }
.tooltipRight { &::before { left: 75% !important; } }
.dark-header {
padding: .25rem !important;
margin-top: 0 !important;
margin-bottom: 0 !important;
color: #ebedef !important;
background-color: #2f3d54 !important;
}
.avatar-lg {
height: 10rem;
width: 10rem;
}

View File

@@ -20,8 +20,12 @@ axiosInstance.interceptors.response.use(
case 401:
break;
case 403:
sessionStorage.clear();
window.location.href = '/';
if (error.response.data?.ErrorCode === 9) {
localStorage.removeItem('access_token');
localStorage.removeItem('gateway_endpoints');
sessionStorage.clear();
window.location.href = '/';
}
break;
default:
break;