Merge pull request #342 from OktopUSP/dev

USP/CWMP Messages Templates
This commit is contained in:
Leandro Antônio Farias Machado 2024-10-30 14:46:56 -03:00 committed by GitHub
commit e4704d806e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 1420 additions and 659 deletions

View File

@ -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)

View File

@ -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")

View File

@ -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) {

View File

@ -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)
}
}

View File

@ -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) {

View File

@ -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)

View File

@ -12,6 +12,7 @@ import (
type Database struct {
client *mongo.Client
users *mongo.Collection
template *mongo.Collection
ctx context.Context
}
@ -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

View 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
}

View File

@ -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) {

View File

@ -211,6 +211,8 @@ export const AuthProvider = (props) => {
};
const signOut = () => {
router.push("/auth/login")
localStorage.removeItem("token")
dispatch({
type: HANDLERS.SIGN_OUT
});

View 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);

View 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);

View File

@ -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,18 +50,18 @@ export const items = [
</SvgIcon>
),
disabled: true
}
]
},
{
title: 'Map',
title: 'Message',
tooltip: 'Upgrade to Business Plan',
disabled: true,
icon: (
<SvgIcon fontSize="small">
<MapIcon color='gray'/>
<EnvelopeIcon color='gray'/>
</SvgIcon>
),
disabled: true
)
},
]
},
{
title: '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>
)
},

View File

@ -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>}
</>
);
});

View File

@ -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,

View File

@ -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,6 +43,9 @@ const App = (props) => {
</Head>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<AuthProvider>
{/* <WsProvider> */}
<AlertProvider>
<BackendProvider>
<ThemeProvider theme={theme}>
<CssBaseline />
<AuthConsumer>
@ -52,6 +56,9 @@ const App = (props) => {
}
</AuthConsumer>
</ThemeProvider>
</BackendProvider>
</AlertProvider>
{/* </WsProvider> */}
</AuthProvider>
</LocalizationProvider>
</CacheProvider>

View File

@ -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>}

View File

@ -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()
}

View File

@ -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()
}

View File

@ -129,7 +129,7 @@ const Page = () => {
<>
<Head>
<title>
Oktopus | TR-369
Oktopus | Controller
</title>
</Head>
<Box

View File

@ -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;

View File

@ -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,130 +64,220 @@ var prettifyXml = function(sourceXml)
return resultXml;
};
const handleClose = () => {
setOpen(false);
};
const handleOpen = () => {
setOpen(true);
var myHeaders = new Headers();
myHeaders.append("Authorization", localStorage.getItem("token"));
var raw = value
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")
}
setOpen(false)
setAnswer(true)
let teste = prettifyXml(result)
console.log(teste)
setContent(teste)
})
.catch(error => console.log('error', error));
};
const handleChangeRPC = (event) => {
setAge(event.target.value);
switch(event.target.value) {
case 1:
setValue(`<?xml version="1.0" encoding="UTF-8"?>
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.</ObjectName>
<ObjectName>InternetGatewayDevice.LANDevice.1.WLANConfiguration.</ObjectName>
<ParameterKey></ParameterKey>
</cwmp:AddObject>
</soap:Body>
</soap:Envelope>`)
break;
case 2:
setValue(`<?xml version="1.0" encoding="UTF-8"?>
</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>
<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>`,`<?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>
<cwmp:GetParameterNames>
<ParameterPath>InternetGatewayDevice.</ParameterPath>
<NextLevel>1</NextLevel>
</cwmp:GetParameterNames>
</soap:Body>
</soap:Envelope>`)
break;
case 4:
setValue(`<?xml version="1.0" encoding="UTF-8"?>
</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.3.</ObjectName>
<ParameterKey></ParameterKey>
</cwmp:DeleteObject>
<cwmp:GetParameterAttributes>
<ParameterNames>
<string>InternetGatewayDevice.LANDevice.1.WLANConfiguration.</string>
</ParameterNames>
</cwmp:GetParameterAttributes>
</soap:Body>
</soap:Envelope>`)
break;
default:
// code block
</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 handleChange = (event) => {
setValue(event.target.value);
const handleCancelNewMsgTemplate = () => {
setNewMessage(false)
setNewMsgName("")
setNewMsgValue(possibleMsgs[age-1])
// setValue(possibleMsgs[age-1])
}
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
}
}))
}
}
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);
setNewMsgValue(possibleMsgs[event.target.value-1])
};
const handleEditMessage = (event) => {
setSaveChanges(true)
setValue(event.target.value)
}
const handleSubmit = useCallback(
(event) => {
event.preventDefault();
@ -206,47 +285,83 @@ 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'
<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)}}
>
<MenuItem value={1}>Create</MenuItem>
<MenuItem value={2}>Read</MenuItem>
<MenuItem value={3}>Update</MenuItem>
<MenuItem value={4}>Delete</MenuItem>
</Select>
</FormControl>
</CardActions>
<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' }}>
{/* <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>}
@ -254,6 +369,7 @@ const 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>
);

View File

@ -19,91 +19,90 @@ 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 [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 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
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;
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
}
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")
]
}
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 handleChangeRPC = (event) => {
setAge(event.target.value);
switch(event.target.value) {
case 1:
setValue(`{
]
}
}
}
}`,
`{
"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": [
{
@ -117,54 +116,200 @@ const handleOpen = () => {
]
}
]
}`)
break;
case 2:
setValue(`{
"param_paths": [
}
}
}
}`,
`{
"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"
],
"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
"maxDepth": 2
}
]
}
]
}`)
break;
case 4:
setValue(`{
"allow_partial": true,
}
}`,`{
"header": {
"msg_id": "b7dc38ea-aefb-4761-aa55-edaa97adb2f0",
"msg_type": 12
},
"body": {
"request": {
"get_supported_dm": {
"obj_paths" : [
"Device.IP.Interface.3."
]
}`)
break;
default:
// code block
"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 handleNewMessageValue = (event) => {
setNewMsgValue(event.target.value)
}
const handleClose = () => {
setOpen(false);
};
const handleChange = (event) => {
setValue(event.target.value);
const handleCancelNewMsgTemplate = () => {
setNewMessage(false)
setNewMsgName("")
setNewMsgValue(possibleMsgs[age-1])
// setValue(possibleMsgs[age-1])
}
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
}
}))
}
}
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);
setNewMsgValue(possibleMsgs[event.target.value-1])
};
const handleEditMessage = (event) => {
if (message) {
setSaveChanges(true)
}
setValue(event.target.value)
}
const handleSubmit = useCallback(
(event) => {
event.preventDefault();
@ -172,47 +317,83 @@ 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'
<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)}}
>
<MenuItem value={1}>Create</MenuItem>
<MenuItem value={2}>Read</MenuItem>
<MenuItem value={3}>Update</MenuItem>
<MenuItem value={4}>Delete</MenuItem>
</Select>
</FormControl>
</CardActions>
<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' }}>
{/* <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>}
@ -220,6 +401,7 @@ const 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>
);

View File

@ -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>