commit
06485cecff
|
|
@ -56,7 +56,7 @@ func (a *Api) StartApi() {
|
||||||
authentication.HandleFunc("/admin/register", a.registerAdminUser).Methods("POST")
|
authentication.HandleFunc("/admin/register", a.registerAdminUser).Methods("POST")
|
||||||
authentication.HandleFunc("/admin/exists", a.adminUserExists).Methods("GET")
|
authentication.HandleFunc("/admin/exists", a.adminUserExists).Methods("GET")
|
||||||
iot := r.PathPrefix("/api/device").Subrouter()
|
iot := r.PathPrefix("/api/device").Subrouter()
|
||||||
iot.HandleFunc("/auth", a.deviceAuth).Methods("GET", "PUT", "DELETE")
|
iot.HandleFunc("/auth", a.deviceAuth).Methods("GET", "POST", "DELETE")
|
||||||
iot.HandleFunc("/cwmp/{sn}/getParameterNames", a.cwmpGetParameterNamesMsg).Methods("GET", "PUT", "DELETE")
|
iot.HandleFunc("/cwmp/{sn}/getParameterNames", a.cwmpGetParameterNamesMsg).Methods("GET", "PUT", "DELETE")
|
||||||
iot.HandleFunc("", a.retrieveDevices).Methods("GET")
|
iot.HandleFunc("", a.retrieveDevices).Methods("GET")
|
||||||
iot.HandleFunc("/{id}", a.retrieveDevices).Methods("GET")
|
iot.HandleFunc("/{id}", a.retrieveDevices).Methods("GET")
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ func (a *Api) deviceAuth(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
utils.MarshallEncoder("No id provided", w)
|
utils.MarshallEncoder("No id provided", w)
|
||||||
|
|
||||||
} else if r.Method == http.MethodPut {
|
} else if r.Method == http.MethodPost {
|
||||||
|
|
||||||
var deviceAuth DeviceAuth
|
var deviceAuth DeviceAuth
|
||||||
|
|
||||||
|
|
@ -200,12 +200,26 @@ func (a *Api) deviceAuth(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if deviceAuth.User != "" {
|
if deviceAuth.User != "" {
|
||||||
_, err := a.kv.PutString(r.Context(), deviceAuth.User, deviceAuth.Password)
|
_, err := a.kv.Get(r.Context(), deviceAuth.User)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
|
if err == jetstream.ErrKeyNotFound {
|
||||||
|
_, err = a.kv.PutString(r.Context(), deviceAuth.User, deviceAuth.Password)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
utils.MarshallEncoder(err, w)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
utils.MarshallEncoder(err, w)
|
utils.MarshallEncoder(err, w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusConflict)
|
||||||
|
utils.MarshallEncoder("Username already exists", w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,15 +44,15 @@ export const items = [
|
||||||
// </SvgIcon>
|
// </SvgIcon>
|
||||||
// )
|
// )
|
||||||
// },
|
// },
|
||||||
// {
|
{
|
||||||
// title: 'Credentials',
|
title: 'Credentials',
|
||||||
// path: '/credentials',
|
path: '/credentials',
|
||||||
// icon: (
|
icon: (
|
||||||
// <SvgIcon fontSize="small">
|
<SvgIcon fontSize="small">
|
||||||
// <KeyIcon/>
|
<KeyIcon/>
|
||||||
// </SvgIcon>
|
</SvgIcon>
|
||||||
// )
|
)
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
title: 'Users',
|
title: 'Users',
|
||||||
path: '/users',
|
path: '/users',
|
||||||
|
|
|
||||||
385
frontend/src/pages/credentials.js
Normal file
385
frontend/src/pages/credentials.js
Normal file
|
|
@ -0,0 +1,385 @@
|
||||||
|
import { useCallback, useState, useEffect } from 'react';
|
||||||
|
import Head from 'next/head';
|
||||||
|
import MagnifyingGlassIcon from '@heroicons/react/24/solid/MagnifyingGlassIcon';
|
||||||
|
import PlusIcon from '@heroicons/react/24/solid/PlusIcon';
|
||||||
|
import { Box, Button, Container, Stack, SvgIcon, Tooltip, Typography, IconButton,
|
||||||
|
DialogActions,
|
||||||
|
Dialog,
|
||||||
|
DialogTitle,
|
||||||
|
DialogContent,
|
||||||
|
TextField,
|
||||||
|
InputAdornment,
|
||||||
|
Input, Backdrop, CircularProgress,
|
||||||
|
InputLabel, FormControl,
|
||||||
|
OutlinedInput,
|
||||||
|
Card } from '@mui/material';
|
||||||
|
import EyeIcon from '@heroicons/react/24/outline/EyeIcon';
|
||||||
|
import EyeSlashIcon from '@heroicons/react/24/outline/EyeSlashIcon';
|
||||||
|
import { Layout as DashboardLayout } from 'src/layouts/dashboard/layout';
|
||||||
|
import { CredentialsTable } from 'src/sections/credentials/credentials-table';
|
||||||
|
import InformactionCircleIcon from '@heroicons/react/24/outline/InformationCircleIcon';
|
||||||
|
import { useAuth } from 'src/hooks/use-auth';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
|
const Page = () => {
|
||||||
|
const auth = useAuth();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const [page, setPage] = useState(0);
|
||||||
|
const [devices, setDevices] = useState({});
|
||||||
|
const [addDeviceDialogOpen, setAddDeviceDialogOpen] = useState(false);
|
||||||
|
const [newDeviceData, setNewDeviceData] = useState({});
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
const [isUsernameEmpty, setIsUsernameEmpty] = useState(false);
|
||||||
|
const [isUsernameExistent, setIsUsernameExistent] = useState(false);
|
||||||
|
const [creatingNewCredential, setCreatingNewCredential] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [credentialNotFound, setCredentialNotFound] = useState(false);
|
||||||
|
|
||||||
|
const deleteCredential = (id) => {
|
||||||
|
console.log("request to delete credentials: ", id)
|
||||||
|
|
||||||
|
var myHeaders = new Headers();
|
||||||
|
myHeaders.append("Content-Type", "application/json");
|
||||||
|
myHeaders.append("Authorization", auth.user.token);
|
||||||
|
|
||||||
|
var requestOptions = {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: myHeaders,
|
||||||
|
redirect: 'follow'
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(process.env.NEXT_PUBLIC_REST_ENDPOINT + '/device/auth?id='+id, requestOptions)
|
||||||
|
.then(response => {
|
||||||
|
if (response.status === 401) {
|
||||||
|
router.push("/auth/login")
|
||||||
|
} else if (response.status === 403) {
|
||||||
|
return router.push("/403")
|
||||||
|
}
|
||||||
|
let copiedDevices = {...devices}
|
||||||
|
delete copiedDevices[id];
|
||||||
|
setDevices(device => ({
|
||||||
|
...copiedDevices
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
return console.error('Error:', error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const createCredential = async (data) => {
|
||||||
|
var myHeaders = new Headers();
|
||||||
|
myHeaders.append("Content-Type", "application/json");
|
||||||
|
myHeaders.append("Authorization", auth.user.token);
|
||||||
|
|
||||||
|
var raw = JSON.stringify(data);
|
||||||
|
|
||||||
|
var requestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: myHeaders,
|
||||||
|
body: raw,
|
||||||
|
redirect: 'follow'
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = await fetch(process.env.NEXT_PUBLIC_REST_ENDPOINT+"/device/auth", requestOptions)
|
||||||
|
|
||||||
|
if (result.status == 200) {
|
||||||
|
console.log("user created: deu boa raça !!")
|
||||||
|
}else if (result.status == 403) {
|
||||||
|
console.log("num tenx permissão, seu boca de sandália")
|
||||||
|
setCreatingNewCredential(false)
|
||||||
|
return router.push("/403")
|
||||||
|
}else if (result.status == 401){
|
||||||
|
console.log("taix nem autenticado, sai fora oh")
|
||||||
|
setCreatingNewCredential(false)
|
||||||
|
return router.push("/auth/login")
|
||||||
|
}else if (result.status == 409){
|
||||||
|
console.log("usuário já existe, seu boca de bagre")
|
||||||
|
setIsUsernameExistent(true)
|
||||||
|
setCreatingNewCredential(false)
|
||||||
|
return
|
||||||
|
}else if (result.status == 400){
|
||||||
|
console.log("faltou mandar dados jow")
|
||||||
|
setAddDeviceDialogOpen(false)
|
||||||
|
setNewDeviceData({})
|
||||||
|
setIsUsernameEmpty(false)
|
||||||
|
setIsUsernameExistent(false)
|
||||||
|
setCreatingNewCredential(false)
|
||||||
|
return
|
||||||
|
}else {
|
||||||
|
console.log("agora quebrasse ux córno mô quiridu")
|
||||||
|
const content = await result.json()
|
||||||
|
setCreatingNewCredential(false)
|
||||||
|
throw new Error(content);
|
||||||
|
}
|
||||||
|
setAddDeviceDialogOpen(false)
|
||||||
|
let newData = {}
|
||||||
|
newData[data.id] = data.password
|
||||||
|
setDevices(prevState =>({...prevState, ...newData}))
|
||||||
|
setNewDeviceData({})
|
||||||
|
setIsUsernameEmpty(false)
|
||||||
|
setIsUsernameExistent(false)
|
||||||
|
setCreatingNewCredential(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchCredentials = async (id) => {
|
||||||
|
console.log("fetching credentials data...")
|
||||||
|
var myHeaders = new Headers();
|
||||||
|
myHeaders.append("Content-Type", "application/json");
|
||||||
|
myHeaders.append("Authorization", auth.user.token);
|
||||||
|
|
||||||
|
var requestOptions = {
|
||||||
|
method: 'GET',
|
||||||
|
headers: myHeaders,
|
||||||
|
redirect: 'follow'
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = process.env.NEXT_PUBLIC_REST_ENDPOINT + '/device/auth'
|
||||||
|
if (id !== undefined && id !== "") {
|
||||||
|
url += "?id="+id
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(url, requestOptions)
|
||||||
|
.then(response => {
|
||||||
|
if (response.status === 401) {
|
||||||
|
router.push("/auth/login")
|
||||||
|
} else if (response.status === 403) {
|
||||||
|
return router.push("/403")
|
||||||
|
}else if (response.status === 404) {
|
||||||
|
setLoading(false)
|
||||||
|
setCredentialNotFound(true)
|
||||||
|
console.log("credential not found: ", credentialNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return response.json()
|
||||||
|
})
|
||||||
|
.then(json => {
|
||||||
|
if (json === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log("devices credentials: ", json)
|
||||||
|
setDevices(json)
|
||||||
|
setLoading(false)
|
||||||
|
setCredentialNotFound(false)
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
setLoading(false)
|
||||||
|
setCredentialNotFound(false)
|
||||||
|
return console.error('Error:', error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchCredentials()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<title>
|
||||||
|
Devices Credentials | Oktopus
|
||||||
|
</title>
|
||||||
|
</Head>
|
||||||
|
<Box
|
||||||
|
component="main"
|
||||||
|
sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
py: 8
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Container maxWidth="xl">
|
||||||
|
<Stack spacing={3}>
|
||||||
|
<Stack
|
||||||
|
direction="row"
|
||||||
|
justifyContent="space-between"
|
||||||
|
spacing={4}
|
||||||
|
>
|
||||||
|
<Stack spacing={1} direction="row" alignItems={'center'}>
|
||||||
|
<Typography variant="h4">
|
||||||
|
Devices Credentials
|
||||||
|
</Typography>
|
||||||
|
<Tooltip title="Defines username and password for devices authentication, this must be enabled through environment vars." placement="top">
|
||||||
|
<IconButton>
|
||||||
|
<SvgIcon>
|
||||||
|
<InformactionCircleIcon />
|
||||||
|
</SvgIcon>
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Stack>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
startIcon={(
|
||||||
|
<SvgIcon fontSize="small">
|
||||||
|
<PlusIcon />
|
||||||
|
</SvgIcon>
|
||||||
|
)}
|
||||||
|
onClick={() => setAddDeviceDialogOpen(true)}
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Add
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
|
<Card sx={{ p: 2 }}>
|
||||||
|
<OutlinedInput
|
||||||
|
defaultValue=""
|
||||||
|
fullWidth
|
||||||
|
placeholder="Search customer"
|
||||||
|
onKeyDownCapture={(e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
console.log("Fetch credentials per username: ", e.target.value)
|
||||||
|
fetchCredentials(e.target.value)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
startAdornment={(
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<SvgIcon
|
||||||
|
color="action"
|
||||||
|
fontSize="small"
|
||||||
|
>
|
||||||
|
<MagnifyingGlassIcon />
|
||||||
|
</SvgIcon>
|
||||||
|
</InputAdornment>
|
||||||
|
)}
|
||||||
|
sx={{ maxWidth: 500 }}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
{!loading ? (credentialNotFound ?
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p>Credential Not Found</p>
|
||||||
|
</Box>:
|
||||||
|
<CredentialsTable
|
||||||
|
items={devices}
|
||||||
|
deleteCredential={deleteCredential}
|
||||||
|
// onPageChange={handlePageChange}
|
||||||
|
page={page}
|
||||||
|
/>):
|
||||||
|
<CircularProgress/>
|
||||||
|
}
|
||||||
|
</Stack>
|
||||||
|
</Container>
|
||||||
|
</Box>
|
||||||
|
<Dialog
|
||||||
|
open={addDeviceDialogOpen}
|
||||||
|
onClose={() => {
|
||||||
|
setAddDeviceDialogOpen(false)
|
||||||
|
setIsUsernameEmpty(false)
|
||||||
|
setIsUsernameExistent(false)
|
||||||
|
setNewDeviceData({})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogTitle>Create New Credentials</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<Stack
|
||||||
|
alignItems="center"
|
||||||
|
direction="row"
|
||||||
|
spacing={2}
|
||||||
|
>
|
||||||
|
<FormControl sx={{ m: 1, width: '25ch' }} variant="standard">
|
||||||
|
<TextField
|
||||||
|
inputProps={{
|
||||||
|
form: {
|
||||||
|
autocomplete: 'new-password',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
// focused={isUsernameEmpty}
|
||||||
|
// color={isUsernameEmpty ? "error" : "primary"}
|
||||||
|
error={isUsernameEmpty || isUsernameExistent}
|
||||||
|
helperText={isUsernameEmpty ? "Username invalid": (isUsernameExistent ? "Username already exists" : "")}
|
||||||
|
autoFocus
|
||||||
|
required
|
||||||
|
margin="dense"
|
||||||
|
id="username"
|
||||||
|
name="username"
|
||||||
|
label="Username"
|
||||||
|
type="username"
|
||||||
|
fullWidth
|
||||||
|
onChange={
|
||||||
|
(event) => {
|
||||||
|
setNewDeviceData({...newDeviceData, id: event.target.value})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
variant="standard">
|
||||||
|
</TextField>
|
||||||
|
</FormControl>
|
||||||
|
<FormControl sx={{ m: 1, width: '25ch' }} variant="standard">
|
||||||
|
<InputLabel htmlFor="standard-adornment-password">Password</InputLabel>
|
||||||
|
<Input
|
||||||
|
id="standard-adornment-password"
|
||||||
|
type={showPassword ? 'text' : 'password'}
|
||||||
|
label="Password"
|
||||||
|
endAdornment={
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton
|
||||||
|
aria-label="toggle password visibility"
|
||||||
|
onClick={()=>{
|
||||||
|
setShowPassword(!showPassword)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SvgIcon>
|
||||||
|
{showPassword ? <EyeSlashIcon /> : <EyeIcon />}
|
||||||
|
</SvgIcon>
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
}
|
||||||
|
onChange={
|
||||||
|
(event) => {
|
||||||
|
setNewDeviceData({...newDeviceData, password: event.target.value})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</Stack>
|
||||||
|
<Stack
|
||||||
|
alignItems="center"
|
||||||
|
direction="row"
|
||||||
|
spacing={2}
|
||||||
|
>
|
||||||
|
</Stack>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={
|
||||||
|
() => {
|
||||||
|
setAddDeviceDialogOpen(false)
|
||||||
|
setIsUsernameEmpty(false)
|
||||||
|
setIsUsernameExistent(false)
|
||||||
|
setNewDeviceData({})
|
||||||
|
}
|
||||||
|
}>Cancel</Button>
|
||||||
|
<Button onClick={()=>{
|
||||||
|
console.log("new user data: ", newDeviceData)
|
||||||
|
if (newDeviceData.id === undefined || newDeviceData.id === "") {
|
||||||
|
setIsUsernameEmpty(true)
|
||||||
|
return
|
||||||
|
}else{
|
||||||
|
setIsUsernameEmpty(false)
|
||||||
|
}
|
||||||
|
setCreatingNewCredential(true)
|
||||||
|
createCredential(newDeviceData)
|
||||||
|
}}>Confirm</Button>
|
||||||
|
</DialogActions>
|
||||||
|
{
|
||||||
|
<Backdrop
|
||||||
|
sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
||||||
|
open={creatingNewCredential}
|
||||||
|
>
|
||||||
|
<CircularProgress color="inherit" />
|
||||||
|
</Backdrop>
|
||||||
|
}
|
||||||
|
</Dialog>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Page.getLayout = (page) => (
|
||||||
|
<DashboardLayout>
|
||||||
|
{page}
|
||||||
|
</DashboardLayout>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Page;
|
||||||
192
frontend/src/sections/credentials/credentials-table.js
Normal file
192
frontend/src/sections/credentials/credentials-table.js
Normal file
|
|
@ -0,0 +1,192 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {
|
||||||
|
Avatar,
|
||||||
|
Box,
|
||||||
|
Card,
|
||||||
|
Checkbox,
|
||||||
|
Icon,
|
||||||
|
Stack,
|
||||||
|
Tab,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
//TablePagination,
|
||||||
|
TableRow,
|
||||||
|
Typography,
|
||||||
|
SvgIcon,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogTitle,
|
||||||
|
DialogContent,
|
||||||
|
DialogContentText,
|
||||||
|
Button,
|
||||||
|
TablePagination,
|
||||||
|
TextField,
|
||||||
|
InputAdornment,
|
||||||
|
IconButton,
|
||||||
|
Input
|
||||||
|
} from '@mui/material';
|
||||||
|
import EyeIcon from '@heroicons/react/24/outline/EyeIcon';
|
||||||
|
import EyeSlashIcon from '@heroicons/react/24/outline/EyeSlashIcon';
|
||||||
|
import { Scrollbar } from 'src/components/scrollbar';
|
||||||
|
import PencilIcon from '@heroicons/react/24/outline/PencilIcon';
|
||||||
|
import TrashIcon from '@heroicons/react/24/outline/TrashIcon';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export const CredentialsTable = (props) => {
|
||||||
|
const {
|
||||||
|
count = 0,
|
||||||
|
items = {},
|
||||||
|
onDeselectAll,
|
||||||
|
onDeselectOne,
|
||||||
|
onPageChange = () => {},
|
||||||
|
onRowsPerPageChange,
|
||||||
|
onSelectAll,
|
||||||
|
onSelectOne,
|
||||||
|
deleteCredential,
|
||||||
|
page = 0,
|
||||||
|
rowsPerPage = 0,
|
||||||
|
// selected = []
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const [showPassword, setShowPassword] = useState({})
|
||||||
|
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
||||||
|
const [credentialToDelete, setCredentialToDelete] = useState("")
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
Object.keys(items).map((key) => {
|
||||||
|
let newData = {};
|
||||||
|
newData[key] = false
|
||||||
|
setShowPassword(prevState => ({
|
||||||
|
...prevState,
|
||||||
|
...newData
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
console.log("showPassword: "+ showPassword)
|
||||||
|
},[])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<Scrollbar>
|
||||||
|
<Box sx={{ minWidth: 800 }}>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell align='center'>
|
||||||
|
Username
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align='center'>
|
||||||
|
Password
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align='center'>
|
||||||
|
Actions
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{Object.keys(items).map((key) => {
|
||||||
|
let value = items[key];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow
|
||||||
|
hover
|
||||||
|
key={key}
|
||||||
|
>
|
||||||
|
<TableCell align='center'>
|
||||||
|
{key}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align='center'>
|
||||||
|
<Input
|
||||||
|
id="standard-adornment-password"
|
||||||
|
type={showPassword[key] ? 'text' : 'password'}
|
||||||
|
endAdornment={
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton
|
||||||
|
aria-label="toggle password visibility"
|
||||||
|
onClick={()=>{
|
||||||
|
let newData = {};
|
||||||
|
newData[key] = !showPassword[key]
|
||||||
|
setShowPassword(previous => ({...previous, ...newData}))
|
||||||
|
}}
|
||||||
|
//onMouseDown={handleMouseDownPassword}
|
||||||
|
>
|
||||||
|
<SvgIcon>
|
||||||
|
{showPassword[key] ? <EyeSlashIcon /> : <EyeIcon />}
|
||||||
|
</SvgIcon>
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
}
|
||||||
|
value={value}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align='center'>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
console.log("delete user: ", key)
|
||||||
|
setCredentialToDelete(key);
|
||||||
|
setShowDeleteDialog(true);
|
||||||
|
}}
|
||||||
|
><SvgIcon
|
||||||
|
color="action"
|
||||||
|
fontSize="small"
|
||||||
|
sx={{ cursor: 'pointer'}}
|
||||||
|
>
|
||||||
|
<TrashIcon
|
||||||
|
></TrashIcon>
|
||||||
|
</SvgIcon></Button>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</Box>
|
||||||
|
</Scrollbar>
|
||||||
|
<Dialog
|
||||||
|
open={showDeleteDialog}
|
||||||
|
onClose={() => setShowDeleteDialog(false)}
|
||||||
|
aria-labelledby="alert-dialog-title"
|
||||||
|
aria-describedby="alert-dialog-description"
|
||||||
|
>
|
||||||
|
<DialogTitle id="alert-dialog-title">{"Delete User"}</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogContentText id="alert-dialog-description">
|
||||||
|
Are you sure you want to delete this credential?
|
||||||
|
</DialogContentText>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={() => {
|
||||||
|
setShowDeleteDialog(false)
|
||||||
|
setCredentialToDelete("")
|
||||||
|
}} color="primary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button onClick={() => {
|
||||||
|
deleteCredential(credentialToDelete);
|
||||||
|
setShowDeleteDialog(false);
|
||||||
|
setCredentialToDelete("")
|
||||||
|
}} color="primary" autoFocus>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
CredentialsTable.propTypes = {
|
||||||
|
count: PropTypes.number,
|
||||||
|
items: PropTypes.object,
|
||||||
|
//onDeselectAll: PropTypes.func,
|
||||||
|
//onDeselectOne: PropTypes.func,
|
||||||
|
onPageChange: PropTypes.func,
|
||||||
|
//onRowsPerPageChange: PropTypes.func,
|
||||||
|
//onSelectAll: PropTypes.func,
|
||||||
|
//onSelectOne: PropTypes.func,
|
||||||
|
deleteCredential: PropTypes.func,
|
||||||
|
//page: PropTypes.number,
|
||||||
|
//rowsPerPage: PropTypes.number,
|
||||||
|
//selected: PropTypes.array
|
||||||
|
};
|
||||||
|
|
@ -97,14 +97,14 @@ export const OverviewLatestOrders = (props) => {
|
||||||
</SeverityPill>
|
</SeverityPill>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{ order.Mqtt == 0 && order.Websockets == 0 && order.Stomp == 0 ? <span></span>: <Button>
|
{ order.Mqtt == 0 && order.Websockets == 0 && order.Stomp == 0 ? <span></span>: <Button
|
||||||
|
onClick={()=>{
|
||||||
|
router.push("devices/"+order.SN+"/discovery")
|
||||||
|
}
|
||||||
|
}>
|
||||||
<SvgIcon
|
<SvgIcon
|
||||||
fontSize="small"
|
fontSize="small"
|
||||||
sx={{cursor: order.Status == 2 && 'pointer'}}
|
sx={{cursor: order.Status == 2 && 'pointer'}}
|
||||||
onClick={()=>{
|
|
||||||
router.push("devices/"+order.SN+"/discovery")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<ArrowTopRightOnSquareIcon />
|
<ArrowTopRightOnSquareIcon />
|
||||||
</SvgIcon></Button>}
|
</SvgIcon></Button>}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,9 @@ const useChartOptions = (labels,title) => {
|
||||||
options.colors = [
|
options.colors = [
|
||||||
theme.palette.primary.main,
|
theme.palette.primary.main,
|
||||||
theme.palette.info.main,
|
theme.palette.info.main,
|
||||||
theme.palette.warning.main
|
theme.palette.warning.main,
|
||||||
|
theme.palette.graphics.lightest,
|
||||||
|
theme.palette.graphics.light,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
return options
|
return options
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user