mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui.git
synced 2025-10-30 02:12:33 +00:00
Compare commits
43 Commits
v2.5.0-RC1
...
v2.6.0-RC1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5101e41565 | ||
|
|
ebd2419634 | ||
|
|
133c256543 | ||
|
|
98a2a72f33 | ||
|
|
f008fd082e | ||
|
|
d2fd895582 | ||
|
|
746a812ae8 | ||
|
|
b67c69b88b | ||
|
|
f6ee20730a | ||
|
|
2829a96c84 | ||
|
|
37e1a92a89 | ||
|
|
81c4717472 | ||
|
|
94aac686c9 | ||
|
|
b75848515b | ||
|
|
a26cf9a3ff | ||
|
|
a7e4f728d2 | ||
|
|
921d234972 | ||
|
|
6bec9f977f | ||
|
|
6eaa9f8af1 | ||
|
|
5ef189b445 | ||
|
|
9f8283892e | ||
|
|
6ba2dc9601 | ||
|
|
e23512c860 | ||
|
|
32b6fe1625 | ||
|
|
8663b6d108 | ||
|
|
7794aa4c99 | ||
|
|
ba90ea59f4 | ||
|
|
aadb4c44a1 | ||
|
|
467ad39873 | ||
|
|
0a92b2db48 | ||
|
|
60a8f1ea61 | ||
|
|
1063061b47 | ||
|
|
54186575e0 | ||
|
|
114005d572 | ||
|
|
cde59a5ab1 | ||
|
|
e6bb26ce12 | ||
|
|
0cde953d58 | ||
|
|
ce7a804a70 | ||
|
|
67716aedde | ||
|
|
54a98cd6e5 | ||
|
|
31a901bea9 | ||
|
|
f0fdc90226 | ||
|
|
e14f892bc6 |
33
.github/workflows/ci.yml
vendored
33
.github/workflows/ci.yml
vendored
@@ -12,6 +12,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- 'release/*'
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -37,3 +38,35 @@ jobs:
|
|||||||
registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||||
registry_user: ucentral
|
registry_user: ucentral
|
||||||
registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
|
registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Notify on failure via Slack
|
||||||
|
if: failure() && github.ref == 'refs/heads/main'
|
||||||
|
uses: rtCamp/action-slack-notify@v2
|
||||||
|
env:
|
||||||
|
SLACK_USERNAME: GitHub Actions failure notifier
|
||||||
|
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
|
||||||
|
SLACK_COLOR: "${{ job.status }}"
|
||||||
|
SLACK_ICON: https://raw.githubusercontent.com/quintessence/slack-icons/master/images/github-logo-slack-icon.png
|
||||||
|
SLACK_TITLE: Docker build failed for OWGW-UI service
|
||||||
|
|
||||||
|
trigger-deploy-to-dev:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.ref == 'refs/heads/main'
|
||||||
|
needs:
|
||||||
|
- docker
|
||||||
|
steps:
|
||||||
|
- name: Checkout actions repo
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: Telecominfraproject/.github
|
||||||
|
path: github
|
||||||
|
|
||||||
|
- name: Trigger deployment of the latest version to dev instance and wait for result
|
||||||
|
uses: ./github/composite-actions/trigger-workflow-and-wait
|
||||||
|
with:
|
||||||
|
owner: Telecominfraproject
|
||||||
|
repo: wlan-testing
|
||||||
|
workflow: ucentralgw-dev-deployment.yaml
|
||||||
|
token: ${{ secrets.WLAN_TESTING_PAT }}
|
||||||
|
ref: master
|
||||||
|
inputs: '{"force_latest": "true"}'
|
||||||
|
|||||||
1
.github/workflows/cleanup.yml
vendored
1
.github/workflows/cleanup.yml
vendored
@@ -4,6 +4,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- 'release/*'
|
||||||
types: [ closed ]
|
types: [ closed ]
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
|
|||||||
46
.github/workflows/release.yml
vendored
Normal file
46
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
name: Release chart package
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
helm-package:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
env:
|
||||||
|
HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
|
||||||
|
HELM_REPO_USERNAME: ucentral
|
||||||
|
steps:
|
||||||
|
- name: Checkout uCentral assembly chart repo
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
path: wlan-cloud-ucentralgw-ui
|
||||||
|
|
||||||
|
- name: Build package
|
||||||
|
working-directory: wlan-cloud-ucentralgw-ui/helm
|
||||||
|
run: |
|
||||||
|
helm plugin install https://github.com/aslafy-z/helm-git --version 0.10.0
|
||||||
|
helm repo add bitnami https://charts.bitnami.com/bitnami
|
||||||
|
helm repo update
|
||||||
|
helm dependency update
|
||||||
|
mkdir dist
|
||||||
|
helm package . -d dist
|
||||||
|
|
||||||
|
- name: Generate GitHub release body
|
||||||
|
working-directory: wlan-cloud-ucentralgw-ui/helm
|
||||||
|
run: |
|
||||||
|
pip3 install yq -q
|
||||||
|
echo "Docker image - tip-tip-wlan-cloud-ucentral.jfrog.io/owgw-ui:$GITHUB_REF_NAME" > release.txt
|
||||||
|
echo "Helm charted may be attached to this release" >> release.txt
|
||||||
|
echo "Deployment artifacts may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/$GITHUB_REF_NAME" >> release.txt
|
||||||
|
|
||||||
|
- name: Create GitHub release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
body_path: wlan-cloud-ucentralgw-ui/helm/release.txt
|
||||||
|
files: wlan-cloud-ucentralgw-ui/helm/dist/*
|
||||||
@@ -30,3 +30,13 @@ Create chart name and version as used by the chart label.
|
|||||||
{{- define "owgwui.chart" -}}
|
{{- define "owgwui.chart" -}}
|
||||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "owgwui.ingress.apiVersion" -}}
|
||||||
|
{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" -}}
|
||||||
|
{{- print "networking.k8s.io/v1" -}}
|
||||||
|
{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
|
||||||
|
{{- print "networking.k8s.io/v1beta1" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- print "extensions/v1beta1" -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
{{- range $ingress, $ingressValue := .Values.ingresses }}
|
{{- range $ingress, $ingressValue := .Values.ingresses }}
|
||||||
{{- if $ingressValue.enabled }}
|
{{- if $ingressValue.enabled }}
|
||||||
---
|
---
|
||||||
apiVersion: extensions/v1beta1
|
apiVersion: {{ include "owgwui.ingress.apiVersion" $root }}
|
||||||
kind: Ingress
|
kind: Ingress
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "owgwui.fullname" $root }}-{{ $ingress }}
|
name: {{ include "owgwui.fullname" $root }}-{{ $ingress }}
|
||||||
@@ -36,9 +36,23 @@ spec:
|
|||||||
paths:
|
paths:
|
||||||
{{- range $ingressValue.paths }}
|
{{- range $ingressValue.paths }}
|
||||||
- path: {{ .path }}
|
- path: {{ .path }}
|
||||||
|
{{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
|
||||||
|
pathType: {{ .pathType | default "ImplementationSpecific" }}
|
||||||
|
{{- end }}
|
||||||
backend:
|
backend:
|
||||||
|
{{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
|
||||||
|
service:
|
||||||
|
name: {{ include "owgwui.fullname" $root }}-{{ .serviceName }}
|
||||||
|
port:
|
||||||
|
{{- if kindIs "string" .servicePort }}
|
||||||
|
name: {{ .servicePort }}
|
||||||
|
{{- else }}
|
||||||
|
number: {{ .servicePort }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
serviceName: {{ include "owgwui.fullname" $root }}-{{ .serviceName }}
|
serviceName: {{ include "owgwui.fullname" $root }}-{{ .serviceName }}
|
||||||
servicePort: {{ .servicePort }}
|
servicePort: {{ .servicePort }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ fullnameOverride: ""
|
|||||||
images:
|
images:
|
||||||
owgwui:
|
owgwui:
|
||||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw-ui
|
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw-ui
|
||||||
tag: main
|
tag: v2.6.0-RC1
|
||||||
pullPolicy: Always
|
pullPolicy: Always
|
||||||
|
|
||||||
services:
|
services:
|
||||||
owgwui:
|
owgwui:
|
||||||
type: NodePort
|
type: ClusterIP
|
||||||
ports:
|
ports:
|
||||||
http:
|
http:
|
||||||
servicePort: 80
|
servicePort: 80
|
||||||
@@ -49,6 +49,7 @@ ingresses:
|
|||||||
- chart-example.local
|
- chart-example.local
|
||||||
paths:
|
paths:
|
||||||
- path: /
|
- path: /
|
||||||
|
pathType: ImplementationSpecific
|
||||||
serviceName: owgwui
|
serviceName: owgwui
|
||||||
servicePort: http
|
servicePort: http
|
||||||
|
|
||||||
|
|||||||
144
package-lock.json
generated
144
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "ucentral-client",
|
"name": "ucentral-client",
|
||||||
"version": "2.5.44",
|
"version": "2.6.25",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ucentral-client",
|
"name": "ucentral-client",
|
||||||
"version": "2.5.44",
|
"version": "2.6.25",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@coreui/coreui": "^3.4.0",
|
"@coreui/coreui": "^3.4.0",
|
||||||
"@coreui/icons": "^2.0.1",
|
"@coreui/icons": "^2.0.1",
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-apexcharts": "^1.3.9",
|
"react-apexcharts": "^1.3.9",
|
||||||
|
"react-country-flag": "^3.0.2",
|
||||||
"react-csv": "^2.2.2",
|
"react-csv": "^2.2.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-flow-renderer": "^9.6.6",
|
"react-flow-renderer": "^9.6.6",
|
||||||
@@ -2944,6 +2945,18 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ansi-escapes/node_modules/type-fest": {
|
||||||
|
"version": "0.21.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
|
||||||
|
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ansi-html": {
|
"node_modules/ansi-html": {
|
||||||
"version": "0.0.7",
|
"version": "0.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
|
||||||
@@ -3176,9 +3189,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/async": {
|
"node_modules/async": {
|
||||||
"version": "2.6.3",
|
"version": "2.6.4",
|
||||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
|
||||||
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
|
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lodash": "^4.17.14"
|
"lodash": "^4.17.14"
|
||||||
@@ -3943,9 +3956,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cliui/node_modules/ansi-regex": {
|
"node_modules/cliui/node_modules/ansi-regex": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
|
||||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
@@ -6740,9 +6753,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.14.7",
|
"version": "1.14.9",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
|
||||||
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
|
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
@@ -9101,9 +9114,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimist": {
|
"node_modules/minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"node_modules/mixin-deep": {
|
"node_modules/mixin-deep": {
|
||||||
@@ -9132,9 +9145,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/moment": {
|
"node_modules/moment": {
|
||||||
"version": "2.29.1",
|
"version": "2.29.3",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",
|
||||||
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
|
"integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
@@ -10915,6 +10928,17 @@
|
|||||||
"react": ">=0.13"
|
"react": ">=0.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-country-flag": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-country-flag/-/react-country-flag-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JPaz+q3QD0/nZtHBKj5x3O7r/SgSG9kxbymdaIU0RqlDAcorJIe4KV0DFhWIdKh69q5cPVkIVERcMYGZdvXgAA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-csv": {
|
"node_modules/react-csv": {
|
||||||
"version": "2.2.2",
|
"version": "2.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-csv/-/react-csv-2.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-csv/-/react-csv-2.2.2.tgz",
|
||||||
@@ -13308,10 +13332,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/type-fest": {
|
"node_modules/type-fest": {
|
||||||
"version": "0.21.3",
|
"version": "0.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
|
||||||
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
|
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
@@ -13570,9 +13596,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/url-parse": {
|
"node_modules/url-parse": {
|
||||||
"version": "1.5.4",
|
"version": "1.5.10",
|
||||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||||
"integrity": "sha512-ITeAByWWoqutFClc/lRZnFplgXgEZr3WJ6XngMM/N9DMIm4K8zXPCZ1Jdu0rERwO84w1WC5wkle2ubwTA4NTBg==",
|
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"querystringify": "^2.1.1",
|
"querystringify": "^2.1.1",
|
||||||
@@ -14804,9 +14830,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/yargs/node_modules/ansi-regex": {
|
"node_modules/yargs/node_modules/ansi-regex": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
|
||||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
@@ -17000,6 +17026,14 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"type-fest": "^0.21.3"
|
"type-fest": "^0.21.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"type-fest": {
|
||||||
|
"version": "0.21.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
|
||||||
|
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ansi-html": {
|
"ansi-html": {
|
||||||
@@ -17168,9 +17202,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"async": {
|
"async": {
|
||||||
"version": "2.6.3",
|
"version": "2.6.4",
|
||||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
|
||||||
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
|
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"lodash": "^4.17.14"
|
"lodash": "^4.17.14"
|
||||||
@@ -17780,9 +17814,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
|
||||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"emoji-regex": {
|
"emoji-regex": {
|
||||||
@@ -19924,9 +19958,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"follow-redirects": {
|
"follow-redirects": {
|
||||||
"version": "1.14.7",
|
"version": "1.14.9",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
|
||||||
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ=="
|
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w=="
|
||||||
},
|
},
|
||||||
"for-in": {
|
"for-in": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@@ -21682,9 +21716,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"mixin-deep": {
|
"mixin-deep": {
|
||||||
@@ -21707,9 +21741,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.29.1",
|
"version": "2.29.3",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",
|
||||||
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
|
"integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw=="
|
||||||
},
|
},
|
||||||
"mrmime": {
|
"mrmime": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -22983,6 +23017,12 @@
|
|||||||
"prop-types": "^15.5.7"
|
"prop-types": "^15.5.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-country-flag": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-country-flag/-/react-country-flag-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JPaz+q3QD0/nZtHBKj5x3O7r/SgSG9kxbymdaIU0RqlDAcorJIe4KV0DFhWIdKh69q5cPVkIVERcMYGZdvXgAA==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"react-csv": {
|
"react-csv": {
|
||||||
"version": "2.2.2",
|
"version": "2.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-csv/-/react-csv-2.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-csv/-/react-csv-2.2.2.tgz",
|
||||||
@@ -24844,10 +24884,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type-fest": {
|
"type-fest": {
|
||||||
"version": "0.21.3",
|
"version": "0.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
|
||||||
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
|
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"type-is": {
|
"type-is": {
|
||||||
"version": "1.6.18",
|
"version": "1.6.18",
|
||||||
@@ -25062,9 +25104,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"url-parse": {
|
"url-parse": {
|
||||||
"version": "1.5.4",
|
"version": "1.5.10",
|
||||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||||
"integrity": "sha512-ITeAByWWoqutFClc/lRZnFplgXgEZr3WJ6XngMM/N9DMIm4K8zXPCZ1Jdu0rERwO84w1WC5wkle2ubwTA4NTBg==",
|
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"querystringify": "^2.1.1",
|
"querystringify": "^2.1.1",
|
||||||
@@ -25983,9 +26025,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
|
||||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"emoji-regex": {
|
"emoji-regex": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ucentral-client",
|
"name": "ucentral-client",
|
||||||
"version": "2.5.44",
|
"version": "2.6.25",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@coreui/coreui": "^3.4.0",
|
"@coreui/coreui": "^3.4.0",
|
||||||
"@coreui/icons": "^2.0.1",
|
"@coreui/icons": "^2.0.1",
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-apexcharts": "^1.3.9",
|
"react-apexcharts": "^1.3.9",
|
||||||
|
"react-country-flag": "^3.0.2",
|
||||||
"react-csv": "^2.2.2",
|
"react-csv": "^2.2.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-flow-renderer": "^9.6.6",
|
"react-flow-renderer": "^9.6.6",
|
||||||
|
|||||||
@@ -62,12 +62,14 @@ const BlinkModal = ({ show, toggleModal }) => {
|
|||||||
{ headers },
|
{ headers },
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
addToast({
|
if (chosenPattern !== 'blink') {
|
||||||
title: t('common.success'),
|
addToast({
|
||||||
body: t('commands.command_success'),
|
title: t('common.success'),
|
||||||
color: 'success',
|
body: t('commands.command_success'),
|
||||||
autohide: true,
|
color: 'success',
|
||||||
});
|
autohide: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
toggleModal();
|
toggleModal();
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@@ -145,8 +147,10 @@ const BlinkModal = ({ show, toggleModal }) => {
|
|||||||
</CModalBody>
|
</CModalBody>
|
||||||
<CModalFooter>
|
<CModalFooter>
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
label={t('blink.set_leds')}
|
label={t('common.submit')}
|
||||||
isLoadingLabel={t('common.loading_ellipsis')}
|
isLoadingLabel={
|
||||||
|
chosenPattern === 'blink' ? 'LEDs are blinking... ' : t('common.loading_ellipsis')
|
||||||
|
}
|
||||||
isLoading={waiting}
|
isLoading={waiting}
|
||||||
action={doAction}
|
action={doAction}
|
||||||
block={false}
|
block={false}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const ConfigurationDisplay = ({ getData, deviceConfig }) => {
|
|||||||
<CopyToClipboardButton
|
<CopyToClipboardButton
|
||||||
t={t}
|
t={t}
|
||||||
size="sm"
|
size="sm"
|
||||||
content={JSON.stringify(deviceConfig?.configuration ?? {})}
|
content={JSON.stringify(deviceConfig?.configuration ?? {}, null, 4)}
|
||||||
/>
|
/>
|
||||||
</h5>
|
</h5>
|
||||||
<CRow>
|
<CRow>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
CAlert,
|
||||||
CButton,
|
CButton,
|
||||||
CModal,
|
CModal,
|
||||||
CModalHeader,
|
CModalHeader,
|
||||||
@@ -100,8 +101,14 @@ const ConfigureModal = ({ show, toggleModal }) => {
|
|||||||
});
|
});
|
||||||
toggleModal();
|
toggleModal();
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((e) => {
|
||||||
setResponseBody('Error while submitting command!');
|
setResponseBody('Error while submitting command!');
|
||||||
|
addToast({
|
||||||
|
title: t('common.error'),
|
||||||
|
body: `${t('common.general_error')}: ${e.response?.data?.ErrorDescription}`,
|
||||||
|
color: 'danger',
|
||||||
|
autohide: true,
|
||||||
|
});
|
||||||
setHadFailure(true);
|
setHadFailure(true);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
@@ -196,11 +203,9 @@ const ConfigureModal = ({ show, toggleModal }) => {
|
|||||||
/>
|
/>
|
||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
<div hidden={!hadSuccess && !hadFailure}>
|
<CAlert color="danger" hidden={!hadSuccess && !hadFailure}>
|
||||||
<div>
|
{responseBody}
|
||||||
<pre className="ignore">{responseBody}</pre>
|
</CAlert>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CModalBody>
|
</CModalBody>
|
||||||
<CModalFooter>
|
<CModalFooter>
|
||||||
<div hidden={!checkingIfSure}>Are you sure?</div>
|
<div hidden={!checkingIfSure}>Are you sure?</div>
|
||||||
|
|||||||
@@ -66,7 +66,16 @@ const DeviceDashboard = ({ t, data, loading }) => (
|
|||||||
</CCol>
|
</CCol>
|
||||||
<CCol>
|
<CCol>
|
||||||
<CWidgetIcon
|
<CWidgetIcon
|
||||||
text={t('common.devices')}
|
text={
|
||||||
|
<div>
|
||||||
|
<div className="float-left">{t('common.devices')}</div>
|
||||||
|
<div className="float-left ml-2">
|
||||||
|
<CPopover content={t('device.count_explanation')}>
|
||||||
|
<CIcon content={cilInfo} />
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
header={<h2>{data.numberOfDevices}</h2>}
|
header={<h2>{data.numberOfDevices}</h2>}
|
||||||
color="primary"
|
color="primary"
|
||||||
iconPadding={false}
|
iconPadding={false}
|
||||||
@@ -87,7 +96,10 @@ const DeviceDashboard = ({ t, data, loading }) => (
|
|||||||
tooltips: {
|
tooltips: {
|
||||||
callbacks: {
|
callbacks: {
|
||||||
title: (item, ds) => ds.labels[item[0].index],
|
title: (item, ds) => ds.labels[item[0].index],
|
||||||
label: (item, ds) => `${ds.datasets[0].data[item.index]}%`,
|
label: (item, ds) =>
|
||||||
|
`${ds.datasets[0].data[item.index]} devices, (${
|
||||||
|
data.statusDevices[ds.datasets[0].data[item.index]]
|
||||||
|
}%)`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
@@ -120,7 +132,9 @@ const DeviceDashboard = ({ t, data, loading }) => (
|
|||||||
callbacks: {
|
callbacks: {
|
||||||
title: (item, ds) => ds.labels[item[0].index],
|
title: (item, ds) => ds.labels[item[0].index],
|
||||||
label: (item, ds) =>
|
label: (item, ds) =>
|
||||||
`${ds.datasets[0].data[item.index]}${t('common.of_connected')}`,
|
`${ds.datasets[0].data[item.index]} connected devices (${
|
||||||
|
data.healthDevices[ds.datasets[0].data[item.index]]
|
||||||
|
}%)`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
@@ -149,9 +163,9 @@ const DeviceDashboard = ({ t, data, loading }) => (
|
|||||||
callbacks: {
|
callbacks: {
|
||||||
title: (item, ds) => ds.labels[item[0].index],
|
title: (item, ds) => ds.labels[item[0].index],
|
||||||
label: (item, ds) =>
|
label: (item, ds) =>
|
||||||
`${ds.datasets[0].data[item.index]}% of ${
|
`${ds.datasets[0].data[item.index]} associations (${
|
||||||
data.totalAssociations
|
data.associationData[ds.datasets[0].data[item.index]]
|
||||||
} associations`,
|
}%)`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
@@ -306,7 +320,9 @@ const DeviceDashboard = ({ t, data, loading }) => (
|
|||||||
callbacks: {
|
callbacks: {
|
||||||
title: (item, ds) => ds.labels[item[0].index],
|
title: (item, ds) => ds.labels[item[0].index],
|
||||||
label: (item, ds) =>
|
label: (item, ds) =>
|
||||||
`${ds.datasets[0].data[item.index]}${t('common.of_connected')}`,
|
`${ds.datasets[0].data[item.index]} connected devices (${
|
||||||
|
data.certificateData[ds.datasets[0].data[item.index]]
|
||||||
|
}%)`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
|
|||||||
@@ -55,9 +55,12 @@ const DeviceDashboard = () => {
|
|||||||
const statusColors = [];
|
const statusColors = [];
|
||||||
const statusLabels = [];
|
const statusLabels = [];
|
||||||
let totalDevices = parsedData.status.reduce((acc, point) => acc + point.value, 0);
|
let totalDevices = parsedData.status.reduce((acc, point) => acc + point.value, 0);
|
||||||
|
parsedData.numberOfDevices = totalDevices;
|
||||||
|
parsedData.statusDevices = {};
|
||||||
for (const point of parsedData.status) {
|
for (const point of parsedData.status) {
|
||||||
statusDs.push(Math.round((point.value / totalDevices) * 100));
|
statusDs.push(point.value);
|
||||||
statusLabels.push(point.tag);
|
statusLabels.push(point.tag);
|
||||||
|
parsedData.statusDevices[point.value] = Math.round((point.value / totalDevices) * 100);
|
||||||
let color = '';
|
let color = '';
|
||||||
switch (point.tag) {
|
switch (point.tag) {
|
||||||
case 'connected':
|
case 'connected':
|
||||||
@@ -96,7 +99,7 @@ const DeviceDashboard = () => {
|
|||||||
const healthLabels = [];
|
const healthLabels = [];
|
||||||
totalDevices = parsedData.healths.reduce((acc, point) => acc + point.value, 0);
|
totalDevices = parsedData.healths.reduce((acc, point) => acc + point.value, 0);
|
||||||
for (const point of parsedData.healths) {
|
for (const point of parsedData.healths) {
|
||||||
healthDs.push(Math.round((point.value / totalDevices) * 100));
|
healthDs.push(point.value);
|
||||||
healthLabels.push(point.tag);
|
healthLabels.push(point.tag);
|
||||||
let color = '';
|
let color = '';
|
||||||
switch (point.tag) {
|
switch (point.tag) {
|
||||||
@@ -122,6 +125,12 @@ const DeviceDashboard = () => {
|
|||||||
}
|
}
|
||||||
healthColors.push(color);
|
healthColors.push(color);
|
||||||
}
|
}
|
||||||
|
parsedData.healthDevices = {
|
||||||
|
[devicesAt100]: Math.round((devicesAt100 / totalDevices) * 100),
|
||||||
|
[devicesUp90]: Math.round((devicesUp90 / totalDevices) * 100),
|
||||||
|
[devicesUp60]: Math.round((devicesUp60 / totalDevices) * 100),
|
||||||
|
[devicesDown60]: Math.round((devicesDown60 / totalDevices) * 100),
|
||||||
|
};
|
||||||
parsedData.healths = {
|
parsedData.healths = {
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
@@ -144,10 +153,12 @@ const DeviceDashboard = () => {
|
|||||||
const associationsColors = [];
|
const associationsColors = [];
|
||||||
const associationsLabels = [];
|
const associationsLabels = [];
|
||||||
const totalAssociations = parsedData.associations.reduce((acc, point) => acc + point.value, 0);
|
const totalAssociations = parsedData.associations.reduce((acc, point) => acc + point.value, 0);
|
||||||
|
parsedData.associationData = {};
|
||||||
for (let i = 0; i < parsedData.associations.length; i += 1) {
|
for (let i = 0; i < parsedData.associations.length; i += 1) {
|
||||||
const point = parsedData.associations[i];
|
const point = parsedData.associations[i];
|
||||||
associationsDs.push(Math.round((point.value / totalAssociations) * 100));
|
associationsDs.push(point.value);
|
||||||
associationsLabels.push(point.tag);
|
associationsLabels.push(point.tag);
|
||||||
|
parsedData.associationData[point.value] = Math.round((point.value / totalAssociations) * 100);
|
||||||
|
|
||||||
switch (parsedData.associations[i].tag) {
|
switch (parsedData.associations[i].tag) {
|
||||||
case '2G':
|
case '2G':
|
||||||
@@ -258,8 +269,10 @@ const DeviceDashboard = () => {
|
|||||||
const certificatesColors = [];
|
const certificatesColors = [];
|
||||||
const certificatesLabels = [];
|
const certificatesLabels = [];
|
||||||
const totalCerts = parsedData.certificates.reduce((acc, point) => acc + point.value, 0);
|
const totalCerts = parsedData.certificates.reduce((acc, point) => acc + point.value, 0);
|
||||||
|
parsedData.certificateData = {};
|
||||||
for (const point of parsedData.certificates) {
|
for (const point of parsedData.certificates) {
|
||||||
certificatesDs.push(Math.round((point.value / totalCerts) * 100));
|
certificatesDs.push(point.value);
|
||||||
|
parsedData.certificateData[point.value] = Math.round((point.value / totalCerts) * 100);
|
||||||
certificatesLabels.push(point.tag);
|
certificatesLabels.push(point.tag);
|
||||||
let color = '';
|
let color = '';
|
||||||
switch (point.tag) {
|
switch (point.tag) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
|
|||||||
import { useAuth, useToast, useToggle } from 'ucentral-libs';
|
import { useAuth, useToast, useToggle } from 'ucentral-libs';
|
||||||
import axiosInstance from 'utils/axiosInstance';
|
import axiosInstance from 'utils/axiosInstance';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useGlobalWebSocket } from 'contexts/WebSocketProvider';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
|
|
||||||
const DeviceFirmwareModal = ({
|
const DeviceFirmwareModal = ({
|
||||||
@@ -19,6 +20,7 @@ const DeviceFirmwareModal = ({
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [firmwareVersions, setFirmwareVersions] = useState([]);
|
const [firmwareVersions, setFirmwareVersions] = useState([]);
|
||||||
const [keepRedirector, toggleKeepRedirector, setKeepRedirector] = useToggle(true);
|
const [keepRedirector, toggleKeepRedirector, setKeepRedirector] = useToggle(true);
|
||||||
|
const { addDeviceListener } = useGlobalWebSocket();
|
||||||
|
|
||||||
const getPartialFirmware = async (offset) => {
|
const getPartialFirmware = async (offset) => {
|
||||||
const headers = {
|
const headers = {
|
||||||
@@ -90,6 +92,17 @@ const DeviceFirmwareModal = ({
|
|||||||
headers,
|
headers,
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
addDeviceListener({
|
||||||
|
serialNumber: device.serialNumber,
|
||||||
|
types: ['device_firmware_upgrade'],
|
||||||
|
addToast: (title, body) =>
|
||||||
|
addToast({
|
||||||
|
title,
|
||||||
|
body,
|
||||||
|
color: 'info',
|
||||||
|
autohide: true,
|
||||||
|
}),
|
||||||
|
});
|
||||||
setUpgradeStatus({
|
setUpgradeStatus({
|
||||||
loading: false,
|
loading: false,
|
||||||
result: {
|
result: {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import ReactTooltip from 'react-tooltip';
|
|||||||
import { v4 as createUuid } from 'uuid';
|
import { v4 as createUuid } from 'uuid';
|
||||||
import { cleanBytesString } from 'utils/helper';
|
import { cleanBytesString } from 'utils/helper';
|
||||||
import { DeviceBadge, LoadingButton } from 'ucentral-libs';
|
import { DeviceBadge, LoadingButton } from 'ucentral-libs';
|
||||||
|
import ReactCountryFlag from 'react-country-flag';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
const DeviceListTable = ({
|
const DeviceListTable = ({
|
||||||
@@ -324,11 +325,18 @@ const DeviceListTable = ({
|
|||||||
ipAddress: (item) => (
|
ipAddress: (item) => (
|
||||||
<td className="align-middle">
|
<td className="align-middle">
|
||||||
<CPopover
|
<CPopover
|
||||||
content={item.ipAddress ? item.ipAddress : t('common.na')}
|
content={`${item.locale !== '' ? `${item.locale} - ` : ''}${item.ipAddress}`}
|
||||||
placement="top"
|
placement="top"
|
||||||
>
|
>
|
||||||
<div style={{ width: 'calc(8vw)' }} className="text-truncate align-middle">
|
<div style={{ width: 'calc(8vw)' }} className="text-truncate align-middle">
|
||||||
{item.ipAddress}
|
{item.locale !== '' && item.ipAddress !== '' && (
|
||||||
|
<ReactCountryFlag
|
||||||
|
style={{ width: '24px', height: '24px' }}
|
||||||
|
countryCode={item?.locale}
|
||||||
|
svg
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{` ${item.ipAddress}`}
|
||||||
</div>
|
</div>
|
||||||
</CPopover>
|
</CPopover>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { getItem, setItem } from 'utils/localStorageHelper';
|
|||||||
import DeviceSearchBar from 'components/DeviceSearchBar';
|
import DeviceSearchBar from 'components/DeviceSearchBar';
|
||||||
import DeviceFirmwareModal from 'components/DeviceFirmwareModal';
|
import DeviceFirmwareModal from 'components/DeviceFirmwareModal';
|
||||||
import FirmwareHistoryModal from 'components/FirmwareHistoryModal';
|
import FirmwareHistoryModal from 'components/FirmwareHistoryModal';
|
||||||
|
import { useGlobalWebSocket } from 'contexts/WebSocketProvider';
|
||||||
import { useAuth, useToast } from 'ucentral-libs';
|
import { useAuth, useToast } from 'ucentral-libs';
|
||||||
import Table from './Table';
|
import Table from './Table';
|
||||||
import meshIcon from '../../assets/icons/Mesh.png';
|
import meshIcon from '../../assets/icons/Mesh.png';
|
||||||
@@ -17,6 +18,7 @@ const DeviceList = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { addToast } = useToast();
|
const { addToast } = useToast();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const [overrides, setOverrides] = useState({});
|
||||||
const [page, setPage] = useState(parseInt(sessionStorage.getItem('deviceTable') ?? 0, 10));
|
const [page, setPage] = useState(parseInt(sessionStorage.getItem('deviceTable') ?? 0, 10));
|
||||||
const { currentToken, endpoints } = useAuth();
|
const { currentToken, endpoints } = useAuth();
|
||||||
const [upgradeStatus, setUpgradeStatus] = useState({
|
const [upgradeStatus, setUpgradeStatus] = useState({
|
||||||
@@ -36,6 +38,7 @@ const DeviceList = () => {
|
|||||||
deviceType: '',
|
deviceType: '',
|
||||||
serialNumber: '',
|
serialNumber: '',
|
||||||
});
|
});
|
||||||
|
const { lastMessage } = useGlobalWebSocket();
|
||||||
|
|
||||||
const deviceIcons = {
|
const deviceIcons = {
|
||||||
meshIcon,
|
meshIcon,
|
||||||
@@ -56,6 +59,7 @@ const DeviceList = () => {
|
|||||||
|
|
||||||
const getDeviceInformation = (selectedPage = page, devicePerPage = devicesPerPage) => {
|
const getDeviceInformation = (selectedPage = page, devicePerPage = devicesPerPage) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
setOverrides({});
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -355,10 +359,28 @@ const DeviceList = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const displayDevices = () =>
|
||||||
|
devices.map((device) => ({
|
||||||
|
...device,
|
||||||
|
connected:
|
||||||
|
overrides[device.serialNumber] !== undefined
|
||||||
|
? overrides[device.serialNumber]
|
||||||
|
: device.connected,
|
||||||
|
}));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getCount();
|
getCount();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (lastMessage && lastMessage.type === 'DEVICE') {
|
||||||
|
const { serialNumber: msgSerial, isConnected } = lastMessage;
|
||||||
|
if (overrides[msgSerial] === undefined || overrides[msgSerial] !== isConnected) {
|
||||||
|
setOverrides({ ...overrides, [msgSerial]: isConnected });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [lastMessage, overrides]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (upgradeStatus.result !== undefined) {
|
if (upgradeStatus.result !== undefined) {
|
||||||
addToast({
|
addToast({
|
||||||
@@ -382,7 +404,7 @@ const DeviceList = () => {
|
|||||||
currentPage={page}
|
currentPage={page}
|
||||||
t={t}
|
t={t}
|
||||||
searchBar={<DeviceSearchBar />}
|
searchBar={<DeviceSearchBar />}
|
||||||
devices={devices}
|
devices={displayDevices()}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
updateDevicesPerPage={updateDevicesPerPage}
|
updateDevicesPerPage={updateDevicesPerPage}
|
||||||
devicesPerPage={devicesPerPage}
|
devicesPerPage={devicesPerPage}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { useAuth, DeviceSearchBar as SearchBar } from 'ucentral-libs';
|
import { useAuth, DeviceSearchBar as SearchBar } from 'ucentral-libs';
|
||||||
import { checkIfJson } from 'utils/helper';
|
import { toJson } from 'utils/helper';
|
||||||
|
|
||||||
const DeviceSearchBar = ({ action }) => {
|
const DeviceSearchBar = ({ action }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -44,11 +44,9 @@ const DeviceSearchBar = ({ action }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
socket.onmessage = (event) => {
|
socket.onmessage = (event) => {
|
||||||
if (checkIfJson(event.data)) {
|
const result = toJson(event.data);
|
||||||
const result = JSON.parse(event.data);
|
if (result && result.serialNumbers) {
|
||||||
if (result.command === 'serial_number_search' && result.serialNumbers) {
|
setResults(result.serialNumbers);
|
||||||
setResults(result.serialNumbers);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,16 @@ const FirmwareDashboard = ({ t, data, loading }) => {
|
|||||||
</CCol>
|
</CCol>
|
||||||
<CCol>
|
<CCol>
|
||||||
<CWidgetIcon
|
<CWidgetIcon
|
||||||
text={t('common.devices')}
|
text={
|
||||||
|
<div>
|
||||||
|
<div className="float-left">{t('common.devices')}</div>
|
||||||
|
<div className="float-left ml-2">
|
||||||
|
<CPopover content={t('device.firmware_count_explanation')}>
|
||||||
|
<CIcon content={cilInfo} />
|
||||||
|
</CPopover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
header={<h2>{data.numberOfDevices}</h2>}
|
header={<h2>{data.numberOfDevices}</h2>}
|
||||||
color="primary"
|
color="primary"
|
||||||
iconPadding={false}
|
iconPadding={false}
|
||||||
@@ -212,7 +221,7 @@ const FirmwareDashboard = ({ t, data, loading }) => {
|
|||||||
tooltips: {
|
tooltips: {
|
||||||
callbacks: {
|
callbacks: {
|
||||||
title: (item, ds) => ds.labels[item[0].index],
|
title: (item, ds) => ds.labels[item[0].index],
|
||||||
label: (item, ds) => `${ds.datasets[0].data[item.index]}%`,
|
label: (item, ds) => `${ds.datasets[0].data[item.index]} devices`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
|
|||||||
@@ -65,9 +65,12 @@ const FirmwareDashboard = () => {
|
|||||||
const statusColors = [];
|
const statusColors = [];
|
||||||
const statusLabels = [];
|
const statusLabels = [];
|
||||||
const totalDevices = parsedData.status.reduce((acc, point) => acc + point.value, 0);
|
const totalDevices = parsedData.status.reduce((acc, point) => acc + point.value, 0);
|
||||||
|
parsedData.statusDevices = {};
|
||||||
|
parsedData.numberOfDevices = totalDevices;
|
||||||
for (const point of parsedData.status) {
|
for (const point of parsedData.status) {
|
||||||
statusDs.push(Math.round((point.value / totalDevices) * 100));
|
statusDs.push(point.value);
|
||||||
statusLabels.push(point.tag);
|
statusLabels.push(point.tag);
|
||||||
|
parsedData[point.value] = point.value;
|
||||||
let color = '';
|
let color = '';
|
||||||
switch (point.tag) {
|
switch (point.tag) {
|
||||||
case 'connected':
|
case 'connected':
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { cilX } from '@coreui/icons';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import axiosInstance from 'utils/axiosInstance';
|
import axiosInstance from 'utils/axiosInstance';
|
||||||
import { useAuth, useDevice } from 'ucentral-libs';
|
import { useAuth, useDevice, CopyToClipboardButton } from 'ucentral-libs';
|
||||||
|
|
||||||
const LatestStatisticsModal = ({ show, toggle }) => {
|
const LatestStatisticsModal = ({ show, toggle }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -51,6 +51,13 @@ const LatestStatisticsModal = ({ show, toggle }) => {
|
|||||||
</div>
|
</div>
|
||||||
</CModalHeader>
|
</CModalHeader>
|
||||||
<CModalBody>
|
<CModalBody>
|
||||||
|
<div style={{ textAlign: 'right' }}>
|
||||||
|
<CopyToClipboardButton
|
||||||
|
t={t}
|
||||||
|
size="lg"
|
||||||
|
content={JSON.stringify(latestStats ?? {}, null, 4)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<pre className="ignore">{JSON.stringify(latestStats, null, 2)}</pre>
|
<pre className="ignore">{JSON.stringify(latestStats, null, 2)}</pre>
|
||||||
</CModalBody>
|
</CModalBody>
|
||||||
</CModal>
|
</CModal>
|
||||||
|
|||||||
@@ -124,50 +124,27 @@ const StatisticsChartList = ({ setOptions, section, setStart, setEnd, time }) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Looping through all the data
|
// Looping through all the data
|
||||||
let prevTx = 0;
|
const prevTxObj = {};
|
||||||
let prevRx = 0;
|
const prevRxObj = {};
|
||||||
for (const log of sortedData) {
|
for (const log of sortedData) {
|
||||||
// Looping through the interfaces of the log
|
// Looping through the interfaces of the log
|
||||||
const version = log.data.version ?? 0;
|
const version = log.data.version ?? 0;
|
||||||
for (const inter of log.data.interfaces) {
|
for (const inter of log.data.interfaces) {
|
||||||
if (inter.ssids?.length > 0) {
|
if (version > 0) {
|
||||||
let totalTx = 0;
|
const prevTx = prevTxObj[inter.name] !== undefined ? prevTxObj[inter.name] : 0;
|
||||||
let totalRx = 0;
|
const prevRx = prevTxObj[inter.name] !== undefined ? prevRxObj[inter.name] : 0;
|
||||||
for (const ssid of inter.ssids) {
|
const tx = inter.counters ? Math.floor(inter.counters.tx_bytes / 1024) : 0;
|
||||||
if (ssid.associations) {
|
const rx = inter.counters ? Math.floor(inter.counters.rx_bytes / 1024) : 0;
|
||||||
for (const assoc of ssid.associations) {
|
interfaceList[interfaceTypes[inter.name]][0].data.push(Math.max(0, tx - prevTx));
|
||||||
if (version === 0) {
|
interfaceList[interfaceTypes[inter.name]][1].data.push(Math.max(0, rx - prevRx));
|
||||||
if (assoc.deltas) {
|
prevTxObj[inter.name] = tx;
|
||||||
totalTx += assoc.deltas?.tx_bytes ?? 0;
|
prevRxObj[inter.name] = rx;
|
||||||
totalRx += assoc.deltas?.rx_bytes ?? 0;
|
|
||||||
} else {
|
|
||||||
totalTx += assoc.tx_bytes ?? 0;
|
|
||||||
totalRx += assoc.rx_bytes ?? 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
totalTx += assoc.tx_bytes ?? 0;
|
|
||||||
totalRx += assoc.rx_bytes ?? 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (version > 0) {
|
|
||||||
const tx = Math.floor(totalTx / 1024);
|
|
||||||
const rx = Math.floor(totalRx / 1024);
|
|
||||||
interfaceList[interfaceTypes[inter.name]][0].data.push(Math.max(tx - prevTx, 0));
|
|
||||||
interfaceList[interfaceTypes[inter.name]][1].data.push(Math.max(rx - prevRx, 0));
|
|
||||||
prevTx = tx;
|
|
||||||
prevRx = rx;
|
|
||||||
} else {
|
|
||||||
interfaceList[interfaceTypes[inter.name]][0].data.push(Math.floor(totalTx / 1024));
|
|
||||||
interfaceList[interfaceTypes[inter.name]][1].data.push(Math.floor(totalRx / 1024));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
interfaceList[interfaceTypes[inter.name]][0].data.push(
|
interfaceList[interfaceTypes[inter.name]][0].data.push(
|
||||||
inter.counters ? Math.floor(inter.counters.tx_bytes) : 0,
|
inter.counters ? Math.floor(inter.counters.tx_bytes / 1024) : 0,
|
||||||
);
|
);
|
||||||
interfaceList[interfaceTypes[inter.name]][1].data.push(
|
interfaceList[interfaceTypes[inter.name]][1].data.push(
|
||||||
inter.counters ? Math.floor(inter.counters.rx_bytes) : 0,
|
inter.counters ? Math.floor(inter.counters.rx_bytes / 1024) : 0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,13 @@ import axiosInstance from 'utils/axiosInstance';
|
|||||||
import eventBus from 'utils/eventBus';
|
import eventBus from 'utils/eventBus';
|
||||||
import { LoadingButton, useAuth, useDevice, useToast } from 'ucentral-libs';
|
import { LoadingButton, useAuth, useDevice, useToast } from 'ucentral-libs';
|
||||||
import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody';
|
import SuccessfulActionModalBody from 'components/SuccessfulActionModalBody';
|
||||||
|
import { useGlobalWebSocket } from 'contexts/WebSocketProvider';
|
||||||
|
|
||||||
const ActionModal = ({ show, toggleModal }) => {
|
const ActionModal = ({ show, toggleModal }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { currentToken, endpoints } = useAuth();
|
const { currentToken, endpoints } = useAuth();
|
||||||
const { deviceSerialNumber } = useDevice();
|
const { deviceSerialNumber } = useDevice();
|
||||||
|
const { addDeviceListener } = useGlobalWebSocket();
|
||||||
const { addToast } = useToast();
|
const { addToast } = useToast();
|
||||||
const [waiting, setWaiting] = useState(false);
|
const [waiting, setWaiting] = useState(false);
|
||||||
const [result, setResult] = useState(null);
|
const [result, setResult] = useState(null);
|
||||||
@@ -74,11 +76,16 @@ const ActionModal = ({ show, toggleModal }) => {
|
|||||||
{ headers },
|
{ headers },
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
addToast({
|
addDeviceListener({
|
||||||
title: t('common.success'),
|
serialNumber: deviceSerialNumber,
|
||||||
body: t('commands.command_success'),
|
types: ['device_connection', 'device_disconnection'],
|
||||||
color: 'success',
|
addToast: (title, body) =>
|
||||||
autohide: true,
|
addToast({
|
||||||
|
title,
|
||||||
|
body,
|
||||||
|
color: 'info',
|
||||||
|
autohide: true,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
toggleModal();
|
toggleModal();
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ const TraceModal = ({ show, toggleModal }) => {
|
|||||||
const [responseBody, setResponseBody] = useState('');
|
const [responseBody, setResponseBody] = useState('');
|
||||||
const [chosenInterface, setChosenInterface] = useState('up');
|
const [chosenInterface, setChosenInterface] = useState('up');
|
||||||
const [isDeviceConnected, setIsDeviceConnected] = useState(false);
|
const [isDeviceConnected, setIsDeviceConnected] = useState(false);
|
||||||
const [waitForTrace, setWaitForTrace] = useState(false);
|
const [waitForTrace, setWaitForTrace] = useState(true);
|
||||||
const [waitingForTrace, setWaitingForTrace] = useState(false);
|
const [waitingForTrace, setWaitingForTrace] = useState(false);
|
||||||
const [commandUuid, setCommandUuid] = useState(null);
|
const [commandUuid, setCommandUuid] = useState(null);
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ const TraceModal = ({ show, toggleModal }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setWaitForTrace(false);
|
setWaitForTrace(true);
|
||||||
setHadSuccess(false);
|
setHadSuccess(false);
|
||||||
setHadFailure(false);
|
setHadFailure(false);
|
||||||
setResponseBody('');
|
setResponseBody('');
|
||||||
@@ -137,25 +137,19 @@ const TraceModal = ({ show, toggleModal }) => {
|
|||||||
<CModalBody>
|
<CModalBody>
|
||||||
<h6>{t('trace.directions')}</h6>
|
<h6>{t('trace.directions')}</h6>
|
||||||
<CRow className="mt-3">
|
<CRow className="mt-3">
|
||||||
<CCol>
|
<CCol md="4" className="pt-2">
|
||||||
<CButton
|
{t('contact.type')}
|
||||||
disabled={blockFields}
|
|
||||||
block
|
|
||||||
color="primary"
|
|
||||||
onClick={() => setUsingDuration(true)}
|
|
||||||
>
|
|
||||||
{t('common.duration')}
|
|
||||||
</CButton>
|
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol>
|
<CCol xs="12" md="8">
|
||||||
<CButton
|
<CSelect
|
||||||
|
custom
|
||||||
|
value={usingDuration ? 'duration' : 'packets'}
|
||||||
disabled={blockFields}
|
disabled={blockFields}
|
||||||
block
|
onChange={(e) => setUsingDuration(e.target.value === 'duration')}
|
||||||
color="primary"
|
|
||||||
onClick={() => setUsingDuration(false)}
|
|
||||||
>
|
>
|
||||||
{t('trace.packets')}
|
<option value="duration">{t('common.duration')}</option>
|
||||||
</CButton>
|
<option value="packets">{t('trace.packets')}</option>
|
||||||
|
</CSelect>
|
||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
<CRow className="mt-3">
|
<CRow className="mt-3">
|
||||||
@@ -220,7 +214,7 @@ const TraceModal = ({ show, toggleModal }) => {
|
|||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
<CRow className="mt-3" hidden={!isDeviceConnected}>
|
<CRow className="mt-3" hidden={!isDeviceConnected}>
|
||||||
<CCol md="8">
|
<CCol md="7">
|
||||||
<p>{t('trace.wait_for_file')}</p>
|
<p>{t('trace.wait_for_file')}</p>
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol>
|
<CCol>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const WifiAnalysisTable = ({ t, data, loading }) => {
|
|||||||
};
|
};
|
||||||
const columns = [
|
const columns = [
|
||||||
{ key: 'radio', label: '#', _style: { width: '1%' } },
|
{ key: 'radio', label: '#', _style: { width: '1%' } },
|
||||||
{ key: 'bssid', label: 'BSSID', _style: { width: '1%' } },
|
{ key: 'station', label: 'Station ID', _style: { width: '1%' } },
|
||||||
{ key: 'vendor', label: t('wifi_analysis.vendor'), _style: { width: '15%' }, sorter: false },
|
{ key: 'vendor', label: t('wifi_analysis.vendor'), _style: { width: '15%' }, sorter: false },
|
||||||
{ key: 'mode', label: t('wifi_analysis.mode'), _style: { width: '1%' }, sorter: false },
|
{ key: 'mode', label: t('wifi_analysis.mode'), _style: { width: '1%' }, sorter: false },
|
||||||
{ key: 'ssid', label: 'SSID', _style: { width: '15%' } },
|
{ key: 'ssid', label: 'SSID', _style: { width: '15%' } },
|
||||||
@@ -84,12 +84,12 @@ const WifiAnalysisTable = ({ t, data, loading }) => {
|
|||||||
sorter
|
sorter
|
||||||
sorterValue={{ column: 'radio', asc: true }}
|
sorterValue={{ column: 'radio', asc: true }}
|
||||||
scopedSlots={{
|
scopedSlots={{
|
||||||
bssid: (item) => (
|
station: (item) => (
|
||||||
<td
|
<td
|
||||||
className="text-center align-middle"
|
className="text-center align-middle"
|
||||||
style={{ fontFamily: 'monospace', fontSize: '0.96rem' }}
|
style={{ fontFamily: 'monospace', fontSize: '0.96rem' }}
|
||||||
>
|
>
|
||||||
{item.bssid}
|
{item.station}
|
||||||
</td>
|
</td>
|
||||||
),
|
),
|
||||||
radio: (item) => <td className="text-center align-middle">{item.radio.radio}</td>,
|
radio: (item) => <td className="text-center align-middle">{item.radio.radio}</td>,
|
||||||
|
|||||||
@@ -147,12 +147,12 @@ const WifiAnalysis = () => {
|
|||||||
|
|
||||||
if ('associations' in ssid) {
|
if ('associations' in ssid) {
|
||||||
for (const association of ssid.associations) {
|
for (const association of ssid.associations) {
|
||||||
bssidObj[association.bssid] = 0;
|
bssidObj[association.station] = 0;
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
radio: radioInfo,
|
radio: radioInfo,
|
||||||
...extractIp(stat.data, association.bssid),
|
...extractIp(stat.data, association.bssid),
|
||||||
bssid: association.bssid,
|
station: association.station,
|
||||||
ssid: ssid.ssid,
|
ssid: ssid.ssid,
|
||||||
rssi: association.rssi ? parseDbm(association.rssi) : '-',
|
rssi: association.rssi ? parseDbm(association.rssi) : '-',
|
||||||
mode: ssid.mode,
|
mode: ssid.mode,
|
||||||
@@ -181,7 +181,7 @@ const WifiAnalysis = () => {
|
|||||||
for (let i = 0; i < newParsedAssociationStats.length; i += 1) {
|
for (let i = 0; i < newParsedAssociationStats.length; i += 1) {
|
||||||
for (let y = 0; y < newParsedAssociationStats[i].length; y += 1) {
|
for (let y = 0; y < newParsedAssociationStats[i].length; y += 1) {
|
||||||
newParsedAssociationStats[i][y].vendor =
|
newParsedAssociationStats[i][y].vendor =
|
||||||
vendors[newParsedAssociationStats[i][y].bssid] ?? '-';
|
vendors[newParsedAssociationStats[i][y].station] ?? '-';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
CCol,
|
CCol,
|
||||||
CSpinner,
|
CSpinner,
|
||||||
CPopover,
|
CPopover,
|
||||||
|
CSelect,
|
||||||
} from '@coreui/react';
|
} from '@coreui/react';
|
||||||
import CIcon from '@coreui/icons-react';
|
import CIcon from '@coreui/icons-react';
|
||||||
import { cilCloudDownload, cilGauge, cilX } from '@coreui/icons';
|
import { cilCloudDownload, cilGauge, cilX } from '@coreui/icons';
|
||||||
@@ -34,6 +35,7 @@ const WifiScanModal = ({ show, toggleModal }) => {
|
|||||||
const [errorCode, setErrorCode] = useState(0);
|
const [errorCode, setErrorCode] = useState(0);
|
||||||
const [waiting, setWaiting] = useState(false);
|
const [waiting, setWaiting] = useState(false);
|
||||||
const [dfs, setDfs] = useState(true);
|
const [dfs, setDfs] = useState(true);
|
||||||
|
const [bandwidth, setBandwidth] = useState('');
|
||||||
const [activeScan, setActiveScan] = useState(false);
|
const [activeScan, setActiveScan] = useState(false);
|
||||||
const [hideOptions, setHideOptions] = useState(false);
|
const [hideOptions, setHideOptions] = useState(false);
|
||||||
const [channelList, setChannelList] = useState([]);
|
const [channelList, setChannelList] = useState([]);
|
||||||
@@ -53,6 +55,7 @@ const WifiScanModal = ({ show, toggleModal }) => {
|
|||||||
setWaiting(false);
|
setWaiting(false);
|
||||||
setChannelList([]);
|
setChannelList([]);
|
||||||
setCsvData(null);
|
setCsvData(null);
|
||||||
|
setBandwidth('');
|
||||||
setDfs(true);
|
setDfs(true);
|
||||||
setActiveScan(false);
|
setActiveScan(false);
|
||||||
setHideOptions(false);
|
setHideOptions(false);
|
||||||
@@ -135,6 +138,7 @@ const WifiScanModal = ({ show, toggleModal }) => {
|
|||||||
const parameters = {
|
const parameters = {
|
||||||
serialNumber: deviceSerialNumber,
|
serialNumber: deviceSerialNumber,
|
||||||
override_dfs: dfs,
|
override_dfs: dfs,
|
||||||
|
bandwidth: bandwidth !== '' ? bandwidth : undefined,
|
||||||
activeScan,
|
activeScan,
|
||||||
};
|
};
|
||||||
const headers = {
|
const headers = {
|
||||||
@@ -246,6 +250,26 @@ const WifiScanModal = ({ show, toggleModal }) => {
|
|||||||
</CForm>
|
</CForm>
|
||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
|
<CRow className="mt-3">
|
||||||
|
<CCol md="3">
|
||||||
|
<p className="pl-2">Bandwidth:</p>
|
||||||
|
</CCol>
|
||||||
|
<CCol>
|
||||||
|
<CForm className="pl-4">
|
||||||
|
<CSelect
|
||||||
|
custom
|
||||||
|
value={bandwidth}
|
||||||
|
onChange={(e) => setBandwidth(e.target.value)}
|
||||||
|
style={{ width: '100px' }}
|
||||||
|
>
|
||||||
|
<option value="">Default</option>
|
||||||
|
<option value="20">20 MHz</option>
|
||||||
|
<option value="40">40 MHz</option>
|
||||||
|
<option value="80">80 MHz</option>
|
||||||
|
</CSelect>
|
||||||
|
</CForm>
|
||||||
|
</CCol>
|
||||||
|
</CRow>
|
||||||
</div>
|
</div>
|
||||||
<div hidden={!waiting}>
|
<div hidden={!waiting}>
|
||||||
<CRow>
|
<CRow>
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import { useToast } from 'ucentral-libs';
|
||||||
|
|
||||||
|
const useWebSocketNotification = () => {
|
||||||
|
const { addToast } = useToast();
|
||||||
|
|
||||||
|
const pushNotification = useCallback((notification) => {
|
||||||
|
addToast({
|
||||||
|
title: notification.content.title,
|
||||||
|
body: notification.content.details,
|
||||||
|
color: 'info',
|
||||||
|
autohide: true,
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const toReturn = useMemo(
|
||||||
|
() => ({
|
||||||
|
pushNotification,
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return toReturn;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useWebSocketNotification;
|
||||||
88
src/contexts/WebSocketProvider/index.js
Normal file
88
src/contexts/WebSocketProvider/index.js
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { useAuth } from 'ucentral-libs';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import useWebSocketNotification from './hooks/NotificationContent/useWebSocketNotification';
|
||||||
|
import useSocketReducer from './useSocketReducer';
|
||||||
|
import { extractWebSocketResponse } from './utils';
|
||||||
|
|
||||||
|
const WebSocketContext = React.createContext({
|
||||||
|
webSocket: undefined,
|
||||||
|
isOpen: false,
|
||||||
|
addDeviceListener: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WebSocketProvider = ({ children }) => {
|
||||||
|
const { currentToken, endpoints } = useAuth();
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const ws = useRef(undefined);
|
||||||
|
const { lastMessage, dispatch } = useSocketReducer();
|
||||||
|
const { pushNotification } = useWebSocketNotification();
|
||||||
|
|
||||||
|
const onMessage = useCallback((message) => {
|
||||||
|
const result = extractWebSocketResponse(message);
|
||||||
|
if (result?.type === 'NOTIFICATION') {
|
||||||
|
dispatch({ type: 'NEW_NOTIFICATION', notification: result.notification });
|
||||||
|
pushNotification(result.notification);
|
||||||
|
}
|
||||||
|
if (result?.type === 'DEVICE_NOTIFICATION') {
|
||||||
|
dispatch({
|
||||||
|
type: 'NEW_DEVICE_NOTIFICATION',
|
||||||
|
serialNumber: result.serialNumber,
|
||||||
|
subType: result.subType,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (result?.type === 'COMMAND') {
|
||||||
|
dispatch({ type: 'NEW_COMMAND', data: result.data });
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// useEffect for created the WebSocket and 'storing' it in useRef
|
||||||
|
useEffect(() => {
|
||||||
|
ws.current = new WebSocket(`${endpoints.owgw.replace('https', 'wss')}/api/v1/ws`);
|
||||||
|
ws.current.onopen = () => {
|
||||||
|
setIsOpen(true);
|
||||||
|
ws.current?.send(`token:${currentToken}`);
|
||||||
|
};
|
||||||
|
ws.current.onclose = () => {
|
||||||
|
setIsOpen(false);
|
||||||
|
};
|
||||||
|
ws.current.onerror = () => {
|
||||||
|
setIsOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const wsCurrent = ws?.current;
|
||||||
|
return () => wsCurrent?.close();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// useEffect for generating global notifications
|
||||||
|
useEffect(() => {
|
||||||
|
if (ws?.current) {
|
||||||
|
ws.current.addEventListener('message', onMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
const wsCurrent = ws?.current;
|
||||||
|
return () => {
|
||||||
|
if (wsCurrent) wsCurrent.removeEventListener('message', onMessage);
|
||||||
|
};
|
||||||
|
}, [ws?.current]);
|
||||||
|
const values = useMemo(
|
||||||
|
() => ({
|
||||||
|
lastMessage,
|
||||||
|
webSocket: ws.current,
|
||||||
|
addDeviceListener: ({ serialNumber, types, addToast, onTrigger }) =>
|
||||||
|
dispatch({ type: 'ADD_DEVICE_LISTENER', serialNumber, types, addToast, onTrigger }),
|
||||||
|
removeDeviceListener: ({ serialNumber }) =>
|
||||||
|
dispatch({ type: 'REMOVE_DEVICE_LISTENER', serialNumber }),
|
||||||
|
isOpen,
|
||||||
|
}),
|
||||||
|
[ws, isOpen, lastMessage],
|
||||||
|
);
|
||||||
|
|
||||||
|
return <WebSocketContext.Provider value={values}>{children}</WebSocketContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
|
WebSocketProvider.propTypes = {
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGlobalWebSocket = () => React.useContext(WebSocketContext);
|
||||||
98
src/contexts/WebSocketProvider/useSocketReducer.js
Normal file
98
src/contexts/WebSocketProvider/useSocketReducer.js
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import { useReducer } from 'react';
|
||||||
|
|
||||||
|
const titles = {
|
||||||
|
device_connection: 'Connected',
|
||||||
|
device_disconnection: 'Disconnected',
|
||||||
|
device_firmware_upgrade: 'Firmware Upgraded',
|
||||||
|
};
|
||||||
|
const bodies = {
|
||||||
|
device_connection: 'This device has rebooted and is now connected!',
|
||||||
|
device_disconnection: 'This device has started rebooting and is now disconnected!',
|
||||||
|
device_firmware_upgrade: 'This device has updated to new firmware!',
|
||||||
|
};
|
||||||
|
|
||||||
|
const reducer = (state, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'NEW_NOTIFICATION': {
|
||||||
|
const obj = { type: 'NOTIFICATION', data: action.notification, timestamp: new Date() };
|
||||||
|
return { ...state, lastMessage: obj };
|
||||||
|
}
|
||||||
|
case 'NEW_COMMAND': {
|
||||||
|
const obj = {
|
||||||
|
type: 'COMMAND',
|
||||||
|
response: action.data.response,
|
||||||
|
timestamp: new Date(),
|
||||||
|
id: action.data.command_response_id,
|
||||||
|
};
|
||||||
|
return { ...state, lastMessage: obj };
|
||||||
|
}
|
||||||
|
case 'NEW_DEVICE_NOTIFICATION': {
|
||||||
|
const newListeners = state.deviceListeners;
|
||||||
|
let obj;
|
||||||
|
|
||||||
|
if (action.subType === 'device_connection' || action.subType === 'device_disconnection') {
|
||||||
|
obj = {
|
||||||
|
type: 'DEVICE',
|
||||||
|
isConnected: action.subType === 'device_connection',
|
||||||
|
serialNumber: action.serialNumber,
|
||||||
|
timestamp: new Date(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
for (let i = 0; i < state.deviceListeners.length; i += 1) {
|
||||||
|
if (
|
||||||
|
state.deviceListeners[i].serialNumber === action.serialNumber &&
|
||||||
|
state.deviceListeners[i].type === action.subType
|
||||||
|
) {
|
||||||
|
if (state.deviceListeners[i].onTrigger) {
|
||||||
|
setTimeout(() => state.deviceListeners[i].onTrigger(action.subType), 1000);
|
||||||
|
} else if (state.deviceListeners[i].addToast) {
|
||||||
|
state.deviceListeners[i].addToast(
|
||||||
|
`${action.serialNumber} ${titles[state.deviceListeners[i].type]}`,
|
||||||
|
bodies[state.deviceListeners[i].type],
|
||||||
|
);
|
||||||
|
const found = newListeners.findIndex(
|
||||||
|
(listener) =>
|
||||||
|
listener.serialNumber === action.serialNumber && listener.type === action.subType,
|
||||||
|
);
|
||||||
|
if (found >= 0) newListeners.splice(found, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...state, lastMessage: obj ?? state.lastMessage, deviceListeners: newListeners };
|
||||||
|
}
|
||||||
|
case 'ADD_DEVICE_LISTENER': {
|
||||||
|
let newListeners = action.types.map((actionType) => ({
|
||||||
|
type: actionType,
|
||||||
|
serialNumber: action.serialNumber,
|
||||||
|
addToast: action.addToast,
|
||||||
|
onTrigger: action.onTrigger,
|
||||||
|
}));
|
||||||
|
newListeners = newListeners.concat(state.deviceListeners);
|
||||||
|
return { ...state, lastMessage: state.lastMessage, deviceListeners: newListeners };
|
||||||
|
}
|
||||||
|
case 'REMOVE_DEVICE_LISTENER': {
|
||||||
|
const newListeners = state.deviceListeners.filter(
|
||||||
|
(listener) =>
|
||||||
|
listener.serialNumber !== action.serialNumber || listener.onTrigger === undefined,
|
||||||
|
);
|
||||||
|
return { ...state, lastMessage: state.lastMessage, deviceListeners: newListeners };
|
||||||
|
}
|
||||||
|
case 'UNKNOWN': {
|
||||||
|
const obj = { type: 'UNKNOWN', data: action.newMessage, timestamp: new Date() };
|
||||||
|
return { ...state, lastMessage: obj };
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const useSocketReducer = () => {
|
||||||
|
const [{ lastMessage, deviceListeners }, dispatch] = useReducer(reducer, {
|
||||||
|
deviceListeners: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
return { lastMessage, deviceListeners, dispatch };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useSocketReducer;
|
||||||
55
src/contexts/WebSocketProvider/utils.js
Normal file
55
src/contexts/WebSocketProvider/utils.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
export const acceptedNotificationTypes = [
|
||||||
|
'venue_configuration_update',
|
||||||
|
'entity_configuration_update',
|
||||||
|
];
|
||||||
|
export const deviceNotificationTypes = [
|
||||||
|
'device_connection',
|
||||||
|
'device_disconnection',
|
||||||
|
'device_firmware_upgrade',
|
||||||
|
'device_statistics',
|
||||||
|
];
|
||||||
|
|
||||||
|
export const extractWebSocketResponse = (message) => {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(message.data);
|
||||||
|
if (data.notification && acceptedNotificationTypes.includes(data.notification.type)) {
|
||||||
|
const { notification } = data;
|
||||||
|
return { notification, type: 'NOTIFICATION' };
|
||||||
|
}
|
||||||
|
if (data.notification && deviceNotificationTypes.includes(data.notification.type)) {
|
||||||
|
return {
|
||||||
|
serialNumber: data.notification.content.serialNumber,
|
||||||
|
type: 'DEVICE_NOTIFICATION',
|
||||||
|
subType: data.notification.type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (data.command_response_id) {
|
||||||
|
return { data, type: 'COMMAND' };
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getStatusFromNotification = (notification) => {
|
||||||
|
let status = 'success';
|
||||||
|
if (notification.content.warning?.length > 0) status = 'warning';
|
||||||
|
if (notification.content.error?.length > 0) status = 'error';
|
||||||
|
|
||||||
|
return status;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getNotificationDescription = (t, notification) => {
|
||||||
|
if (
|
||||||
|
notification.content.type === 'venue_configuration_update' ||
|
||||||
|
notification.content.type === 'entity_configuration_update'
|
||||||
|
) {
|
||||||
|
return t('configurations.notification_details', {
|
||||||
|
success: notification.content.success.length,
|
||||||
|
warning: notification.content.warning.length,
|
||||||
|
error: notification.content.error.length,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return notification.content.details;
|
||||||
|
};
|
||||||
@@ -5,6 +5,7 @@ import { CSidebarNavItem } from '@coreui/react';
|
|||||||
import { cilBarcode, cilRouter, cilSave, cilSettings, cilPeople } from '@coreui/icons';
|
import { cilBarcode, cilRouter, cilSave, cilSettings, cilPeople } from '@coreui/icons';
|
||||||
import CIcon from '@coreui/icons-react';
|
import CIcon from '@coreui/icons-react';
|
||||||
import { Header, Sidebar, Footer, PageContainer, ToastProvider, useAuth } from 'ucentral-libs';
|
import { Header, Sidebar, Footer, PageContainer, ToastProvider, useAuth } from 'ucentral-libs';
|
||||||
|
import { WebSocketProvider } from 'contexts/WebSocketProvider';
|
||||||
|
|
||||||
const TheLayout = () => {
|
const TheLayout = () => {
|
||||||
const [showSidebar, setShowSidebar] = useState('responsive');
|
const [showSidebar, setShowSidebar] = useState('responsive');
|
||||||
@@ -70,7 +71,9 @@ const TheLayout = () => {
|
|||||||
/>
|
/>
|
||||||
<div className="c-body">
|
<div className="c-body">
|
||||||
<ToastProvider>
|
<ToastProvider>
|
||||||
<PageContainer t={t} routes={routes} redirectTo="/devices" />
|
<WebSocketProvider>
|
||||||
|
<PageContainer t={t} routes={routes} redirectTo="/devices" />
|
||||||
|
</WebSocketProvider>
|
||||||
</ToastProvider>
|
</ToastProvider>
|
||||||
</div>
|
</div>
|
||||||
<Footer t={t} version={process.env.VERSION} />
|
<Footer t={t} version={process.env.VERSION} />
|
||||||
|
|||||||
@@ -15,12 +15,17 @@ import {
|
|||||||
import CIcon from '@coreui/icons-react';
|
import CIcon from '@coreui/icons-react';
|
||||||
import { cilSync } from '@coreui/icons';
|
import { cilSync } from '@coreui/icons';
|
||||||
import { prettyDate } from 'utils/helper';
|
import { prettyDate } from 'utils/helper';
|
||||||
import { CopyToClipboardButton, HideTextButton } from 'ucentral-libs';
|
import { CopyToClipboardButton, HideTextButton, useAuth } from 'ucentral-libs';
|
||||||
|
import { getCountryFromLocale } from 'utils/countries';
|
||||||
|
import ReactCountryFlag from 'react-country-flag';
|
||||||
|
import axiosInstance from 'utils/axiosInstance';
|
||||||
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
const DeviceDetails = ({ t, loading, getData, status, deviceConfig, lastStats }) => {
|
const DeviceDetails = ({ t, loading, getData, status, deviceConfig, lastStats }) => {
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
const [subName, setSubName] = useState('');
|
||||||
|
const { currentToken, endpoints } = useAuth();
|
||||||
|
|
||||||
const toggleShowPassword = () => {
|
const toggleShowPassword = () => {
|
||||||
setShowPassword(!showPassword);
|
setShowPassword(!showPassword);
|
||||||
@@ -32,21 +37,51 @@ const DeviceDetails = ({ t, loading, getData, status, deviceConfig, lastStats })
|
|||||||
return showPassword ? password : '******';
|
return showPassword ? password : '******';
|
||||||
};
|
};
|
||||||
|
|
||||||
const displayExtra = (key, value, extraData) => {
|
const getSubData = async (subId) => {
|
||||||
if (!extraData || !extraData[key]) return value;
|
const options = {
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
Authorization: `Bearer ${currentToken}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
if (!localStorage.getItem('owprov-ui') || key === 'owner') return extraData[key].name;
|
axiosInstance
|
||||||
|
.get(`${endpoints.owsec}/api/v1/subuser/${subId}`, options)
|
||||||
|
.then((response) => setSubName(response.data.name ?? ''))
|
||||||
|
.catch(() => setSubName(''));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSubscriber = () => {
|
||||||
|
if (!deviceConfig?.subscriber || deviceConfig.subscriber === '') return '';
|
||||||
|
getSubData(deviceConfig.subscriber);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CLink
|
<CLink
|
||||||
className="c-subheader-nav-link align-self-center"
|
className="c-subheader-nav-link align-self-center"
|
||||||
aria-current="page"
|
aria-current="page"
|
||||||
href={`${localStorage.getItem('owprov-ui')}/#/${key === 'entity' ? 'entity' : 'venue'}/${
|
href={`${localStorage.getItem('owprov-ui')}/#/subscriber/${deviceConfig.subscriber}`}
|
||||||
extraData[key].id
|
|
||||||
}`}
|
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
{extraData[key].name}
|
{subName !== '' ? subName : deviceConfig.subscriber}
|
||||||
|
</CLink>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const displayExtra = (key, value, extraData) => {
|
||||||
|
if (!extraData || !extraData[key]) return value;
|
||||||
|
|
||||||
|
if (!localStorage.getItem('owprov-ui')) return extraData[key].name;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CLink
|
||||||
|
className="c-subheader-nav-link align-self-center"
|
||||||
|
aria-current="page"
|
||||||
|
href={`${localStorage.getItem('owprov-ui')}/#/${
|
||||||
|
key === 'entity' ? 'entity' : 'venue'
|
||||||
|
}/${value}`}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{!extraData || !extraData[key] ? value : extraData[key].name}
|
||||||
</CLink>
|
</CLink>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -99,13 +134,13 @@ const DeviceDetails = ({ t, loading, getData, status, deviceConfig, lastStats })
|
|||||||
/>
|
/>
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol className="border-left" lg="2" xl="1" xxl="1">
|
<CCol className="border-left" lg="2" xl="1" xxl="1">
|
||||||
<CLabel>{t('configuration.owner')}:</CLabel>
|
<CLabel>{t('inventory.subscriber')}:</CLabel>
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol lg="2" xl="3" xxl="3">
|
<CCol lg="2" xl="3" xxl="3">
|
||||||
{deviceConfig?.owner}
|
{getSubscriber()}
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol lg="2" xl="1" xxl="1">
|
<CCol lg="2" xl="1" xxl="1">
|
||||||
<CLabel>{t('common.mac')}:</CLabel>
|
<CLabel>MAC:</CLabel>
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol className="border-right" lg="2" xl="3" xxl="3">
|
<CCol className="border-right" lg="2" xl="3" xxl="3">
|
||||||
{deviceConfig?.macAddress}
|
{deviceConfig?.macAddress}
|
||||||
@@ -117,25 +152,16 @@ const DeviceDetails = ({ t, loading, getData, status, deviceConfig, lastStats })
|
|||||||
{deviceConfig?.deviceType}
|
{deviceConfig?.deviceType}
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol className="border-left" lg="2" xl="1" xxl="1">
|
<CCol className="border-left" lg="2" xl="1" xxl="1">
|
||||||
<CLabel>
|
<CLabel>{t('entity.entity')}:</CLabel>
|
||||||
{deviceConfig?.venue?.substring(0, 3) === 'ent'
|
|
||||||
? t('entity.entity')
|
|
||||||
: t('inventory.venue')}
|
|
||||||
:
|
|
||||||
</CLabel>
|
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol lg="2" xl="3" xxl="3">
|
<CCol lg="2" xl="3" xxl="3">
|
||||||
{deviceConfig?.venue?.substring(0, 3) === 'ent'
|
{deviceConfig?.entity !== ''
|
||||||
? displayExtra(
|
? displayExtra(
|
||||||
'entity',
|
'entity',
|
||||||
deviceConfig?.venue?.slice(4),
|
deviceConfig?.venue?.slice(4),
|
||||||
deviceConfig?.extendedInfo,
|
deviceConfig?.extendedInfo,
|
||||||
)
|
)
|
||||||
: displayExtra(
|
: ''}
|
||||||
'venue',
|
|
||||||
deviceConfig?.venue?.slice(4),
|
|
||||||
deviceConfig?.extendedInfo,
|
|
||||||
)}
|
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol lg="2" xl="1" xxl="1">
|
<CCol lg="2" xl="1" xxl="1">
|
||||||
<CLabel>{t('common.manufacturer')}:</CLabel>
|
<CLabel>{t('common.manufacturer')}:</CLabel>
|
||||||
@@ -149,6 +175,37 @@ const DeviceDetails = ({ t, loading, getData, status, deviceConfig, lastStats })
|
|||||||
<CCol lg="2" xl="3" xxl="3">
|
<CCol lg="2" xl="3" xxl="3">
|
||||||
{prettyDate(deviceConfig?.createdTimestamp)}
|
{prettyDate(deviceConfig?.createdTimestamp)}
|
||||||
</CCol>
|
</CCol>
|
||||||
|
<CCol className="border-left" lg="2" xl="1" xxl="1">
|
||||||
|
<CLabel>{t('inventory.venue')}:</CLabel>
|
||||||
|
</CCol>
|
||||||
|
<CCol lg="2" xl="3" xxl="3">
|
||||||
|
{deviceConfig?.venue !== ''
|
||||||
|
? displayExtra('venue', deviceConfig?.venue?.slice(4), deviceConfig?.extendedInfo)
|
||||||
|
: ''}
|
||||||
|
</CCol>
|
||||||
|
<CCol lg="2" xl="1" xxl="1">
|
||||||
|
<CLabel>Locale:</CLabel>
|
||||||
|
</CCol>
|
||||||
|
<CCol className="border-right" lg="2" xl="3" xxl="3">
|
||||||
|
{deviceConfig?.locale !== '' && (
|
||||||
|
<ReactCountryFlag
|
||||||
|
style={{ width: '24px', height: '24px' }}
|
||||||
|
countryCode={deviceConfig?.locale}
|
||||||
|
svg
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{' '}
|
||||||
|
{deviceConfig?.locale && deviceConfig?.locale !== ''
|
||||||
|
? `${deviceConfig.locale} - `
|
||||||
|
: 'Unknown'}
|
||||||
|
{getCountryFromLocale(deviceConfig?.locale ?? '')}
|
||||||
|
</CCol>
|
||||||
|
<CCol lg="2" xl="1" xxl="1">
|
||||||
|
<CLabel>{t('common.modified')}: </CLabel>
|
||||||
|
</CCol>
|
||||||
|
<CCol lg="2" xl="3" xxl="3">
|
||||||
|
{prettyDate(deviceConfig?.modified)}
|
||||||
|
</CCol>
|
||||||
<CCol className="border-left" lg="2" xl="1" xxl="1">
|
<CCol className="border-left" lg="2" xl="1" xxl="1">
|
||||||
<CLabel>{t('configuration.location')}:</CLabel>
|
<CLabel>{t('configuration.location')}:</CLabel>
|
||||||
</CCol>
|
</CCol>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import ConfigurationDisplay from 'components/ConfigurationDisplay';
|
import ConfigurationDisplay from 'components/ConfigurationDisplay';
|
||||||
import WifiAnalysis from 'components/WifiAnalysis';
|
import WifiAnalysis from 'components/WifiAnalysis';
|
||||||
import CapabilitiesDisplay from 'components/CapabilitiesDisplay';
|
import CapabilitiesDisplay from 'components/CapabilitiesDisplay';
|
||||||
|
import { useGlobalWebSocket } from 'contexts/WebSocketProvider';
|
||||||
import NotesTab from './NotesTab';
|
import NotesTab from './NotesTab';
|
||||||
import DeviceDetails from './Details';
|
import DeviceDetails from './Details';
|
||||||
import DeviceStatusCard from './DeviceStatusCard';
|
import DeviceStatusCard from './DeviceStatusCard';
|
||||||
@@ -26,6 +27,7 @@ const DevicePage = () => {
|
|||||||
const [deviceConfig, setDeviceConfig] = useState(null);
|
const [deviceConfig, setDeviceConfig] = useState(null);
|
||||||
const [error, setError] = useState(false);
|
const [error, setError] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const { addDeviceListener, removeDeviceListener } = useGlobalWebSocket();
|
||||||
|
|
||||||
const updateNav = (target) => {
|
const updateNav = (target) => {
|
||||||
sessionStorage.setItem('devicePageIndex', target);
|
sessionStorage.setItem('devicePageIndex', target);
|
||||||
@@ -115,9 +117,26 @@ const DevicePage = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setError(false);
|
setError(false);
|
||||||
if (deviceId) {
|
if (deviceId) {
|
||||||
getDevice();
|
addDeviceListener({
|
||||||
getData();
|
serialNumber: deviceId,
|
||||||
|
types: [
|
||||||
|
'device_connection',
|
||||||
|
'device_disconnection',
|
||||||
|
'device_firmware_upgrade',
|
||||||
|
'device_statistics',
|
||||||
|
],
|
||||||
|
onTrigger: () => refresh(),
|
||||||
|
});
|
||||||
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (deviceId) {
|
||||||
|
removeDeviceListener({
|
||||||
|
serialNumber: deviceId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
}, [deviceId]);
|
}, [deviceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ axiosRetry(axiosInstance, {
|
|||||||
retryDelay: () => axiosRetry.exponentialDelay,
|
retryDelay: () => axiosRetry.exponentialDelay,
|
||||||
});
|
});
|
||||||
|
|
||||||
axiosInstance.defaults.timeout = 60000;
|
axiosInstance.defaults.timeout = 160000;
|
||||||
axiosInstance.defaults.headers.get.Accept = 'application/json';
|
axiosInstance.defaults.headers.get.Accept = 'application/json';
|
||||||
axiosInstance.defaults.headers.post.Accept = 'application/json';
|
axiosInstance.defaults.headers.post.Accept = 'application/json';
|
||||||
|
|
||||||
|
|||||||
253
src/utils/countries.js
Normal file
253
src/utils/countries.js
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
export const COUNTRY_LIST = [
|
||||||
|
{ value: 'US', label: 'United States' },
|
||||||
|
{ value: 'CA', label: 'Canada' },
|
||||||
|
{ value: 'AF', label: 'Afghanistan' },
|
||||||
|
{ value: 'AX', label: 'Aland Islands' },
|
||||||
|
{ value: 'AL', label: 'Albania' },
|
||||||
|
{ value: 'DZ', label: 'Algeria' },
|
||||||
|
{ value: 'AS', label: 'American Samoa' },
|
||||||
|
{ value: 'AD', label: 'Andorra' },
|
||||||
|
{ value: 'AO', label: 'Angola' },
|
||||||
|
{ value: 'AI', label: 'Anguilla' },
|
||||||
|
{ value: 'AQ', label: 'Antarctica' },
|
||||||
|
{ value: 'AG', label: 'Antigua And Barbuda' },
|
||||||
|
{ value: 'AR', label: 'Argentina' },
|
||||||
|
{ value: 'AM', label: 'Armenia' },
|
||||||
|
{ value: 'AN', label: 'Netherlands Antilles' },
|
||||||
|
{ value: 'AW', label: 'Aruba' },
|
||||||
|
{ value: 'AU', label: 'Australia' },
|
||||||
|
{ value: 'AT', label: 'Austria' },
|
||||||
|
{ value: 'AZ', label: 'Azerbaijan' },
|
||||||
|
{ value: 'BS', label: 'Bahamas' },
|
||||||
|
{ value: 'BH', label: 'Bahrain' },
|
||||||
|
{ value: 'BD', label: 'Bangladesh' },
|
||||||
|
{ value: 'BB', label: 'Barbados' },
|
||||||
|
{ value: 'BY', label: 'Belarus' },
|
||||||
|
{ value: 'BE', label: 'Belgium' },
|
||||||
|
{ value: 'BZ', label: 'Belize' },
|
||||||
|
{ value: 'BJ', label: 'Benin' },
|
||||||
|
{ value: 'BM', label: 'Bermuda' },
|
||||||
|
{ value: 'BT', label: 'Bhutan' },
|
||||||
|
{ value: 'BO', label: 'Bolivia' },
|
||||||
|
{ value: 'BA', label: 'Bosnia And Herzegovina' },
|
||||||
|
{ value: 'BW', label: 'Botswana' },
|
||||||
|
{ value: 'BV', label: 'Bouvet Island' },
|
||||||
|
{ value: 'BR', label: 'Brazil' },
|
||||||
|
{ value: 'IO', label: 'British Indian Ocean Territory' },
|
||||||
|
{ value: 'BN', label: 'Brunei Darussalam' },
|
||||||
|
{ value: 'BG', label: 'Bulgaria' },
|
||||||
|
{ value: 'BF', label: 'Burkina Faso' },
|
||||||
|
{ value: 'BI', label: 'Burundi' },
|
||||||
|
{ value: 'KH', label: 'Cambodia' },
|
||||||
|
{ value: 'CM', label: 'Cameroon' },
|
||||||
|
{ value: 'CA', label: 'Canada' },
|
||||||
|
{ value: 'CV', label: 'Cape Verde' },
|
||||||
|
{ value: 'KY', label: 'Cayman Islands' },
|
||||||
|
{ value: 'CF', label: 'Central African Republic' },
|
||||||
|
{ value: 'TD', label: 'Chad' },
|
||||||
|
{ value: 'CL', label: 'Chile' },
|
||||||
|
{ value: 'CN', label: 'China' },
|
||||||
|
{ value: 'CX', label: 'Christmas Island' },
|
||||||
|
{ value: 'CC', label: 'Cocos (Keeling) Islands' },
|
||||||
|
{ value: 'CO', label: 'Colombia' },
|
||||||
|
{ value: 'KM', label: 'Comoros' },
|
||||||
|
{ value: 'CG', label: 'Congo' },
|
||||||
|
{ value: 'CD', label: 'Congo, Democratic Republic' },
|
||||||
|
{ value: 'CK', label: 'Cook Islands' },
|
||||||
|
{ value: 'CR', label: 'Costa Rica' },
|
||||||
|
{ value: 'CI', label: "Cote D'Ivoire" },
|
||||||
|
{ value: 'HR', label: 'Croatia' },
|
||||||
|
{ value: 'CU', label: 'Cuba' },
|
||||||
|
{ value: 'CY', label: 'Cyprus' },
|
||||||
|
{ value: 'CZ', label: 'Czech Republic' },
|
||||||
|
{ value: 'DK', label: 'Denmark' },
|
||||||
|
{ value: 'DJ', label: 'Djibouti' },
|
||||||
|
{ value: 'DM', label: 'Dominica' },
|
||||||
|
{ value: 'DO', label: 'Dominican Republic' },
|
||||||
|
{ value: 'EC', label: 'Ecuador' },
|
||||||
|
{ value: 'EG', label: 'Egypt' },
|
||||||
|
{ value: 'SV', label: 'El Salvador' },
|
||||||
|
{ value: 'GQ', label: 'Equatorial Guinea' },
|
||||||
|
{ value: 'ER', label: 'Eritrea' },
|
||||||
|
{ value: 'EE', label: 'Estonia' },
|
||||||
|
{ value: 'ET', label: 'Ethiopia' },
|
||||||
|
{ value: 'FK', label: 'Falkland Islands (Malvinas)' },
|
||||||
|
{ value: 'FO', label: 'Faroe Islands' },
|
||||||
|
{ value: 'FJ', label: 'Fiji' },
|
||||||
|
{ value: 'FI', label: 'Finland' },
|
||||||
|
{ value: 'FR', label: 'France' },
|
||||||
|
{ value: 'GF', label: 'French Guiana' },
|
||||||
|
{ value: 'PF', label: 'French Polynesia' },
|
||||||
|
{ value: 'TF', label: 'French Southern Territories' },
|
||||||
|
{ value: 'GA', label: 'Gabon' },
|
||||||
|
{ value: 'GM', label: 'Gambia' },
|
||||||
|
{ value: 'GE', label: 'Georgia' },
|
||||||
|
{ value: 'DE', label: 'Germany' },
|
||||||
|
{ value: 'GH', label: 'Ghana' },
|
||||||
|
{ value: 'GI', label: 'Gibraltar' },
|
||||||
|
{ value: 'GR', label: 'Greece' },
|
||||||
|
{ value: 'GL', label: 'Greenland' },
|
||||||
|
{ value: 'GD', label: 'Grenada' },
|
||||||
|
{ value: 'GP', label: 'Guadeloupe' },
|
||||||
|
{ value: 'GU', label: 'Guam' },
|
||||||
|
{ value: 'GT', label: 'Guatemala' },
|
||||||
|
{ value: 'GG', label: 'Guernsey' },
|
||||||
|
{ value: 'GN', label: 'Guinea' },
|
||||||
|
{ value: 'GW', label: 'Guinea-Bissau' },
|
||||||
|
{ value: 'GY', label: 'Guyana' },
|
||||||
|
{ value: 'HT', label: 'Haiti' },
|
||||||
|
{ value: 'HM', label: 'Heard Island & Mcdonald Islands' },
|
||||||
|
{ value: 'VA', label: 'Holy See (Vatican City State)' },
|
||||||
|
{ value: 'HN', label: 'Honduras' },
|
||||||
|
{ value: 'HK', label: 'Hong Kong' },
|
||||||
|
{ value: 'HU', label: 'Hungary' },
|
||||||
|
{ value: 'IS', label: 'Iceland' },
|
||||||
|
{ value: 'IN', label: 'India' },
|
||||||
|
{ value: 'ID', label: 'Indonesia' },
|
||||||
|
{ value: 'IR', label: 'Iran, Islamic Republic Of' },
|
||||||
|
{ value: 'IQ', label: 'Iraq' },
|
||||||
|
{ value: 'IE', label: 'Ireland' },
|
||||||
|
{ value: 'IM', label: 'Isle Of Man' },
|
||||||
|
{ value: 'IL', label: 'Israel' },
|
||||||
|
{ value: 'IT', label: 'Italy' },
|
||||||
|
{ value: 'JM', label: 'Jamaica' },
|
||||||
|
{ value: 'JP', label: 'Japan' },
|
||||||
|
{ value: 'JE', label: 'Jersey' },
|
||||||
|
{ value: 'JO', label: 'Jordan' },
|
||||||
|
{ value: 'KZ', label: 'Kazakhstan' },
|
||||||
|
{ value: 'KE', label: 'Kenya' },
|
||||||
|
{ value: 'KI', label: 'Kiribati' },
|
||||||
|
{ value: 'KR', label: 'Korea' },
|
||||||
|
{ value: 'KW', label: 'Kuwait' },
|
||||||
|
{ value: 'KG', label: 'Kyrgyzstan' },
|
||||||
|
{ value: 'LA', label: "Lao People's Democratic Republic" },
|
||||||
|
{ value: 'LV', label: 'Latvia' },
|
||||||
|
{ value: 'LB', label: 'Lebanon' },
|
||||||
|
{ value: 'LS', label: 'Lesotho' },
|
||||||
|
{ value: 'LR', label: 'Liberia' },
|
||||||
|
{ value: 'LY', label: 'Libyan Arab Jamahiriya' },
|
||||||
|
{ value: 'LI', label: 'Liechtenstein' },
|
||||||
|
{ value: 'LT', label: 'Lithuania' },
|
||||||
|
{ value: 'LU', label: 'Luxembourg' },
|
||||||
|
{ value: 'MO', label: 'Macao' },
|
||||||
|
{ value: 'MK', label: 'Macedonia' },
|
||||||
|
{ value: 'MG', label: 'Madagascar' },
|
||||||
|
{ value: 'MW', label: 'Malawi' },
|
||||||
|
{ value: 'MY', label: 'Malaysia' },
|
||||||
|
{ value: 'MV', label: 'Maldives' },
|
||||||
|
{ value: 'ML', label: 'Mali' },
|
||||||
|
{ value: 'MT', label: 'Malta' },
|
||||||
|
{ value: 'MH', label: 'Marshall Islands' },
|
||||||
|
{ value: 'MQ', label: 'Martinique' },
|
||||||
|
{ value: 'MR', label: 'Mauritania' },
|
||||||
|
{ value: 'MU', label: 'Mauritius' },
|
||||||
|
{ value: 'YT', label: 'Mayotte' },
|
||||||
|
{ value: 'MX', label: 'Mexico' },
|
||||||
|
{ value: 'FM', label: 'Micronesia, Federated States Of' },
|
||||||
|
{ value: 'MD', label: 'Moldova' },
|
||||||
|
{ value: 'MC', label: 'Monaco' },
|
||||||
|
{ value: 'MN', label: 'Mongolia' },
|
||||||
|
{ value: 'ME', label: 'Montenegro' },
|
||||||
|
{ value: 'MS', label: 'Montserrat' },
|
||||||
|
{ value: 'MA', label: 'Morocco' },
|
||||||
|
{ value: 'MZ', label: 'Mozambique' },
|
||||||
|
{ value: 'MM', label: 'Myanmar' },
|
||||||
|
{ value: 'NA', label: 'Namibia' },
|
||||||
|
{ value: 'NR', label: 'Nauru' },
|
||||||
|
{ value: 'NP', label: 'Nepal' },
|
||||||
|
{ value: 'NL', label: 'Netherlands' },
|
||||||
|
{ value: 'AN', label: 'Netherlands Antilles' },
|
||||||
|
{ value: 'NC', label: 'New Caledonia' },
|
||||||
|
{ value: 'NZ', label: 'New Zealand' },
|
||||||
|
{ value: 'NI', label: 'Nicaragua' },
|
||||||
|
{ value: 'NE', label: 'Niger' },
|
||||||
|
{ value: 'NG', label: 'Nigeria' },
|
||||||
|
{ value: 'NU', label: 'Niue' },
|
||||||
|
{ value: 'NF', label: 'Norfolk Island' },
|
||||||
|
{ value: 'MP', label: 'Northern Mariana Islands' },
|
||||||
|
{ value: 'NO', label: 'Norway' },
|
||||||
|
{ value: 'OM', label: 'Oman' },
|
||||||
|
{ value: 'PK', label: 'Pakistan' },
|
||||||
|
{ value: 'PW', label: 'Palau' },
|
||||||
|
{ value: 'PS', label: 'Palestinian Territory, Occupied' },
|
||||||
|
{ value: 'PA', label: 'Panama' },
|
||||||
|
{ value: 'PG', label: 'Papua New Guinea' },
|
||||||
|
{ value: 'PY', label: 'Paraguay' },
|
||||||
|
{ value: 'PE', label: 'Peru' },
|
||||||
|
{ value: 'PH', label: 'Philippines' },
|
||||||
|
{ value: 'PN', label: 'Pitcairn' },
|
||||||
|
{ value: 'PL', label: 'Poland' },
|
||||||
|
{ value: 'PT', label: 'Portugal' },
|
||||||
|
{ value: 'PR', label: 'Puerto Rico' },
|
||||||
|
{ value: 'QA', label: 'Qatar' },
|
||||||
|
{ value: 'RE', label: 'Reunion' },
|
||||||
|
{ value: 'RO', label: 'Romania' },
|
||||||
|
{ value: 'RU', label: 'Russian Federation' },
|
||||||
|
{ value: 'RW', label: 'Rwanda' },
|
||||||
|
{ value: 'BL', label: 'Saint Barthelemy' },
|
||||||
|
{ value: 'SH', label: 'Saint Helena' },
|
||||||
|
{ value: 'KN', label: 'Saint Kitts And Nevis' },
|
||||||
|
{ value: 'LC', label: 'Saint Lucia' },
|
||||||
|
{ value: 'MF', label: 'Saint Martin' },
|
||||||
|
{ value: 'PM', label: 'Saint Pierre And Miquelon' },
|
||||||
|
{ value: 'VC', label: 'Saint Vincent And Grenadines' },
|
||||||
|
{ value: 'WS', label: 'Samoa' },
|
||||||
|
{ value: 'SM', label: 'San Marino' },
|
||||||
|
{ value: 'ST', label: 'Sao Tome And Principe' },
|
||||||
|
{ value: 'SA', label: 'Saudi Arabia' },
|
||||||
|
{ value: 'SN', label: 'Senegal' },
|
||||||
|
{ value: 'RS', label: 'Serbia' },
|
||||||
|
{ value: 'SC', label: 'Seychelles' },
|
||||||
|
{ value: 'SL', label: 'Sierra Leone' },
|
||||||
|
{ value: 'SG', label: 'Singapore' },
|
||||||
|
{ value: 'SK', label: 'Slovakia' },
|
||||||
|
{ value: 'SI', label: 'Slovenia' },
|
||||||
|
{ value: 'SB', label: 'Solomon Islands' },
|
||||||
|
{ value: 'SO', label: 'Somalia' },
|
||||||
|
{ value: 'ZA', label: 'South Africa' },
|
||||||
|
{ value: 'GS', label: 'South Georgia And Sandwich Isl.' },
|
||||||
|
{ value: 'ES', label: 'Spain' },
|
||||||
|
{ value: 'LK', label: 'Sri Lanka' },
|
||||||
|
{ value: 'SD', label: 'Sudan' },
|
||||||
|
{ value: 'SR', label: 'Surilabel' },
|
||||||
|
{ value: 'SJ', label: 'Svalbard And Jan Mayen' },
|
||||||
|
{ value: 'SZ', label: 'Swaziland' },
|
||||||
|
{ value: 'SE', label: 'Sweden' },
|
||||||
|
{ value: 'CH', label: 'Switzerland' },
|
||||||
|
{ value: 'SY', label: 'Syrian Arab Republic' },
|
||||||
|
{ value: 'TW', label: 'Taiwan' },
|
||||||
|
{ value: 'TJ', label: 'Tajikistan' },
|
||||||
|
{ value: 'TZ', label: 'Tanzania' },
|
||||||
|
{ value: 'TH', label: 'Thailand' },
|
||||||
|
{ value: 'TL', label: 'Timor-Leste' },
|
||||||
|
{ value: 'TG', label: 'Togo' },
|
||||||
|
{ value: 'TK', label: 'Tokelau' },
|
||||||
|
{ value: 'TO', label: 'Tonga' },
|
||||||
|
{ value: 'TT', label: 'Trinidad And Tobago' },
|
||||||
|
{ value: 'TN', label: 'Tunisia' },
|
||||||
|
{ value: 'TR', label: 'Turkey' },
|
||||||
|
{ value: 'TM', label: 'Turkmenistan' },
|
||||||
|
{ value: 'TC', label: 'Turks And Caicos Islands' },
|
||||||
|
{ value: 'TV', label: 'Tuvalu' },
|
||||||
|
{ value: 'UG', label: 'Uganda' },
|
||||||
|
{ value: 'UA', label: 'Ukraine' },
|
||||||
|
{ value: 'AE', label: 'United Arab Emirates' },
|
||||||
|
{ value: 'GB', label: 'United Kingdom' },
|
||||||
|
{ value: 'US', label: 'United States' },
|
||||||
|
{ value: 'UM', label: 'United States Outlying Islands' },
|
||||||
|
{ value: 'UY', label: 'Uruguay' },
|
||||||
|
{ value: 'UZ', label: 'Uzbekistan' },
|
||||||
|
{ value: 'VU', label: 'Vanuatu' },
|
||||||
|
{ value: 'VE', label: 'Venezuela' },
|
||||||
|
{ value: 'VN', label: 'Viet Nam' },
|
||||||
|
{ value: 'VG', label: 'Virgin Islands, British' },
|
||||||
|
{ value: 'VI', label: 'Virgin Islands, U.S.' },
|
||||||
|
{ value: 'WF', label: 'Wallis And Futuna' },
|
||||||
|
{ value: 'EH', label: 'Western Sahara' },
|
||||||
|
{ value: 'YE', label: 'Yemen' },
|
||||||
|
{ value: 'ZM', label: 'Zambia' },
|
||||||
|
{ value: 'ZW', label: 'Zimbabwe' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const getCountryFromLocale = (locale) =>
|
||||||
|
COUNTRY_LIST.find((country) => country.value === locale)?.label ?? '';
|
||||||
@@ -59,6 +59,14 @@ export const checkIfJson = (string) => {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const toJson = (string) => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(string);
|
||||||
|
} catch (e) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const secondsToDetailed = (
|
export const secondsToDetailed = (
|
||||||
seconds,
|
seconds,
|
||||||
dayLabel,
|
dayLabel,
|
||||||
|
|||||||
Reference in New Issue
Block a user