commit
e4704d806e
|
|
@ -80,6 +80,8 @@ func (h *Handler) CwmpHandler(w http.ResponseWriter, r *http.Request) {
|
|||
h.pub(NATS_CWMP_SUBJECT_PREFIX+sn+".info", tmp)
|
||||
}
|
||||
|
||||
cpe.ConnectionRequestURL = Inform.GetConnectionRequest() // Update connection request URL, in case the CPE changed IP
|
||||
|
||||
log.Printf("Received an Inform from device %s withEventCodes %s", addr, Inform.GetEvents())
|
||||
|
||||
expiration := time.Now().AddDate(0, 0, 1)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,11 @@ func (a *Api) StartApi() {
|
|||
iot := r.PathPrefix("/api/device").Subrouter()
|
||||
iot.HandleFunc("/alias", a.setDeviceAlias).Methods("PUT")
|
||||
iot.HandleFunc("/auth", a.deviceAuth).Methods("GET", "POST", "DELETE")
|
||||
iot.HandleFunc("/message/{type}", a.addTemplate).Methods("POST")
|
||||
iot.HandleFunc("/message", a.updateTemplate).Methods("PUT")
|
||||
iot.HandleFunc("/message", a.getTemplate).Methods("GET")
|
||||
iot.HandleFunc("/message", a.deleteTemplate).Methods("DELETE")
|
||||
iot.HandleFunc("/cwmp/{sn}/generic", a.cwmpGenericMsg).Methods("PUT")
|
||||
iot.HandleFunc("/cwmp/{sn}/getParameterNames", a.cwmpGetParameterNamesMsg).Methods("PUT")
|
||||
iot.HandleFunc("/cwmp/{sn}/getParameterValues", a.cwmpGetParameterValuesMsg).Methods("PUT")
|
||||
iot.HandleFunc("/cwmp/{sn}/getParameterAttributes", a.cwmpGetParameterAttributesMsg).Methods("PUT")
|
||||
|
|
@ -61,6 +66,7 @@ func (a *Api) StartApi() {
|
|||
iot.HandleFunc("/cwmp/{sn}/deleteObject", a.cwmpDeleteObjectMsg).Methods("PUT")
|
||||
iot.HandleFunc("", a.retrieveDevices).Methods("GET")
|
||||
iot.HandleFunc("/filterOptions", a.filterOptions).Methods("GET")
|
||||
iot.HandleFunc("/{sn}/{mtp}/generic", a.deviceGenericMessage).Methods("PUT")
|
||||
iot.HandleFunc("/{sn}/{mtp}/get", a.deviceGetMsg).Methods("PUT")
|
||||
iot.HandleFunc("/{sn}/{mtp}/add", a.deviceCreateMsg).Methods("PUT")
|
||||
iot.HandleFunc("/{sn}/{mtp}/del", a.deviceDeleteMsg).Methods("PUT")
|
||||
|
|
|
|||
|
|
@ -17,6 +17,31 @@ import (
|
|||
|
||||
var errDeviceModelNotFound = errors.New("device model not found")
|
||||
|
||||
func (a *Api) cwmpGenericMsg(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
sn := getSerialNumberFromRequest(r)
|
||||
|
||||
payload, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write(utils.Marshall(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if len(payload) == 0 {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write(utils.Marshall("Empty payload"))
|
||||
return
|
||||
}
|
||||
|
||||
data, _, err := cwmpInteraction[cwmp.SoapEnvelope](sn, payload, w, a.nc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(data)
|
||||
}
|
||||
|
||||
func (a *Api) cwmpGetParameterNamesMsg(w http.ResponseWriter, r *http.Request) {
|
||||
sn := getSerialNumberFromRequest(r)
|
||||
|
||||
|
|
@ -125,7 +150,7 @@ func (a *Api) cwmpDeleteObjectMsg(w http.ResponseWriter, r *http.Request) {
|
|||
w.Write(data)
|
||||
}
|
||||
|
||||
func cwmpInteraction[T cwmp.SetParameterValuesResponse | cwmp.DeleteObjectResponse | cwmp.GetParameterAttributesResponse | cwmp.GetParameterNamesResponse | cwmp.GetParameterValuesResponse | cwmp.AddObjectResponse](
|
||||
func cwmpInteraction[T cwmp.SetParameterValuesResponse | cwmp.SoapEnvelope | cwmp.DeleteObjectResponse | cwmp.GetParameterAttributesResponse | cwmp.GetParameterNamesResponse | cwmp.GetParameterValuesResponse | cwmp.AddObjectResponse](
|
||||
sn string, payload []byte, w http.ResponseWriter, nc *nats.Conn,
|
||||
) ([]byte, T, error) {
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/leandrofars/oktopus/internal/bridge"
|
||||
"github.com/leandrofars/oktopus/internal/db"
|
||||
"github.com/leandrofars/oktopus/internal/entity"
|
||||
|
|
@ -367,3 +368,141 @@ func (a *Api) filterOptions(w http.ResponseWriter, r *http.Request) {
|
|||
w.WriteHeader(resp.Code)
|
||||
w.Write(utils.Marshall(resp.Msg))
|
||||
}
|
||||
|
||||
func (a *Api) updateTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
name := r.URL.Query().Get("name")
|
||||
if name == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
utils.MarshallEncoder("No name provided", w)
|
||||
return
|
||||
}
|
||||
|
||||
payload, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
utils.MarshallEncoder("Error to decode payload: "+err.Error(), w)
|
||||
return
|
||||
}
|
||||
|
||||
payloadLen := len(payload)
|
||||
if payloadLen == 0 {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
utils.MarshallEncoder("No payload provided", w)
|
||||
return
|
||||
}
|
||||
|
||||
err = a.db.UpdateTemplate(name, string(payload))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
json.NewEncoder(w).Encode(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (a *Api) addTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
name := r.URL.Query().Get("name")
|
||||
if name == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
utils.MarshallEncoder("No name provided", w)
|
||||
return
|
||||
}
|
||||
|
||||
payload, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
utils.MarshallEncoder("Error to decode payload: "+err.Error(), w)
|
||||
return
|
||||
}
|
||||
|
||||
payloadLen := len(payload)
|
||||
if payloadLen == 0 {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
utils.MarshallEncoder("No payload provided", w)
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
switch vars["type"] {
|
||||
case "cwmp":
|
||||
err = a.db.AddTemplate(name, "cwmp", string(payload))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
json.NewEncoder(w).Encode(err.Error())
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
case "usp":
|
||||
err = a.db.AddTemplate(name, "usp", string(payload))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
json.NewEncoder(w).Encode(err.Error())
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
default:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
utils.MarshallEncoder("Invalid template type", w)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Api) getTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
name := r.URL.Query().Get("name")
|
||||
msgType := r.URL.Query().Get("type")
|
||||
|
||||
if name == "" {
|
||||
|
||||
var filter bson.D
|
||||
if msgType == "" {
|
||||
filter = bson.D{}
|
||||
} else {
|
||||
filter = bson.D{{"type", msgType}}
|
||||
}
|
||||
|
||||
result, err := a.db.AllTemplates(filter)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode("Error to get all templates: " + err.Error())
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(result)
|
||||
return
|
||||
} else {
|
||||
t, err := a.db.FindTemplate(bson.D{{"name", name}})
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
json.NewEncoder(w).Encode("error to find message: " + err.Error())
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(t.Value))
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (a *Api) deleteTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
name := r.URL.Query().Get("name")
|
||||
if name == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode("needs template name!")
|
||||
return
|
||||
} else {
|
||||
err := a.db.DeleteTemplate(name)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode("error to delete template: " + err.Error())
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,16 +135,6 @@ func (a *Api) changePassword(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
userToChangePasswd := mux.Vars(r)["user"]
|
||||
if userToChangePasswd != "" && userToChangePasswd != email {
|
||||
rUser, _ := a.db.FindUser(email)
|
||||
if rUser.Level != db.AdminUser {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
email = userToChangePasswd
|
||||
}
|
||||
|
||||
var user db.User
|
||||
err = json.NewDecoder(r.Body).Decode(&user)
|
||||
if err != nil {
|
||||
|
|
@ -154,6 +144,12 @@ func (a *Api) changePassword(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
user.Email = email
|
||||
|
||||
if len(user.Password) < 8 {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte("Password must be at least 8 characters long"))
|
||||
return
|
||||
}
|
||||
|
||||
if err := user.HashPassword(user.Password); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
|
|
@ -164,6 +160,7 @@ func (a *Api) changePassword(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (a *Api) registerAdminUser(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -12,6 +13,7 @@ import (
|
|||
"github.com/leandrofars/oktopus/internal/usp/usp_utils"
|
||||
"github.com/leandrofars/oktopus/internal/utils"
|
||||
"github.com/nats-io/nats.go"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
|
|
@ -59,6 +61,16 @@ func sendUspMsg(msg usp_msg.Msg, sn string, w http.ResponseWriter, nc *nats.Conn
|
|||
}
|
||||
|
||||
body := receivedMsg.Body.GetResponse()
|
||||
if body == nil {
|
||||
errorMsg := receivedMsg.Body.GetError()
|
||||
if errorMsg == nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
log.Println("No response body or error")
|
||||
return nil
|
||||
}
|
||||
w.Write(utils.Marshall(errorMsg))
|
||||
return nil
|
||||
}
|
||||
|
||||
switch body.RespType.(type) {
|
||||
case *usp_msg.Response_GetResp:
|
||||
|
|
@ -86,6 +98,44 @@ func sendUspMsg(msg usp_msg.Msg, sn string, w http.ResponseWriter, nc *nats.Conn
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *Api) deviceGenericMessage(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
sn := getSerialNumberFromRequest(r)
|
||||
mtp, err := getMtpFromRequest(r, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if mtp == "" {
|
||||
var ok bool
|
||||
mtp, ok = deviceStateOK(w, a.nc, sn)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
payload, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write(utils.Marshall(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
var msg usp_msg.Msg
|
||||
|
||||
err = protojson.Unmarshal(payload, &msg)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write(utils.Marshall(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
err = sendUspMsg(msg, sn, w, a.nc, mtp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Api) deviceGetMsg(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
sn := getSerialNumberFromRequest(r)
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@ import (
|
|||
)
|
||||
|
||||
type Database struct {
|
||||
client *mongo.Client
|
||||
users *mongo.Collection
|
||||
ctx context.Context
|
||||
client *mongo.Client
|
||||
users *mongo.Collection
|
||||
template *mongo.Collection
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func NewDatabase(ctx context.Context, mongoUri string) Database {
|
||||
|
|
@ -43,6 +44,16 @@ func NewDatabase(ctx context.Context, mongoUri string) Database {
|
|||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
db.template = client.Database("general").Collection("templates")
|
||||
indexField = bson.M{"name": 1}
|
||||
_, err = db.template.Indexes().CreateOne(ctx, mongo.IndexModel{
|
||||
Keys: indexField,
|
||||
Options: options.Index().SetUnique(true),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
db.ctx = ctx
|
||||
|
||||
return db
|
||||
|
|
|
|||
72
backend/services/controller/internal/db/template.go
Normal file
72
backend/services/controller/internal/db/template.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
type Template struct {
|
||||
Name string `json:"name" bson:"name"`
|
||||
Type string `json:"type" bson:"type"`
|
||||
Value string `json:"value" bson:"value"`
|
||||
}
|
||||
|
||||
var ErrorTemplateExists = errors.New("message already exists")
|
||||
var ErrorTemplateNotExists = errors.New("message don't exist")
|
||||
|
||||
func (d *Database) FindTemplate(filter interface{}) (Template, error) {
|
||||
var result Template
|
||||
err := d.template.FindOne(d.ctx, filter).Decode(&result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (d *Database) AllTemplates(filter interface{}) ([]Template, error) {
|
||||
var results []Template
|
||||
|
||||
cursor, err := d.template.Find(d.ctx, filter)
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
if err = cursor.All(d.ctx, &results); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return results, err
|
||||
}
|
||||
|
||||
func (d *Database) AddTemplate(name, tr string, t string) error {
|
||||
opts := options.FindOneAndReplace().SetUpsert(true)
|
||||
err := d.template.FindOneAndReplace(d.ctx, bson.D{{"name", name}}, Template{Name: name, Type: tr, Value: t}, opts).Err()
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
log.Printf("New message %s added to database", name)
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
log.Printf("Message %s already existed, and got replaced for new payload", name)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Database) UpdateTemplate(name, t string) error {
|
||||
result, err := d.template.UpdateOne(d.ctx, bson.D{{"name", name}}, bson.D{{"$set", bson.D{{"value", t}}}})
|
||||
if err == nil {
|
||||
if result.MatchedCount == 0 {
|
||||
return ErrorTemplateNotExists
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Database) DeleteTemplate(name string) error {
|
||||
result, err := d.template.DeleteOne(d.ctx, bson.D{{"name", name}})
|
||||
if err == nil {
|
||||
if result.DeletedCount == 0 {
|
||||
return ErrorTemplateNotExists
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
@ -82,6 +82,13 @@ func (d *Database) CreateDevice(device Device) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------- Do not overwrite alias ------------------------- */
|
||||
if deviceExistent.Alias != "" {
|
||||
device.Alias = deviceExistent.Alias
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
callback := func(sessCtx mongo.SessionContext) (interface{}, error) {
|
||||
|
|
|
|||
|
|
@ -211,6 +211,8 @@ export const AuthProvider = (props) => {
|
|||
};
|
||||
|
||||
const signOut = () => {
|
||||
router.push("/auth/login")
|
||||
localStorage.removeItem("token")
|
||||
dispatch({
|
||||
type: HANDLERS.SIGN_OUT
|
||||
});
|
||||
|
|
|
|||
91
frontend/src/contexts/backend-context.js
Normal file
91
frontend/src/contexts/backend-context.js
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import { createContext, useContext, } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useAlertContext } from './error-context';
|
||||
|
||||
export const BackendContext = createContext({ undefined });
|
||||
|
||||
export const BackendProvider = (props) => {
|
||||
const { children } = props;
|
||||
|
||||
const { setAlert } = useAlertContext();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
var myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/json");
|
||||
myHeaders.append("Authorization", localStorage.getItem("token"));
|
||||
|
||||
const httpRequest = async (path, method, body, headers, encoding) => {
|
||||
|
||||
var requestOptions = {
|
||||
method: method,
|
||||
redirect: 'follow',
|
||||
};
|
||||
|
||||
if (body) {
|
||||
requestOptions.body = body
|
||||
}
|
||||
|
||||
console.log("headers:", headers)
|
||||
if (headers) {
|
||||
requestOptions.headers = headers
|
||||
}else {
|
||||
requestOptions.headers = myHeaders
|
||||
}
|
||||
|
||||
const response = await fetch(`${process.env.NEXT_PUBLIC_REST_ENDPOINT || ""}${path}`, requestOptions)
|
||||
console.log("status:", response.status)
|
||||
if (response.status != 200) {
|
||||
if (response.status == 401) {
|
||||
router.push("/auth/login")
|
||||
}
|
||||
if (response.status == 204 || response.status == 201) {
|
||||
return {status : response.status, result: null}
|
||||
}
|
||||
const data = await response.text()
|
||||
// setAlert({
|
||||
// severity: "error",
|
||||
// title: "Error",
|
||||
// message: `Status: ${response.status}, Content: ${data}`,
|
||||
// })
|
||||
setAlert({
|
||||
severity: "error",
|
||||
// title: "Error",
|
||||
message: `${data}`,
|
||||
})
|
||||
return {status : response.status, result: null}
|
||||
}
|
||||
if (encoding) {
|
||||
console.log("encoding:", encoding)
|
||||
if (encoding == "text") {
|
||||
const data = await response.text()
|
||||
return {status: response.status, result: data}
|
||||
}else if (encoding == "blob") {
|
||||
const data = await response.blob()
|
||||
return {status: response.status, result: data}
|
||||
}else if (encoding == "json") {
|
||||
const data = await response.json()
|
||||
return {status: response.status, result: data}
|
||||
}else{
|
||||
return {status: response.status, result: response}
|
||||
}
|
||||
}
|
||||
const data = await response.json()
|
||||
return {status: response.status, result: data}
|
||||
}
|
||||
|
||||
return (
|
||||
<BackendContext.Provider
|
||||
value={{
|
||||
httpRequest,
|
||||
setAlert,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</BackendContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const BackendConsumer = BackendContext.Consumer;
|
||||
|
||||
export const useBackendContext = () => useContext(BackendContext);
|
||||
32
frontend/src/contexts/error-context.js
Normal file
32
frontend/src/contexts/error-context.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { createContext, useContext, useState } from 'react';
|
||||
|
||||
|
||||
export const AlertContext = createContext({ undefined });
|
||||
|
||||
export const AlertProvider = (props) => {
|
||||
const { children } = props;
|
||||
/*
|
||||
{
|
||||
severity: '', // options => error, warning, info, success
|
||||
message: '',
|
||||
title: '',
|
||||
}
|
||||
*/
|
||||
// const [alert, setAlert] = useState(null);
|
||||
const [alert, setAlert] = useState();
|
||||
|
||||
return (
|
||||
<AlertContext.Provider
|
||||
value={{
|
||||
alert,
|
||||
setAlert,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AlertContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const AlertConsumer = AlertContext.Consumer;
|
||||
|
||||
export const useAlertContext = () => useContext(AlertContext);
|
||||
|
|
@ -1,14 +1,16 @@
|
|||
import ChartBarIcon from '@heroicons/react/24/solid/ChartBarIcon';
|
||||
import CogIcon from '@heroicons/react/24/solid/CogIcon';
|
||||
import ChatBubbleLeftRightIcon from '@heroicons/react/24/solid/ChatBubbleLeftRightIcon'
|
||||
import MapIcon from '@heroicons/react/24/solid/MapIcon'
|
||||
import RectangleGroupIcon from '@heroicons/react/24/solid/RectangleGroupIcon'
|
||||
import ArrowDownOnSquareStackIcon from '@heroicons/react/24/solid/ArrowDownOnSquareStackIcon'
|
||||
import UserGroupIcon from '@heroicons/react/24/solid/UserGroupIcon'
|
||||
import KeyIcon from '@heroicons/react/24/solid/KeyIcon'
|
||||
import CpuChip from '@heroicons/react/24/solid/CpuChipIcon';
|
||||
import BriefCaseIcon from '@heroicons/react/24/outline/BriefcaseIcon';
|
||||
import { SvgIcon } from '@mui/material';
|
||||
import FolderIcon from '@heroicons/react/24/solid/FolderIcon';
|
||||
import ShieldCheckIcon from '@heroicons/react/24/solid/ShieldCheckIcon';
|
||||
import EnvelopeIcon from '@heroicons/react/24/solid/EnvelopeIcon';
|
||||
import UserIcon from '@heroicons/react/24/solid/UserIcon';
|
||||
|
||||
export const items = [
|
||||
{
|
||||
|
|
@ -48,19 +50,19 @@ export const items = [
|
|||
</SvgIcon>
|
||||
),
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Message',
|
||||
tooltip: 'Upgrade to Business Plan',
|
||||
disabled: true,
|
||||
icon: (
|
||||
<SvgIcon fontSize="small">
|
||||
<EnvelopeIcon color='gray'/>
|
||||
</SvgIcon>
|
||||
)
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Map',
|
||||
tooltip: 'Upgrade to Business Plan',
|
||||
icon: (
|
||||
<SvgIcon fontSize="small">
|
||||
<MapIcon color='gray'/>
|
||||
</SvgIcon>
|
||||
),
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
title: 'Credentials',
|
||||
path: '/credentials',
|
||||
|
|
@ -71,11 +73,43 @@ export const items = [
|
|||
)
|
||||
},
|
||||
{
|
||||
title: 'Users',
|
||||
path: '/users',
|
||||
title: 'Access Control',
|
||||
disabled: true,
|
||||
tooltip: 'Upgrade to Business Plan',
|
||||
icon: (
|
||||
<SvgIcon fontSize="small">
|
||||
<UserGroupIcon />
|
||||
<UserGroupIcon color='gray'/>
|
||||
</SvgIcon>
|
||||
),
|
||||
children: [
|
||||
{
|
||||
title: 'Roles',
|
||||
disabled: true,
|
||||
tooltip: 'Upgrade to Business Plan',
|
||||
icon: (
|
||||
<SvgIcon fontSize="small">
|
||||
<ShieldCheckIcon color='gray'/>
|
||||
</SvgIcon>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Users',
|
||||
path: '/access-control/users',
|
||||
icon: (
|
||||
<SvgIcon fontSize="small">
|
||||
<UserIcon/>
|
||||
</SvgIcon>
|
||||
)
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'File Server',
|
||||
tooltip: 'Upgrade to Business Plan',
|
||||
disabled: true,
|
||||
icon: (
|
||||
<SvgIcon fontSize="small">
|
||||
<FolderIcon color='gray'/>
|
||||
</SvgIcon>
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import { styled } from '@mui/material/styles';
|
|||
import { withAuthGuard } from 'src/hocs/with-auth-guard';
|
||||
import { SideNav } from './side-nav';
|
||||
import { TopNav } from './top-nav';
|
||||
import { useAlertContext } from 'src/contexts/error-context';
|
||||
import { Alert, AlertTitle, Snackbar } from '@mui/material';
|
||||
|
||||
const SIDE_NAV_WIDTH = 280;
|
||||
|
||||
|
|
@ -28,6 +30,8 @@ export const Layout = withAuthGuard((props) => {
|
|||
const pathname = usePathname();
|
||||
const [openNav, setOpenNav] = useState(false);
|
||||
|
||||
const {alert, setAlert} = useAlertContext();
|
||||
|
||||
const handlePathnameChange = useCallback(
|
||||
() => {
|
||||
if (openNav) {
|
||||
|
|
@ -57,6 +61,21 @@ export const Layout = withAuthGuard((props) => {
|
|||
{children}
|
||||
</LayoutContainer>
|
||||
</LayoutRoot>
|
||||
{alert && <Snackbar
|
||||
open={true}
|
||||
autoHideDuration={4000}
|
||||
anchorOrigin={{vertical:'bottom', horizontal: 'right'}}
|
||||
onClose={() => setAlert(null)}
|
||||
>
|
||||
<Alert
|
||||
severity={alert?.severity}
|
||||
variant={alert?.severity == 'success' ? 'standard' : 'filled'}
|
||||
sx={{ width: '100%' }}
|
||||
>
|
||||
{alert?.title && <AlertTitle>{alert.title}</AlertTitle>}
|
||||
{alert?.message}
|
||||
</Alert>
|
||||
</Snackbar>}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
|
@ -9,7 +9,7 @@ import { usePathname } from 'next/navigation';
|
|||
export const SideNavItem = (props) => {
|
||||
const { active = false, disabled, external, icon, path, title, children, padleft, tooltip } = props;
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [open, setOpen] = useState(true);
|
||||
const pathname = usePathname();
|
||||
|
||||
const isItemActive = (currentPath, itemPath) => {
|
||||
|
|
@ -64,10 +64,14 @@ export const SideNavItem = (props) => {
|
|||
}
|
||||
}}
|
||||
>
|
||||
|
||||
{icon && (
|
||||
<Box
|
||||
component="span"
|
||||
onClick={()=>{
|
||||
if (!path){
|
||||
setOpen(!open)
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
alignItems: 'center',
|
||||
color: 'neutral.400',
|
||||
|
|
@ -85,6 +89,11 @@ export const SideNavItem = (props) => {
|
|||
)}
|
||||
<Box
|
||||
component="span"
|
||||
onClick={()=>{
|
||||
if (!path){
|
||||
setOpen(!open)
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
color: 'neutral.400',
|
||||
flexGrow: 1,
|
||||
|
|
|
|||
|
|
@ -9,9 +9,10 @@ import { useNProgress } from 'src/hooks/use-nprogress';
|
|||
import { createTheme } from 'src/theme';
|
||||
import { createEmotionCache } from 'src/utils/create-emotion-cache';
|
||||
import 'simplebar-react/dist/simplebar.min.css';
|
||||
import { WsProvider } from 'src/contexts/socketio-context';
|
||||
import '../utils/map.css';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { BackendProvider } from 'src/contexts/backend-context';
|
||||
import { AlertProvider } from 'src/contexts/error-context';
|
||||
|
||||
const clientSideEmotionCache = createEmotionCache();
|
||||
|
||||
|
|
@ -33,7 +34,7 @@ const App = (props) => {
|
|||
<CacheProvider value={emotionCache}>
|
||||
<Head>
|
||||
<title>
|
||||
Oktopus | TR-369 Controller
|
||||
Oktopus | Controller
|
||||
</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
|
|
@ -42,16 +43,22 @@ const App = (props) => {
|
|||
</Head>
|
||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||
<AuthProvider>
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<AuthConsumer>
|
||||
{
|
||||
(auth) => auth.isLoading
|
||||
? <SplashScreen />
|
||||
: getLayout(<Component {...pageProps} />)
|
||||
}
|
||||
</AuthConsumer>
|
||||
</ThemeProvider>
|
||||
{/* <WsProvider> */}
|
||||
<AlertProvider>
|
||||
<BackendProvider>
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<AuthConsumer>
|
||||
{
|
||||
(auth) => auth.isLoading
|
||||
? <SplashScreen />
|
||||
: getLayout(<Component {...pageProps} />)
|
||||
}
|
||||
</AuthConsumer>
|
||||
</ThemeProvider>
|
||||
</BackendProvider>
|
||||
</AlertProvider>
|
||||
{/* </WsProvider> */}
|
||||
</AuthProvider>
|
||||
</LocalizationProvider>
|
||||
</CacheProvider>
|
||||
|
|
|
|||
|
|
@ -204,15 +204,10 @@ const Page = () => {
|
|||
useEffect(() => {
|
||||
getColumns()
|
||||
setLoading(true)
|
||||
if (auth.user.token) {
|
||||
console.log("auth.user.token =", auth.user.token)
|
||||
} else {
|
||||
auth.user.token = localStorage.getItem("token")
|
||||
}
|
||||
|
||||
var myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/json");
|
||||
myHeaders.append("Authorization", auth.user.token);
|
||||
myHeaders.append("Authorization", localStorage.getItem("token"));
|
||||
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
|
|
@ -293,8 +288,9 @@ const Page = () => {
|
|||
console.log("set alias result:", content)
|
||||
setShowSetDeviceAlias(false)
|
||||
setDeviceAlias(null)
|
||||
orders[deviceToBeChanged].Alias = alias
|
||||
devices[deviceToBeChanged].Alias = alias
|
||||
setDeviceToBeChanged(null)
|
||||
setDevices([...devices])
|
||||
}
|
||||
// .then(response => {
|
||||
// if (response.status === 401) {
|
||||
|
|
@ -415,7 +411,7 @@ const Page = () => {
|
|||
<>
|
||||
<Head>
|
||||
<title>
|
||||
Oktopus | TR-369
|
||||
Oktopus | Controller
|
||||
</title>
|
||||
</Head>
|
||||
|
||||
|
|
@ -651,7 +647,7 @@ const Page = () => {
|
|||
</SvgIcon>
|
||||
</Button>
|
||||
</Tooltip>}
|
||||
{/* <Tooltip title="Edit the device alias">
|
||||
<Tooltip title="Edit the device alias">
|
||||
<Button
|
||||
onClick={()=>{
|
||||
setDeviceToBeChanged(index)
|
||||
|
|
@ -667,7 +663,7 @@ const Page = () => {
|
|||
</SvgIcon>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Edit device labels">
|
||||
{/* <Tooltip title="Edit device labels">
|
||||
<Button
|
||||
onClick={()=>{
|
||||
setDeviceToBeChanged(index)
|
||||
|
|
@ -724,7 +720,7 @@ const Page = () => {
|
|||
<Input value={deviceAlias} onChange={(e) => { setDeviceAlias(e.target.value) }}
|
||||
onKeyUp={e => {
|
||||
if (e.key === 'Enter') {
|
||||
setNewDeviceAlias(deviceAlias, orders[deviceToBeChanged].SN)
|
||||
setNewDeviceAlias(deviceAlias, devices[deviceToBeChanged].SN)
|
||||
}
|
||||
}}>
|
||||
</Input>
|
||||
|
|
@ -736,7 +732,7 @@ const Page = () => {
|
|||
setDeviceToBeChanged(null)
|
||||
}}>Cancel</Button>
|
||||
<Button onClick={() => {
|
||||
setNewDeviceAlias(deviceAlias, orders[deviceToBeChanged].SN)
|
||||
setNewDeviceAlias(deviceAlias, devices[deviceToBeChanged].SN)
|
||||
}}>Save</Button>
|
||||
</DialogActions>
|
||||
</Dialog>}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ import DevicePhoneMobile from '@heroicons/react/24/solid/DevicePhoneMobileIcon';
|
|||
import WrenchScrewDriverIcon from '@heroicons/react/24/outline/WrenchScrewdriverIcon';
|
||||
import CommandLineIcon from '@heroicons/react/24/outline/CommandLineIcon';
|
||||
import { DevicesWiFi } from 'src/sections/devices/cwmp/devices-wifi';
|
||||
import ArrowTrendingUpIcon from '@heroicons/react/24/outline/ArrowTrendingUpIcon';
|
||||
import DocumentTextIcon from '@heroicons/react/24/outline/DocumentTextIcon';
|
||||
import MapPinIcon from '@heroicons/react/24/outline/MapPinIcon';
|
||||
|
||||
|
||||
const Page = () => {
|
||||
|
|
@ -31,10 +34,10 @@ const Page = () => {
|
|||
switch(section){
|
||||
case "msg":
|
||||
return <DevicesRPC/>
|
||||
case "wifi":
|
||||
return <DevicesWiFi/>
|
||||
/* case "wifi":
|
||||
return <DevicesWiFi/> */
|
||||
default:
|
||||
router.push(`/devices/cwmp/${deviceID}/wifi`)
|
||||
router.replace(`/devices/cwmp/${deviceID}/msg`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +45,7 @@ const Page = () => {
|
|||
<>
|
||||
<Head>
|
||||
<title>
|
||||
Oktopus | TR-369
|
||||
Oktopus | Controller
|
||||
</title>
|
||||
</Head>
|
||||
<Box
|
||||
|
|
@ -52,9 +55,9 @@ const Page = () => {
|
|||
py: 0,
|
||||
}}
|
||||
>
|
||||
<Container maxWidth="lg" >
|
||||
<Stack spacing={3} >
|
||||
<Breadcrumbs separator="›" aria-label="breadcrumb" sx={{md: 40, mr: 20}}>
|
||||
<Container maxWidth="xg">
|
||||
<Stack spacing={3} mb={3}>
|
||||
<Breadcrumbs separator="›" aria-label="breadcrumb" ml={10}>
|
||||
{[<Link underline="hover" key="1" color="inherit" href="/devices">
|
||||
Devices
|
||||
</Link>,
|
||||
|
|
@ -71,19 +74,19 @@ const Page = () => {
|
|||
display:'flex',
|
||||
justifyContent:'center',
|
||||
}}>
|
||||
<Tabs value={router.query.id[1]} aria-label="icon label tabs example">
|
||||
<Tabs value={router.query.id[1]} aria-label="icon label tabs example" variant='scrollable'>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
<Tab
|
||||
icon={<SvgIcon><WifiIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Wi-Fi"
|
||||
onClick={()=>{router.push(`/devices/cwmp/${deviceID}/wifi`)}}
|
||||
value={"wifi"}/>
|
||||
value={"wifi"}
|
||||
style={{opacity:"0.5", cursor:"default"}}/></Tooltip>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
<Tab
|
||||
icon={<SvgIcon><SignalIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Site Survey"
|
||||
onClick={()=>{router.push(`/devices/cwmp/${deviceID}/site-survey`)}}
|
||||
value={"site-survey"}
|
||||
style={{opacity:"0.5", cursor:"default"}}/></Tooltip>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
|
|
@ -92,7 +95,6 @@ const Page = () => {
|
|||
iconPosition={"end"}
|
||||
label="Connected Devices"
|
||||
style={{opacity:"0.5", cursor:"default"}}
|
||||
onClick={()=>{router.push(`/devices/cwmp/${deviceID}/connected-devices`)}}
|
||||
value={"connected-devices"}
|
||||
/></Tooltip>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
|
|
@ -100,7 +102,6 @@ const Page = () => {
|
|||
icon={<SvgIcon><WrenchScrewDriverIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Diagnostic"
|
||||
onClick={()=>{router.push(`/devices/cwmp/${deviceID}/diagnostic`)}}
|
||||
value={"diagnostic"}
|
||||
style={{opacity:"0.5", cursor:"default"}}/></Tooltip>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
|
|
@ -108,25 +109,48 @@ const Page = () => {
|
|||
icon={<SvgIcon><ServerStackIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Ports"
|
||||
onClick={()=>{router.push(`/devices/usp/${deviceID}/ports`)}}
|
||||
style={{opacity:"0.5", cursor:"default"}}
|
||||
value={"ports"} /></Tooltip>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
<Tab
|
||||
icon={<SvgIcon><ArrowTrendingUpIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Historic"
|
||||
value={"historic"}
|
||||
style={{opacity:"0.5", cursor:"default"}}/></Tooltip>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
<Tab
|
||||
icon={<SvgIcon><CommandLineIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Actions"
|
||||
onClick={()=>{router.push(`/devices/usp/${deviceID}/actions`)}}
|
||||
style={{opacity:"0.5", cursor:"default"}}
|
||||
value={"actions"} /></Tooltip>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
<Tab
|
||||
icon={<SvgIcon><DocumentTextIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Logs"
|
||||
style={{opacity:"0.5", cursor:"default"}}
|
||||
value={"logs"} /></Tooltip>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
<Tab
|
||||
icon={<SvgIcon><MapPinIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Location"
|
||||
style={{opacity:"0.5", cursor:"default"}}
|
||||
value={"location"} /></Tooltip>
|
||||
<Tab
|
||||
value={"msg"}
|
||||
onClick={()=>{router.push(`/devices/cwmp/${deviceID}/msg`)}}
|
||||
icon={<SvgIcon><EnvelopeIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Remote Messages" />
|
||||
label="Messages" />
|
||||
</Tabs>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Container>
|
||||
<Container maxWidth="lg">
|
||||
<Stack spacing={3}>
|
||||
{
|
||||
sectionHandler()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ import SignalIcon from '@heroicons/react/24/solid/SignalIcon';
|
|||
import DevicePhoneMobile from '@heroicons/react/24/solid/DevicePhoneMobileIcon';
|
||||
import WrenchScrewDriverIcon from '@heroicons/react/24/outline/WrenchScrewdriverIcon';
|
||||
import CommandLineIcon from '@heroicons/react/24/outline/CommandLineIcon';
|
||||
import CubeTransparentIcon from '@heroicons/react/24/outline/CubeTransparentIcon';
|
||||
import MapPin from '@heroicons/react/24/outline/MapPinIcon';
|
||||
import ArrowTrendingUp from '@heroicons/react/24/outline/ArrowTrendingUpIcon';
|
||||
|
||||
const Page = () => {
|
||||
const router = useRouter()
|
||||
|
|
@ -36,7 +39,7 @@ const Page = () => {
|
|||
case "discovery":
|
||||
return <DevicesDiscovery/>
|
||||
default:
|
||||
router.push(`/devices/usp/${deviceID}/discovery`)
|
||||
router.replace(`/devices/usp/${deviceID}/discovery`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -44,7 +47,7 @@ const Page = () => {
|
|||
<>
|
||||
<Head>
|
||||
<title>
|
||||
Oktopus | TR-369
|
||||
Oktopus | Controller
|
||||
</title>
|
||||
</Head>
|
||||
<Box
|
||||
|
|
@ -54,9 +57,9 @@ const Page = () => {
|
|||
py: 0,
|
||||
}}
|
||||
>
|
||||
<Container maxWidth="lg" >
|
||||
<Stack spacing={3} >
|
||||
<Breadcrumbs separator="›" aria-label="breadcrumb" sx={{md: 40, mr: 20}}>
|
||||
<Container maxWidth="xg" >
|
||||
<Stack spacing={3} mb={3}>
|
||||
<Breadcrumbs separator="›" aria-label="breadcrumb"ml={10}>
|
||||
{[<Link underline="hover" key="1" color="inherit" href="/devices">
|
||||
Devices
|
||||
</Link>,
|
||||
|
|
@ -72,9 +75,8 @@ const Page = () => {
|
|||
<Box sx={{
|
||||
display:'flex',
|
||||
justifyContent:'center'
|
||||
}}
|
||||
mb={3}>
|
||||
<Tabs value={router.query.id[1]} aria-label="icon label tabs example">
|
||||
}}>
|
||||
<Tabs value={router.query.id[1]} aria-label="icon label tabs example" variant='scrollable'>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
<Tab
|
||||
icon={<SvgIcon><WifiIcon/></SvgIcon>}
|
||||
|
|
@ -117,6 +119,27 @@ const Page = () => {
|
|||
value={"ports"} /></Tooltip>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
<Tab
|
||||
icon={<SvgIcon><ArrowTrendingUp/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Historic"
|
||||
style={{cursor:"default", opacity: 0.5}}
|
||||
value={"historic"} /></Tooltip>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
<Tab
|
||||
icon={<SvgIcon><CubeTransparentIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="LCM"
|
||||
style={{cursor:"default", opacity: 0.5}}
|
||||
value={"lcm"} /></Tooltip>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
<Tab
|
||||
icon={<SvgIcon><MapPin/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Location"
|
||||
style={{cursor:"default", opacity: 0.5}}
|
||||
value={"location"} /></Tooltip>
|
||||
<Tooltip title="Upgrade to Business Plan" placement="bottom">
|
||||
<Tab
|
||||
icon={<SvgIcon><CommandLineIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Actions"
|
||||
|
|
@ -127,15 +150,19 @@ const Page = () => {
|
|||
onClick={()=>{router.push(`/devices/usp/${deviceID}/discovery`)}}
|
||||
icon={<SvgIcon><MagnifyingGlassIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Discover Parameters" />
|
||||
label="Parameters" />
|
||||
<Tab
|
||||
value={"msg"}
|
||||
onClick={()=>{router.push(`/devices/usp/${deviceID}/msg`)}}
|
||||
icon={<SvgIcon><EnvelopeIcon/></SvgIcon>}
|
||||
iconPosition={"end"}
|
||||
label="Remote Messages" />
|
||||
label="Messages" />
|
||||
</Tabs>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Container>
|
||||
<Container maxWidth="lg">
|
||||
<Stack spacing={3}>
|
||||
{
|
||||
sectionHandler()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ const Page = () => {
|
|||
<>
|
||||
<Head>
|
||||
<title>
|
||||
Oktopus | TR-369
|
||||
Oktopus | Controller
|
||||
</title>
|
||||
</Head>
|
||||
<Box
|
||||
|
|
|
|||
|
|
@ -1,259 +0,0 @@
|
|||
import Head from 'next/head';
|
||||
import { GoogleMap, useLoadScript, Marker, OverlayView } from "@react-google-maps/api"
|
||||
import { Layout as DashboardLayout } from 'src/layouts/dashboard/layout';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import mapStyles from '../utils/mapStyles.json';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
const getPixelPositionOffset = pixelOffset => (width, height) => ({
|
||||
x: -(width / 2) + pixelOffset.x,
|
||||
y: -(height / 2) + pixelOffset.y
|
||||
});
|
||||
|
||||
const Popup = props => {
|
||||
return (
|
||||
<OverlayView
|
||||
position={props.anchorPosition}
|
||||
mapPaneName={OverlayView.OVERLAY_MOUSE_TARGET}
|
||||
getPixelPositionOffset={getPixelPositionOffset(props.markerPixelOffset)}
|
||||
>
|
||||
<div className="popup-tip-anchor">
|
||||
<div className="popup-bubble-anchor">
|
||||
<div className="popup-bubble-content">{props.content}</div>
|
||||
</div>
|
||||
</div>
|
||||
</OverlayView>
|
||||
);
|
||||
};
|
||||
|
||||
const Page = () => {
|
||||
|
||||
const libraries = useMemo(() => ['places'], []);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const [mapRef, setMapRef] = useState(null);
|
||||
|
||||
const [mapCenter, setMapCenter] = useState(null);
|
||||
const [markers, setMarkers] = useState([]);
|
||||
const [activeMarker, setActiveMarker] = useState(null);
|
||||
const [activeMarkerdata, setActiveMarkerdata] = useState(null);
|
||||
const [zoom, setZoom] = useState(null)
|
||||
|
||||
const handleDragEnd = () => {
|
||||
if (mapRef) {
|
||||
const newCenter = mapRef.getCenter();
|
||||
console.log("newCenter:",newCenter.lat(), newCenter.lng());
|
||||
localStorage.setItem("mapCenter", JSON.stringify({"lat":newCenter.lat(),"lng":newCenter.lng()}))
|
||||
}
|
||||
}
|
||||
|
||||
const handleZoomChange = () => {
|
||||
if (mapRef) {
|
||||
const newZoom = mapRef.getZoom();
|
||||
console.log("new zoom", newZoom)
|
||||
localStorage.setItem("zoom", newZoom)
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnLoad = map => {
|
||||
setMapRef(map);
|
||||
};
|
||||
|
||||
const fetchMarkers = async () => {
|
||||
|
||||
var myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/json");
|
||||
myHeaders.append("Authorization", localStorage.getItem("token"));
|
||||
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
headers: myHeaders,
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
let result = await fetch(`${process.env.NEXT_PUBLIC_REST_ENDPOINT || ""}/api/map`, requestOptions)
|
||||
|
||||
if (result.status == 200) {
|
||||
const content = await result.json()
|
||||
setMarkers(content)
|
||||
}else if (result.status == 403) {
|
||||
console.log("num tenx permissão, seu boca de sandália")
|
||||
return router.push("/403")
|
||||
}else if (result.status == 401){
|
||||
console.log("taix nem autenticado, sai fora oh")
|
||||
return router.push("/auth/login")
|
||||
} else {
|
||||
setMarkers([])
|
||||
console.log("error to get map markers")
|
||||
}
|
||||
}
|
||||
|
||||
const fetchActiveMarkerData = async (id) => {
|
||||
var myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/json");
|
||||
myHeaders.append("Authorization", localStorage.getItem("token"));
|
||||
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
headers: myHeaders,
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
let result = await fetch(`${process.env.NEXT_PUBLIC_REST_ENDPOINT || ""}/api/device?id=`+id, requestOptions)
|
||||
|
||||
if (result.status == 200) {
|
||||
const content = await result.json()
|
||||
setActiveMarkerdata(content)
|
||||
}else if (result.status == 403) {
|
||||
return router.push("/403")
|
||||
}else if (result.status == 401){
|
||||
return router.push("/auth/login")
|
||||
} else {
|
||||
console.log("no device info found")
|
||||
const content = await result.json()
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(()=> {
|
||||
fetchMarkers();
|
||||
|
||||
let zoomFromLocalStorage = localStorage.getItem("zoom")
|
||||
if (zoomFromLocalStorage) {
|
||||
setZoom(Number(zoomFromLocalStorage))
|
||||
}else{
|
||||
setZoom(25)
|
||||
}
|
||||
|
||||
let mapCenterFromLocalStorage = localStorage.getItem("mapCenter")
|
||||
if (mapCenterFromLocalStorage){
|
||||
let fmtMapCenter = JSON.parse(localStorage.getItem("mapCenter"))
|
||||
console.log("mapCenterFromLocalStorage:", fmtMapCenter)
|
||||
setMapCenter({
|
||||
lat: Number(fmtMapCenter.lat),
|
||||
lng: Number(fmtMapCenter.lng),
|
||||
})
|
||||
return
|
||||
}
|
||||
// Check if geolocation is supported by the browser
|
||||
if ("geolocation" in navigator) {
|
||||
// Prompt user for permission to access their location
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
// Get the user's latitude and longitude coordinates
|
||||
// Success callback function
|
||||
function(position) {
|
||||
// Update the map with the user's new location
|
||||
setMapCenter({
|
||||
lat: position.coords.latitude,
|
||||
lng: position.coords.longitude,
|
||||
})
|
||||
},
|
||||
// Error callback function
|
||||
function(error) {
|
||||
// Handle errors, e.g. user denied location sharing permissions
|
||||
console.log("Error getting user location:", error);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// Geolocation is not supported by the browser
|
||||
console.log("Geolocation is not supported by this browser, or the user denied access");
|
||||
}
|
||||
},[])
|
||||
|
||||
const mapOptions = useMemo(
|
||||
() => ({
|
||||
disableDefaultUI: false,
|
||||
clickableIcons: true,
|
||||
zoomControl: true,
|
||||
controlSize: 23,
|
||||
styles: mapStyles,
|
||||
mapTypeControlOptions: {
|
||||
mapTypeIds: ['roadmap', 'satellite'],
|
||||
}
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const { isLoaded } = useLoadScript({
|
||||
googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_KEY,
|
||||
libraries: libraries,
|
||||
});
|
||||
|
||||
if (!isLoaded) {
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
|
||||
return ( markers && zoom &&
|
||||
<>
|
||||
<Head>
|
||||
<title>
|
||||
Maps | Oktopus
|
||||
</title>
|
||||
</Head>
|
||||
<GoogleMap
|
||||
options={mapOptions}
|
||||
zoom={zoom}
|
||||
center={mapCenter ? mapCenter : {
|
||||
lat: 0.0,
|
||||
lng: 0.0,
|
||||
}}
|
||||
mapContainerStyle={{ width: '100%', height: '100%' }}
|
||||
onLoad={handleOnLoad}
|
||||
clickableIcons={false}
|
||||
onDragEnd={handleDragEnd}
|
||||
onZoomChanged={handleZoomChange}
|
||||
>
|
||||
{
|
||||
markers.map((marker, index) => (
|
||||
<Marker
|
||||
key={index}
|
||||
position={{ lat: marker.coordinates.lat, lng: marker.coordinates.lng }}
|
||||
icon={{
|
||||
url: marker.img,
|
||||
scaledSize: new window.google.maps.Size(50, 50),
|
||||
anchor: new window.google.maps.Point(25, 25),
|
||||
}}
|
||||
draggable={false}
|
||||
clickable={true}
|
||||
onClick={() => {
|
||||
setActiveMarkerdata(null);
|
||||
if (activeMarker?.sn === marker.sn) {
|
||||
setActiveMarker(null);
|
||||
return;
|
||||
}
|
||||
fetchActiveMarkerData(marker.sn);
|
||||
setActiveMarker({
|
||||
sn: marker.sn,
|
||||
position: { lat: marker.coordinates.lat, lng: marker.coordinates.lng }
|
||||
});
|
||||
}}
|
||||
>
|
||||
</Marker>
|
||||
))
|
||||
}
|
||||
{activeMarker &&
|
||||
<Popup
|
||||
anchorPosition={activeMarker.position}
|
||||
markerPixelOffset={{ x: 0, y: -32 }}
|
||||
content={activeMarkerdata ?
|
||||
<div>
|
||||
<div>SN: {activeMarker.sn}</div>
|
||||
<div>
|
||||
<div>Model: {activeMarkerdata.Model?activeMarkerdata.Model:activeMarkerdata.ProductClass}</div>
|
||||
<div>Alias: {activeMarkerdata.Alias}</div>
|
||||
<div>Status: {activeMarkerdata.Status == 2 ? <span style={{color:"green"}}>online</span> : <span style={{color:"red"}}>offline</span>}</div>
|
||||
</div>
|
||||
</div>
|
||||
: <p>no device info found</p>}
|
||||
/>}
|
||||
</GoogleMap>
|
||||
</>
|
||||
)};
|
||||
|
||||
Page.getLayout = (page) => (
|
||||
<DashboardLayout>
|
||||
{page}
|
||||
</DashboardLayout>
|
||||
);
|
||||
|
||||
export default Page;
|
||||
|
|
@ -19,37 +19,26 @@ import {
|
|||
DialogContentText,
|
||||
DialogActions,
|
||||
Box,
|
||||
IconButton
|
||||
IconButton,
|
||||
Grid
|
||||
} from '@mui/material';
|
||||
import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
|
||||
import PaperAirplane from '@heroicons/react/24/solid/PaperAirplaneIcon';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import Backdrop from '@mui/material/Backdrop';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useBackendContext } from 'src/contexts/backend-context';
|
||||
import DocumentArrowDown from '@heroicons/react/24/outline/DocumentArrowDownIcon';
|
||||
import TrashIcon from '@heroicons/react/24/outline/TrashIcon';
|
||||
import PlusCircleIcon from '@heroicons/react/24/outline/PlusCircleIcon';
|
||||
import EnvelopeIcon from '@heroicons/react/24/outline/EnvelopeIcon';
|
||||
import CheckIcon from '@heroicons/react/24/outline/CheckIcon';
|
||||
|
||||
|
||||
export const DevicesRPC = () => {
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [scroll, setScroll] = useState('paper');
|
||||
const [answer, setAnswer] = useState(false)
|
||||
const [content, setContent] = useState('')
|
||||
const [age, setAge] = useState(2);
|
||||
|
||||
const [value, setValue] = useState(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..\schemas\wt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<soap:Header/>
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<cwmp:GetParameterValues>
|
||||
<ParameterNames>
|
||||
<string>InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.</string>
|
||||
<string>InternetGatewayDevice.LANDevice.1.WLANConfiguration.2.</string>
|
||||
</ParameterNames>
|
||||
</cwmp:GetParameterValues>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`)
|
||||
let { httpRequest } = useBackendContext()
|
||||
|
||||
var prettifyXml = function(sourceXml)
|
||||
{
|
||||
|
|
@ -75,129 +64,219 @@ var prettifyXml = function(sourceXml)
|
|||
return resultXml;
|
||||
};
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [scroll, setScroll] = useState('paper');
|
||||
const [answer, setAnswer] = useState(false)
|
||||
const [content, setContent] = useState('')
|
||||
const [age, setAge] = useState(6);
|
||||
const [newMessage, setNewMessage] = useState(false)
|
||||
const [message, setMessage] = useState(null)
|
||||
const [currentMsg, setCurrentMsg] = useState(0)
|
||||
const [newMsgName, setNewMsgName] = useState("")
|
||||
const [value, setValue] = useState()
|
||||
const [saveChanges, setSaveChanges] = useState(false)
|
||||
const [loadingSaveMsg, setLoadingSaveMsg] = useState(false)
|
||||
const possibleMsgs = [
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..\schemas\wt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<soap:Header/>
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<cwmp:SetParameterValues>
|
||||
<ParameterList soapenc:arrayType="cwmp:ParameterValueStruct[4]">
|
||||
<ParameterValueStruct>
|
||||
<Name>InternetGatewayDevice.TraceRouteDiagnostics.Host</Name>
|
||||
<Value>192.168.60.4</Value>
|
||||
</ParameterValueStruct>
|
||||
</ParameterList>
|
||||
<ParameterKey></ParameterKey>
|
||||
</cwmp:SetParameterValues>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..\schemas\wt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<soap:Header/>
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<cwmp:DeleteObject>
|
||||
<ObjectName>InternetGatewayDevice.LANDevice.1.WLANConfiguration.2.</ObjectName>
|
||||
<ParameterKey></ParameterKey>
|
||||
</cwmp:DeleteObject>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..\schemas\wt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<soap:Header/>
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<cwmp:AddObject>
|
||||
<ObjectName>InternetGatewayDevice.LANDevice.1.WLANConfiguration.</ObjectName>
|
||||
<ParameterKey></ParameterKey>
|
||||
</cwmp:AddObject>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..\schemas\wt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<soap:Header/>
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<cwmp:Reboot>
|
||||
<CommandKey>
|
||||
007
|
||||
</CommandKey>
|
||||
</cwmp:Reboot>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..schemaswt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<soap:Header/>
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<cwmp:GetParameterValues>
|
||||
<ParameterNames>
|
||||
<string>InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.</string>
|
||||
</ParameterNames>
|
||||
</cwmp:GetParameterValues>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`,`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..\schemas\wt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<soap:Header/>
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<cwmp:GetParameterNames>
|
||||
<ParameterPath>InternetGatewayDevice.</ParameterPath>
|
||||
<NextLevel>1</NextLevel>
|
||||
</cwmp:GetParameterNames>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..\schemas\wt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<soap:Header/>
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<cwmp:GetParameterAttributes>
|
||||
<ParameterNames>
|
||||
<string>InternetGatewayDevice.LANDevice.1.WLANConfiguration.</string>
|
||||
</ParameterNames>
|
||||
</cwmp:GetParameterAttributes>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`]
|
||||
const [newMsgValue, setNewMsgValue] = useState(possibleMsgs[age-1])
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleNewMessageValue = (event) => {
|
||||
setNewMsgValue(event.target.value)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
const handleOpen = () => {
|
||||
setOpen(true);
|
||||
var myHeaders = new Headers();
|
||||
myHeaders.append("Authorization", localStorage.getItem("token"));
|
||||
|
||||
var raw = value
|
||||
const handleCancelNewMsgTemplate = () => {
|
||||
setNewMessage(false)
|
||||
setNewMsgName("")
|
||||
setNewMsgValue(possibleMsgs[age-1])
|
||||
// setValue(possibleMsgs[age-1])
|
||||
}
|
||||
|
||||
var requestOptions = {
|
||||
method: 'PUT',
|
||||
headers: myHeaders,
|
||||
body: raw,
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
var method;
|
||||
|
||||
switch(age) {
|
||||
case 1:
|
||||
method="addObject"
|
||||
break;
|
||||
case 2:
|
||||
method="getParameterValues"
|
||||
break;
|
||||
case 3:
|
||||
method="setParameterValues"
|
||||
break;
|
||||
case 4:
|
||||
method="deleteObject"
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
fetch(`${process.env.NEXT_PUBLIC_REST_ENDPOINT || ""}/api/device/cwmp/${router.query.id[0]}/${method}`, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
if (result.status === 401){
|
||||
router.push("/auth/login")
|
||||
const saveMsg = async () => {
|
||||
let {status} = await httpRequest(
|
||||
`/api/device/message?name=`+message[currentMsg].name,
|
||||
"PUT",
|
||||
value,
|
||||
null,
|
||||
)
|
||||
if ( status === 204){
|
||||
setSaveChanges(false)
|
||||
setMessage(message.map((msg, index) => {
|
||||
if (index === currentMsg) {
|
||||
return {...msg, value: value}
|
||||
}else{
|
||||
return msg
|
||||
}
|
||||
setOpen(false)
|
||||
setAnswer(true)
|
||||
let teste = prettifyXml(result)
|
||||
console.log(teste)
|
||||
setContent(teste)
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
};
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
const createNewMsg = async () => {
|
||||
setLoading(true)
|
||||
let {status} = await httpRequest(
|
||||
`/api/device/message/cwmp?name=`+newMsgName,
|
||||
"POST",
|
||||
newMsgValue,
|
||||
null,
|
||||
)
|
||||
if ( status === 204){
|
||||
setNewMessage(false)
|
||||
setNewMsgName("")
|
||||
let result = await fetchMessages()
|
||||
if (result) {
|
||||
setCurrentMsg(result.length-1)
|
||||
}
|
||||
setValue(newMsgValue)
|
||||
setNewMsgValue(possibleMsgs[age-1])
|
||||
}
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const handleChangeMessage = (event) => {
|
||||
setSaveChanges(false)
|
||||
setCurrentMsg(event.target.value)
|
||||
setValue(message[event.target.value].value)
|
||||
}
|
||||
|
||||
const handleDeleteMessage = async () => {
|
||||
let {status} = await httpRequest(
|
||||
`/api/device/message?name=`+message[currentMsg].name.replace(" ", '+'),
|
||||
"DELETE",
|
||||
)
|
||||
if ( status === 204){
|
||||
fetchMessages()
|
||||
setCurrentMsg(0)
|
||||
setValue("")
|
||||
}
|
||||
}
|
||||
|
||||
const handleOpen = async () => {
|
||||
setOpen(true);
|
||||
|
||||
let {result, status} = await httpRequest(
|
||||
`/api/device/cwmp/${router.query.id[0]}/generic`,
|
||||
"PUT",
|
||||
value,
|
||||
null,
|
||||
"text",
|
||||
)
|
||||
if (status === 200){
|
||||
setAnswer(true)
|
||||
console.log("result:",result)
|
||||
let answer = prettifyXml(result)
|
||||
if (answer == "null"){
|
||||
answer = result
|
||||
}
|
||||
console.log(answer)
|
||||
setContent(answer)
|
||||
}
|
||||
setOpen(false)
|
||||
|
||||
}
|
||||
|
||||
const fetchMessages = async () => {
|
||||
let {result, status} = await httpRequest(
|
||||
`/api/device/message?type=cwmp`,
|
||||
"GET",
|
||||
null,
|
||||
null,
|
||||
)
|
||||
if ( status === 200){
|
||||
setMessage(result)
|
||||
setValue(result ? result[0].value : "")
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
const handleChangeRPC = (event) => {
|
||||
setAge(event.target.value);
|
||||
switch(event.target.value) {
|
||||
case 1:
|
||||
setValue(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..\schemas\wt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<soap:Header/>
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<cwmp:AddObject>
|
||||
<ObjectName>InternetGatewayDevice.LANDevice.</ObjectName>
|
||||
<ParameterKey></ParameterKey>
|
||||
</cwmp:AddObject>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`)
|
||||
break;
|
||||
case 2:
|
||||
setValue(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..\schemas\wt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<soap:Header/>
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<cwmp:GetParameterValues>
|
||||
<ParameterNames>
|
||||
<string>InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.</string>
|
||||
<string>InternetGatewayDevice.LANDevice.1.WLANConfiguration.2.</string>
|
||||
<string>InternetGatewayDevice.LANDevice.2.WLANConfiguration.2.</string>
|
||||
<string>InternetGatewayDevice.LANDevice.2.WLANConfiguration.1.</string>
|
||||
</ParameterNames>
|
||||
</cwmp:GetParameterValues>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`)
|
||||
break;
|
||||
case 3:
|
||||
setValue(`
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..\schemas\wt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<soap:Header/>
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<cwmp:SetParameterValues>
|
||||
<ParameterList soapenc:arrayType="cwmp:ParameterValueStruct[3]">
|
||||
<ParameterValueStruct>
|
||||
<Name>InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.Enable</Name>
|
||||
<Value>0</Value>
|
||||
</ParameterValueStruct>
|
||||
<ParameterValueStruct>
|
||||
<Name>InternetGatewayDevice.LANDevice.1.WLANConfiguration.2.SSID</Name>
|
||||
<Value>HUAWEI_TEST-2</Value>
|
||||
</ParameterValueStruct>
|
||||
</ParameterList>
|
||||
<ParameterKey>LC1309123</ParameterKey>
|
||||
</cwmp:SetParameterValues>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`)
|
||||
break;
|
||||
case 4:
|
||||
setValue(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..\schemas\wt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<soap:Header/>
|
||||
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
<cwmp:DeleteObject>
|
||||
<ObjectName>InternetGatewayDevice.LANDevice.3.</ObjectName>
|
||||
<ParameterKey></ParameterKey>
|
||||
</cwmp:DeleteObject>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`)
|
||||
break;
|
||||
default:
|
||||
// code block
|
||||
}
|
||||
setNewMsgValue(possibleMsgs[event.target.value-1])
|
||||
};
|
||||
|
||||
const handleChange = (event) => {
|
||||
setValue(event.target.value);
|
||||
};
|
||||
const handleEditMessage = (event) => {
|
||||
setSaveChanges(true)
|
||||
setValue(event.target.value)
|
||||
}
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
(event) => {
|
||||
|
|
@ -206,54 +285,91 @@ const handleOpen = () => {
|
|||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchMessages();
|
||||
},[]);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Card>
|
||||
<CardActions sx={{ justifyContent: 'flex-end'}}>
|
||||
<FormControl sx={{width:'100px'}}>
|
||||
<Select
|
||||
labelId="demo-simple-select-standard-label"
|
||||
id="demo-simple-select-standard"
|
||||
value={age}
|
||||
label="Action"
|
||||
onChange={(event)=>{handleChangeRPC(event)}}
|
||||
variant='standard'
|
||||
>
|
||||
<MenuItem value={1}>Create</MenuItem>
|
||||
<MenuItem value={2}>Read</MenuItem>
|
||||
<MenuItem value={3}>Update</MenuItem>
|
||||
<MenuItem value={4}>Delete</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</CardActions>
|
||||
<CardHeader sx={{ justifyContent: 'flex-end'}}
|
||||
avatar={<SvgIcon>< EnvelopeIcon/></SvgIcon>}
|
||||
title="Custom Message"
|
||||
action={
|
||||
<Stack direction={"row"} spacing={1} width={"100%"} justifyContent={"flex-end"}>
|
||||
<Button sx={{ backgroundColor: "rgba(48, 109, 111, 0.04)" }}
|
||||
endIcon={<SvgIcon><PlusCircleIcon /></SvgIcon>}
|
||||
onClick={()=>{setNewMessage(true)}}
|
||||
>
|
||||
<Stack direction={"row"} spacing={1}>
|
||||
New Message
|
||||
</Stack>
|
||||
</Button>
|
||||
</Stack>}
|
||||
>
|
||||
</CardHeader>
|
||||
<Divider />
|
||||
<CardContent>
|
||||
<Stack pb={4} spacing={5} direction={"row"}>
|
||||
<FormControl sx={{display:"flex", width: "15%"}} variant="standard" >
|
||||
<InputLabel>Message</InputLabel>
|
||||
<Select
|
||||
value={currentMsg}
|
||||
onChange={(event)=>{handleChangeMessage(event)}}
|
||||
>
|
||||
{message && message.map((msg, index) => {
|
||||
return <MenuItem value={index}>{msg.name}</MenuItem>
|
||||
})}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
<Stack
|
||||
spacing={3}
|
||||
alignItems={'stretch'}
|
||||
>
|
||||
<TextField
|
||||
{!loadingSaveMsg ? <TextField
|
||||
id="outlined-multiline-static"
|
||||
size="large"
|
||||
multiline="true"
|
||||
label="Mensagem"
|
||||
// label="Payload"
|
||||
name="password"
|
||||
onChange={handleChange}
|
||||
onChange={handleEditMessage}
|
||||
value={value}
|
||||
variant="filled"
|
||||
fullWidth
|
||||
rows="15"
|
||||
/>
|
||||
/>:<CircularProgress />}
|
||||
</Stack>
|
||||
</CardContent>
|
||||
<Divider />
|
||||
<CardActions sx={{ justifyContent: 'flex-end' }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
endIcon={<SvgIcon><PaperAirplane /></SvgIcon>}
|
||||
onClick={handleOpen}
|
||||
>
|
||||
Send
|
||||
</Button>
|
||||
{/* <Divider /> */}
|
||||
<CardActions>
|
||||
<Stack direction={"row"} spacing={1} width={"100%"} justifyContent={"flex-start"}>
|
||||
<Button
|
||||
variant="contained"
|
||||
endIcon={<SvgIcon><TrashIcon /></SvgIcon>}
|
||||
onClick={handleDeleteMessage}
|
||||
disabled={!message}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
{!loadingSaveMsg ? <Button
|
||||
variant="contained"
|
||||
endIcon={<SvgIcon><DocumentArrowDown /></SvgIcon>}
|
||||
onClick={saveMsg}
|
||||
disabled={!saveChanges}
|
||||
>
|
||||
Save
|
||||
</Button>: <CircularProgress />}
|
||||
</Stack>
|
||||
<Stack direction={"row"} spacing={1} width={"100%"} justifyContent={"flex-end"}>
|
||||
<Button
|
||||
variant="contained"
|
||||
endIcon={<SvgIcon><PaperAirplane /></SvgIcon>}
|
||||
onClick={handleOpen}
|
||||
>
|
||||
Send
|
||||
</Button>
|
||||
</Stack>
|
||||
</CardActions>
|
||||
<Backdrop
|
||||
sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
||||
|
|
@ -307,6 +423,83 @@ const handleOpen = () => {
|
|||
}}>Ok</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog open={newMessage} maxWidth={"800px"}>
|
||||
<DialogTitle>
|
||||
<SvgIcon><EnvelopeIcon/></SvgIcon>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Stack
|
||||
direction={"row"}
|
||||
container
|
||||
pb={3}
|
||||
// direction="column"
|
||||
// alignItems="center"
|
||||
// justifyContent="center"
|
||||
pt={1}
|
||||
spacing={3}
|
||||
>
|
||||
<TextField
|
||||
variant='standard'
|
||||
fullWidth
|
||||
value={newMsgName}
|
||||
onChange={(event)=>{setNewMsgName(event.target.value)}}
|
||||
label="Name"
|
||||
sx={{maxWidth: "30%", justifyContent:"center"}}
|
||||
/>
|
||||
<FormControl sx={{display:"flex", width: "30%"}} variant="standard" >
|
||||
<InputLabel>Template</InputLabel>
|
||||
<Select
|
||||
value={age}
|
||||
label="Action"
|
||||
name='action'
|
||||
onChange={(event)=>{handleChangeRPC(event)}}
|
||||
>
|
||||
<MenuItem value={1}>SetParameterValues</MenuItem>
|
||||
<MenuItem value={2}>DeleteObject</MenuItem>
|
||||
<MenuItem value={3}>AddObject</MenuItem>
|
||||
<MenuItem value={4}>Reboot</MenuItem>
|
||||
<MenuItem value={5}>GetParameterValues</MenuItem>
|
||||
<MenuItem value={6}>GetParameterNames</MenuItem>
|
||||
<MenuItem value={7}>GetParameterAttributes</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
<Stack
|
||||
spacing={3}
|
||||
alignItems={'stretch'}
|
||||
width={"600px"}
|
||||
>
|
||||
<TextField
|
||||
id="outlined-multiline-static"
|
||||
size="large"
|
||||
multiline="true"
|
||||
label="Payload"
|
||||
name="password"
|
||||
onChange={handleNewMessageValue}
|
||||
value={newMsgValue}
|
||||
// fullWidth
|
||||
// rows="15"
|
||||
/>
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
{/* <Divider/> */}
|
||||
<Stack direction={"row"} spacing={1} width={"100%"} justifyContent={"flex-end"} p={2}>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleCancelNewMsgTemplate}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
{!loading ?
|
||||
<Button
|
||||
variant="contained"
|
||||
endIcon={<SvgIcon><CheckIcon /></SvgIcon>}
|
||||
onClick={createNewMsg}
|
||||
>
|
||||
Save
|
||||
</Button>:<CircularProgress />}
|
||||
</Stack>
|
||||
</Dialog>
|
||||
</Card>
|
||||
</form>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -19,151 +19,296 @@ import {
|
|||
DialogContentText,
|
||||
DialogActions,
|
||||
Box,
|
||||
IconButton
|
||||
IconButton,
|
||||
Grid
|
||||
} from '@mui/material';
|
||||
import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
|
||||
import PaperAirplane from '@heroicons/react/24/solid/PaperAirplaneIcon';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import Backdrop from '@mui/material/Backdrop';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useBackendContext } from 'src/contexts/backend-context';
|
||||
import DocumentArrowDown from '@heroicons/react/24/outline/DocumentArrowDownIcon';
|
||||
import TrashIcon from '@heroicons/react/24/outline/TrashIcon';
|
||||
import PlusCircleIcon from '@heroicons/react/24/outline/PlusCircleIcon';
|
||||
import EnvelopeIcon from '@heroicons/react/24/outline/EnvelopeIcon';
|
||||
import CheckIcon from '@heroicons/react/24/outline/CheckIcon';
|
||||
|
||||
|
||||
export const DevicesRPC = () => {
|
||||
|
||||
const router = useRouter()
|
||||
let { httpRequest } = useBackendContext()
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [scroll, setScroll] = useState('paper');
|
||||
const [answer, setAnswer] = useState(false)
|
||||
const [content, setContent] = useState('')
|
||||
const [age, setAge] = useState(2);
|
||||
const [age, setAge] = useState(6);
|
||||
const [newMessage, setNewMessage] = useState(false)
|
||||
const [message, setMessage] = useState(null)
|
||||
const [currentMsg, setCurrentMsg] = useState(0)
|
||||
const [newMsgName, setNewMsgName] = useState("")
|
||||
const [value, setValue] = useState()
|
||||
const [saveChanges, setSaveChanges] = useState(false)
|
||||
const [loadingSaveMsg, setLoadingSaveMsg] = useState(false)
|
||||
const possibleMsgs = [
|
||||
`{
|
||||
"header": {
|
||||
"msg_id": "b7dc38ea-aefb-4761-aa55-edaa97adb2f0",
|
||||
"msg_type": 4
|
||||
},
|
||||
"body": {
|
||||
"request": {
|
||||
"set": {
|
||||
"allow_partial":true,
|
||||
"update_objs":[
|
||||
{
|
||||
"obj_path":"Device.IP.Interface.1.",
|
||||
"param_settings":[
|
||||
{
|
||||
"param":"Alias",
|
||||
"value":"test",
|
||||
"required":true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
`{
|
||||
"header": {
|
||||
"msg_id": "b7dc38ea-aefb-4761-aa55-edaa97adb2f0",
|
||||
"msg_type": 10
|
||||
},
|
||||
"body": {
|
||||
"request": {
|
||||
"delete": {
|
||||
"allow_partial": true,
|
||||
"obj_paths": [
|
||||
"Device.IP.Interface.[Alias==test]."
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
`
|
||||
{
|
||||
"header": {
|
||||
"msg_id": "b7dc38ea-aefb-4761-aa55-edaa97adb2f0",
|
||||
"msg_type": 8
|
||||
},
|
||||
"body": {
|
||||
"request": {
|
||||
"add": {
|
||||
"allow_partial": true,
|
||||
"create_objs": [
|
||||
{
|
||||
"obj_path": "Device.IP.Interface.",
|
||||
"param_settings": [
|
||||
{
|
||||
"param": "Alias",
|
||||
"value": "test",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
`{
|
||||
"header": {
|
||||
"msg_id": "b7dc38ea-aefb-4761-aa55-edaa97adb2f0",
|
||||
"msg_type": 6
|
||||
},
|
||||
"body": {
|
||||
"request": {
|
||||
"operate": {
|
||||
"command": "Device.Reboot()",
|
||||
"send_resp": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
`{
|
||||
"header": {
|
||||
"msg_id": "b7dc38ea-aefb-4761-aa55-edaa97adb2f0",
|
||||
"msg_type": 1
|
||||
},
|
||||
"body": {
|
||||
"request": {
|
||||
"get": {
|
||||
"paramPaths": [
|
||||
"Device.WiFi.SSID.[Name==wlan0].",
|
||||
"Device.IP.Interface.*.Alias",
|
||||
"Device.DeviceInfo.FirmwareImage.*.Alias",
|
||||
"Device.IP.Interface.1.IPv4Address.1.IPAddress"
|
||||
],
|
||||
"maxDepth": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,`{
|
||||
"header": {
|
||||
"msg_id": "b7dc38ea-aefb-4761-aa55-edaa97adb2f0",
|
||||
"msg_type": 12
|
||||
},
|
||||
"body": {
|
||||
"request": {
|
||||
"get_supported_dm": {
|
||||
"obj_paths" : [
|
||||
"Device."
|
||||
],
|
||||
"first_level_only" : false,
|
||||
"return_commands" : false,
|
||||
"return_events" : false,
|
||||
"return_params" : true
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
`{
|
||||
"header": {
|
||||
"msg_id": "b7dc38ea-aefb-4761-aa55-edaa97adb2f0",
|
||||
"msg_type": 14
|
||||
},
|
||||
"body": {
|
||||
"request": {
|
||||
"get_instances": {
|
||||
"obj_paths" : ["Device.DeviceInfo."],
|
||||
"first_level_only" : false
|
||||
}
|
||||
}
|
||||
}
|
||||
}`]
|
||||
const [newMsgValue, setNewMsgValue] = useState(possibleMsgs[age-1])
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const [value, setValue] = useState(`{
|
||||
"param_paths": [
|
||||
"Device.WiFi.SSID.[Name==wlan0].",
|
||||
"Device.IP.Interface.*.Alias",
|
||||
"Device.DeviceInfo.FirmwareImage.*.Alias",
|
||||
"Device.IP.Interface.1.IPv4Address.1.IPAddress"
|
||||
],
|
||||
"max_depth": 2
|
||||
}`)
|
||||
const handleNewMessageValue = (event) => {
|
||||
setNewMsgValue(event.target.value)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
const handleOpen = () => {
|
||||
setOpen(true);
|
||||
var myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/json");
|
||||
myHeaders.append("Authorization", localStorage.getItem("token"));
|
||||
|
||||
var raw = value
|
||||
const handleCancelNewMsgTemplate = () => {
|
||||
setNewMessage(false)
|
||||
setNewMsgName("")
|
||||
setNewMsgValue(possibleMsgs[age-1])
|
||||
// setValue(possibleMsgs[age-1])
|
||||
}
|
||||
|
||||
var requestOptions = {
|
||||
method: 'PUT',
|
||||
headers: myHeaders,
|
||||
body: raw,
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
var method;
|
||||
|
||||
switch(age) {
|
||||
case 1:
|
||||
method="add"
|
||||
break;
|
||||
case 2:
|
||||
method="get"
|
||||
break;
|
||||
case 3:
|
||||
method="set"
|
||||
break;
|
||||
case 4:
|
||||
method="del"
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
fetch(`${process.env.NEXT_PUBLIC_REST_ENDPOINT || ""}/api/device/${router.query.id[0]}/any/${method}`, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
if (result.status === 401){
|
||||
router.push("/auth/login")
|
||||
const saveMsg = async () => {
|
||||
let {status} = await httpRequest(
|
||||
`/api/device/message?name=`+message[currentMsg].name,
|
||||
"PUT",
|
||||
value,
|
||||
null,
|
||||
)
|
||||
if ( status === 204){
|
||||
setSaveChanges(false)
|
||||
setMessage(message.map((msg, index) => {
|
||||
if (index === currentMsg) {
|
||||
return {...msg, value: value}
|
||||
}else{
|
||||
return msg
|
||||
}
|
||||
setOpen(false)
|
||||
setAnswer(true)
|
||||
let teste = JSON.stringify(JSON.parse(result), null, 2)
|
||||
console.log(teste)
|
||||
setContent(teste)
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
};
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
const createNewMsg = async () => {
|
||||
setLoading(true)
|
||||
let {status} = await httpRequest(
|
||||
`/api/device/message/usp?name=`+newMsgName,
|
||||
"POST",
|
||||
newMsgValue,
|
||||
null,
|
||||
)
|
||||
if ( status === 204){
|
||||
setNewMessage(false)
|
||||
setNewMsgName("")
|
||||
let result = await fetchMessages()
|
||||
if (result) {
|
||||
setCurrentMsg(result.length-1)
|
||||
}
|
||||
setValue(newMsgValue)
|
||||
setNewMsgValue(possibleMsgs[age-1])
|
||||
}
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const handleChangeMessage = (event) => {
|
||||
setSaveChanges(false)
|
||||
setCurrentMsg(event.target.value)
|
||||
setValue(message[event.target.value].value)
|
||||
}
|
||||
|
||||
const handleDeleteMessage = async () => {
|
||||
let {status} = await httpRequest(
|
||||
`/api/device/message?name=`+message[currentMsg].name.replace(" ", '+'),
|
||||
"DELETE",
|
||||
)
|
||||
if ( status === 204){
|
||||
fetchMessages()
|
||||
setCurrentMsg(0)
|
||||
setValue("")
|
||||
}
|
||||
}
|
||||
|
||||
const handleOpen = async () => {
|
||||
setOpen(true);
|
||||
|
||||
let {result, status} = await httpRequest(
|
||||
`/api/device/${router.query.id[0]}/any/generic`,
|
||||
"PUT",
|
||||
value,
|
||||
null,
|
||||
)
|
||||
if (status === 200){
|
||||
setAnswer(true)
|
||||
console.log("result:",result)
|
||||
let answer = JSON.stringify(result, null, 2)
|
||||
if (answer == "null"){
|
||||
answer = result
|
||||
}
|
||||
console.log(answer)
|
||||
setContent(answer)
|
||||
}
|
||||
setOpen(false)
|
||||
|
||||
}
|
||||
|
||||
const fetchMessages = async () => {
|
||||
let {result, status} = await httpRequest(
|
||||
`/api/device/message?type=usp`,
|
||||
"GET",
|
||||
null,
|
||||
null,
|
||||
)
|
||||
if ( status === 200){
|
||||
setMessage(result)
|
||||
setValue(result ? result[0].value : "")
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
const handleChangeRPC = (event) => {
|
||||
setAge(event.target.value);
|
||||
switch(event.target.value) {
|
||||
case 1:
|
||||
setValue(`{
|
||||
"allow_partial": true,
|
||||
"create_objs": [
|
||||
{
|
||||
"obj_path": "Device.IP.Interface.",
|
||||
"param_settings": [
|
||||
{
|
||||
"param": "Alias",
|
||||
"value": "test",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
break;
|
||||
case 2:
|
||||
setValue(`{
|
||||
"param_paths": [
|
||||
"Device.WiFi.SSID.[Name==wlan0].",
|
||||
"Device.IP.Interface.*.Alias",
|
||||
"Device.DeviceInfo.FirmwareImage.*.Alias",
|
||||
"Device.IP.Interface.1.IPv4Address.1.IPAddress"
|
||||
],
|
||||
"max_depth": 2
|
||||
}`)
|
||||
break;
|
||||
case 3:
|
||||
setValue(`
|
||||
{
|
||||
"allow_partial":true,
|
||||
"update_objs":[
|
||||
{
|
||||
"obj_path":"Device.IP.Interface.[Alias==pamonha].",
|
||||
"param_settings":[
|
||||
{
|
||||
"param":"Alias",
|
||||
"value":"goiaba",
|
||||
"required":true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
break;
|
||||
case 4:
|
||||
setValue(`{
|
||||
"allow_partial": true,
|
||||
"obj_paths": [
|
||||
"Device.IP.Interface.3."
|
||||
]
|
||||
}`)
|
||||
break;
|
||||
default:
|
||||
// code block
|
||||
}
|
||||
setNewMsgValue(possibleMsgs[event.target.value-1])
|
||||
};
|
||||
|
||||
const handleChange = (event) => {
|
||||
setValue(event.target.value);
|
||||
};
|
||||
const handleEditMessage = (event) => {
|
||||
if (message) {
|
||||
setSaveChanges(true)
|
||||
}
|
||||
setValue(event.target.value)
|
||||
}
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
(event) => {
|
||||
|
|
@ -172,54 +317,91 @@ const handleOpen = () => {
|
|||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchMessages();
|
||||
},[]);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Card>
|
||||
<CardActions sx={{ justifyContent: 'flex-end'}}>
|
||||
<FormControl sx={{width:'100px'}}>
|
||||
<Select
|
||||
labelId="demo-simple-select-standard-label"
|
||||
id="demo-simple-select-standard"
|
||||
value={age}
|
||||
label="Action"
|
||||
onChange={(event)=>{handleChangeRPC(event)}}
|
||||
variant='standard'
|
||||
>
|
||||
<MenuItem value={1}>Create</MenuItem>
|
||||
<MenuItem value={2}>Read</MenuItem>
|
||||
<MenuItem value={3}>Update</MenuItem>
|
||||
<MenuItem value={4}>Delete</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</CardActions>
|
||||
<CardHeader sx={{ justifyContent: 'flex-end'}}
|
||||
avatar={<SvgIcon>< EnvelopeIcon/></SvgIcon>}
|
||||
title="Custom Message"
|
||||
action={
|
||||
<Stack direction={"row"} spacing={1} width={"100%"} justifyContent={"flex-end"}>
|
||||
<Button sx={{ backgroundColor: "rgba(48, 109, 111, 0.04)" }}
|
||||
endIcon={<SvgIcon><PlusCircleIcon /></SvgIcon>}
|
||||
onClick={()=>{setNewMessage(true)}}
|
||||
>
|
||||
<Stack direction={"row"} spacing={1}>
|
||||
New Message
|
||||
</Stack>
|
||||
</Button>
|
||||
</Stack>}
|
||||
>
|
||||
</CardHeader>
|
||||
<Divider />
|
||||
<CardContent>
|
||||
<Stack pb={4} spacing={5} direction={"row"}>
|
||||
<FormControl sx={{display:"flex", width: "15%"}} variant="standard" >
|
||||
<InputLabel>Message</InputLabel>
|
||||
<Select
|
||||
value={currentMsg}
|
||||
onChange={(event)=>{handleChangeMessage(event)}}
|
||||
>
|
||||
{message && message.map((msg, index) => {
|
||||
return <MenuItem value={index}>{msg.name}</MenuItem>
|
||||
})}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
<Stack
|
||||
spacing={3}
|
||||
alignItems={'stretch'}
|
||||
>
|
||||
<TextField
|
||||
{!loadingSaveMsg ? <TextField
|
||||
id="outlined-multiline-static"
|
||||
size="large"
|
||||
multiline="true"
|
||||
label="Mensagem"
|
||||
// label="Payload"
|
||||
name="password"
|
||||
onChange={handleChange}
|
||||
onChange={handleEditMessage}
|
||||
value={value}
|
||||
variant="filled"
|
||||
fullWidth
|
||||
rows="15"
|
||||
/>
|
||||
/>:<CircularProgress />}
|
||||
</Stack>
|
||||
</CardContent>
|
||||
<Divider />
|
||||
<CardActions sx={{ justifyContent: 'flex-end' }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
endIcon={<SvgIcon><PaperAirplane /></SvgIcon>}
|
||||
onClick={handleOpen}
|
||||
>
|
||||
Send
|
||||
</Button>
|
||||
{/* <Divider /> */}
|
||||
<CardActions>
|
||||
<Stack direction={"row"} spacing={1} width={"100%"} justifyContent={"flex-start"}>
|
||||
<Button
|
||||
variant="contained"
|
||||
endIcon={<SvgIcon><TrashIcon /></SvgIcon>}
|
||||
onClick={handleDeleteMessage}
|
||||
disabled={!message}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
{!loadingSaveMsg ? <Button
|
||||
variant="contained"
|
||||
endIcon={<SvgIcon><DocumentArrowDown /></SvgIcon>}
|
||||
onClick={saveMsg}
|
||||
disabled={!saveChanges}
|
||||
>
|
||||
Save
|
||||
</Button>: <CircularProgress />}
|
||||
</Stack>
|
||||
<Stack direction={"row"} spacing={1} width={"100%"} justifyContent={"flex-end"}>
|
||||
<Button
|
||||
variant="contained"
|
||||
endIcon={<SvgIcon><PaperAirplane /></SvgIcon>}
|
||||
onClick={handleOpen}
|
||||
>
|
||||
Send
|
||||
</Button>
|
||||
</Stack>
|
||||
</CardActions>
|
||||
<Backdrop
|
||||
sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
||||
|
|
@ -273,6 +455,83 @@ const handleOpen = () => {
|
|||
}}>Ok</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog open={newMessage} maxWidth={"800px"}>
|
||||
<DialogTitle>
|
||||
<SvgIcon><EnvelopeIcon/></SvgIcon>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Stack
|
||||
direction={"row"}
|
||||
container
|
||||
pb={3}
|
||||
// direction="column"
|
||||
// alignItems="center"
|
||||
// justifyContent="center"
|
||||
pt={1}
|
||||
spacing={3}
|
||||
>
|
||||
<TextField
|
||||
variant='standard'
|
||||
fullWidth
|
||||
value={newMsgName}
|
||||
onChange={(event)=>{setNewMsgName(event.target.value)}}
|
||||
label="Name"
|
||||
sx={{maxWidth: "30%", justifyContent:"center"}}
|
||||
/>
|
||||
<FormControl sx={{display:"flex", width: "30%"}} variant="standard" >
|
||||
<InputLabel>Template</InputLabel>
|
||||
<Select
|
||||
value={age}
|
||||
label="Action"
|
||||
name='action'
|
||||
onChange={(event)=>{handleChangeRPC(event)}}
|
||||
>
|
||||
<MenuItem value={1}>Set</MenuItem>
|
||||
<MenuItem value={2}>Delete</MenuItem>
|
||||
<MenuItem value={3}>Add</MenuItem>
|
||||
<MenuItem value={4}>Operate</MenuItem>
|
||||
<MenuItem value={5}>Get</MenuItem>
|
||||
<MenuItem value={6}>Get Supported DM</MenuItem>
|
||||
<MenuItem value={7}>Get Instances</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
<Stack
|
||||
spacing={3}
|
||||
alignItems={'stretch'}
|
||||
width={"600px"}
|
||||
>
|
||||
<TextField
|
||||
id="outlined-multiline-static"
|
||||
size="large"
|
||||
multiline="true"
|
||||
label="Payload"
|
||||
name="password"
|
||||
onChange={handleNewMessageValue}
|
||||
value={newMsgValue}
|
||||
// fullWidth
|
||||
// rows="15"
|
||||
/>
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
{/* <Divider/> */}
|
||||
<Stack direction={"row"} spacing={1} width={"100%"} justifyContent={"flex-end"} p={2}>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleCancelNewMsgTemplate}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
{!loading ?
|
||||
<Button
|
||||
variant="contained"
|
||||
endIcon={<SvgIcon><CheckIcon /></SvgIcon>}
|
||||
onClick={createNewMsg}
|
||||
>
|
||||
Save
|
||||
</Button>:<CircularProgress />}
|
||||
</Stack>
|
||||
</Dialog>
|
||||
</Card>
|
||||
</form>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -9,8 +9,14 @@ import {
|
|||
Stack,
|
||||
TextField
|
||||
} from '@mui/material';
|
||||
import { useBackendContext } from 'src/contexts/backend-context';
|
||||
import { useAlertContext } from 'src/contexts/error-context';
|
||||
|
||||
export const SettingsPassword = () => {
|
||||
|
||||
let {httpRequest} = useBackendContext();
|
||||
let {setAlert} = useAlertContext();
|
||||
|
||||
const [values, setValues] = useState({
|
||||
password: '',
|
||||
confirm: ''
|
||||
|
|
@ -26,15 +32,8 @@ export const SettingsPassword = () => {
|
|||
[]
|
||||
);
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<form>
|
||||
<Card>
|
||||
<CardHeader
|
||||
subheader="Update password"
|
||||
|
|
@ -66,7 +65,26 @@ export const SettingsPassword = () => {
|
|||
</CardContent>
|
||||
<Divider />
|
||||
<CardActions sx={{ justifyContent: 'flex-end' }}>
|
||||
<Button variant="contained">
|
||||
<Button variant="contained"
|
||||
onClick={async ()=>{
|
||||
if (values.password !== values.confirm) {
|
||||
console.log("Passwords do not match")
|
||||
setAlert({
|
||||
severity: 'error',
|
||||
message: 'Passwords do not match'
|
||||
});
|
||||
return
|
||||
}
|
||||
let {status} = await httpRequest('/api/auth/password', 'PUT', JSON.stringify({"password": values.password}))
|
||||
if (status === 204) {
|
||||
console.log("Password updated")
|
||||
setAlert({
|
||||
severity: 'success',
|
||||
message: 'Password updated'
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
Update
|
||||
</Button>
|
||||
</CardActions>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user