{message}}\n action={\n \n \n OK\n \n \n \n \n \n }\n />\n );\n};\n\nSimpleSnackbar.defaultProps = {\n message: \"Alarm\"\n};\n\nSimpleSnackbar.propTypes = {\n classes: PropTypes.object.isRequired\n};\n\nexport default withStyles(styles)(SimpleSnackbar);\n","import React from \"react\";\n// import { makeStyles } from \"@material-ui/core/styles\";\nimport { Snackbar, IconButton } from \"@material-ui/core\";\nimport { Alert, AlertTitle } from \"@material-ui/lab\";\nimport CloseIcon from \"@material-ui/icons/Close\";\n\nconst AlertSnackbar = (props) => {\n // const classes = useStyles();\n const { message, open, handleClose, severity, autoHideDuration, horizontal } = props;\n\n return (\n \n \n \n \n }\n >\n {message} \n \n \n );\n};\n\nAlertSnackbar.defaultProps = {\n message: \"Alert\",\n severity: \"success\",\n autoHideDuration: 2000,\n horizontal: \"right\"\n};\n\nexport default AlertSnackbar;\n","import React from \"react\";\nimport { Button, CircularProgress, colors } from \"@material-ui/core\";\nimport { makeStyles } from \"@material-ui/styles\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n display: \"flex\",\n paddingBottom: theme.spacing(2),\n marginBottom: theme.spacing(2)\n },\n wrapper: {\n position: \"relative\",\n display: \"flex\"\n },\n buttonProgress: {\n color: colors.blueGrey[500],\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n marginTop: -12,\n marginLeft: -12\n }\n}));\n\nconst ProgressButton = (props) => {\n const classes = useStyles();\n const { children, loading, onClick, color, variant, size, disabled, align } = props;\n\n return (\n \n
\n \n {children}\n \n {loading && }\n
\n
\n );\n};\n\nProgressButton.defaultProps = {\n loading: false,\n color: \"primary\",\n variant: \"contained\",\n size: \"small\",\n align: \"center\"\n};\n\nexport default ProgressButton;\n","import React from 'react';\nimport PropTypes from 'prop-types';\nimport clsx from 'clsx';\nimport { makeStyles } from '@material-ui/styles';\nimport { Typography, Link } from '@material-ui/core';\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(4),\n textAlign: 'center'\n },\n quote: {\n backgroundColor: theme.palette.neutral,\n height: '100%',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n backgroundImage: 'url(/images/wizcloud_bg_02.png)',\n backgroundSize: 'cover',\n backgroundRepeat: 'no-repeat',\n backgroundPosition: 'center'\n },\n quoteInner: {\n textAlign: 'center',\n flexBasis: '600px'\n }\n}));\n\nconst Footer = (props) => {\n const { className, ...rest } = props;\n\n const classes = useStyles();\n\n return (\n \n \n Copyright ©\n \n 2022 WIZnet Co., Ltd. All Rights Reserved\n \n \n \n {/* Created with love for the environment. By designers and developers who love to\n work together in offices! */}\n \n
\n );\n};\n\nFooter.propTypes = {\n className: PropTypes.string\n};\n\nexport default Footer;\n","// Config object to be passed to Msal on creation\n\nconst targetUrl =\n process.env.NODE_ENV === \"development\"\n ? \"http://localhost:3000\"\n : // : \"https://wizasg.winc.ai\";\n \"https://asgdm.azurewebsites.net\";\n\nexport const msalConfig = {\n auth: {\n // clientId: process.env.REACT_APP_ASGWEBAPP_AD_APPLICATION_ID,\n clientId: process.env.REACT_APP_ASGDM_B2CAPP_APPLICATION_ID,\n authority: \"https://wizasg.b2clogin.com/wizasg.onmicrosoft.com/B2C_1_signin\",\n knownAuthorities: [ \"https://wizasg.b2clogin.com\" ],\n redirectUri: targetUrl,\n postLogoutRedirectUri: targetUrl\n // validateAuthority: false,\n // navigateToLoginRequestUrl: true\n }\n};\n\n// Add here scopes for id token to be used at MS Identity Platform endpoints.\nexport const loginRequest = {\n scopes: [\n \"https://wizasg.onmicrosoft.com/helloapi/demo.read\",\n \"openid\",\n \"offline_access\"\n ]\n};\n\nexport const forgotPasswordRequest = {\n authority: \"https://wizasg.b2clogin.com/wizasg.onmicrosoft.com/tfp/B2C_1_signin\"\n};\n\n// Add here the endpoints for MS Graph API services you would like to use.\nexport const graphConfig = {\n graphMeEndpoint: \"https://graph.microsoft.com/v1.0/me\"\n};\n","import axios from \"axios\";\n\nconst asgapiHost = process.env.REACT_APP_FUNCTION_ASGAPI;\nconst asgapiFuncKey = process.env.REACT_APP_FUNCTION_ASGAPI_KEY;\n\nconst saveUser = async (userInfo) => {\n const config = {\n method: \"POST\",\n data: JSON.stringify(userInfo),\n headers: {\n \"Content-type\": \"Application/json\"\n },\n url: `${asgapiHost}/saveuser?code=${asgapiFuncKey}&id=${userInfo.email}`\n };\n\n // console.log(\"userInfo\", userInfo);\n try {\n const { data } = await axios(config);\n // console.log(\"saveUser resp:\", resp);\n return data;\n } catch (error) {\n console.log(error);\n return false;\n }\n};\n\n/**\n * Internal API\n */\n\nconst sendC2dMessage = async (deviceId, data) => {\n try {\n await fetch(\n `${asgapiHost}/sendc2dmessage?code=${asgapiFuncKey}&deviceId=${deviceId}&data=${data}`\n );\n console.info(`Sent c2d message[${data}] to [${deviceId}]`);\n return true;\n } catch (error) {\n console.log(error);\n return false;\n }\n};\n\nconst invokeMethod = async (deviceId, methodName, payload) => {\n try {\n const resp = await fetch(\n `${asgapiHost}/invokemethod?code=${asgapiFuncKey}&deviceId=${deviceId}&methodName=${methodName}&payload=${payload}`\n );\n const jsondata = await resp.json();\n return jsondata;\n } catch (error) {\n console.log(error);\n return false;\n }\n};\n\nconst queryDevice = async () => {\n try {\n const resp = await fetch(`${asgapiHost}/queryasgdevice`);\n // console.log(\"resp:\", resp);\n const jsondata = await resp.json();\n return jsondata;\n } catch (error) {\n console.log(error);\n return false;\n }\n};\n\nconst queryUser = async (email) => {\n try {\n const resp = await fetch(\n `${asgapiHost}/queryuser?code=${asgapiFuncKey}&email=${email}`\n );\n const jsondata = await resp.json();\n // console.log(\"jsondata:\", jsondata);\n return jsondata;\n } catch (error) {\n console.log(error);\n return false;\n }\n};\n\nconst queryEvents = async (deviceId, limit) => {\n try {\n const resp = await fetch(\n deviceId.length === 0\n ? `${asgapiHost}/queryevents?limit=${limit}`\n : `${asgapiHost}/queryevents?deviceId=${deviceId}&limit=${limit}`\n );\n // console.log(\"resp:\", resp);\n const jsondata = await resp.json();\n // console.log(\"jsondata:\", jsondata);\n return jsondata;\n } catch (error) {\n console.log(\"queryEvents err:\", error);\n return false;\n }\n};\n\nconst queryEventsContinue = async (deviceId, continuationToken, count) => {\n var config = {\n method: \"GET\",\n url: `${asgapiHost}/queryeventscont?code=${asgapiFuncKey}&deviceId=${deviceId}&maxItemCount=${count}`,\n headers: {\n \"Content-Type\": \"application/json\",\n \"continuation-token\": continuationToken\n }\n };\n\n try {\n const { data } = await axios(config);\n // console.log(\"data:\", data);\n return data;\n } catch (error) {\n console.log(\"queryEventsContinue err:\", error);\n return false;\n }\n};\n\nconst queryUserDevice = async (email) => {\n const config = {\n method: \"GET\",\n url: `${asgapiHost}/queryuserdevice?code=${asgapiFuncKey}&owner=${email}`\n };\n\n try {\n const { data } = await axios(config);\n // console.log(\"data:\", data);\n return data;\n } catch (error) {\n console.log(\"queryUserDevice err:\", error);\n return false;\n }\n};\n\nconst queryDeviceUpdate = async (deviceId, data) => {\n const config = {\n method: \"POST\",\n headers: {\n \"Content-type\": \"Application/json\"\n },\n url: `${asgapiHost}/querydevice/update?code=${asgapiFuncKey}&deviceId=${deviceId}`,\n data: JSON.stringify(data)\n };\n\n try {\n const { data } = await axios(config);\n // console.log(\"data:\", data);\n return data;\n } catch (error) {\n console.log(\"queryDeviceUpdate err:\", error);\n return false;\n }\n};\n\nconst queryWithSql = async (container, query) => {\n const config = {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"text/plain\"\n },\n url: `${asgapiHost}/querywithsql?code=${asgapiFuncKey}&containerName=${container}`,\n data: query\n };\n\n try {\n const { data } = await axios(config);\n // console.log(\"data:\", data);\n return data;\n } catch (error) {\n console.log(\"queryWithSql err:\", error);\n return false;\n }\n};\n\nconst updateTwin = async (deviceId, data) => {\n const config = {\n method: \"POST\",\n headers: {\n \"Content-type\": \"Application/json\"\n },\n url: `${asgapiHost}/twin/update?code=${asgapiFuncKey}&deviceId=${deviceId}`,\n data: JSON.stringify(data)\n };\n\n try {\n const { data } = await axios(config);\n // console.log(\"data:\", data);\n return data;\n } catch (error) {\n console.log(\"updateTwin err:\", error);\n return false;\n }\n};\n\nconst createDocument = async (containerId, data) => {\n const config = {\n method: \"POST\",\n headers: {\n \"Content-type\": \"Application/json\"\n },\n url: `${asgapiHost}/document/create?code=${asgapiFuncKey}&containerId=${containerId}`,\n data: JSON.stringify(data)\n };\n\n try {\n const { data } = await axios(config);\n // console.log(\"data:\", data);\n return data;\n } catch (error) {\n console.log(\"createDocument err:\", error);\n return false;\n }\n};\n\nconst updateAS3Info = async (deviceId) => {\n const config = {\n method: \"GET\",\n url: `${process.env\n .Function_asgapi}/update/as3info?code=${asgapiFuncKey}&deviceId=${deviceId}`\n };\n\n try {\n const { data } = await axios(config);\n console.log(\"RequestAS3Update response:\", data);\n return data;\n } catch (error) {\n console.log(error);\n return false;\n }\n};\n\nexport {\n sendC2dMessage,\n invokeMethod,\n saveUser,\n queryEvents,\n queryEventsContinue,\n queryDevice,\n queryUser,\n queryUserDevice,\n queryDeviceUpdate,\n updateTwin,\n createDocument,\n updateAS3Info,\n queryWithSql\n};\n","import axios from \"axios\";\nimport { config } from \"./asgConfig\";\n\nconst endpoint = \"https://prod.core.sphere.azure.net\";\nconst tenantId = config.tenantId;\n\nconst asgapiHost = process.env.REACT_APP_FUNCTION_ASGAPI;\nconst asgapiFuncKey = process.env.REACT_APP_FUNCTION_ASGAPI_KEY;\n\nconst devicesGet = async (deviceId) => {\n console.log(\"[Azsphere] get device\");\n const resp = await axios(`${asgapiHost}/getauthtoken?code=${asgapiFuncKey}`);\n const token = resp.data;\n const config = {\n method: \"GET\",\n url: `${endpoint}/v2/tenants/${tenantId}/devices/${deviceId}`,\n headers: {\n Authorization: `Bearer ${token}`\n }\n };\n\n const { data } = await axios(config);\n\n return data;\n};\n\nconst devicesList = async () => {\n console.log(\"[Azsphere] get devices\");\n const resp = await axios(`${asgapiHost}/getauthtoken?code=${asgapiFuncKey}`);\n const token = resp.data;\n const config = {\n method: \"GET\",\n url: `${endpoint}/v2/tenants/${tenantId}/devices`,\n headers: {\n Authorization: `Bearer ${token}`\n }\n };\n\n const { data } = await axios(config);\n\n return data;\n};\n\nconst devicesListInGroup = async (groupId) => {\n console.log(\"[Azsphere] get devices in group\");\n const resp = await axios(`${asgapiHost}/getauthtoken?code=${asgapiFuncKey}`);\n const token = resp.data;\n const config = {\n method: \"GET\",\n url: `${endpoint}/v2/tenants/${tenantId}/devicegroups/${groupId}/devices`,\n headers: {\n Authorization: `Bearer ${token}`\n }\n };\n\n const { data } = await axios(config);\n return data;\n};\n\nconst devicesMove = async (deviceId, groupId) => {\n console.log(\"[Azsphere] move device\");\n const resp = await axios(`${asgapiHost}/getauthtoken?code=${asgapiFuncKey}`);\n const token = resp.data;\n // console.log(\"token\", token);\n\n const config = {\n method: \"PUT\",\n url: `${endpoint}/v2/tenants/${tenantId}/devices/${deviceId}/deviceGroup`,\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-type\": \"Application/json;charset=utf-8\"\n },\n data: JSON.stringify(groupId)\n };\n\n const { data } = await axios(config);\n // console.log(\"data:\", data);\n return data;\n};\n\nconst deviceGroupGet = async (groupId) => {\n console.log(\"[Azsphere] get group\");\n const resp = await axios(`${asgapiHost}/getauthtoken?code=${asgapiFuncKey}`);\n const token = resp.data;\n const config = {\n method: \"GET\",\n url: `${endpoint}/v2/tenants/${tenantId}/devicegroups/${groupId}`,\n headers: {\n Authorization: `Bearer ${token}`\n }\n };\n\n const { data } = await axios(config);\n return data;\n};\n\nconst productListGroups = async (productId) => {\n console.log(\"[Azsphere] get groups in product\");\n const resp = await axios(`${asgapiHost}/getauthtoken?code=${asgapiFuncKey}`);\n const token = resp.data;\n // console.log(\"token\", token);\n\n const config = {\n method: \"GET\",\n url: `${endpoint}/v2/tenants/${tenantId}/products/${productId}/deviceGroups`,\n headers: {\n Authorization: `Bearer ${token}`\n }\n };\n\n const { data } = await axios(config);\n // console.log(\"data:\", data);\n return data;\n};\n\nconst productGetByName = async (productName) => {\n console.log(\"[Azsphere] get product by name\");\n const resp = await axios(`${asgapiHost}/getauthtoken?code=${asgapiFuncKey}`);\n const token = resp.data;\n // console.log(\"token\", token);\n\n const config = {\n method: \"GET\",\n url: `${endpoint}/v2/tenants/${tenantId}/products/name/${productName}`,\n headers: {\n Authorization: `Bearer ${token}`\n }\n };\n\n try {\n const { data } = await axios(config);\n // console.log(\"data:\", data);\n return data;\n } catch (error) {\n console.log(error);\n return false;\n }\n};\n\nconst deploymentsList = async (groupId) => {\n console.log(\"[Azsphere] get deployments\");\n const resp = await axios(`${asgapiHost}/getauthtoken?code=${asgapiFuncKey}`);\n const token = resp.data;\n // console.log(\"token\", token);\n\n const config = {\n method: \"GET\",\n url: `${endpoint}/v2/tenants/${tenantId}/devicegroups/${groupId}/deployments`,\n headers: {\n Authorization: `Bearer ${token}`\n }\n };\n\n const { data } = await axios(config);\n // console.log(\"data:\", data);\n return data;\n};\n\nconst deploymentsCreate = async (groupId, imageIds) => {\n console.log(\"[Azsphere] create deployment\");\n const resp = await axios(`${asgapiHost}/getauthtoken?code=${asgapiFuncKey}`);\n const token = resp.data;\n // console.log(\"token\", token);\n\n const config = {\n method: \"POST\",\n url: `${endpoint}/v2/tenants/${tenantId}/devicegroups/${groupId}/deployments`,\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-type\": \"Application/json;charset=utf-8\"\n },\n data: imageIds\n };\n\n const { data } = await axios(config);\n // console.log(\"data:\", data);\n return data;\n};\n\nconst imageUpload = async (filedata) => {\n console.log(\"[Azsphere] upload image\");\n const resp = await axios(`${asgapiHost}/getauthtoken?code=${asgapiFuncKey}`);\n const token = resp.data;\n // console.log(\"token\", token);\n\n const config = {\n method: \"POST\",\n url: `${endpoint}/v2/tenants/${tenantId}/images`,\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-type\": \"application/octet-stream\"\n },\n data: filedata\n };\n\n const { data } = await axios(config);\n // console.log(\"imageUpload data:\", data);\n return data;\n};\n\nconst imageGetMetadata = async (imageId) => {\n const resp = await axios(`${asgapiHost}/getauthtoken?code=${asgapiFuncKey}`);\n const token = resp.data;\n\n const config = {\n method: \"GET\",\n url: `${endpoint}/v2/tenants/${tenantId}/images/${imageId}/metadata`,\n headers: {\n Authorization: `Bearer ${token}`\n }\n };\n\n const { data } = await axios(config);\n // console.log(\"data:\", data);\n return data;\n};\n\nexport {\n devicesGet,\n devicesList,\n devicesMove,\n deviceGroupGet,\n devicesListInGroup,\n productListGroups,\n productGetByName,\n deploymentsList,\n deploymentsCreate,\n imageUpload,\n imageGetMetadata\n};\n","export const config = {\n tenantId: process.env.REACT_APP_AZSPHERE_TENANT_ID\n};\n","import { atom } from \"recoil\";\n\n/**\n * ASG Device State\n */\nexport const deviceIdState = atom({\n key: \"deviceIdState\",\n default: \"\"\n});\n\nexport const deviceGroupState = atom({\n key: \"deviceGroupState\",\n default: {\n id: \"\",\n name: \"\"\n }\n});\n\nexport const userDeviceListState = atom({\n key: \"userDeviceListState\",\n default: []\n});\n\nexport const isDeviceLoadedState = atom({\n key: \"isDeviceLoadedState\",\n default: false\n});\n\n/**\n * Waton Device State\n */\nexport const treeState = atom({\n key: \"treeState\",\n default: {\n bank: 1,\n cell: 10\n }\n});\n\n/**\n * Node Device State\n */\nexport const deviceIndexState = atom({\n key: \"deviceIndexState\",\n default: \"17\" // WIZ750SR\n});\n\nexport const searchDataState = atom({\n key: \"searchDataState\",\n default: \"\"\n});\n\nexport const s2eConfigState = atom({\n key: \"s2eConfigState\",\n default: {}\n});\n\nexport const continuationTokenState = atom({\n key: \"continuationTokenState\",\n default: [\n {\n fileName: \"\",\n componentId: \"\",\n imageId: \"\"\n }\n ]\n});\n\n/**\n * FOTA State\n */\n\nexport const groupListLoadedState = atom({\n key: \"groupListLoadedState\",\n default: false\n});\n\nexport const groupListState = atom({\n key: \"groupListState\",\n default: []\n});\n\nexport const targetGroupIdState = atom({\n key: \"targetGroupIdState\",\n default: \"\"\n});\n\nexport const fotaImageState = atom({\n key: \"fotaImageState\",\n default: [\n // {\n // fileName: \"\",\n // componentId: \"\",\n // imageId: \"\"\n // }\n ]\n});\n\n/**\n * Component State\n */\nexport const snackbarState = atom({\n key: \"snackbarState\",\n default: {\n open: false,\n message: \"\",\n severity: \"success\",\n autoHideDuration: 3000,\n horizontal: \"right\"\n }\n});\n","import React, { createContext, useEffect, useState } from \"react\";\nimport { useIsAuthenticated, useMsal, useAccount } from \"@azure/msal-react\";\nimport { loginRequest } from \"common/authConfig\";\nimport { saveUser, queryUser, queryUserDevice } from \"common/apiConfig\";\nimport { productGetByName, productListGroups } from \"common/azsphereApi\";\nimport { useSetRecoilState } from \"recoil\";\nimport {\n userDeviceListState,\n isDeviceLoadedState,\n groupListState,\n groupListLoadedState\n} from \"common/store\";\n\nconst MsalAuthContext = createContext();\n\nconst MsalAuthProvider = (props) => {\n const { instance, accounts, inProgress } = useMsal();\n const isAuthenticated = useIsAuthenticated();\n const account = useAccount(accounts[0] || {});\n\n const [ values, setValues ] = useState({\n user: false,\n // accessToken: null,\n product: \"\",\n account: account,\n isAuthenticated: isAuthenticated,\n logout: () => instance.logout()\n });\n\n // const [ userDevices, setUserDeivces ] = useRecoilState(userDeviceListState);\n const setUserDeivces = useSetRecoilState(userDeviceListState);\n const setIsDeviceLoaded = useSetRecoilState(isDeviceLoadedState);\n\n const setGroupList = useSetRecoilState(groupListState);\n const setGroupLoaded = useSetRecoilState(groupListLoadedState);\n\n useEffect(\n () => {\n if (account && inProgress === \"none\") {\n instance\n .acquireTokenSilent({\n ...loginRequest,\n account: account\n })\n .then((response) => {\n // console.log(\"response\", response);\n // getProfile(response);\n });\n }\n },\n [ instance, account, inProgress ]\n );\n\n // const getProfile = async (response) => {\n // const config = {\n // method: \"GET\",\n // headers: {\n // Authorization: `Bearer ${response.accessToken}`\n // }\n // };\n // console.log(config);\n\n // const result = await fetch(graphConfig.graphMeEndpoint, config)\n // .then((response) => response.json())\n // .catch((error) => console.log(error));\n\n // console.log(\"result =>\", result);\n // };\n\n useEffect(\n () => {\n const getUserDevice = async () => {\n try {\n const data = await queryUserDevice(account.username);\n // console.log(\"getUserDevice data\", data);\n console.log(\"Get user devices:\", data.length);\n\n localStorage.setItem(\"userdevice_list\", JSON.stringify(data));\n // console.log(\"Save user devices to web storage\");\n\n setUserDeivces(data);\n setIsDeviceLoaded(true);\n } catch (error) {\n console.error(error);\n setIsDeviceLoaded(true);\n setUserDeivces([]);\n }\n };\n\n if (Object.keys(account).length > 0) {\n const localDevices = localStorage.getItem(\"userdevice_list\");\n if (localDevices) {\n setUserDeivces(JSON.parse(localDevices));\n }\n getUserDevice();\n }\n },\n [ account ]\n );\n\n useEffect(\n () => {\n const getGroupListByProduct = async () => {\n try {\n // console.log(\"values.product.id\", values.product.id);\n const data = await productListGroups(values.product.id);\n // console.log(\"productListGroups\", data);\n setGroupList(data.Items);\n setGroupLoaded(true);\n } catch (error) {\n console.log(error);\n }\n };\n\n // console.log(values.product);\n if (values.product !== \"\" || values.product !== null) {\n if (values.product.id !== undefined) {\n getGroupListByProduct();\n }\n }\n },\n [ values.product ]\n );\n\n useEffect(\n () => {\n const getProductGetByName = async () => {\n try {\n if (Object.keys(values.account).length > 0) {\n const data = await productGetByName(values.account.name);\n // console.log(\"productGetByName\", data);\n if (data) {\n setValues({\n ...values,\n product: {\n name: data.Name,\n id: data.Id,\n description: data.Description\n }\n });\n\n // save user information\n saveUser({\n displayName: values.account.name,\n email: values.account.username,\n // userIdPart: user.id.slice(0, 8),\n account: values.account,\n role: \"user\",\n // AS3 product info\n product: {\n name: data.Name,\n id: data.Id,\n description: data.Description\n }\n });\n }\n }\n } catch (error) {\n console.log(error);\n }\n };\n\n const saveUserInfo = async () => {\n if (Object.keys(values.account).length > 0 && inProgress === \"none\") {\n const userDoc = await queryUser(values.account.username);\n console.log(\"Query user device\");\n // console.log(\"userDoc\", userDoc);\n if (Object.keys(userDoc).length > 0) {\n setValues({\n ...values,\n account: userDoc.account,\n product: userDoc.product\n });\n } else {\n await getProductGetByName();\n }\n }\n };\n\n saveUserInfo();\n },\n [ account, inProgress ]\n );\n\n return (\n {props.children} \n );\n};\n\nexport { MsalAuthContext, MsalAuthProvider };\n","import React, { useContext } from \"react\";\nimport { Redirect } from \"react-router-dom\";\nimport clsx from \"clsx\";\nimport PropTypes from \"prop-types\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { Typography } from \"@material-ui/core\";\n\nimport { MsalAuthContext } from \"contexts/msalAuthContext\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n minHeight: \"fit-content\",\n color: \"#f2f2f2\"\n },\n avatar: {\n width: 60,\n height: 60\n },\n name: {\n marginTop: theme.spacing(1),\n color: \"#f2f2f2\",\n // color: theme.palette.text.secondary,\n fontSize: \"11pt\",\n fontWeight: theme.typography.fontWeightMedium\n }\n}));\n\nconst Profile = (props) => {\n const { className, ...rest } = props;\n const authState = useContext(MsalAuthContext);\n\n const classes = useStyles();\n\n if (!authState.isAuthenticated) {\n return ;\n } else {\n return (\n \n \n Hello, {authState.account.name}\n \n {authState.account.username} \n
\n );\n }\n};\n\nProfile.propTypes = {\n className: PropTypes.string\n};\n\nexport default Profile;\n","/* eslint-disable react/no-multi-comp */\n/* eslint-disable react/display-name */\nimport React, { forwardRef } from \"react\";\nimport { NavLink as RouterLink } from \"react-router-dom\";\nimport clsx from \"clsx\";\nimport PropTypes from \"prop-types\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { List, ListItem, Button } from \"@material-ui/core\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {},\n item: {\n display: \"flex\",\n paddingTop: 0,\n paddingBottom: 0\n },\n button: {\n color: \"#f2f2f2\",\n padding: \"10px 8px\",\n justifyContent: \"flex-start\",\n textTransform: \"none\",\n letterSpacing: 0,\n width: \"100%\",\n fontWeight: theme.typography.fontWeightMedium\n },\n icon: {\n // color: theme.palette.icon,\n color: \"#f2f2f2\",\n width: 24,\n height: 24,\n display: \"flex\",\n alignItems: \"center\",\n marginRight: theme.spacing(1)\n },\n active: {\n // color: theme.palette.primary.main,\n color: \"#d75b51\",\n fontWeight: theme.typography.fontWeightMedium,\n \"& $icon\": {\n color: theme.palette.primary.main\n }\n }\n}));\n\nconst CustomRouterLink = forwardRef((props, ref) => (\n \n \n
\n));\n\nconst SidebarNav = (props) => {\n const { pages, className, ...rest } = props;\n\n const classes = useStyles();\n\n return (\n \n {pages.map((page) => (\n \n \n {page.icon}
\n {page.title}\n \n \n ))}\n
\n );\n};\n\nSidebarNav.propTypes = {\n className: PropTypes.string,\n pages: PropTypes.array.isRequired\n};\n\nexport default SidebarNav;\n","import StorageIcon from \"@material-ui/icons/Storage\";\nimport DeviceIcon from \"@material-ui/icons/DeviceHubOutlined\";\nimport CloudDownloadIcon from \"@material-ui/icons/CloudDownload\";\nimport AccountTreeIcon from \"@material-ui/icons/AccountTree\";\nimport EqualizerIcon from \"@material-ui/icons/Equalizer\";\nimport DescriptionIcon from \"@material-ui/icons/Description\";\n\nexport const topbar = {\n headerText: \"ASG Device Management System\"\n};\n\nexport const sidebar = {\n page: [\n {\n title: \"My Devices\",\n href: \"/mydevices\",\n icon: \n },\n {\n title: \"Linked Nodes\",\n href: \"/linkednodes\",\n icon: \n },\n {\n title: \"Node's Dashboard\",\n href: \"/nodedashboard\",\n icon: \n },\n {\n title: \"Node's Data\",\n href: \"/nodesdata\",\n icon: \n },\n // {\n // title: \"Node's Log\",\n // href: \"/nodelog\",\n // icon: \n // },\n {\n title: \"FOTA\",\n href: \"/fota\",\n icon: \n },\n {\n title: \"Documents\",\n href: \"/docs\",\n icon: \n }\n ]\n};\n\nexport const docsUrl = \"https://wiznet-azure-sphere.github.io/WIZnet-ASG-DM-Docs/\";\n","import React, { useContext } from \"react\";\nimport clsx from \"clsx\";\nimport PropTypes from \"prop-types\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { Divider, Drawer, IconButton, Hidden, Chip, Avatar } from \"@material-ui/core\";\n\n// import { Dashboard as DashboardIcon } from \"icons\";\n// import DashboardIcon from \"@material-ui/icons/Dashboard\";\n\nimport InputIcon from \"@material-ui/icons/Input\";\nimport BusinessIcon from \"@material-ui/icons/Business\";\n\nimport { MsalAuthContext } from \"contexts/msalAuthContext\";\nimport { Profile, SidebarNav } from \"./components\";\n\nimport { sidebar } from \"common/webConfig\";\n\nconst useStyles = makeStyles((theme) => ({\n drawer: {\n width: 240,\n [theme.breakpoints.up(\"lg\")]: {\n marginTop: 64,\n height: \"calc(100% - 64px)\"\n },\n backgroundColor: \"#1e2738\"\n },\n root: {\n backgroundColor: theme.palette.white,\n display: \"flex\",\n flexDirection: \"column\",\n height: \"100%\",\n padding: theme.spacing(2)\n },\n signOutButton: {\n position: \"absolute\",\n bottom: \"0\",\n height: \"3rem\"\n // width: \"100%\"\n },\n divider: {\n margin: theme.spacing(2, 0)\n },\n nav: {\n marginBottom: theme.spacing(2)\n },\n chipWrapper: {\n flexDirection: \"column\",\n alignItems: \"center\",\n display: \"flex\",\n marginTop: theme.spacing(3)\n // borderColor: \"#f2f2f2\",\n },\n chip: {\n border: \"1px solid #f2f2f2\",\n marginBottom: theme.spacing(1),\n color: \"#f2f2f2\"\n }\n}));\n\nconst Sidebar = (props) => {\n const { open, variant, onClose, className, ...rest } = props;\n\n const authState = useContext(MsalAuthContext);\n const classes = useStyles();\n\n return (\n \n \n
\n
\n T}\n label=\"Tenant - WIZnet\"\n variant=\"outlined\"\n />\n }\n label={\n authState.product.name !== undefined ? (\n \"Company - \" + authState.product.name\n ) : (\n \"Company\"\n )\n }\n variant=\"outlined\"\n />\n
\n
\n
\n
\n \n \n \n \n
\n \n );\n};\n\nSidebar.propTypes = {\n className: PropTypes.string,\n onClose: PropTypes.func,\n open: PropTypes.bool.isRequired,\n variant: PropTypes.string.isRequired\n};\n\nexport default Sidebar;\n","import React, { useContext } from \"react\";\nimport { Link as RouterLink, Redirect } from \"react-router-dom\";\nimport clsx from \"clsx\";\nimport PropTypes from \"prop-types\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { AppBar, Toolbar, Hidden, IconButton, Typography } from \"@material-ui/core\";\nimport MenuIcon from \"@material-ui/icons/Menu\";\nimport InputIcon from \"@material-ui/icons/Input\";\nimport { MsalAuthContext } from \"contexts/msalAuthContext\";\nimport WincLogo from \"image/winc_logo_sm_notext.png\";\n\nimport { topbar } from \"common/webConfig\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n boxShadow: \"none\",\n backgroundColor: \"#121b2a\"\n },\n header: {\n marginLeft: 2\n },\n flexGrow: {\n flexGrow: 1\n },\n signOutButton: {\n marginLeft: theme.spacing(1)\n },\n toolbarName: {\n marginTop: theme.spacing(2),\n marginBottom: theme.spacing(2),\n marginLeft: 12,\n marginRignt: theme.spacing(1),\n color: \"#f2f2f2\",\n // fontFamily: 'Lucida Sans',\n fontFamily: [ \"Roboto\", \"Helvetica\", \"Arial\", \"sans-serif\" ]\n },\n logo: {\n marginTop: 5\n },\n logoImage: {\n height: 33\n }\n}));\n\nconst Topbar = (props) => {\n const { className, onSidebarOpen, ...rest } = props;\n const authState = useContext(MsalAuthContext);\n\n const classes = useStyles();\n\n if (!authState.isAuthenticated) {\n return ;\n } else {\n return (\n \n \n \n
\n
\n \n \n \n {topbar.headerText}\n \n \n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n );\n }\n};\n\nTopbar.propTypes = {\n className: PropTypes.string,\n onSidebarOpen: PropTypes.func\n};\n\nexport default Topbar;\n","export default \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAAAtCAYAAADm45atAAAACXBIWXMAAC4jAAAuIwF4pT92AAAI20lEQVR42t2aC3BU5RXHTxKDBMLDYKRxeEqJASQCCU6Qp7VqWx8oILVS6zRjq9KqREFUBOWNRJ3RiiMOdkDxiQWhVkWpAyIgBao2agdpG6JI9pENhDwWsq/+z5ez8nFz7+7eze4GuTO/mezmu/ee73/Pd875zl0KhUJ0hpMDLgBDQREYBUaD8eAygf8eB8aAEjACXAT6gGyQzpyJ4gwEPwd3gefBTuAOxXY0gQZwDBwB/wbbQTnodCaIw15zN3gL7DcR4Dg4IJN+G7wKVoInwHKwBJSBtRYCfgJ+CTJ+qAKNBAtBFWgUj6gH+8Cz4DYwFvQHuewVIC3C9YrBVuDXRDoESvVxPySBfgweFQ/hZbUNrBBhhsZ5TY5FT5p40xqQZxx/ugt0HrgCPAM2gVVgmiy9RFz7fYNI1eAWq3NOV5E6SWZir3lQMlb3BD+ETw1CfRjtISRrspky4e7izmxcN9AVZHGwjHL+jySOdEmCbWzHPw1CPR7LuYkyoBDcBJbJcmFjKkGtBF5OxUeBRzITZ5i/gj9JJrsODE+SOEb0rBcQ76Vki9VBJroZ+EJtP4LgS7AOLACXg7MTLNSN2v04i15r5/x4bzoZVISSe/BT/wa8KZPs30ahsrQ6zC+FKyVbrPtimOhu8ByYC34HJolxV4Gr5fNvJXgvF2/iGskb4Zq8jFeD34hXt8Wrro9HcLsn3BxhMnvAH8BgeYp2r91ZtipcKjwsRaLT4l7sIY+BQTau/zc59654vdPO4HOAy8Twg+Ilyaqz2JNeAt9axLkXZCMc6TodZfy2tthjZ3CZibH89HumqPbiEmQq2Cj7PeOxXroJZudyp+HrthazsQ5MEyP1o0rqoYSI4d/8LgV2fNwK//Zt5N+1wzh+sJQdVSZJYaWJKLy0b22rjXYyyT6DYdMSIVLzK2up7oaJ9B0RVVMHE4gc1Jma5jxATfPnUdDl0M9nr54tNZ1+eCQR6YVoWqrE4uyzSzPGJU2xiOcFqw7SiRVPU21JCR2deI0pztw8CHIWeYqLqKawsDXDLqaaoRdhTBodhnA1Q4aQd/FCswbfXNnb6ccWKXYT4v12Bq827KOsRaqvp+NPPQkBipUQLIgV7oJBVDN8mFGk8eB+8Dh4GiwCt0C4Hq683kq4+rv/SP6PPzLeu7dsuo0NvempFmuKZsDfrdw66HZT3dQpdAhe4M6/0EyISNwE9gI/CJlQBZ7wFA3POayWZ1fybXqLgl6v0Y6x8kD1Y7WUJykRi9PvF1orw3QZNj4yRwmllk/sInUAL1kIZMbXEKzI1fcCCNaRai+boB6SiT1crzUbiuX+qRArnFXCx+Wt/u/zUeOsMrVMbAiVDjYaxHhPLbvCwjFgJLgSlIMj2hgvGMsPRQk2bgyFHIetuqqfGeLthFSIxcyTm77TKv1v/ZAc6d1VELYQphMYAApAb5AGFmoC1IObIwibD7Zo4ytBV3iZyprsYSGPx+oNzxuaYHXSL0u6WMyLctOr9O99773TkrFaL8FrwFrwGagFjaAa7ARBmbhbAns0T8wwCLZcfY/Y6KAMqh09ioIHK63sXqoJdixCEZvwFs1TsnfL/d6zPthsXIIDwdsxxqFHbSzdXsAj5/HS7MHfc/nh6HKuSiyN999nZfdMQxu5VyrEYubISwMu+lBxb1fLQSb0E/EWXZBvwXqwRkTU/89ZsJsNwZ7Tzp2i12WuPn2Vh0cQ7B5NsB3S2U1Jp/RSbgEHAwHyrXsNSyGLjS4GPm0y+8GvQZ5hwn3ADHBCxt1rQ6zrtOsvMitmlWCz7rWy+zFNsAdT2VbOwPafPCOLyT1gIJcBn2sT+QCcG2XioyV27bQhVrF2j3LTyn/I4BbBZs+0snuzFvDzUiUWeZctIWdOT96azNAmsQdkxjh5zor/sCHWJdp9/iXedadk2pPjEPiVYDPLzOzOlwo/JO8kky+Wd+liZRAC61l4ontlAlyFj7Ix+Www2cb4EotEwfXXC6cseZQyYQ8L1h21yuwfRXvrdHKb4vdTqLExJnF8GzeoWOBdskgVoY70LmqzC6EKta3KuzYmHg8lUbIrJ5Oh3y9JwJ0N/66dVt1fT7SlePKD00l1N06i2pJLqG7yRMsuAePq209aKkyWXlddrxn7QJLFypbqfhyYAK4AC8AhzYavZJw6x5HZnQL79lrtShqilRGnfAjs20PObrlKCFdeL+tOgfUGeZpmaGmSxbLifCl+w3bM02OXf/cnRhFKRayKaK/eWncNKv9LHq6GsbQse0zWTNWMnN5OYoW3RU2ad2VwK8idn0+BigrjnLeKWGVxBfjggf3Ke1R2s9c9GK+JtaIdxWI2iB0N8KpB7FXexQvMiuqQ/EAkM+5sGPymSvWLeElaNOjMyJHAykY6QJd2FKtc7PAhpFyq2jhVleGfGfWWnUdAevkd21yUcrZruOM24r6Rq0+/lowX3chVmnctPQ08q95BHQfVT789PK+z5cXvs/Ib08RupJvXv4nA31MFf16a3BKJEi9OaIJNawehhkm9xff/EruKTF4d/i3vx1FHBu0XpcHvDpF34SMI/iOQgnMgWMTgP8NQ83BGOi9FQvF+81Pt3g/VwGYOJ03z58Y+3/8cULsSLqXCJZNtpYPV1apnxAGTywjef1kkgWcMgv1PlmWp1GOTEghf71dgvvTJwvf8XBqOqibklyixzO94+TIVpx3pnU8pmeLa3gSP1ZFv3evkGT+WHFk5kcqMh6XRF2oHuGToF7aFH27zmj9HnBe/m/SIF7oHsxOcmtTavC88sep5OvKLn7XcYGC+WdYcAV4BzhSJ1ABWGttBzm496Fjpra3j8asvk2/TBmp6aHbLaokQkxOykeZXUc1/eQNCXUzO7B5WN+NYcjX4PZiVYGaDe6QJWGA2UdVFxQo4cuVP1d6W4b/D2zZOXjVFIyLGw4T+eCOwe5d6Ms7s3JaXFrGVGimDlxj/JMA1YICC/+bvYj0/4b92CX5RQTUFBWqz7ex5vrlg+M7yf8kGyUhtfbjQtrc7of8DTIJpwd3U+2gAAAAASUVORK5CYII=\"","import React, { useState } from 'react';\nimport PropTypes from 'prop-types';\nimport clsx from 'clsx';\nimport { makeStyles, useTheme } from '@material-ui/styles';\nimport { useMediaQuery } from '@material-ui/core';\n\nimport { Sidebar, Topbar, Footer } from './components';\n\nconst useStyles = makeStyles(theme => ({\n root: {\n paddingTop: 56,\n [theme.breakpoints.up('sm')]: {\n paddingTop: 64\n }\n },\n shiftContent: {\n paddingLeft: 240\n },\n content: {\n minHeight: '85vh',\n position: 'relative'\n },\n footer: {\n position: 'absolute',\n bottom: '0',\n height: '2.5rem',\n marginBottom: '-2rem',\n width: '100%'\n }\n}));\n\nconst Main = props => {\n const { children } = props;\n\n const classes = useStyles();\n const theme = useTheme();\n const isDesktop = useMediaQuery(theme.breakpoints.up('lg'), {\n defaultMatches: true\n });\n\n const [openSidebar, setOpenSidebar] = useState(false);\n\n const handleSidebarOpen = () => {\n setOpenSidebar(true);\n };\n\n const handleSidebarClose = () => {\n setOpenSidebar(false);\n };\n\n const shouldOpenSidebar = isDesktop ? true : openSidebar;\n\n return (\n \n \n \n \n {children}\n \n \n
\n );\n};\n\nMain.propTypes = {\n children: PropTypes.node\n};\n\nexport default Main;\n","import React from \"react\";\nimport { Link as RouterLink } from \"react-router-dom\";\nimport clsx from \"clsx\";\nimport PropTypes from \"prop-types\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { AppBar, Toolbar, Typography } from \"@material-ui/core\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n boxShadow: \"none\"\n },\n toolbarName: {\n marginTop: theme.spacing(2),\n marginBottom: theme.spacing(2),\n marginLeft: theme.spacing(1),\n marginRignt: theme.spacing(1),\n color: \"white\",\n // fontFamily: 'Lucida Sans',\n fontFamily: [ \"Roboto\", \"Helvetica\", \"Arial\", \"sans-serif\" ]\n }\n}));\n\nconst Topbar = (props) => {\n const { className, ...rest } = props;\n\n const classes = useStyles();\n\n return (\n \n \n \n
\n {/* */}\n \n ASG Device Management System\n \n \n
\n \n \n );\n};\n\nTopbar.propTypes = {\n className: PropTypes.string\n};\n\nexport default Topbar;\n","import React from 'react';\nimport PropTypes from 'prop-types';\nimport { makeStyles } from '@material-ui/styles';\n\nimport { Topbar } from './components';\n\nconst useStyles = makeStyles(() => ({\n root: {\n paddingTop: 64,\n height: '100%'\n },\n content: {\n height: '100%'\n }\n}));\n\nconst Minimal = props => {\n const { children } = props;\n\n const classes = useStyles();\n\n return (\n \n \n {children} \n
\n );\n};\n\nMinimal.propTypes = {\n children: PropTypes.node,\n className: PropTypes.string\n};\n\nexport default Minimal;\n","import React from 'react';\nimport { makeStyles } from '@material-ui/styles';\nimport { Grid, Typography } from '@material-ui/core';\n\nconst useStyles = makeStyles(theme => ({\n root: {\n padding: theme.spacing(4)\n },\n content: {\n paddingTop: 150,\n textAlign: 'center'\n },\n image: {\n marginTop: 50,\n display: 'inline-block',\n maxWidth: '100%',\n width: 560\n }\n}));\n\nconst NotFound = () => {\n const classes = useStyles();\n\n return (\n \n
\n \n \n
\n 404: The page you are looking for isn’t here\n \n
\n You either tried some shady route or you came here by mistake.\n Whichever it is, try using the navigation\n \n
\n
\n \n \n
\n );\n};\n\nexport default NotFound;\n","import React, { useState, useEffect } from \"react\";\nimport {\n Button,\n Dialog,\n Typography,\n TextField,\n Card,\n CardContent,\n // CardMedia,\n Grid\n} from \"@material-ui/core\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { CheckCircleOutline, HighlightOff } from \"@material-ui/icons\";\n// import ASG210Img from \"image/asg210.png\";\n\nimport { queryDeviceUpdate } from \"common/apiConfig\";\n\nconst useStyles = makeStyles((theme) => ({\n card: {\n minWidth: 260,\n maxWidth: 400,\n padding: theme.spacing(1)\n },\n select: {\n minWidth: 110\n },\n paper: {\n boxShadow: \"none\",\n overflow: \"hidden\"\n }\n}));\n\nconst UserDeviceConfigForm = (props) => {\n const classes = useStyles();\n const { open, handleClose, device, handleRefresh } = props;\n\n const [ values, setValues ] = useState({\n displayName: \"\"\n });\n\n const handleSave = async () => {\n // document update request\n let data = {\n displayName: values.displayName\n };\n try {\n const resp = await queryDeviceUpdate(device.id, data);\n if (resp.includes(\"OK\")) {\n console.log(\"resp\", resp);\n // refresh device list\n handleRefresh();\n }\n } catch (error) {\n console.log(error);\n }\n\n handleClose();\n };\n\n const handleChange = (name) => (event) => {\n // console.log(\"handleChange()\", name, event.target.value);\n setValues({ ...values, [name]: event.target.value });\n // error check\n };\n\n useEffect(\n () => {\n if (Object.keys(device).length > 0) {\n // Get initial value\n setValues({ ...values, displayName: device.displayName });\n }\n },\n [ device.displayName ]\n );\n\n return (\n \n \n {/* */}\n \n \n \n \n Device Id: \n \n \n \n {device.id}\n \n \n\n \n Product(Company): \n \n \n \n {device.hasOwnProperty(\"azureSphere\") ? device.azureSphere.product ? (\n device.azureSphere.product.name\n ) : (\n \"-\"\n ) : (\n \"-\"\n )}\n \n \n \n Device Group(Site): \n \n \n \n {device.hasOwnProperty(\"azureSphere\") ? device.azureSphere.deviceGroup ? (\n device.azureSphere.deviceGroup.name\n ) : (\n \"-\"\n ) : (\n \"-\"\n )}\n \n \n \n Connection state: \n \n \n \n {device.connectionState === \"Connected\" ? (\n \n ) : (\n \n )}\n \n \n \n State Updated Time: \n \n \n \n {new Date(device.connectionStateUpdatedTime).toLocaleString(\"en\", {\n timeZone: \"Asia/Seoul\"\n // timeZoneName: \"short\"\n })}\n \n \n \n {device.hasOwnProperty(\"properties\") ? (\n M4 Network Settings: \n ) : null}\n \n \n {device.hasOwnProperty(\n \"properties\"\n ) ? device.properties.reported.hasOwnProperty(\"M4_NETINFO\") ? (\n Object.keys(\n device.properties.reported[\"M4_NETINFO\"]\n ).map((name, index) => (\n \n {name}: {device.properties.reported[\"M4_NETINFO\"][name]}\n \n ))\n ) : (\n \n No Network Info\n \n ) : null}\n \n \n \n \n \n CANCLE\n \n \n SAVE\n \n
\n \n \n );\n};\n\nexport default UserDeviceConfigForm;\n","import React, { useState } from \"react\";\nimport PropTypes from \"prop-types\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TablePagination,\n TableContainer,\n Paper\n} from \"@material-ui/core\";\nimport { CheckCircleOutline, HighlightOff } from \"@material-ui/icons\";\nimport UserDeviceConfigForm from \"./UserDeviceConfigForm\";\n\nconst UserDeviceTable = (props) => {\n const { devices, handleRefresh } = props;\n const classes = useStyles();\n\n const [ rowsPerPage, setRowsPerPage ] = useState(10);\n const [ page, setPage ] = useState(0);\n\n const handlePageChange = (event, page) => {\n setPage(page);\n };\n\n const handleRowsPerPageChange = (event) => {\n setRowsPerPage(event.target.value);\n };\n\n return (\n \n
\n \n \n \n \n No \n Name \n Product(Company) \n Device Group(Site) \n {/* Device Id */}\n Connection state \n Connection State Updated Time \n \n \n \n {devices\n .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)\n .map((device, index) => (\n \n ))}\n \n
\n \n \n \n
\n );\n};\n\nconst DeviceRow = (props) => {\n const { device, index, handleRefresh } = props;\n\n const classes = useStyles();\n\n const [ clickedDeviceIndex, setClickedDeviceIndex ] = useState(0);\n const [ openConfigForm, setOpenConfigForm ] = useState(false);\n\n const handleDeviceClick = (index) => {\n // console.log(\"handleDeviceClick()\", index, device);\n setClickedDeviceIndex(index);\n setOpenConfigForm(true);\n };\n\n const handleClose = () => {\n setOpenConfigForm(false);\n };\n\n return (\n \n handleDeviceClick(index)}\n align=\"center\"\n >\n {index + 1} \n \n {device.hasOwnProperty(\"displayName\") ? device.displayName : \"-\"}\n \n \n {device.hasOwnProperty(\"azureSphere\") ? device.azureSphere.product ? (\n device.azureSphere.product.name\n ) : (\n \"-\"\n ) : (\n \"-\"\n )}\n \n \n {device.hasOwnProperty(\"azureSphere\") ? device.azureSphere.deviceGroup ? (\n device.azureSphere.deviceGroup.name\n ) : (\n \"-\"\n ) : (\n \"-\"\n )}\n \n {/* handleDeviceClick(index)}>\n \n {device.deviceId}\n \n */}\n handleDeviceClick(index)}>\n {device.connectionState === \"Connected\" ? (\n \n ) : (\n \n )}\n \n\n \n {device.hasOwnProperty(\"connectionStateUpdatedTime\") ? (\n new Date(device.connectionStateUpdatedTime).toLocaleString(\"en\", {\n timeZone: \"Asia/Seoul\"\n // timeZoneName: \"short\"\n })\n ) : (\n \"-\"\n )}\n \n \n \n \n );\n};\n\nconst useStyles = makeStyles((theme) => ({\n content: {\n padding: 0\n },\n table: {\n overflowX: \"auto\"\n },\n deviceRow: {\n // \"& > *\": {\n // borderBottom: \"unset\"\n // },\n cursor: \"pointer\"\n }\n}));\n\nUserDeviceTable.propTypes = {\n className: PropTypes.string,\n devices: PropTypes.array.isRequired\n};\n\nexport default UserDeviceTable;\n","import React, { useEffect, useCallback, useContext } from \"react\";\nimport { useRecoilState } from \"recoil\";\n\nimport { Button, Typography, CircularProgress } from \"@material-ui/core\";\nimport { makeStyles } from \"@material-ui/styles\";\n\nimport { MsalAuthContext } from \"contexts/msalAuthContext\";\nimport { queryUserDevice } from \"common/apiConfig\";\n// import DeviceTable from \"./DeviceTable\";\nimport UserDeviceTable from \"./UserDeviceTable\";\nimport { snackbarState, userDeviceListState, isDeviceLoadedState } from \"common/store\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(1)\n },\n text: {\n paddingTop: 50,\n paddingBottom: 50,\n textAlign: \"center\",\n color: theme.palette.primary.main\n },\n progressWrapper: {\n paddingTop: \"48px\",\n paddingBottom: \"24px\",\n display: \"flex\",\n justifyContent: \"center\"\n },\n button: {\n marginBottom: theme.spacing(2),\n marginTop: theme.spacing(2)\n }\n}));\n\nconst UserDeviceList = () => {\n const classes = useStyles();\n const authState = useContext(MsalAuthContext);\n\n const [ isLoaded, setIsLoaded ] = useRecoilState(isDeviceLoadedState);\n const [ userDevices, setUserDevices ] = useRecoilState(userDeviceListState);\n\n const [ snackbar, setSnackbar ] = useRecoilState(snackbarState);\n\n const openAlert = (message) => {\n setSnackbar({\n ...snackbar,\n open: true,\n message: message,\n severity: \"info\",\n autoHideDuration: 2000\n });\n };\n\n const getUserDevice = useCallback(\n async () => {\n try {\n if (authState.account.username.length > 0) {\n const deviceList = await queryUserDevice(authState.account.username);\n console.debug(\"queryUserDevice\", deviceList);\n\n setUserDevices(deviceList);\n setIsLoaded(true);\n\n localStorage.setItem(\"userdevice_list\", JSON.stringify(deviceList));\n console.info(\"Save user devices to web storage\");\n }\n } catch (error) {\n console.error(error);\n setIsLoaded(true);\n setUserDevices([]);\n }\n },\n [ authState.account.username ]\n );\n\n useEffect(\n () => {\n const localDevices = localStorage.getItem(\"userdevice_list\");\n if (localDevices) {\n console.info(\"Load devices from web storage\");\n setUserDevices(JSON.parse(localDevices));\n setIsLoaded(true);\n } else {\n getUserDevice();\n }\n },\n [ getUserDevice, setUserDevices ]\n );\n\n const handleRefresh = async () => {\n // console.log(\"Refresh user devices\");\n await getUserDevice();\n openAlert(\"Device list updated!\");\n };\n\n if (!isLoaded) {\n return (\n \n \n
\n );\n } else {\n return (\n \n
\n Refresh\n \n {userDevices.length !== 0 ? (\n
\n {/* */}\n\n \n
\n ) : (\n
\n There is no registered device.\n \n )}\n
\n );\n }\n};\n\nexport default UserDeviceList;\n","import React from \"react\";\nimport { useRecoilState } from \"recoil\";\n// import { makeStyles } from \"@material-ui/styles\";\nimport { makeStyles } from \"@material-ui/core\";\n\nimport { UserDeviceList } from \"./components\";\n\nimport { AlertSnackbar } from \"components\";\nimport { snackbarState } from \"common/store\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(3)\n },\n content: {\n marginTop: theme.spacing(2)\n }\n}));\n\nconst UserDeviceView = () => {\n const classes = useStyles();\n const [ snackbar, setSnackbar ] = useRecoilState(snackbarState);\n\n return (\n \n {/*
\n My Devices\n */}\n\n
\n\n
setSnackbar({ ...snackbar, open: false })}\n open={snackbar.open}\n autoHideDuration={snackbar.autoHideDuration}\n severity={snackbar.severity}\n />\n \n );\n};\n\nexport default UserDeviceView;\n","import React, { useState, useEffect } from \"react\";\nimport { useRecoilState } from \"recoil\";\n\nimport { makeStyles } from \"@material-ui/styles\";\nimport { TextField, Grid } from \"@material-ui/core\";\nimport { DataGrid } from \"@material-ui/data-grid\";\n\nimport { deviceIdState, deviceGroupState } from \"common/store\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(3),\n width: \"100%\"\n },\n select: {\n minWidth: 150\n },\n progressWrapper: {\n display: \"flex\",\n justifyContent: \"center\"\n },\n chip: {\n display: \"flex\"\n // justifyContent: \"center\"\n }\n}));\n\nconst columns = [\n { field: \"id\", headerName: \"ID\", width: 70 },\n { field: \"name\", headerName: \"Name\", width: 180 },\n { field: \"product\", headerName: \"Product(Company)\", width: 160 },\n { field: \"group\", headerName: \"Group(Site)\", width: 160 },\n { field: \"connectionState\", headerName: \"Connection State\", width: 180 }\n];\n\nconst SelectDeviceFromTable = (props) => {\n const classes = useStyles();\n const { userDevices, handleSelect } = props;\n\n const [ deviceId, setDeviceId ] = useRecoilState(deviceIdState);\n const [ deviceGroup, setDeviceGroup ] = useRecoilState(deviceGroupState);\n\n const [ deviceRows, setDeviceRows ] = useState([]);\n\n useEffect(\n () => {\n try {\n // ! get device rows\n let rows = [];\n userDevices.forEach((device, index) => {\n rows.push({\n id: index + 1,\n name: device.displayName,\n product: device.hasOwnProperty(\"azureSphere\")\n ? device.azureSphere.product ? device.azureSphere.product.name : \"-\"\n : \"-\",\n group: device.hasOwnProperty(\"azureSphere\")\n ? device.azureSphere.deviceGroup ? device.azureSphere.deviceGroup.name : \"-\"\n : \"-\",\n connectionState: device.connectionState\n // device.connectionState === \"Connected\" ? (\n // \n // ) : (\n // \n // )\n });\n });\n // console.log(\"rows\", rows);\n setDeviceRows(rows);\n } catch (error) {\n console.log(error);\n }\n },\n [ userDevices ]\n );\n\n useEffect(\n () => {\n if (deviceId !== \"\") {\n handleSelect(deviceId);\n\n try {\n // If device is selected from other pages, group will be selected automatically\n userDevices.map(\n (device) =>\n device.id === deviceId\n ? setDeviceGroup(device.azureSphere.deviceGroup)\n : null\n );\n } catch (error) {}\n }\n },\n [ deviceId, handleSelect ]\n );\n\n // const handleDeviceSelected = (params) => {\n // console.log(\"handleDeviceSelected\", params);\n // };\n\n const handleSelectionModelChange = (params) => {\n // selected rows\n console.log(\"handleSelectionModelChange:\", params, params.selectionModel.length);\n };\n\n return (\n \n
\n \n \n \n
\n \n \n\n
\n \n setDeviceId(e.target.value)}\n variant=\"outlined\"\n helperText=\"Select a device\"\n size=\"small\"\n disabled={deviceGroup.id.length > 0 ? false : true}\n />\n \n \n
\n );\n};\n\nexport default SelectDeviceFromTable;\n","import React, { useState, useRef } from \"react\";\nimport { useRecoilState, useRecoilValue } from \"recoil\";\nimport { makeStyles } from \"@material-ui/core\";\n// import { deviceIdState } from \"common/store\";\n\nimport { ProgressButton } from \"components\";\nimport { deviceIdState, userDeviceListState, isDeviceLoadedState } from \"common/store\";\n\nimport SelectDeviceFromTable from \"views/LinkedNode/SelectDeviceFromTable\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n margin: theme.spacing(5)\n }\n}));\n\nconst TestPage = () => {\n const classes = useStyles();\n const timer = useRef();\n\n const [ loading, setLoading ] = useState(false);\n const [ deviceId, setDeviceId ] = useRecoilState(deviceIdState);\n const isDeviceLoaded = useRecoilValue(isDeviceLoadedState);\n const userDevices = useRecoilValue(userDeviceListState);\n\n const handleClick = async () => {\n console.log(\"handleClick\");\n\n setLoading(true);\n timer.current = window.setTimeout(() => {\n setLoading(false);\n }, 2000);\n };\n\n const handleSelect = (value) => {\n setDeviceId(value);\n };\n\n return (\n \n
\n Test Button\n \n
\n
\n );\n};\n\nexport default TestPage;\n","import React, { useState, useEffect, useContext } from \"react\";\nimport { useRecoilState } from \"recoil\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport {\n Typography,\n Grid,\n Button,\n CircularProgress,\n TableContainer,\n Table,\n TableHead,\n TableBody,\n TableRow,\n TableCell,\n Paper,\n TextField,\n Avatar,\n colors\n} from \"@material-ui/core\";\nimport CheckIcon from \"@material-ui/icons/Check\";\n\nimport { MsalAuthContext } from \"contexts/msalAuthContext\";\n\nimport { createDocument, queryWithSql } from \"common/apiConfig\";\nimport { deploymentsCreate } from \"common/azsphereApi\";\nimport { fotaImageState } from \"common/store\";\nimport { ProgressButton } from \"components\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n paddingTop: theme.spacing(1)\n // maxWidth: 900\n },\n content: {\n paddingLeft: theme.spacing(3)\n },\n wrapper: {\n marginTop: theme.spacing(2),\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\"\n },\n imageGrid: {\n marginBottom: theme.spacing(1)\n },\n buttonProgress: {\n color: colors.blueGrey[500],\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n marginTop: -12,\n marginLeft: -12\n },\n textSuccess: {\n marginTop: theme.spacing(2),\n marginLeft: theme.spacing(2),\n color: colors.green[500],\n fontSize: \"2rem\"\n },\n avatar: {\n width: theme.spacing(5),\n height: theme.spacing(5),\n fontSize: \"0.75rem\",\n backgroundColor: colors.blueGrey[300],\n color: \"white\"\n },\n clearButton: {\n verticalAlign: \"bottom\"\n }\n}));\n\nconst imageInfo = [\n { avatar: \"App\", label: \"Application Image ID\" },\n { avatar: \"App\", label: \"Application Image ID\" },\n { avatar: \"App\", label: \"Application Image ID\" },\n { avatar: \"App\", label: \"Application Image ID\" }\n];\n\nconst imageRows = [\n { id: \"fileName\", label: \"Image file name\" },\n { id: \"imageId\", label: \"Image ID\" },\n { id: \"componentId\", label: \"Component ID\" }\n];\n\nconst uuidRegx = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/;\n\nconst CreateDeployment = (props) => {\n const { groupId } = props;\n const classes = useStyles();\n const authState = useContext(MsalAuthContext);\n\n const [ justCreateDep, setJustCreateDep ] = useState(false);\n\n // const fotaImages = useRecoilValue(fotaImageState);\n const [ fotaImages, setFotaImages ] = useRecoilState(fotaImageState);\n\n const [ imageIds, setImageIds ] = useState([ \"\", \"\", \"\", \"\" ]);\n\n const [ isValidImages, setIsValidImages ] = useState(false);\n\n const [ loading, setLoading ] = useState(false);\n const [ success, setSuccess ] = useState(false);\n\n const [ deploymentGetLoading, setDeploymentGetLoading ] = useState(false);\n\n const handleDeploy = () => {\n try {\n // make body for imageIds\n let imageIdArray = [];\n if (fotaImages.length === 0) {\n // imageIdArray = Object.values(imageIds).filter((id) => id.length > 0);\n imageIdArray = imageIds.filter((id) => id.length > 0);\n } else {\n imageIdArray = fotaImages.map((image) => image.imageId);\n }\n console.log(\"imageIdArray:\", imageIdArray);\n let imageIdData = JSON.stringify(imageIdArray);\n\n if (window.confirm(`Image Ids are right?\\n\\n${imageIdData}`)) {\n setSuccess(false);\n setLoading(true);\n createDeployment(imageIdData);\n }\n } catch (error) {\n console.log(error);\n }\n };\n\n const createDeployment = async (imageIdData) => {\n try {\n const resp = await deploymentsCreate(groupId, imageIdData);\n // console.log(\"createDeployment resp:\", resp);\n if (resp) {\n setSuccess(true);\n setLoading(false);\n }\n\n // Save document\n const data = {\n groupId: groupId,\n imageInfo: fotaImages,\n createdTime: new Date(),\n createdBy: authState.isAuthenticated ? authState.account.username : null\n };\n const result = await createDocument(\"FotaContainer\", data);\n console.log(\"result:\", result);\n } catch (error) {\n console.log(error);\n }\n };\n\n const handleChange = (index) => (event) => {\n // console.log(index, event.target.value);\n\n try {\n // if (name.includes(\"Image\")) {\n // setImageIds({ ...imageIds, [name]: event.target.value });\n // }\n let newImageIds = imageIds.slice();\n newImageIds[index] = event.target.value;\n setImageIds(newImageIds);\n } catch (error) {\n console.log(error);\n }\n };\n\n useEffect(\n () => {\n const checkValidImages = () => {\n let result;\n const isValidUuid = (id) => uuidRegx.test(id);\n\n if (fotaImages.length > 0) {\n // Check image and component Id\n let imageIdArray = fotaImages.map((image) => image.imageId);\n let componentIdArray = fotaImages.map((image) => image.componentId);\n\n result = imageIdArray.every(isValidUuid) && componentIdArray.every(isValidUuid);\n } else {\n // Check image id\n // let array = Object.values(imageIds);\n // let imageIdArray = array.filter((id) => id.length > 0);\n let imageIdArray = imageIds.filter((id) => id.length > 0);\n\n result = imageIdArray.every(isValidUuid);\n }\n // console.log(\"validation check:\", result);\n\n setIsValidImages(result);\n };\n\n checkValidImages();\n },\n [ fotaImages, imageIds ]\n );\n\n // const handleGetDeploymentClick = async () => {\n // setDeploymentGetLoading(true);\n // try {\n // const resp = await deploymentsList(groupId);\n // // console.log(\"@ getDeploymentList resp\", resp.Items);\n // if (resp) {\n // setDeploymentGetLoading(false);\n // // reverse array\n // let letestDeployment = resp.Items.reverse()[0];\n // console.log(\"letestDeployment\", letestDeployment);\n // setImageIds(letestDeployment.DeployedImages);\n // }\n // } catch (err) {\n // setDeploymentGetLoading(false);\n // console.log(\"handleGetDeploymentClick err\", err);\n // }\n // };\n\n const getLatestDeployment = async () => {\n setDeploymentGetLoading(true);\n try {\n let container = \"FotaContainer\";\n let select = \"SELECT c.groupId, c.imageInfo, c.createdTime, c.createdBy FROM c\";\n let where = ` WHERE c.groupId = \"${groupId}\"`;\n let order = \" ORDER BY c._ts DESC OFFSET 0 LIMIT 1\";\n\n const query = select + where + order;\n let result = await queryWithSql(container, query);\n\n if (result.length > 0) {\n // console.log(\"result[0] =>\", result[0]);\n setDeploymentGetLoading(false);\n setFotaImages(result[0].imageInfo);\n } else {\n setDeploymentGetLoading(false);\n setFotaImages([]);\n }\n } catch (err) {\n setDeploymentGetLoading(false);\n console.log(\"getLatestDeployment err\", err);\n }\n };\n\n const handleClear = () => {\n if (window.confirm(`Do you want to clear the currently image setttings?`)) {\n setFotaImages([]);\n }\n };\n\n return (\n \n
\n Enter image id(s) to deploy. \n If you have uploaded a new image in the previous step, it will be filled in\n automatically. \n \n\n {/*
setJustCreateDep(e.target.checked)}\n name=\"checkJustCreateDep\"\n color=\"primary\"\n />\n }\n label=\"Just Create deployment\"\n /> */}\n \n Get latest deployment\n \n\n \n {justCreateDep ? (\n
\n {fotaImages.map((image, index) => (\n
\n \n \n {imageInfo[index].avatar}\n \n \n \n \n \n \n ))}\n
\n ) : (\n
\n {fotaImages.length === 0 ? (\n
\n {/* {Object.keys(imageIds).map((name, index) => ( */}\n {imageIds.map((name, index) => (\n
\n \n \n {imageInfo[index].avatar}\n \n \n \n 0 ? (\n !uuidRegx.test(imageIds[index])\n ) : (\n false\n )\n }\n />\n \n \n ))}\n
\n ) : (\n
\n \n \n \n \n \n {\"No.\"} \n {imageRows.map((row, index) => (\n {row.label} \n ))}\n \n \n \n {fotaImages.map((image, imageIndex) => (\n \n {imageIndex + 1} \n {image.fileName} \n {image.imageId} \n {image.componentId} \n \n ))}\n \n
\n \n \n \n \n \n Clear current values\n \n
\n \n \n )}\n
\n )}\n\n
\n
\n id.length > 0).length === 0)\n }\n onClick={handleDeploy}\n >\n Create Deployment\n \n\n {loading && }\n
\n {success ?
: null}\n
\n {groupId.length === 0 ? (\n
\n Select a device group in Step 1.\n \n ) : (\n
\n {isValidImages ? null : (\n \n Invalid Image or Component ID\n \n )}\n
\n )}\n
\n \n );\n};\n\nexport default CreateDeployment;\n","import React, { useState } from \"react\";\n\nimport { makeStyles } from \"@material-ui/styles\";\nimport {\n Typography,\n Grid,\n Button,\n TextField,\n CircularProgress,\n Avatar,\n colors\n} from \"@material-ui/core\";\nimport CheckIcon from \"@material-ui/icons/Check\";\n\nimport { deploymentsCreate } from \"common/azsphereApi\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n paddingTop: theme.spacing(1)\n },\n content: {\n paddingLeft: theme.spacing(3)\n },\n wrapper: {\n position: \"relative\",\n display: \"flex\"\n },\n imageGrid: {\n marginBottom: theme.spacing(1)\n },\n buttonProgress: {\n color: colors.blueGrey[500],\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n marginTop: -12,\n marginLeft: -12\n },\n textSuccess: {\n marginTop: theme.spacing(1),\n marginLeft: theme.spacing(3),\n color: colors.green[500]\n },\n avatar: {\n width: theme.spacing(5),\n height: theme.spacing(5),\n fontSize: \"0.75rem\",\n backgroundColor: colors.blueGrey[300],\n color: \"white\"\n }\n}));\n\nconst imageInfo = [\n { avatar: \"HL\", label: \"A7 core Image ID\" },\n { avatar: \"RT\", label: \"M4 core Image A\" },\n { avatar: \"RT\", label: \"M4 core Image B\" },\n { avatar: \"Board\", label: \"Board configuration Image (ethernet)\" }\n];\n\nconst DeployFirmware = (props) => {\n const { groupId } = props;\n const classes = useStyles();\n\n const [ imageIds, setImageIds ] = useState({\n // 20201124 Case1-WIZ750SR-HL/RTApp.imagepackage\n hlImageId: \"\",\n rtAImageId: \"\",\n rtBImageId: \"\",\n configImageId: \"6c6b485d-d6bf-477b-b385-991eb849faa5\"\n });\n\n const [ validation, setValidation ] = useState({\n hlImageId: true,\n rtAImageId: true,\n rtBImageId: true,\n configImageId: true\n });\n\n const [ loading, setLoading ] = useState(false);\n const [ success, setSuccess ] = useState(false);\n\n const handleDeploy = () => {\n try {\n console.log(\"imageIds:\", imageIds);\n\n // make body for imageIds\n let idList = Object.values(imageIds);\n console.log(\"idList\", idList);\n let imageIdArray = idList.filter((id) => id.length > 0);\n let imageIdData = JSON.stringify(imageIdArray);\n\n if (window.confirm(`Image Ids are right?\\n\\n${imageIdData}`)) {\n setSuccess(false);\n setLoading(true);\n createDeployment(imageIdData);\n }\n } catch (error) {\n console.log(error);\n }\n };\n\n const createDeployment = async (imageIdData) => {\n try {\n const resp = await deploymentsCreate(groupId, imageIdData);\n // console.log(\"createDeployment resp:\", resp);\n if (resp) {\n setSuccess(true);\n setLoading(false);\n }\n } catch (error) {\n console.log(error);\n }\n };\n\n const handleChange = (name) => (event) => {\n console.log(name, event.target.value);\n\n try {\n if (name.includes(\"Image\")) {\n const uuidRegx = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/;\n const uuidResult = uuidRegx.test(event.target.value);\n // console.log(\"uuidResult:\", uuidResult);\n\n setImageIds({ ...imageIds, [name]: event.target.value });\n setValidation({ ...validation, [name]: uuidResult });\n }\n } catch (error) {\n console.log(error);\n }\n };\n\n return (\n \n {/*
\n Create Deployment\n */}\n
\n Enter image id(s) to deploy. \n Board Config Image is already deployed to use ethernet interface.\n \n
\n {Object.keys(imageIds).map((name, index) => (\n
\n \n \n {imageInfo[index].avatar}\n \n \n \n \n \n \n ))}\n\n {/* */}\n
\n \n \n 0 ? false : true}\n onClick={handleDeploy}\n style={{ marginTop: 10 }}\n >\n Create Deployment\n \n\n {loading && (\n \n )}\n {success ? : null}\n
\n \n \n
\n
\n );\n};\n\nexport default DeployFirmware;\n","import React, { useState, useEffect } from \"react\";\nimport {\n Dialog,\n Card,\n CardContent,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n CircularProgress,\n Typography\n} from \"@material-ui/core\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { imageGetMetadata } from \"common/azsphereApi\";\n\nconst useStyles = makeStyles((theme) => ({\n card: {\n minWidth: 450,\n padding: theme.spacing(2)\n },\n progressWrapper: {\n paddingTop: \"48px\",\n paddingBottom: \"24px\",\n display: \"flex\",\n justifyContent: \"center\"\n }\n}));\n\nconst ImagesDetailDialog = (props) => {\n const classes = useStyles();\n const { images, handleClose, open } = props;\n\n const [ metadataList, setMetadataList ] = useState([]);\n const [ isLoaded, setIsLoaded ] = useState(false);\n\n const getImageData = async (images) => {\n const imagesData = await Promise.all(\n images.map(\n (imageId) => new Promise((resolve) => resolve(imageGetMetadata(imageId)))\n )\n );\n setIsLoaded(true);\n setMetadataList(imagesData);\n console.log(\"getImageData\", imagesData);\n };\n\n useEffect(\n () => {\n if (images !== undefined) {\n if (images.length > 0 && open) {\n getImageData(images);\n }\n }\n },\n [ images, open ]\n );\n\n const handleDialogClose = () => {\n // Clear previous data\n setIsLoaded(false);\n setMetadataList([]);\n\n handleClose();\n };\n\n return (\n \n \n \n \n Deployed Images Information\n \n {isLoaded ? (\n \n \n \n No. \n Image Id \n Name \n Component Id \n Type \n \n \n \n {metadataList.map((metadata, index) => (\n \n {index + 1} \n {metadata.Id} \n {metadata.Name} \n {metadata.ComponentId} \n \n {metadata.Type === 0 ? \"Applications\" : metadata.Type}\n \n \n ))}\n \n
\n ) : (\n \n \n
\n )}\n \n \n \n );\n};\n\nexport default ImagesDetailDialog;\n","import React, { useState, useEffect, useCallback } from \"react\";\nimport { useRecoilState } from \"recoil\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TableContainer,\n TablePagination,\n Typography,\n CircularProgress,\n Button,\n Chip,\n Paper\n} from \"@material-ui/core\";\n\nimport { deploymentsList } from \"common/azsphereApi\";\nimport { snackbarState } from \"common/store\";\n\nimport ImagesDetailDialog from \"./ImagesDetailDialog\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n paddingTop: theme.spacing(3),\n maxWidth: 1100\n },\n progressWrapper: {\n paddingTop: \"48px\",\n paddingBottom: \"24px\",\n display: \"flex\",\n justifyContent: \"center\"\n },\n container: {\n padding: 0,\n width: \"100%\"\n },\n table: {\n overflowX: \"auto\",\n width: \"100%\"\n },\n button: {\n marginBottom: theme.spacing(2)\n },\n chip: {\n // display: \"flex\",\n justifyContent: \"center\",\n borderColor: \"#E0E0E0\"\n }\n}));\n\nconst DeploymentList = (props) => {\n const { groupId } = props;\n const classes = useStyles();\n\n const [ snackbar, setSnackbar ] = useRecoilState(snackbarState);\n\n const [ isLoaded, setIsLoaded ] = useState(false);\n const [ deploymentList, setDeploymentList ] = useState([]);\n\n const [ open, setOpen ] = useState(false);\n const [ selectedDeployment, setSelectedDeployment ] = useState({});\n\n const [ rowsPerPage, setRowsPerPage ] = useState(2);\n const [ page, setPage ] = useState(0);\n\n const getDeploymentList = useCallback(\n async () => {\n try {\n const resp = await deploymentsList(groupId);\n console.log(\"@ getDeploymentList resp\", resp.Items);\n if (resp) {\n setIsLoaded(true);\n // reverse array\n setDeploymentList(resp.Items.reverse());\n }\n\n setSnackbar({\n ...snackbar,\n open: true,\n message: \"Deployment list updated!\",\n severity: \"info\",\n autoHideDuration: 2000\n });\n } catch (err) {\n console.log(\"getDeploymentList err\", err);\n }\n },\n [ groupId ]\n );\n\n useEffect(\n () => {\n if (groupId.length > 0) {\n getDeploymentList();\n }\n },\n [ groupId, getDeploymentList ]\n );\n\n const handleClick = (deployment) => {\n setOpen(true);\n // setSelectedIndex(index);\n setSelectedDeployment(deployment);\n };\n\n const handlePageChange = (event, page) => {\n setPage(page);\n };\n\n const handleRowsPerPageChange = (event) => {\n setRowsPerPage(event.target.value);\n };\n\n return (\n \n {/*
\n Deployment List\n */}\n
\n Check deployment list from selected device group.\n \n\n {groupId.length > 0 ? (\n
\n {!isLoaded ? (\n
\n \n
\n ) : (\n
\n
getDeploymentList()}\n >\n Refresh\n \n {deploymentList.length === 0 ? (\n
No deployment data. \n ) : (\n
\n \n \n \n \n No. \n Deployment Id \n Deployed Images \n Deployed Date \n \n \n \n {deploymentList\n .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)\n .map((deployment, idx) => (\n handleClick(deployment)}\n key={idx}\n style={{ cursor: \"pointer\" }}\n >\n {idx + 1} \n {deployment.Id} \n \n {deployment.DeployedImages.map((imageId, index) => (\n \n ))}\n {/* {JSON.stringify(deployment.DeployedImages, null, 2)} */}\n \n \n {new Date(\n deployment.DeploymentDateUtc\n ).toLocaleString(\"en\", {\n timeZone: \"Asia/Seoul\"\n // timeZoneName: \"short\"\n })}\n \n \n ))}\n \n
\n \n \n \n )}\n
\n )}\n {Object.keys(selectedDeployment).length > 0 ? (\n
setOpen(false)}\n />\n ) : null}\n \n ) : (\n
\n Select a device group first.\n \n )}\n
\n );\n};\n\nexport default DeploymentList;\n","import React, { useState } from \"react\";\nimport { useRecoilValue, useRecoilState } from \"recoil\";\nimport {\n Typography,\n Grid,\n Button,\n CircularProgress,\n MenuItem,\n TextField,\n makeStyles,\n colors\n} from \"@material-ui/core\";\nimport CheckIcon from \"@material-ui/icons/Check\";\nimport { invokeMethod, updateAS3Info } from \"common/apiConfig\";\nimport { devicesMove } from \"common/azsphereApi\";\nimport { userDeviceListState, deviceIdState, snackbarState } from \"common/store\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n paddingTop: theme.spacing(3)\n },\n wrapper: {\n position: \"relative\",\n display: \"flex\"\n },\n successIcon: {\n color: colors.green[500],\n fontSize: 30,\n marginTop: 5,\n marginLeft: theme.spacing(3)\n },\n buttonProgress: {\n color: colors.blueGrey[500],\n marginTop: 5,\n marginLeft: theme.spacing(3)\n }\n}));\n\nconst UpdateDevice = (props) => {\n const classes = useStyles();\n const { groupId } = props;\n\n // const [ devices, setDeivces ] = useRecoilState(userDeviceListState);\n const userDevices = useRecoilValue(userDeviceListState);\n const [ deviceId, setDeviceId ] = useRecoilState(deviceIdState);\n const [ snackbar, setSnackbar ] = useRecoilState(snackbarState);\n\n const [ loading, setLoading ] = useState(false);\n const [ success, setSuccess ] = useState(false);\n\n const moveDevice = async () => {\n setSuccess(false);\n setLoading(true);\n try {\n const resp = await devicesMove(deviceId, groupId);\n if (resp) {\n setSuccess(true);\n setLoading(false);\n\n // Request update AS3 information\n updateAS3Info(deviceId);\n console.log(\"Send update request AS3 information for device\");\n }\n console.log(\"Device moved to current group\");\n } catch (error) {\n console.log(error);\n }\n };\n\n const handleUpdate = async () => {\n try {\n setLoading(true);\n\n // Check selected device's group\n const selectedDevice = userDevices.filter((device) => device.id === deviceId);\n console.log(\"selectedDevice >\", selectedDevice);\n if (selectedDevice[0].azureSphere.deviceGroup === null) {\n moveDevice();\n } else {\n let currentGroupId = selectedDevice[0].azureSphere.deviceGroup.id;\n if (currentGroupId !== groupId) {\n // Selected device's group !== Selected group -> update\n moveDevice();\n } else {\n console.info(\"would not move device group\");\n }\n }\n\n //! Send restart request to device\n let result = await invokeMethod(deviceId, \"WebForceRestart\", \"\");\n if (result) {\n setLoading(false);\n\n if (result.hasOwnProperty(\"ExceptionMessage\")) {\n console.log(\"result:\", result);\n // let errorCode = JSON.parse(result.Message).errorCode\n let errorMsg = JSON.parse(result.Message).message;\n setSnackbar({\n ...snackbar,\n open: true,\n message: errorMsg,\n autoHideDuration: 8000,\n severity: \"error\"\n });\n } else {\n console.log(\"Sent restart request\");\n setSnackbar({\n ...snackbar,\n open: true,\n message: \"Sent Update request to device\",\n autoHideDuration: 3000,\n severity: \"info\"\n });\n }\n }\n } catch (error) {\n console.log(error);\n setLoading(false);\n }\n };\n\n const handleChange = (event) => {\n setDeviceId(event.target.value);\n };\n\n return (\n \n
\n Select device to update and Click Update button. \n \n
\n [Note] The device will be moved to the selected group and restart for the update.\n \n If the current device's group is the same as the selected group, it will not be\n moved.\n \n
\n \n \n {userDevices.map((device, index) => (\n \n {device.displayName}\n \n ))}\n \n \n \n \n \n Update Device\n \n {loading && }\n {success ? : null}\n
\n \n \n
\n );\n};\n\nexport default UpdateDevice;\n","import React, { useState, useEffect } from \"react\";\nimport { useRecoilState } from \"recoil\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport {\n Typography,\n Button,\n CircularProgress,\n TextField,\n FormControlLabel,\n Checkbox,\n colors\n} from \"@material-ui/core\";\nimport DoneIcon from \"@material-ui/icons/Done\";\nimport { imageUpload } from \"common/azsphereApi\";\nimport { fotaImageState } from \"common/store\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n paddingTop: theme.spacing(1),\n marginBottom: 20\n },\n content: {\n paddingLeft: theme.spacing(3)\n },\n wrapper: {\n marginTop: theme.spacing(2),\n marginLeft: theme.spacing(2),\n position: \"relative\"\n },\n buttonProgress: {\n color: colors.blueGrey[500],\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n marginTop: -12,\n marginLeft: -12\n },\n textSuccess: {\n position: \"absolute\",\n marginLeft: theme.spacing(2),\n color: colors.green[500],\n fontSize: \"2rem\"\n },\n textWrapper: {\n margin: theme.spacing(2),\n fontSize: 14\n },\n selectButton: {\n width: 160,\n height: 35,\n backgroundColor: colors.blueGrey[300]\n },\n form: {\n \"& .MuiTextField-root\": {\n margin: theme.spacing(1),\n width: \"35ch\"\n }\n },\n container: {\n marginTop: theme.spacing(1),\n marginBottom: theme.spacing(1),\n display: \"flex\"\n }\n}));\n\nconst imageRows = [\n { id: \"fileName\", label: \"Image file name\" },\n { id: \"imageId\", label: \"Image ID\" },\n { id: \"componentId\", label: \"Component ID\" }\n];\n\nconst uuidRegx = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/;\n\nconst UploadImage = () => {\n const classes = useStyles();\n const formRef = React.useRef();\n\n const [ uploadResult, setUploadResult ] = useState(false);\n const [ uploadLoading, setUploadLoading ] = useState(false);\n\n const [ fileList, setFileList ] = useState([]);\n const [ isValidImages, setIsValidImages ] = useState(false);\n const [ isUploadOnly, setIsUploadOnly ] = useState(false);\n\n const [ fotaImages, setFotaImages ] = useRecoilState(fotaImageState);\n\n const handleSelect = (event) => {\n try {\n setUploadResult(false);\n\n const files = event.currentTarget.files;\n console.log(\"Image files\", typeof files, files);\n\n // const fileNames = Object.keys(files).map((index) => files[index].name);\n // console.log(\"fileNames\", fileNames);\n setFileList(files);\n\n // Init imageInfo\n const imageArray = Object.keys(files).map((index) => ({\n fileName: files[index].name,\n componentId: \"\",\n imageId: \"\"\n }));\n console.log(\"imageArray\", imageArray);\n setFotaImages(imageArray);\n } catch (error) {\n console.log(error);\n }\n };\n\n const handleUpload = async () => {\n // ! Save info to database\n\n try {\n setUploadLoading(true);\n let uploadSuccess = true;\n\n // for await (let idx of Object.keys(fileList)) {\n // const resp = await imageUpload(fileList[idx]);\n // console.log(\"resp\", resp);\n // if (!resp) {\n // uploadSuccess = false;\n // }\n // }\n\n // Parallel\n const promiseArray = Object.keys(fileList).map(\n (file, index) => new Promise((resolve) => resolve(imageUpload(fileList[index])))\n );\n // console.log(\"promiseArray\", promiseArray);\n const uploadResult = await Promise.all(promiseArray);\n console.log(\"Image update complete =>\", uploadResult);\n if (uploadResult.find((result) => result === false)) {\n uploadSuccess = false;\n }\n\n if (uploadSuccess) {\n setUploadResult(true);\n } else {\n setUploadResult(false);\n }\n setUploadLoading(false);\n } catch (error) {\n console.log(error);\n }\n };\n\n const handleChange = (fileIndex, rowId, event) => {\n console.log(\"handleChange =>\", rowId, event.target.value);\n try {\n let newArray = [ ...fotaImages ];\n newArray[fileIndex] = {\n ...fotaImages[fileIndex],\n [rowId]: event.target.value\n };\n setFotaImages(newArray);\n\n console.log(\"newArray:\", newArray);\n } catch (error) {\n console.log(error);\n }\n };\n\n const handleSubmit = async (event) => {\n event.preventDefault();\n console.log(\"@fotaImages:\", fotaImages);\n\n // Image upload\n handleUpload();\n };\n\n useEffect(\n () => {\n const checkValidImages = () => {\n let result;\n const isValidUuid = (id) => uuidRegx.test(id);\n\n if (fotaImages.length > 0) {\n // Check image and component Id\n let imageIdArray = fotaImages.map((image) => image.imageId);\n let componentIdArray = fotaImages.map((image) => image.componentId);\n\n result = imageIdArray.every(isValidUuid) && componentIdArray.every(isValidUuid);\n }\n // console.log(\"validation check:\", result);\n\n setIsValidImages(result);\n };\n\n checkValidImages();\n },\n [ fotaImages ]\n );\n\n return (\n \n
\n Select imagepackage file(s) to deploy and click Upload button. \n \n
setIsUploadOnly(e.target.checked)}\n name=\"checkUploadOnly\"\n color=\"primary\"\n />\n }\n label=\"Just Upload selected file\"\n />\n \n
\n setUploadResult(false)}\n className={classes.selectButton}\n >\n Select file(s)\n \n \n {Object.keys(fileList).length > 0 || fotaImages.length > 0 ? (\n \n {Object.keys(fileList).length} file(s) selected\n \n ) : (\n \n Select imagepackage file(s).\n \n )}\n
\n
\n
\n \n );\n};\n\nexport default UploadImage;\n","import React, { createContext, useEffect, useState } from \"react\";\nimport { HubConnectionBuilder, LogLevel } from \"@microsoft/signalr\";\nimport { useRecoilValue } from \"recoil\";\n\nimport { userDeviceListState } from \"common/store\";\n\nconst functionKey = process.env.REACT_APP_FUNCTION_ASGAPI_KEY;\nconst SignalContext = createContext();\n\nconst SignalProvider = (props) => {\n const [ values, setValues ] = useState({\n isLoaded: false,\n eventData: null\n });\n const [ connectionState, setConnectionState ] = useState(false);\n\n const userDeviceList = useRecoilValue(userDeviceListState);\n\n const connection = new HubConnectionBuilder()\n .withUrl(`${process.env.REACT_APP_FUNCTION_ASGAPI}?code=${functionKey}`)\n .withAutomaticReconnect()\n .configureLogging(\n process.env.NODE_ENV === \"development\" ? LogLevel.Debug : LogLevel.Warning\n )\n .build();\n\n useEffect(\n () => {\n async function start() {\n try {\n await connection.start();\n console.info(\"SignalR Connected.\");\n setConnectionState(true);\n } catch (err) {\n setConnectionState(false);\n console.error(err);\n setTimeout(start, 5000);\n }\n }\n\n connection.onclose((error) => {\n console.log(\"SignalR onclose:\", error);\n setConnectionState(false);\n start();\n });\n\n // Start the connection.\n if (!connectionState) {\n console.log(\"@@ Start the connection\");\n start();\n }\n\n try {\n connection.on(\"ReceiveMessage\", (messages) => {\n const dataArray = JSON.parse(messages);\n if (process.env.NODE_ENV === \"development\") {\n console.log(`SignalR received [${dataArray.length}] message.`);\n // console.log(\"Messages=>\", dataArray);\n }\n\n for (const message of dataArray) {\n setValues({\n isLoaded: true,\n eventData: message\n // eventData: JSON.parse(message)\n });\n\n // Filter log\n if (userDeviceList.length > 0) {\n const deviceIdList = userDeviceList.map((device) => device.deviceId);\n\n if (deviceIdList.includes(message.deviceId)) {\n console.info(\"Received message:\", message);\n }\n }\n }\n });\n } catch (error) {\n console.log(\"error\");\n }\n },\n [ values.isLoaded ]\n );\n\n return {props.children} ;\n};\n\nexport { SignalContext, SignalProvider };\n","import React, { useState, useEffect } from \"react\";\nimport { useRecoilState, useRecoilValue } from \"recoil\";\nimport PropTypes from \"prop-types\";\nimport clsx from \"clsx\";\nimport { lighten, makeStyles } from \"@material-ui/core/styles\";\nimport {\n Table,\n TableBody,\n TableCell,\n TableContainer,\n TableHead,\n TablePagination,\n TableRow,\n TableSortLabel,\n Toolbar,\n Typography,\n Paper,\n Checkbox,\n Button,\n CircularProgress,\n colors\n} from \"@material-ui/core\";\n// import { ToastContainer, toast } from \"react-toastify\";\n// import \"react-toastify/dist/ReactToastify.css\";\n\nimport { invokeMethod } from \"common/apiConfig\";\nimport { deviceIdState, snackbarState } from \"common/store\";\n\nconst headCells = [\n { id: \"mac\", disablePadding: true, label: \"Mac address\" },\n { id: \"name\", disablePadding: true, label: \"Name\" },\n { id: \"ver\", disablePadding: true, label: \"Current Version\" },\n { id: \"available\", disablePadding: true, label: \"Available Version\" },\n { id: \"status\", disablePadding: true, label: \"Status\" }\n];\n\nfunction descendingComparator(a, b, orderBy) {\n if (b[orderBy] < a[orderBy]) {\n return -1;\n }\n if (b[orderBy] > a[orderBy]) {\n return 1;\n }\n return 0;\n}\n\nfunction getComparator(order, orderBy) {\n return order === \"desc\"\n ? (a, b) => descendingComparator(a, b, orderBy)\n : (a, b) => -descendingComparator(a, b, orderBy);\n}\n\nfunction stableSort(array, comparator) {\n const stabilizedThis = array.map((el, index) => [ el, index ]);\n stabilizedThis.sort((a, b) => {\n const order = comparator(a[0], b[0]);\n if (order !== 0) return order;\n return a[1] - b[1];\n });\n return stabilizedThis.map((el) => el[0]);\n}\n\nfunction NodeTableHead(props) {\n const {\n classes,\n onSelectAllClick,\n order,\n orderBy,\n numSelected,\n rowCount,\n onRequestSort\n } = props;\n\n const createSortHandler = (property) => (event) => {\n onRequestSort(event, property);\n };\n\n return (\n \n \n \n 0 && numSelected < rowCount}\n checked={rowCount > 0 && numSelected === rowCount}\n onChange={onSelectAllClick}\n inputProps={{ \"aria-label\": \"select all desserts\" }}\n />\n \n {headCells.map((headCell) => (\n \n \n {headCell.label}\n {orderBy === headCell.id ? (\n \n {order === \"desc\" ? \"sorted descending\" : \"sorted ascending\"}\n \n ) : null}\n \n \n ))}\n \n \n );\n}\n\nNodeTableHead.propTypes = {\n classes: PropTypes.object.isRequired,\n numSelected: PropTypes.number.isRequired,\n onRequestSort: PropTypes.func.isRequired,\n onSelectAllClick: PropTypes.func.isRequired,\n order: PropTypes.oneOf([ \"asc\", \"desc\" ]).isRequired,\n orderBy: PropTypes.string.isRequired,\n rowCount: PropTypes.number.isRequired\n};\n\nconst useToolbarStyles = makeStyles((theme) => ({\n root: {\n paddingLeft: theme.spacing(2),\n paddingRight: theme.spacing(1)\n },\n highlight:\n theme.palette.type === \"light\"\n ? {\n color: theme.palette.secondary.main,\n backgroundColor: lighten(theme.palette.secondary.light, 0.85)\n }\n : {\n color: theme.palette.text.primary,\n backgroundColor: theme.palette.secondary.dark\n },\n title: {\n flex: \"1 1 100%\"\n },\n wrapper: {\n position: \"relative\",\n display: \"flex\"\n },\n buttonProgress: {\n color: colors.blueGrey[500],\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n marginTop: -12,\n marginLeft: -12\n }\n}));\n\nconst NodeTableToolbar = (props) => {\n const classes = useToolbarStyles();\n const { numSelected, handleUpdate, handleRefresh, loading } = props;\n\n return (\n 0\n })}\n >\n {numSelected > 0 ? (\n \n {numSelected} selected\n \n ) : (\n \n Node devices\n \n )}\n\n {numSelected > 0 ? (\n \n \n Update\n \n\n {loading && }\n
\n ) : (\n \n Refresh\n \n )}\n \n );\n};\n\nNodeTableToolbar.propTypes = {\n numSelected: PropTypes.number.isRequired\n};\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n width: \"100%\",\n maxWidth: 850,\n padding: theme.spacing(3)\n },\n paper: {\n width: \"100%\",\n marginBottom: theme.spacing(2)\n },\n table: {\n minWidth: 750\n },\n visuallyHidden: {\n border: 0,\n clip: \"rect(0 0 0 0)\",\n height: 1,\n margin: -1,\n overflow: \"hidden\",\n padding: 0,\n position: \"absolute\",\n top: 20,\n width: 1\n }\n}));\n\nexport default function NodeTable(props) {\n const classes = useStyles();\n const { nodeDevices, nodeFW, updateResult, handleRefresh } = props;\n\n const [ order, setOrder ] = useState(\"asc\");\n const [ orderBy, setOrderBy ] = useState(\"calories\");\n const [ selected, setSelected ] = useState([]);\n const [ page, setPage ] = useState(0);\n const [ rowsPerPage, setRowsPerPage ] = useState(3);\n\n const [ loading, setLoading ] = useState(false);\n const [ updateStatus, setUpdateStatus ] = useState([]);\n\n const deviceId = useRecoilValue(deviceIdState);\n const [ snackbar, setSnackbar ] = useRecoilState(snackbarState);\n\n useEffect(\n () => {\n if (nodeDevices.length > 0 && updateStatus.length === 0) {\n setUpdateStatus(new Array(nodeDevices.length).fill(\"READY\"));\n }\n },\n [ nodeDevices.length ]\n );\n\n useEffect(\n () => {\n try {\n if (updateResult.length > 0) {\n // console.log(\"Updated Result 1:\", updateResult);\n let newStatus = updateStatus.slice();\n let result = JSON.parse(updateResult);\n\n nodeDevices.map(\n (node, index) =>\n node.mac.split(\":\").join(\"\") === result.updatedMac\n ? (newStatus[index] =\n result.updatedResult === \"1\" ? \"UPDATING..2\" : \"READY\")\n : null\n );\n\n if (result.updatedResult === \"2\") {\n setLoading(false);\n setSnackbar({\n ...snackbar,\n open: true,\n message: `${result.updatedMac} update complete!`,\n autoHideDuration: 3000,\n severity: \"success\"\n });\n }\n\n console.log(\"Updated Result new status:\", newStatus);\n setUpdateStatus(newStatus);\n }\n } catch (error) {\n console.log(error);\n }\n },\n [ updateResult ]\n );\n\n const handleRequestSort = (event, property) => {\n const isAsc = orderBy === property && order === \"asc\";\n setOrder(isAsc ? \"desc\" : \"asc\");\n setOrderBy(property);\n };\n\n const handleSelectAllClick = (event) => {\n if (event.target.checked) {\n const newSelecteds = nodeDevices.map((n) => n.mac);\n setSelected(newSelecteds);\n return;\n }\n setSelected([]);\n };\n\n const handleClick = (event, name) => {\n // console.log(\"handleClick:\", name);\n\n const selectedIndex = selected.indexOf(name);\n let newSelected = [];\n\n if (selectedIndex === -1) {\n newSelected = newSelected.concat(selected, name);\n } else if (selectedIndex === 0) {\n newSelected = newSelected.concat(selected.slice(1));\n } else if (selectedIndex === selected.length - 1) {\n newSelected = newSelected.concat(selected.slice(0, -1));\n } else if (selectedIndex > 0) {\n newSelected = newSelected.concat(\n selected.slice(0, selectedIndex),\n selected.slice(selectedIndex + 1)\n );\n }\n\n setSelected(newSelected);\n };\n\n const handleChangePage = (event, newPage) => {\n setPage(newPage);\n };\n\n const handleChangeRowsPerPage = (event) => {\n setRowsPerPage(parseInt(event.target.value, 10));\n setPage(0);\n };\n\n const isSelected = (macaddr) => selected.indexOf(macaddr) !== -1;\n\n const handleUpdate = async () => {\n console.log(\"Start Update\", selected, updateStatus);\n setLoading(true);\n\n // Update status\n let newStatus = updateStatus.slice();\n selected.map((selectedMac) =>\n nodeDevices.forEach((dev, index) => {\n if (dev.mac === selectedMac) {\n newStatus[index] = \"UPDATING..1\";\n }\n })\n );\n // console.log(\"newStatus:\", newStatus);\n setUpdateStatus(newStatus);\n\n // Remove colon\n let maclist = selected.map((mac) => mac.split(\":\").join(\"\"));\n console.log(\"maclist:\", maclist);\n\n // Update payload message\n const message = maclist.join(\",\");\n\n try {\n let result = await invokeMethod(deviceId, \"Update\", message);\n if (result) {\n // setLoading(false);\n if (result.hasOwnProperty(\"ExceptionMessage\")) {\n console.log(\"result:\", result);\n let errorMsg = JSON.parse(result.Message).message;\n setSnackbar({\n ...snackbar,\n open: true,\n message: errorMsg,\n autoHideDuration: 8000,\n severity: \"error\"\n });\n } else {\n console.log(\"Sent update command\", message);\n setSnackbar({\n ...snackbar,\n open: true,\n message: \"Sent update request successfully\",\n autoHideDuration: 5000,\n severity: \"info\"\n });\n }\n\n // 개별 상태 업데이트 필요\n // setUpdateStatus(new Array(nodeDevices.length).fill(\"READY\"));\n }\n } catch (error) {\n setLoading(false);\n console.log(error);\n }\n // setLoading(false);\n };\n\n if (nodeDevices.length === 0) {\n return (\n There is no connected node device. \n );\n } else {\n return (\n \n
\n
\n \n \n \n \n \n {stableSort(nodeDevices, getComparator(order, orderBy))\n .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)\n .map((row, index) => {\n const isItemSelected = isSelected(row.mac);\n const labelId = `enhanced-table-checkbox-${index}`;\n\n return (\n handleClick(event, row.mac)}\n role=\"checkbox\"\n aria-checked={isItemSelected}\n tabIndex={-1}\n key={row.mac}\n selected={isItemSelected}\n >\n \n \n \n \n {row.mac}\n \n {row.name} \n \n \n {row.ver}\n
\n \n \n \n {nodeFW}\n
\n \n \n {updateStatus[index] === \"READY\" ? (\n updateStatus[index]\n ) : (\n \n {updateStatus[index]}\n
\n )}\n \n \n );\n })}\n \n
\n \n \n \n
\n {/*
*/}\n
\n );\n }\n}\n","import React, { useState, useEffect, useContext } from \"react\";\nimport { useRecoilState, useRecoilValue } from \"recoil\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { Typography, Grid, CircularProgress } from \"@material-ui/core\";\n\nimport { SignalContext } from \"contexts/signalContext\";\nimport { MsalAuthContext } from \"contexts/msalAuthContext\";\nimport { queryUserDevice } from \"common/apiConfig\";\n\nimport { deviceIdState, userDeviceListState, isDeviceLoadedState } from \"common/store\";\nimport NodeTable from \"./NodeTable\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(1)\n },\n button: {\n marginLeft: theme.spacing(3)\n }\n}));\n\nconst NodeFotaView = () => {\n const classes = useStyles();\n const signalState = useContext(SignalContext);\n const authState = useContext(MsalAuthContext);\n\n const [ isLoaded, setIsLoaded ] = useRecoilState(isDeviceLoadedState);\n const [ userDevices, setUserDevices ] = useRecoilState(userDeviceListState);\n // const userDevices = useRecoilValue(userDeviceListState);\n // const isLoaded = useRecoilValue(isDeviceLoadedState);\n const deviceId = useRecoilValue(deviceIdState);\n\n const [ nodeDevices, setNodeDevices ] = useState([]);\n const [ nodeFW, setNodeFW ] = useState(\"\");\n\n const [ updateResult, setUpdateResult ] = useState(\"\");\n\n useEffect(\n () => {\n try {\n // Initial value\n const selectedDevice = userDevices.filter((device) => device.id === deviceId)[0];\n if (selectedDevice !== undefined) {\n console.log(\"@Init node devices\");\n getNodeInfo(selectedDevice);\n }\n } catch (error) {\n console.log(error);\n }\n },\n [ userDevices, deviceId ]\n );\n\n useEffect(\n () => {\n const getSignalData = async () => {\n try {\n const signalData = signalState.eventData;\n if (signalData !== null) {\n // Check message source: Telemetry / twinChangeEvents\n if (signalData.messageSource === \"twinChangeEvents\") {\n console.log(\"Twin change event:\", signalData);\n\n if (signalData[\"deviceId\"] === deviceId) {\n console.log(\"@Update node devices\");\n getNodeInfo(signalData.message);\n\n //? Update device document\n }\n } else if (signalData.messageSource === \"Telemetry\") {\n // node update event check\n if (signalData.message.hasOwnProperty(\"updatedMac\")) {\n setUpdateResult(JSON.stringify(signalData.message));\n }\n }\n }\n } catch (err) {\n console.log(err);\n }\n };\n\n // start subscribe signal\n getSignalData();\n },\n [ signalState.eventData ]\n );\n\n const getNodeInfo = (data) => {\n // Get node device information from reported properties\n try {\n if (data.hasOwnProperty(\"properties\")) {\n if (data.properties.hasOwnProperty(\"reported\")) {\n if (data.properties.reported.hasOwnProperty(\"NodeDevices\")) {\n // Node device list\n let newNodeDevices = data.properties.reported.NodeDevices;\n // console.log(\"=> NodeDevices:\", newNodeDevices);\n setNodeDevices(newNodeDevices);\n }\n if (data.properties.reported.hasOwnProperty(\"ASG_INFO\")) {\n // get available NodeFW\n if (data.properties.reported[\"ASG_INFO\"].hasOwnProperty(\"NodeFW\")) {\n let newNodeFW = data.properties.reported[\"ASG_INFO\"].NodeFW;\n // console.log(\"=> NodeFW:\", newNodeFW);\n setNodeFW(newNodeFW);\n } else {\n setNodeFW(\"-\");\n }\n }\n }\n }\n } catch (error) {\n console.log(error);\n }\n };\n\n const handleRefresh = async () => {\n try {\n if (authState.account.username.length > 0) {\n const deviceList = await queryUserDevice(authState.account.username);\n console.debug(\"queryUserDevice\", deviceList);\n\n setUserDevices(deviceList);\n setIsLoaded(true);\n\n localStorage.setItem(\"userdevice_list\", JSON.stringify(deviceList));\n console.info(\"Save user devices to web storage\");\n }\n } catch (error) {\n console.error(error);\n setIsLoaded(true);\n setUserDevices([]);\n }\n };\n\n if (!isLoaded) {\n return (\n \n \n
\n );\n } else {\n return (\n \n {/* \n Refresh\n */}\n \n {/* node device table */}\n {deviceId.length > 0 ? (\n \n ) : (\n \n Device not selected. Select a target device.\n \n )}\n \n
\n );\n }\n};\n\nexport default NodeFotaView;\n","import React, { useState } from \"react\";\nimport { useRecoilState, useRecoilValue } from \"recoil\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport {\n Typography,\n Grid,\n TextField,\n MenuItem,\n CircularProgress,\n Stepper,\n Step,\n StepLabel,\n StepContent,\n Button,\n Paper,\n Switch,\n FormControlLabel\n} from \"@material-ui/core\";\n\nimport { AlertSnackbar } from \"components\";\nimport {\n snackbarState,\n targetGroupIdState,\n groupListState,\n groupListLoadedState\n} from \"common/store\";\n\nimport {\n // DeployFirmware,\n CreateDeployment,\n DeploymentList,\n UploadImage,\n UpdateDevice,\n NodeFotaView\n} from \"./components\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(3)\n },\n contents: {\n paddingTop: theme.spacing(2),\n paddingLeft: theme.spacing(1)\n },\n button: {\n marginTop: theme.spacing(2),\n marginRight: theme.spacing(1)\n },\n actionsContainer: {\n marginBottom: theme.spacing(2)\n },\n resetContainer: {\n padding: theme.spacing(3)\n }\n}));\n\nconst DeviceFotaView = () => {\n const classes = useStyles();\n\n const [ snackbar, setSnackbar ] = useRecoilState(snackbarState);\n\n const groupList = useRecoilValue(groupListState);\n const groupLoaded = useRecoilValue(groupListLoadedState);\n // const [ groupList, setGroupList ] = useRecoilState(groupListState);\n // const [ groupLoaded, setGroupLoaded ] = useRecoilState(groupListLoadedState);\n\n const [ groupId, setGroupId ] = useRecoilState(targetGroupIdState);\n\n const [ activeStep, setActiveStep ] = useState(0);\n const [ isExpanded, setIsExpanded ] = useState(false);\n\n const handleChange = (event) => {\n // console.log(name, event.target.value);\n setGroupId(event.target.value);\n };\n\n function getSteps() {\n return [\n \"Select Device Group\",\n \"Upload Imagepackage\",\n \"Create a Deployment\",\n \"Check the Deployment\",\n \"Update ASG Device\",\n \"Update Node Device\"\n ];\n }\n\n function getStepContent(step) {\n switch (step) {\n case 0:\n return (\n \n \n \n Select a device group to deploy firmware.\n \n \n \n {!groupLoaded ? (\n \n ) : (\n \n {groupList.map((group, index) => (\n \n {group.Name}\n \n ))}\n \n )}\n \n \n );\n case 1:\n return ;\n case 2:\n // return ;\n return ;\n case 3:\n return ;\n case 4:\n return ;\n case 5:\n return ;\n default:\n return \"Unknown step\";\n }\n }\n\n const steps = getSteps();\n\n return (\n \n {/*
\n FOTA\n */}\n\n
setSnackbar({ ...snackbar, open: false })}\n open={snackbar.open}\n autoHideDuration={snackbar.autoHideDuration}\n severity={snackbar.severity}\n />\n\n \n
setIsExpanded(!isExpanded)}\n name=\"expand\"\n inputProps={{ \"aria-label\": \"secondary checkbox\" }}\n />\n }\n label=\"Expand All Steps\"\n style={{ marginBottom: 10 }}\n />\n\n {/* setActiveStep(0)}\n className={classes.button}\n >\n Reset Step\n */}\n\n \n {steps.map((label, index) => (\n \n \n \n {label}\n \n \n \n {getStepContent(index)} \n {isExpanded ? null : (\n \n
\n \n setActiveStep((prevActiveStep) => prevActiveStep - 1)}\n className={classes.button}\n >\n Back\n \n \n setActiveStep((prevActiveStep) => prevActiveStep + 1)}\n className={classes.button}\n disabled={groupId.length > 0 ? false : true}\n >\n {activeStep === steps.length - 1 ? \"Finish\" : \"Next\"}\n \n
\n
\n )}\n \n \n ))}\n \n {activeStep === steps.length && (\n \n All steps completed! \n \n setActiveStep(0)}\n className={classes.button}\n >\n Reset\n \n
\n \n )}\n \n \n );\n};\n\nexport default DeviceFotaView;\n","import React, { useState, useEffect, useContext } from \"react\";\nimport { useRecoilState } from \"recoil\";\n\nimport { makeStyles } from \"@material-ui/styles\";\nimport { TextField, MenuItem, Grid, CircularProgress, Chip } from \"@material-ui/core\";\nimport { MsalAuthContext } from \"contexts/msalAuthContext\";\nimport { deviceIdState, deviceGroupState } from \"common/store\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(3),\n width: \"100%\"\n },\n select: {\n minWidth: 150\n },\n progressWrapper: {\n display: \"flex\",\n justifyContent: \"center\"\n },\n chip: {\n display: \"flex\"\n // justifyContent: \"center\"\n }\n}));\n\nconst SelectUserDevice = (props) => {\n const classes = useStyles();\n const { userDevices, handleSelect } = props;\n const authState = useContext(MsalAuthContext);\n\n const [ deviceId, setDeviceId ] = useRecoilState(deviceIdState);\n const [ deviceGroup, setDeviceGroup ] = useRecoilState(deviceGroupState);\n\n const [ userGroupList, setUserGroupList ] = useState([]);\n const [ userDevicesInGroup, setUserDevicesInGroup ] = useState([]);\n\n const [ values, setValues ] = useState({\n productId: authState.product.id,\n productName: authState.product.name\n });\n\n useEffect(\n () => {\n try {\n if (authState.product !== \"\") {\n setValues({\n productId: authState.product.id,\n productName: authState.product.name\n });\n } else {\n setValues({\n productId: null,\n productName: null\n });\n }\n } catch (error) {\n console.log(error);\n }\n },\n [ authState ]\n );\n\n useEffect(\n () => {\n try {\n const groups = userDevices.map((dev) => dev.azureSphere.deviceGroup);\n // console.log(\"groups\", groups);\n\n // Filter valid values\n let availableGroups = groups.filter((group) => group !== null);\n\n // remove duplicate\n const uniqueGroups = Array.from(\n new Set(availableGroups.map((g) => g.id))\n ).map((id) => {\n return availableGroups.find((group) => group.id === id);\n });\n // console.log(\"uniqueGroups\", uniqueGroups);\n\n setUserGroupList(uniqueGroups);\n\n if (uniqueGroups.length === 1) {\n setDeviceGroup({ ...deviceGroup, id: uniqueGroups[0].id });\n }\n } catch (error) {\n console.log(error);\n }\n },\n [ userDevices ]\n );\n\n useEffect(\n () => {\n try {\n // console.log(\"deviceGroup\", deviceGroup);\n if (deviceGroup.id.length > 0) {\n // console.log(\"userDevices\", userDevices);\n\n // Filter valid devices\n const availableDevices = userDevices.filter(\n (device) => device.azureSphere.deviceGroup !== null\n );\n\n const devicesInGroup = availableDevices.filter(\n (dev) => dev.azureSphere.deviceGroup.id === deviceGroup.id\n );\n // console.log(\"devicesInGroup\", devicesInGroup);\n\n setUserDevicesInGroup(devicesInGroup);\n }\n } catch (error) {\n console.log(error);\n }\n },\n [ deviceGroup.id, userDevices ]\n );\n\n useEffect(\n () => {\n if (deviceId !== \"\") {\n handleSelect(deviceId);\n\n try {\n // If device is selected from other pages, group will be selected automatically\n userDevices.map(\n (device) =>\n device.id === deviceId\n ? setDeviceGroup(device.azureSphere.deviceGroup)\n : null\n );\n } catch (error) {}\n }\n },\n [ deviceId, handleSelect ]\n );\n\n return (\n \n
\n \n \n \n \n {userGroupList.length === 0 ? (\n \n \n
\n ) : (\n setDeviceGroup({ ...deviceGroup, id: e.target.value })}\n variant=\"outlined\"\n helperText=\"Device Group (Site)\"\n size=\"small\"\n disabled={userGroupList.length > 0 ? false : true}\n >\n {userGroupList.map((group, index) => (\n \n {group.name}\n \n ))}\n \n )}\n \n \n {userDevicesInGroup.length === 0 ? (\n \n \n
\n ) : (\n setDeviceId(e.target.value)}\n variant=\"outlined\"\n helperText=\"Select a device\"\n size=\"small\"\n disabled={deviceGroup.id.length > 0 ? false : true}\n >\n {userDevicesInGroup.map((userDevice, index) => (\n \n {userDevice.displayName}\n \n ))}\n \n )}\n \n \n
\n );\n};\n\nexport default SelectUserDevice;\n","import React, { useCallback } from \"react\";\nimport { useRecoilValue, useRecoilState } from \"recoil\";\n\nimport { makeStyles } from \"@material-ui/styles\";\nimport { Button } from \"@material-ui/core\";\nimport SearchIcon from \"@material-ui/icons/Search\";\nimport { sendC2dMessage } from \"common/apiConfig\";\nimport { deviceIdState, snackbarState, deviceIndexState } from \"common/store\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(3)\n },\n divider: {\n margin: theme.spacing(1)\n }\n}));\n\nconst SearchDevice = (props) => {\n const { buttonDisable } = props;\n const classes = useStyles();\n\n const deviceId = useRecoilValue(deviceIdState);\n const deviceIndex = useRecoilValue(deviceIndexState);\n const [ snackbar, setSnackbar ] = useRecoilState(snackbarState);\n\n const handleSearch = useCallback(\n async () => {\n console.log(\"handleSearch\");\n\n if (await sendC2dMessage(deviceId, `${deviceIndex},0,`)) {\n console.log(\"Send search command\");\n setSnackbar({\n ...snackbar,\n open: true,\n message: \"Sent search request.\\nWaiting for a response from device...\",\n autoHideDuration: 5000,\n severity: \"success\"\n });\n }\n },\n [ deviceId, deviceIndex ]\n );\n\n return (\n \n {buttonDisable ? null : (\n }\n disabled={buttonDisable}\n >\n Search Device \n \n )}\n
\n );\n};\n\nexport default SearchDevice;\n","import React, { useState, useEffect } from \"react\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { TextField, MenuItem, Grid, Typography, Paper, Button } from \"@material-ui/core\";\nimport { sendC2dMessage } from \"common/apiConfig\";\n\nimport { useSetRecoilState, useRecoilValue } from \"recoil\";\nimport { snackbarState, deviceIndexState, deviceIdState } from \"common/store\";\n\nconst serialConfigName = [\n \"Baud rate\",\n \"Data bit\",\n \"Parity bit\",\n \"Stop bit\",\n \"Flow control\"\n];\nconst serialConfigValues = [\n [\n 300,\n 600,\n 1200,\n 1800,\n 2400,\n 4800,\n 9600,\n 14400,\n 19200,\n 28800,\n 38400,\n 57600,\n 115200,\n 230400,\n 460800\n ],\n [ \"7 Bit\", \"8 Bit\" ],\n [ \"NONE\", \"ODD\", \"EVEN\" ],\n [ \"1 Bit\", \"2 Bit\" ],\n [ \"NONE\", \"XON/XOFF\", \"RTS/CTS\", \"RTS on TX\", \"RTS on TX (invert)\" ]\n];\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(1),\n width: \"100%\"\n },\n paper: {\n padding: theme.spacing(2)\n // height: theme.spacing(15)\n },\n select: {\n minWidth: 110\n },\n subject: {\n marginBottom: 30\n }\n}));\n\nconst SerialConfig = (props) => {\n const { macaddr, getData, setData } = props;\n const classes = useStyles();\n\n const setSnackbar = useSetRecoilState(snackbarState);\n const deviceIndex = useRecoilValue(deviceIndexState);\n const deviceId = useRecoilValue(deviceIdState);\n\n const [ serialValues, setSerialValues ] = useState([ \"\", \"\", \"\", \"\", \"\" ]);\n\n useEffect(\n () => {\n if (setData !== undefined) {\n const params = setData.split(\",\");\n console.log(\"serial params\", params);\n const data = params.splice(3);\n console.log(\"serial data\", data);\n\n // [12,1,0,0,0]\n setSerialValues(data);\n }\n },\n [ setData ]\n );\n\n useEffect(\n () => {\n if (getData !== undefined) {\n const params = getData.split(\",\");\n console.log(\"serial params\", params);\n const data = params.splice(3);\n console.log(\"serial data\", data);\n\n setSerialValues(data);\n }\n },\n [ getData ]\n );\n\n const handleValueChange = (index) => (event) => {\n let newValues = serialValues.slice();\n newValues[index] = event.target.value;\n setSerialValues(newValues);\n };\n\n const handleGet = async () => {\n const serialGetCmd = [ deviceIndex, \"4\", macaddr ].join(\",\");\n if (await sendC2dMessage(deviceId, serialGetCmd)) {\n console.log(\"Send get serial command:\", serialGetCmd);\n openAlert(`[${macaddr}] Sent 'Get UART' message`);\n }\n };\n\n const handleSet = async () => {\n // console.log(\"handleSet\", serialValues);\n const serialSetCmd = [ deviceIndex, \"5\", macaddr, serialValues.join(\",\") ].join(\",\");\n if (await sendC2dMessage(deviceId, serialSetCmd)) {\n console.log(\"Send set serial command:\", serialSetCmd);\n openAlert(`[${macaddr}] Sent 'Set UART' message`);\n }\n };\n\n const openAlert = (message) => {\n setSnackbar({\n open: true,\n message: message,\n severity: \"success\",\n autoHideDuration: 3000\n });\n };\n\n return (\n \n
\n \n Serial Configuration\n \n \n {serialValues.map((serialValue, idx) => (\n \n \n {serialConfigValues[idx].map((item, index) => (\n \n {item}\n \n ))}\n \n \n ))}\n \n \n \n \n \n Get\n \n \n \n \n Setting\n \n \n \n \n
\n );\n};\n\nexport default SerialConfig;\n","import React, { useState, useEffect } from \"react\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { TextField, Grid, Typography, Paper, Button } from \"@material-ui/core\";\nimport { sendC2dMessage } from \"common/apiConfig\";\n\nimport { useSetRecoilState, useRecoilValue } from \"recoil\";\nimport { snackbarState, deviceIndexState, deviceIdState } from \"common/store\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(1),\n width: \"100%\"\n },\n paper: {\n padding: theme.spacing(2)\n // height: theme.spacing(15)\n },\n input: {\n minWidth: 110\n },\n subject: {\n marginBottom: 30\n }\n}));\n\nconst deviceConfigName = [\n \"MAC address\",\n \"F/W version\",\n \"Product name\",\n \"Operation status\"\n // \"UART interface\"\n];\n\nconst DeviceConfig = (props) => {\n const { macaddr, getData, searchData } = props;\n const classes = useStyles();\n\n const setSnackbar = useSetRecoilState(snackbarState);\n const deviceIndex = useRecoilValue(deviceIndexState);\n const deviceId = useRecoilValue(deviceIdState);\n\n const [ deviceValues, setDeviceValues ] = useState([ \"\", \"\", \"\", \"\", \"\" ]);\n // const [ result, setResult ] = useState(\"\");\n\n const handleGet = async () => {\n const devInfoGetCmd = [ deviceIndex, \"1\", macaddr ].join(\",\");\n if (await sendC2dMessage(deviceId, devInfoGetCmd)) {\n console.log(\"Send get device info command:\", devInfoGetCmd);\n setSnackbar({\n open: true,\n message: `[${macaddr}] Sent Get Device Info OK`,\n severity: \"success\",\n autoHideDuration: 3000\n });\n }\n };\n\n useEffect(\n () => {\n if (getData !== undefined) {\n const params = getData.split(\",\");\n // console.log(\"device info params\", params);\n\n // Get data part\n const data = params.splice(3);\n // console.log(\"device info data\", data);\n\n setDeviceValues(data);\n }\n },\n [ getData ]\n );\n\n useEffect(\n () => {\n if (searchData !== undefined) {\n // \"00:08:DC:53:AE:8F,00:08:DC:53:AE:8F,1.3.3,WIZ750SR,OPEN,1,1,192.168.50.227,255.255.255.0,192.168.50.1\"\n // index 1~4: 00:08:DC:53:AE:8F,1.3.3,WIZ750SR,OPEN\n const params = searchData.split(\",\");\n const deviceConfigParams = params.slice(1, 5);\n console.log(\"deviceConfigParams\", deviceConfigParams);\n\n setDeviceValues(deviceConfigParams);\n }\n },\n [ searchData ]\n );\n\n return (\n \n
\n \n \n \n Device Info\n \n \n {/* \n {result}\n */}\n \n \n {deviceConfigName.map((name, index) => (\n \n \n \n ))}\n \n \n Get\n \n \n \n \n
\n );\n};\n\nexport default DeviceConfig;\n","import React, { useState, useEffect } from \"react\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { TextField, Grid, Typography, Paper, Button } from \"@material-ui/core\";\nimport Radio from \"@material-ui/core/Radio\";\nimport RadioGroup from \"@material-ui/core/RadioGroup\";\nimport FormControlLabel from \"@material-ui/core/FormControlLabel\";\nimport FormControl from \"@material-ui/core/FormControl\";\nimport { sendC2dMessage } from \"common/apiConfig\";\n\nimport { useSetRecoilState, useRecoilValue } from \"recoil\";\nimport { snackbarState, deviceIndexState, deviceIdState } from \"common/store\";\n\nconst operationMode = [ \"TCP Client\", \"TCP Server\", \"TCP Mixed\", \"UDP\" ];\nconst allocationMode = [ \"Static IP\", \"DHCP\" ];\nconst netConfig = [ \"Local IP\", \"Subnet mask\", \"Gateway\", \"DNS server\" ];\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(1),\n width: \"100%\"\n },\n paper: {\n padding: theme.spacing(2)\n // height: theme.spacing(40)\n },\n input: {\n minWidth: 110\n },\n lineSpace: {\n marginBottom: 10\n },\n subject: {\n marginBottom: 20\n },\n radio: {\n minWidth: 130\n }\n}));\n\nconst NetworkConfig = (props) => {\n const { macaddr, getData, setData } = props;\n const classes = useStyles();\n\n const deviceIndex = useRecoilValue(deviceIndexState);\n const deviceId = useRecoilValue(deviceIdState);\n\n const setSnackbar = useSetRecoilState(snackbarState);\n const [ networkValues, setNetworkValues ] = useState([\n \"\",\n \"\",\n \"\",\n \"\",\n \"\",\n \"\",\n \"\",\n \"\",\n \"\"\n ]);\n\n useEffect(\n () => {\n if (setData !== undefined) {\n const params = setData.split(\",\");\n console.log(\"network set params\", params);\n const data = params.splice(3);\n // console.log(\"network set data\", data);\n\n // 1,0,192.168.11.2,255.255.255.0,192.168.11.1,8.8.8.8,5000,192.168.11.3,5000\n setNetworkValues(data);\n }\n },\n [ setData ]\n );\n\n useEffect(\n () => {\n if (getData !== undefined) {\n const params = getData.split(\",\");\n console.log(\"network get params\", params);\n const data = params.splice(3);\n // console.log(\"network get data\", data);\n\n setNetworkValues(data);\n }\n },\n [ getData ]\n );\n\n const handleValueChange = (index) => (event) => {\n let newValues = networkValues.slice();\n newValues[index] = event.target.value;\n setNetworkValues(newValues);\n };\n\n const handleGet = async () => {\n const networkGetCmd = [ deviceIndex, \"2\", macaddr ].join(\",\");\n // const networkGetCmd = `${deviceIndex},2,${macaddr}`;\n if (await sendC2dMessage(deviceId, networkGetCmd)) {\n console.log(\"Send get network command:\", networkGetCmd);\n openAlert(`[${macaddr}] Sent 'Get Network' message`);\n }\n };\n\n const handleSet = async () => {\n try {\n const params = [ deviceIndex, \"3\", macaddr, networkValues.join(\",\") ];\n console.log(\"handleSet\", networkValues);\n const netSetCmd = params.join(\",\");\n console.log(\"netSetCmd:\", netSetCmd);\n if (await sendC2dMessage(deviceId, netSetCmd)) {\n console.log(\"Sent set network command:\", netSetCmd);\n openAlert(`[${macaddr}] Sent 'Set Network' message`);\n }\n } catch (error) {\n console.log(\"handleSet error\", error);\n }\n };\n\n const openAlert = (message) => {\n setSnackbar({\n open: true,\n message: message,\n severity: \"success\",\n autoHideDuration: 3000\n });\n };\n\n return (\n \n
\n \n Network Configuration\n \n\n \n \n \n \n {allocationMode.map((mode, index) => (\n }\n label={mode}\n labelPlacement=\"end\"\n className={classes.radio}\n />\n ))}\n \n \n \n \n \n {netConfig.map((configName, index) => (\n \n \n \n ))}\n \n\n \n \n \n \n {operationMode.map((mode, index) => (\n }\n label={mode}\n labelPlacement=\"end\"\n className={classes.radio}\n />\n ))}\n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n }\n fullWidth\n >\n Get\n \n \n \n }\n fullWidth\n >\n Setting\n \n \n \n \n
\n );\n};\n\nexport default NetworkConfig;\n","import React, { useState, useEffect } from \"react\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { TextField, Grid, Typography, Paper, Button } from \"@material-ui/core\";\nimport { sendC2dMessage } from \"common/apiConfig\";\n\nimport { useSetRecoilState, useRecoilValue } from \"recoil\";\nimport { snackbarState, deviceIndexState, deviceIdState } from \"common/store\";\n\nconst serialPackingConfigName = [\n \"Time delimiter(ms)\",\n \"Size delimiter\",\n \"Char delimiter\"\n];\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(1),\n width: \"100%\"\n },\n paper: {\n padding: theme.spacing(2)\n },\n select: {\n minWidth: 110\n },\n subject: {\n marginBottom: 30\n }\n}));\n\nconst SerialPackingConfig = (props) => {\n const { macaddr, getData, setData } = props;\n const classes = useStyles();\n\n const setSnackbar = useSetRecoilState(snackbarState);\n const deviceIndex = useRecoilValue(deviceIndexState);\n const deviceId = useRecoilValue(deviceIdState);\n\n const [ serialPackingValues, setSerialPackingValues ] = useState([ \"\", \"\", \"\" ]);\n\n useEffect(\n () => {\n if (setData !== undefined) {\n const params = setData.split(\",\");\n console.log(\"serial params\", params);\n const data = params.splice(3);\n console.log(\"serial data\", data);\n\n setSerialPackingValues(data);\n }\n },\n [ setData ]\n );\n\n useEffect(\n () => {\n if (getData !== undefined) {\n const params = getData.split(\",\");\n console.log(\"serial params\", params);\n const data = params.splice(3);\n console.log(\"serial data\", data);\n\n setSerialPackingValues(data);\n }\n },\n [ getData ]\n );\n\n const handleValueChange = (index) => (event) => {\n let newValues = serialPackingValues.slice();\n newValues[index] = event.target.value;\n setSerialPackingValues(newValues);\n };\n\n const handleGet = async () => {\n const serialPackingGetCmd = [ deviceIndex, \"6\", macaddr ].join(\",\");\n if (await sendC2dMessage(deviceId, serialPackingGetCmd)) {\n console.log(\"Send get serialPacking command:\", serialPackingGetCmd);\n openAlert(`[${macaddr}] Sent 'Get Serial Packing Option' message`);\n }\n };\n\n const handleSet = async () => {\n // console.log(\"handleSet\", serialPackingValues);\n const serialPackingSetCmd = [\n deviceIndex,\n \"7\",\n macaddr,\n serialPackingValues.join(\",\")\n ].join(\",\");\n\n if (await sendC2dMessage(deviceId, serialPackingSetCmd)) {\n console.log(\"Send set serialPacking command:\", serialPackingSetCmd);\n openAlert(`[${macaddr}] Sent 'Set Serial Packing Option' message`);\n }\n };\n\n const openAlert = (message) => {\n setSnackbar({\n open: true,\n message: message,\n severity: \"success\",\n autoHideDuration: 3000\n });\n };\n\n return (\n \n
\n \n Serial Data Packing Options\n \n \n {serialPackingValues.map((option, idx) => (\n \n \n \n ))}\n \n \n \n Get\n \n \n \n \n Setting\n \n \n \n \n
\n );\n};\n\nexport default SerialPackingConfig;\n","import React from \"react\";\nimport { useRecoilValue } from \"recoil\";\nimport {\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle\n} from \"@material-ui/core\";\nimport SerialConfig from \"./configuration/SerialConfig\";\nimport DeviceConfig from \"./configuration/DeviceConfig\";\nimport NetworkConfig from \"./configuration/NetworkConfig\";\nimport SerialPackingConfig from \"./configuration/SerialPackingConfig\";\n// import WatonConfig from \"./configuration/WatonConfig\";\n\nimport { deviceIndexState } from \"common/store\";\n\nconst NodeConfigDialog = (props) => {\n const { open, handleClose, macaddr, devName, devData } = props;\n\n const devIdx = useRecoilValue(deviceIndexState);\n\n return (\n \n \n {\"Configuration\"} \n {devData === undefined ? null : (\n \n \n \n \n \n {/* Waton cutomized F/W configuration */}\n {/* {devName.includes(\"WATON\") ? (\n \n ) : null} */}\n \n )}\n \n \n OK \n \n \n CANCEL \n \n \n \n
\n );\n};\n\nexport default NodeConfigDialog;\n","export default __webpack_public_path__ + \"static/media/wiz750sr.856bb9ea.png\";","export default __webpack_public_path__ + \"static/media/wiz750sr110.4dd19014.png\";","import React, { useState } from \"react\";\nimport { useRecoilValue } from \"recoil\";\nimport { makeStyles } from \"@material-ui/core/styles\";\nimport Card from \"@material-ui/core/Card\";\nimport CardContent from \"@material-ui/core/CardContent\";\nimport Typography from \"@material-ui/core/Typography\";\nimport { CardActionArea, CardMedia } from \"@material-ui/core\";\n\nimport NodeConfigDialog from \"./NodeConfigDialog\";\nimport Wiz750srImg from \"image/wiz750sr.png\";\nimport Wiz750sr110Img from \"image/wiz750sr110.png\";\nimport { s2eConfigState } from \"common/store\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n minWidth: 240,\n width: 280,\n padding: theme.spacing(1)\n },\n card: {\n display: \"flex\",\n justifyContent: \"center\",\n width: \"100%\"\n },\n media: {\n height: 170\n }\n}));\n\nconst NodeCard = (props) => {\n const { nodeInfo } = props;\n const classes = useStyles();\n\n const s2eConfig = useRecoilValue(s2eConfigState);\n\n // console.log(\"s2eConfig\", s2eConfig);\n\n const [ open, setOpen ] = useState(false);\n\n const handleClickOpen = () => {\n // console.log(\"clicked\");\n setOpen(true);\n };\n\n const handleClose = () => {\n setOpen(false);\n };\n\n // if (Object.keys(s2eConfig).length === 0) {\n // return No data
;\n // }\n\n return (\n \n \n \n {nodeInfo.name === \"WIZ750SR\" ? (\n \n ) : (\n \n )}\n \n \n {nodeInfo.name}\n \n \n MAC: {nodeInfo.mac} {\" / FW: \"} {nodeInfo.ver}\n \n \n \n \n \n
\n );\n};\n\nexport default NodeCard;\n","import React, { useState, useEffect, useContext, useCallback } from \"react\";\nimport { useRecoilState, useRecoilValue } from \"recoil\";\n\nimport { makeStyles } from \"@material-ui/styles\";\nimport { Grid } from \"@material-ui/core\";\n\nimport { SignalContext } from \"contexts/signalContext\";\nimport NodeCard from \"./NodeCard\";\nimport {\n deviceIdState,\n s2eConfigState,\n searchDataState,\n snackbarState,\n deviceIndexState,\n userDeviceListState\n} from \"common/store\";\nimport { queryDeviceUpdate } from \"common/apiConfig\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(3)\n },\n divider: {\n margin: theme.spacing(1)\n }\n}));\n\nconst BrownfieldDevice = () => {\n const classes = useStyles();\n const signalState = useContext(SignalContext);\n\n const [ configData, setConfigData ] = useRecoilState(s2eConfigState);\n const [ searchData, setSearchdata ] = useRecoilState(searchDataState);\n const [ snackbar, setSnackbar ] = useRecoilState(snackbarState);\n\n const deviceId = useRecoilValue(deviceIdState);\n const deviceIndex = useRecoilValue(deviceIndexState);\n const userDevices = useRecoilValue(userDeviceListState);\n\n const [ nodes, setNodes ] = useState([]);\n\n useEffect(\n () => {\n try {\n const selectedDevice = userDevices.filter((device) => device.id === deviceId)[0];\n\n if (selectedDevice !== undefined) {\n if (selectedDevice.hasOwnProperty(\"properties\")) {\n if (selectedDevice.properties.hasOwnProperty(\"reported\")) {\n if (selectedDevice.properties.reported.hasOwnProperty(\"NodeDevices\")) {\n // Node device list\n let newNodes = selectedDevice.properties.reported.NodeDevices;\n // console.log(\"=> Load Nodes:\", newNodes);\n setNodes(newNodes);\n\n // update info to configData\n let newConfigData = { ...configData };\n\n newNodes.map(\n (node) =>\n newConfigData[node.mac] !== undefined\n ? (newConfigData[node.mac] = {\n ...newConfigData[node.mac],\n info: node\n })\n : (newConfigData[node.mac] = { info: node })\n );\n\n // console.log(\"@newConfigData: \", newConfigData);\n setConfigData(newConfigData);\n } else {\n setNodes([]);\n }\n } else {\n setNodes([]);\n }\n } else {\n setNodes([]);\n }\n }\n } catch (error) {\n console.log(error);\n }\n },\n [ deviceId ]\n );\n\n const parseSearchMessage = useCallback(\n () => {\n /* Search */\n if (searchData.length > 0) {\n if (process.env.NODE_ENV === \"development\") {\n console.log(\"searchDataState =>\", searchData);\n }\n // remove index\n const payload = searchData.replace(`${deviceIndex},0,`, \"\");\n const messages = payload.split(\";\");\n\n const newConfigData = { ...configData };\n\n setSnackbar({\n ...snackbar,\n open: true,\n message: `${messages.length} device(s) searched`,\n severity: \"info\"\n // horizontal: \"center\"\n });\n\n for (var i = 0; i < messages.length; i++) {\n const message = messages[i];\n // console.log(\"search message =>\", message);\n\n // update configData\n const macaddr = message.split(\",\")[0];\n if (newConfigData[macaddr] !== undefined) {\n newConfigData[macaddr] = {\n ...newConfigData[macaddr],\n [`${deviceIndex},0`]: message\n };\n } else {\n newConfigData[macaddr] = {\n [`${deviceIndex},0`]: message\n };\n }\n }\n setConfigData(newConfigData);\n // console.log(\"newConfigData for search =>\", JSON.stringify(newConfigData, null, 2));\n\n // Update node device info in device document\n updateNodeDeviceInfo(messages);\n }\n },\n [ searchData ]\n );\n\n const updateNodeDeviceInfo = async (messages) => {\n console.log(\"update Nodes:\", messages);\n // [\"00:08:DC:55:CC:78,00:08:DC:55:CC:78,1.2.8,WIZ750SR…x,OPEN,0,1,192.168.0.61,255.255.255.0,192.168.0.1\",]\n\n const nodeDevicesInfo = messages.map((message) => ({\n mac: message.split(\",\")[0],\n name: message.split(\",\")[3],\n ver: message.split(\",\")[2]\n }));\n\n // console.log(\"nodeDevicesInfo\", nodeDevicesInfo);\n\n setNodes(nodeDevicesInfo);\n\n const data = {\n nodeDevices: nodeDevicesInfo\n };\n try {\n const resp = await queryDeviceUpdate(deviceId, data);\n if (resp.includes(\"OK\")) {\n console.log(\"Device update:\", resp);\n }\n } catch (error) {\n console.log(error);\n }\n };\n\n const parseMessage = (message) => {\n const messageDevIndex = message.split(\",\")[0];\n const cmdIndex = message.split(\",\")[1];\n\n if (messageDevIndex === deviceIndex) {\n if (cmdIndex === \"0\") {\n setSearchdata(message);\n } else if (cmdIndex === \"254\") {\n // node data\n // console.log(\"\");\n } else {\n // Get index and node's mac address\n const index = message.slice(0, 4); // xx,x\n const macaddr = message.split(\",\")[2];\n\n const newConfigData = {\n ...configData,\n [macaddr]: {\n ...configData[macaddr],\n [index]: message\n }\n };\n console.log(`new message received: [${index}] [${macaddr}] [${message}]`);\n setConfigData(newConfigData);\n // console.log(\"newConfigData =>\", JSON.stringify(newConfigData, null, 2));\n\n messageAlert(index, macaddr);\n }\n }\n };\n\n const messageAlert = (index, macaddr) => {\n const cmdIndex = index.split(\",\")[1];\n let message = \"\";\n switch (cmdIndex) {\n case \"1\":\n message = \"Received [Get Device] message\";\n break;\n case \"2\":\n message = \"Received [Get Network] message\";\n break;\n case \"3\":\n message = \"Received [Set Network] message\";\n break;\n case \"4\":\n message = \"Received [Get UART] message\";\n break;\n case \"5\":\n message = \"Received [Set UART] message\";\n break;\n case \"6\":\n message = \"Received [Get Serial Packing Option] message\";\n break;\n case \"7\":\n message = \"Received [Get Serial Packing Option] message\";\n break;\n default:\n break;\n }\n\n setSnackbar({\n open: true,\n message: message,\n severity: \"info\",\n autoHideDuration: 3000\n });\n };\n\n useEffect(\n () => {\n const getSignalData = async () => {\n try {\n const signalData = signalState.eventData;\n if (signalData !== null) {\n // Check message source: Telemetry / twinChangeEvents\n if (signalData.messageSource === \"Telemetry\") {\n const jsonstr = JSON.stringify(signalData);\n // console.log(\"Received event:\", jsonstr);\n\n const jsondata = JSON.parse(jsonstr);\n // console.log(jsondata);\n\n if (jsondata[\"deviceId\"] === deviceId) {\n // ! parsing message\n parseMessage(jsondata[\"message\"]);\n }\n }\n }\n } catch (err) {\n console.log(err);\n }\n };\n\n // start subscribe signal\n getSignalData();\n },\n [ signalState.eventData ]\n );\n\n useEffect(\n () => {\n parseSearchMessage();\n },\n [ parseSearchMessage ]\n );\n\n return (\n \n \n {nodes.map((node, index) => (\n \n \n \n ))}\n \n
\n );\n};\n\nexport default BrownfieldDevice;\n","import React, { useState } from \"react\";\nimport { useRecoilState, useRecoilValue } from \"recoil\";\n\nimport { makeStyles } from \"@material-ui/styles\";\nimport { Typography, Grid, CircularProgress } from \"@material-ui/core\";\n\nimport SelectUserDevice from \"./SelectUserDevice\";\nimport SearchDevice from \"./SearchDevice\";\nimport BrownfieldDevice from \"./BrownfieldDevice\";\n// import SelectDeviceType from \"./SelectDeviceType\";\n\nimport { deviceIdState, userDeviceListState, isDeviceLoadedState } from \"common/store\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(3)\n },\n progressWrapper: {\n paddingTop: \"48px\",\n paddingBottom: \"24px\",\n display: \"flex\",\n justifyContent: \"center\"\n }\n}));\n\nconst DeviceDashboard = () => {\n const classes = useStyles();\n\n const [ buttonDisable, setButtonDisable ] = useState(true);\n\n const [ deviceId, setDeviceId ] = useRecoilState(deviceIdState);\n const userDevices = useRecoilValue(userDeviceListState);\n const isLoaded = useRecoilValue(isDeviceLoadedState);\n\n const handleSelect = (value) => {\n setDeviceId(value);\n setButtonDisable(false);\n };\n\n if (!isLoaded) {\n return (\n \n \n
\n );\n } else {\n return (\n \n {/* \n Linked Nodes Dashboard\n */}\n \n \n {userDevices.length > 0 ? (\n \n ) : (\n \n There is no registered device.\n \n )}\n \n \n {/* */}\n \n \n \n {/* \n Legacy device sample message: \n */}\n {deviceId.length > 0 ? : null}\n \n \n
\n );\n }\n};\n\nexport default DeviceDashboard;\n","import React from \"react\";\nimport DeviceDashboard from \"./DeviceDashboard\";\nimport { AlertSnackbar } from \"components\";\nimport { useRecoilState } from \"recoil\";\nimport { snackbarState } from \"common/store\";\n\nconst LinkedNodeView = () => {\n const [ snackbar, setSnackbar ] = useRecoilState(snackbarState);\n\n return (\n \n
\n\n
setSnackbar({ ...snackbar, open: false })}\n open={snackbar.open}\n autoHideDuration={snackbar.autoHideDuration}\n severity={snackbar.severity}\n />\n \n );\n};\n\nexport default LinkedNodeView;\n","import React, { useState } from \"react\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TableContainer,\n Typography,\n TablePagination,\n Paper,\n Collapse,\n Box\n} from \"@material-ui/core\";\n\nconst columns = [\n { id: \"deviceId\", label: \"Device Id\", style: { minWidth: 130, maxWidth: 130 } },\n { id: \"message\", label: \"Message\", style: { minWidth: 500, maxWidth: 800 } },\n {\n id: \"EnqueuedTimeUtc\",\n label: \"Enqueued Time(UTC)\",\n style: { minWidth: 160, maxWidth: 200 }\n }\n];\n\nconst NodeLogTable = (props) => {\n const { eventList } = props;\n\n const classes = useStyles();\n\n const [ rowsPerPage, setRowsPerPage ] = useState(20);\n const [ page, setPage ] = useState(0);\n\n const handlePageChange = (event, page) => {\n setPage(page);\n };\n\n const handleRowsPerPageChange = (event) => {\n setRowsPerPage(event.target.value);\n };\n\n return (\n \n
\n \n \n \n \n \n \n No.\n \n \n {columns.map((column, index) => (\n \n \n {column.label}\n \n \n ))}\n \n \n \n {eventList\n .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)\n .map((eventData, index) => {\n return (\n \n );\n })}\n \n
\n \n \n \n
\n );\n};\n\nconst NodeLogRow = (props) => {\n const { eventData, index, classes } = props;\n\n const [ collapseOpen, setCollapseOpen ] = useState(false);\n\n return (\n \n setCollapseOpen(false) : () => setCollapseOpen(true)\n }\n >\n \n \n {index + 1}\n \n \n \n \n {eventData.deviceId}\n \n \n \n \n {typeof eventData.message === \"string\" ? (\n eventData.message\n ) : (\n JSON.stringify(eventData.message)\n )}\n \n \n \n \n {/* {eventData.EnqueuedTimeUtc} */}\n {new Date(eventData.EnqueuedTimeUtc).toLocaleString(\"en\", {\n timeZone: \"Asia/Seoul\"\n })}\n \n \n \n \n {} \n \n \n \n \n {typeof eventData.message === \"string\" ? (\n eventData.message\n ) : (\n JSON.stringify(eventData.message)\n )}\n \n \n \n \n \n \n );\n};\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n width: \"100%\",\n padding: theme.spacing(2)\n },\n container: {\n maxHeight: 800,\n width: \"100%\"\n // maxWidth: 1400\n },\n table: {\n overflowX: \"auto\"\n },\n collapseCell: {\n paddingBottom: 0,\n paddingTop: 0\n }\n}));\n\nexport default NodeLogTable;\n","import React, { useState, useEffect, useCallback } from \"react\";\nimport { useRecoilValue } from \"recoil\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport { CircularProgress, Typography, Button, Grid } from \"@material-ui/core\";\nimport SearchIcon from \"@material-ui/icons/Search\";\n\nimport {\n // queryEventsContinue,\n queryEvents\n} from \"common/apiConfig\";\nimport {\n // continuationTokenState,\n userDeviceListState,\n isDeviceLoadedState\n} from \"common/store\";\n\n// import { EventsTable } from \"./components\";\nimport NodeLogTable from \"./components/NodeLogTable\";\nimport SelectUserDevice from \"views/LinkedNode/SelectUserDevice\";\n\nconst NodeData = () => {\n const classes = useStyles();\n\n const [ deviceId, setDeviceId ] = useState(\"\");\n const [ buttonDisable, setButtonDisable ] = useState(true);\n\n const userDevices = useRecoilValue(userDeviceListState);\n const isDeviceLoaded = useRecoilValue(isDeviceLoadedState);\n\n const [ isEventLoaded, setIsEventLoaded ] = useState(false);\n const [ eventList, setEventList ] = useState([]);\n\n // const [ continuationToken, setContinuationToken ] = useRecoilState(\n // continuationTokenState\n // );\n\n /* Get events */\n const getEventList = useCallback(\n async () => {\n try {\n // Continuation query\n // const resp = await queryEventsContinue(deviceId, continuationToken, 20);\n // console.log(\"@ resp\", resp);\n // if (resp) {\n // // console.debug(\"resp.nextPageToken:\", resp.nextPageToken);\n // console.debug(\"events[0]:\", resp.events[0]);\n\n // setContinuationToken(resp.nextPageToken);\n\n // setIsEventLoaded(true);\n // setEventList(resp.events);\n // }\n\n // Simple query\n const eventData = await queryEvents(deviceId, 50);\n // console.log(\"@ eventData\", eventData);\n if (eventData) {\n // console.debug(\"resp.nextPageToken:\", resp.nextPageToken);\n // console.debug(\"events[0]:\", eventData[0]);\n\n setIsEventLoaded(true);\n setEventList(eventData);\n }\n } catch (err) {\n console.log(\"getEventList err\", err);\n }\n },\n [ deviceId ]\n // [ deviceId, continuationToken, setContinuationToken ]\n );\n\n useEffect(\n () => {\n // if (deviceId.length > 0 && continuationToken === \"\") {\n if (deviceId.length > 0) {\n // initial eventdata\n getEventList();\n }\n },\n // [ deviceId, getEventList, continuationToken ]\n [ deviceId, getEventList ]\n );\n\n const handleSelect = (value) => {\n setDeviceId(value);\n setButtonDisable(false);\n };\n\n const handleSearch = async () => {\n await getEventList();\n };\n\n if (!isDeviceLoaded) {\n return (\n \n \n
\n );\n } else {\n return (\n \n {/*
\n Node's Log\n */}\n
\n \n {userDevices.length > 0 ? (\n \n ) : (\n \n There is no registered device.\n \n )}\n \n \n {deviceId.length > 0 ? (\n }\n disabled={buttonDisable}\n >\n Search Log \n \n ) : null}\n \n \n\n {deviceId.length > 0 ? (\n
\n {isEventLoaded ? (\n
\n {eventList.length > 0 ? (\n \n ) : (\n No log from selected device \n )}\n
\n ) : null}\n
\n ) : null}\n
\n );\n }\n};\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(3)\n },\n content: {\n padding: theme.spacing(1)\n },\n text: {\n paddingTop: 135,\n paddingBottom: 70,\n textAlign: \"center\",\n color: theme.palette.primary.main\n },\n progressWrapper: {\n paddingTop: \"48px\",\n paddingBottom: \"24px\",\n display: \"flex\",\n justifyContent: \"center\"\n },\n button: {\n margin: theme.spacing(3),\n paddingTop: \"6.9px\",\n paddingBottom: \"6.9px\",\n paddingLeft: \"15px\",\n paddingRight: \"15px\"\n }\n}));\n\nexport default NodeData;\n","import React, { useState } from \"react\";\nimport { makeStyles } from \"@material-ui/styles\";\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TableContainer,\n Typography,\n TablePagination,\n Paper,\n Collapse,\n Box\n} from \"@material-ui/core\";\n\nconst columns = [\n // { id: \"deviceId\", label: \"Device Id\", style: { minWidth: 110, maxWidth: 110 } },\n { id: \"displayName\", label: \"Device Name\", style: { minWidth: 160, maxWidth: 180 } },\n { id: \"nodeMac\", label: \"Node's Mac\", style: { minWidth: 100, maxWidth: 150 } },\n { id: \"message\", label: \"Message\", style: { minWidth: 400, maxWidth: 700 } },\n {\n id: \"EnqueuedTimeUtc\",\n label: \"Enqueued Time\",\n style: { minWidth: 160, maxWidth: 200 }\n }\n];\n\nconst NodeDataTable = (props) => {\n const { eventList } = props;\n\n const classes = useStyles();\n\n const [ rowsPerPage, setRowsPerPage ] = useState(20);\n const [ page, setPage ] = useState(0);\n\n const handlePageChange = (event, page) => {\n setPage(page);\n };\n\n const handleRowsPerPageChange = (event) => {\n setRowsPerPage(event.target.value);\n };\n\n return (\n \n
\n \n \n \n \n \n \n No.\n \n \n {columns.map((column, index) => (\n \n \n {column.label}\n \n \n ))}\n \n \n \n {eventList\n .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)\n .map((eventData, index) => {\n return (\n \n );\n })}\n \n
\n \n \n \n
\n );\n};\n\nconst NodeDataRow = (props) => {\n const { eventData, index, classes } = props;\n const [ collapseOpen, setCollapseOpen ] = useState(false);\n\n return (\n \n setCollapseOpen(false) : () => setCollapseOpen(true)\n }\n >\n \n \n {index + 1}\n \n \n \n \n {eventData.hasOwnProperty(\"displayName\") ? (\n eventData.displayName\n ) : (\n eventData.deviceId\n )}\n \n \n \n \n {eventData.message.split(\",\")[2]}\n \n \n \n \n {eventData.message.replace(\n eventData.message.split(\",\", 3).join(\",\") + \",\",\n \"\"\n )}\n \n \n \n \n {/* {eventData.EnqueuedTimeUtc} */}\n {new Date(eventData.EnqueuedTimeUtc).toLocaleString(\"en\", {\n timeZone: \"Asia/Seoul\"\n // timeZoneName: \"short\"\n })}\n \n \n \n \n {} \n \n \n \n \n {eventData.message}\n \n \n \n \n \n \n );\n};\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n width: \"100%\",\n padding: theme.spacing(2)\n },\n container: {\n maxHeight: 800,\n width: \"100%\"\n // maxWidth: 1400\n },\n table: {\n overflowX: \"auto\"\n },\n collapseCell: {\n paddingBottom: 0,\n paddingTop: 0\n }\n}));\n\nexport default NodeDataTable;\n","import React, { useState, useEffect, useCallback } from \"react\";\nimport { useRecoilState, useRecoilValue } from \"recoil\";\n\nimport { makeStyles } from \"@material-ui/styles\";\nimport { CircularProgress, Typography, Button, Grid } from \"@material-ui/core\";\nimport SearchIcon from \"@material-ui/icons/Search\";\n\nimport { queryEvents } from \"common/apiConfig\";\n\n// import { EventsTable } from \"./components\";\nimport NodeDataTable from \"./components/NodeDataTable\";\nimport SelectUserDevice from \"views/LinkedNode/SelectUserDevice\";\n\nimport { deviceIdState, userDeviceListState, isDeviceLoadedState } from \"common/store\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(3)\n },\n content: {\n padding: theme.spacing(1)\n },\n text: {\n paddingTop: 135,\n paddingBottom: 70,\n textAlign: \"center\",\n color: theme.palette.primary.main\n },\n progressWrapper: {\n paddingTop: \"48px\",\n paddingBottom: \"24px\",\n display: \"flex\",\n justifyContent: \"center\"\n },\n button: {\n margin: theme.spacing(3),\n paddingTop: \"6.9px\",\n paddingBottom: \"6.9px\",\n paddingLeft: \"15px\",\n paddingRight: \"15px\"\n }\n}));\n\nconst NodeData = () => {\n const classes = useStyles();\n\n // const [ deviceId, setDeviceId ] = useState(\"\");\n const [ deviceId, setDeviceId ] = useRecoilState(deviceIdState);\n\n // const [ userDevices, setUserDeivces ] = useState([]);\n // const [ isDeviceLoaded, setIsDeviceLoaded ] = useState(false);\n const userDevices = useRecoilValue(userDeviceListState);\n const isDeviceLoaded = useRecoilValue(isDeviceLoadedState);\n\n const [ buttonDisable, setButtonDisable ] = useState(true);\n\n const [ isEventLoaded, setIsEventLoaded ] = useState(false);\n const [ eventList, setEventList ] = useState([]);\n\n const handleSelect = (value) => {\n setDeviceId(value);\n setButtonDisable(false);\n };\n\n const handleSearch = async () => {\n await getEventList();\n };\n\n /* data table */\n const getEventList = useCallback(\n async () => {\n try {\n let eventData = [];\n let filteredData = [];\n\n eventData = await queryEvents(deviceId, 50);\n // console.log(\"@ eventData\", eventData);\n\n // Filter data\n if (eventData.length > 0) {\n filteredData = eventData.filter(\n (data) => typeof data.message === \"string\" && data.message.includes(\"17,254\")\n );\n // console.log(\"@ filteredData\", filteredData);\n\n // Add displayName property\n const selectedDevice = userDevices.filter(\n (device) => device.id === deviceId\n )[0];\n\n if (selectedDevice.hasOwnProperty(\"displayName\")) {\n filteredData.map(\n (data) => (data[\"displayName\"] = selectedDevice.displayName)\n );\n }\n\n if (filteredData.length > 0) {\n // Add nodeMac property\n filteredData.map((data) => (data[\"nodeMac\"] = data.message.split(\",\")[2]));\n // console.log(\"@ filteredData 22\", filteredData);\n }\n }\n\n setIsEventLoaded(true);\n setEventList(filteredData);\n } catch (err) {\n console.log(\"getEventList err\", err);\n }\n },\n [ deviceId ]\n );\n\n useEffect(\n () => {\n if (deviceId.length > 0) {\n getEventList();\n }\n },\n [ deviceId, getEventList ]\n );\n\n if (!isDeviceLoaded) {\n return (\n \n \n
\n );\n } else {\n return (\n \n {/*
\n Node's Data\n */}\n
\n \n {userDevices.length > 0 ? (\n \n ) : (\n \n There is no registered device.\n \n )}\n \n \n {deviceId.length > 0 ? (\n }\n disabled={buttonDisable}\n >\n Search Data \n \n ) : null}\n \n \n\n {deviceId.length > 0 ? (\n
\n {isEventLoaded ? (\n
\n {eventList.length > 0 ? (\n \n ) : (\n \n Not found node's data from selected device\n \n )}\n
\n ) : null}\n
\n ) : null}\n
\n );\n }\n};\n\nexport default NodeData;\n","import React, { useEffect, useRef } from \"react\";\n\nfunction useInterval(callback, delay) {\n const savedCallback = useRef();\n\n // Remember the latest function.\n useEffect(\n () => {\n savedCallback.current = callback;\n },\n [ callback ]\n );\n\n // Set up the interval.\n useEffect(\n () => {\n function tick() {\n savedCallback.current();\n }\n if (delay !== null) {\n let id = setInterval(tick, delay);\n return () => clearInterval(id);\n }\n },\n [ delay ]\n );\n}\n\nexport default useInterval;\n","import React from \"react\";\n\nimport { Typography, makeStyles } from \"@material-ui/core\";\n// import isJson from \"helpers/isJson\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n // display: \"flex\",\n // minWidth: 200\n // padding: 10\n },\n title: { fontSize: 16 },\n subTitle: {\n fontSize: 14\n },\n typo: {\n // backgroundColor: \"#f2f2f2\",\n padding: 5,\n width: \"100%\",\n textAlign: \"center\",\n color: \"#1f2737\"\n },\n unit: {\n fontSize: 16\n // color: \"#1f2737\"\n }\n}));\n\nconst TextWidget = (props) => {\n const classes = useStyles();\n const { data, title, variant, subTitle, dataColor, unit } = props;\n\n // console.log(\"\", data, title);\n\n return (\n \n \n {title}\n \n \n {subTitle}\n \n \n {data} \n {data === \"\" ||\n data === \"-\" ||\n data === undefined ||\n data === \"\\u0005\\u0000\" ? null : (\n {\" \" + unit} \n )}\n \n
\n );\n};\n\nTextWidget.defaultProps = {\n variant: \"h2\",\n subTitle: \"\",\n unit: \"\"\n};\n\nexport default TextWidget;\n","import React from \"react\";\n\nimport { Typography, makeStyles } from \"@material-ui/core\";\n// import isJson from \"helpers/isJson\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n // display: \"flex\",\n // minWidth: 200\n // padding: 10\n },\n title: { fontSize: 16 },\n subTitle: {\n fontSize: 14\n },\n typo: {\n // backgroundColor: \"#f2f2f2\",\n padding: 5,\n width: \"100%\",\n textAlign: \"center\",\n color: \"#1f2737\"\n },\n unit: {\n fontSize: 14,\n color: \"#1f2737\"\n }\n}));\n\nconst TextArrayWidget = (props) => {\n const classes = useStyles();\n const { dataArray, title, variant, subTitle, dataColor, unitArray } = props;\n\n // console.log(\"\", data, title);\n\n return (\n \n \n {title}\n \n \n {subTitle}\n \n {dataArray.map((data, index) => (\n \n {data} \n {data !== \"\" && data !== \"-\" ? (\n {\" \" + unitArray[index]} \n ) : null}\n \n ))}\n
\n );\n};\n\nTextArrayWidget.defaultProps = {\n variant: \"h2\",\n subTitle: \"\",\n unit: \"\"\n};\n\nexport default TextArrayWidget;\n","import React, { useEffect, useState } from \"react\";\n\nimport { Typography, makeStyles } from \"@material-ui/core\";\n// component and styles\nimport BillboardChart from \"react-billboardjs\";\nimport { line, zoom } from \"billboard.js\";\n// import \"react-billboardjs/lib/billboard.css\";\nimport \"helpers/bbtheme-graph.css\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n // display: \"flex\",\n // minWidth: 200\n },\n title: { fontSize: 14 },\n typo: {\n backgroundColor: theme.palette.common.white,\n padding: theme.spacing(1) * 1,\n width: \"100%\",\n textAlign: \"center\"\n }\n}));\n\nconst BBChart = (props) => {\n const classes = useStyles();\n const { xAxis, values, color } = props;\n const [ chartInstance, setChartInstance ] = useState(null);\n\n useEffect(\n () => {\n // console.log(\"chartInstance\", chartInstance);\n if (chartInstance !== null) {\n chartInstance.loadData({\n columns: xAxis !== undefined ? [ xAxis, values ] : [ values ]\n });\n\n // chartInstance.redraw();\n }\n },\n [ xAxis, values ]\n );\n\n // console.log(\"\", xAxis, values);\n return (\n \n \n {values[0]}\n \n {values.length > 0 ? (\n setChartInstance(chartInstance)}\n data={{\n x: \"EnqueuedTimeUtc\",\n // xFormat: \"%Y-%m-%d %H:%M:%S\",\n columns: xAxis !== undefined ? [ xAxis, values ] : [ values ],\n type: line(),\n colors: {\n [values[0]]: color\n }\n }}\n axis={{\n x: {\n type: \"timeseries\",\n tick: {\n count: 10,\n fit: true,\n format: \"%Y-%m-%d %H:%M:%S\",\n culling: false\n }\n },\n y: {\n min: 0,\n max: values[0].includes(\"String\") ? 500 : 40\n }\n }}\n padding={{\n top: 20,\n right: 20,\n bottom: 20,\n left: 30\n }}\n point={{\n // show: false,\n // focus: {\n // only: true\n // }\n }}\n zoom={{\n enabled: zoom()\n // type: \"drag\"\n }}\n />\n ) : null}\n
\n );\n};\n\nBBChart.defaultProps = {\n type: \"line\"\n};\n\nexport default BBChart;\n","import React, { useEffect, useState } from \"react\";\n\n// import { makeStyles } from \"@material-ui/core\";\n// component and styles\nimport BillboardChart from \"react-billboardjs\";\nimport { line, zoom } from \"billboard.js\";\n// import \"react-billboardjs/lib/billboard.css\";\nimport \"helpers/bbtheme-graph.css\";\n\n// const useStyles = makeStyles((theme) => ({\n// root: {\n// // display: \"flex\",\n// // minWidth: 200\n// },\n// title: { fontSize: 14 },\n// typo: {\n// backgroundColor: theme.palette.common.white,\n// padding: theme.spacing(1) * 1,\n// width: \"100%\",\n// textAlign: \"center\"\n// }\n// }));\n\nconst BBMultiChart = (props) => {\n // const classes = useStyles();\n const { xAxis, values, min, max } = props;\n const [ chartInstance, setChartInstance ] = useState(null);\n\n // console.log(\"BBMultiChart()\", values.length);\n\n useEffect(\n () => {\n // console.log(\"chartInstance\", chartInstance);\n if (chartInstance !== null) {\n try {\n chartInstance.loadData({\n columns: xAxis !== undefined ? [ xAxis, values ] : values\n });\n\n // chartInstance.redraw();\n } catch (error) {\n console.log(error);\n }\n // console.log(\"Chart load data\");\n }\n },\n [ xAxis, values ]\n );\n\n return (\n \n {values.length > 0 ? (\n setChartInstance(chartInstance)}\n data={{\n x: \"EnqueuedTimeUtc\",\n // xFormat: \"%Y-%m-%d %H:%M:%S\",\n columns: values,\n type: line()\n // colors: {\n // [values[0]]: color\n // }\n }}\n axis={{\n x: {\n type: \"timeseries\",\n tick: {\n count: 10,\n fit: true,\n format: \"%Y-%m-%d %H:%M:%S\",\n culling: false\n }\n },\n y: {\n min: min,\n // max: values[0].includes(\"String\") ? 500 : 40\n max: max\n }\n }}\n padding={{\n top: 20,\n right: 20,\n bottom: 20,\n left: 30\n }}\n point={{\n // show: false,\n // focus: {\n // only: true\n // }\n }}\n zoom={{\n enabled: zoom()\n // type: \"drag\"\n }}\n />\n ) : null}\n
\n );\n};\n\nBBMultiChart.defaultProps = {\n type: \"line\",\n min: 0,\n max: 50\n};\n\nexport default BBMultiChart;\n","import React, { useState, useEffect, useContext } from \"react\";\nimport { useRecoilValue } from \"recoil\";\nimport {\n makeStyles,\n Card,\n CardContent,\n Grid,\n Typography,\n CircularProgress,\n Paper\n} from \"@material-ui/core\";\nimport { SignalContext } from \"contexts/signalContext\";\nimport { deviceIdState } from \"common/store\";\nimport { queryWithSql } from \"common/apiConfig\";\nimport { useInterval } from \"helpers\";\n\nimport { TextWidget, BBMultiChart } from \"./widgets\";\n\nconst colors = [ \"#9500ae\", \"#3f51b5\", \"#015f92\" ];\nconst CellKeys = [ \"Voltage\", \"Internal Resistance\", \"Temperature\" ];\nconst CellUnits = [ \"V\", \"mΩ\", \"℃\" ];\n\nconst DATA_LIMIT = 100;\nconst BANKDATA_LENGTH = 4;\n\nconst defaultQuery =\n \"SELECT c.EnqueuedTimeUtc, c.message, c.deviceId, c.snmpData FROM c WHERE c.messageSource = 'Telemetry' AND IS_DEFINED(c.snmpData)\";\n\nconst BankDetail = (props) => {\n const { bankIndex, selectedMac, tree } = props;\n const classes = useStyles();\n const signalState = useContext(SignalContext);\n\n const deviceId = useRecoilValue(deviceIdState);\n\n const [ isLoaded, setIsLoaded ] = useState(false);\n const [ isCellDataLoaded, setIsCellDataLoaded ] = useState(false);\n\n const [ bbValueArray, setBbValueArray ] = useState(null);\n const [ latestCellData, setLatestCellData ] = useState([]);\n\n const [ bankEventList, setBankEventList ] = useState([]);\n\n const [ refreshTime, setRefreshTime ] = useState(3000);\n\n if (process.env.NODE_ENV === \"development\") {\n // console.log(\"\", selectedMac, bankIndex);\n }\n\n useInterval(() => {\n // update bbchart data\n if (bankEventList.length > 0) {\n // console.log(\n // \"Compare timestamp\",\n // Date.parse(bankEventList[0].EnqueuedTimeUtc),\n // bbValueArray[0][1]\n // );\n if (bbValueArray.length > 0) {\n try {\n // Compare timestamp value=\n if (Date.parse(bankEventList[0].EnqueuedTimeUtc) !== bbValueArray[0][1]) {\n // if timestamp is different, bbValueArray not updated yet\n getBBChartValuesWithTime(bankEventList);\n }\n } catch (error) {\n console.log(error);\n }\n } else {\n getBBChartValuesWithTime(bankEventList);\n }\n } else {\n setBbValueArray([]);\n }\n }, refreshTime);\n\n useEffect(\n () => {\n const getSignalEvent = async () => {\n try {\n const signalData = signalState.eventData;\n // console.log(\"signalData:\", signalData);\n if (signalData !== null) {\n if (signalData.messageSource === \"Telemetry\") {\n // node update event check\n if (signalData.hasOwnProperty(\"snmpData\")) {\n // console.log(\"getSignalEvent snmpData:\", signalData.snmpData);\n if (signalData.snmpData.object.cell === \"String\") {\n if (signalData.snmpData.value.length === BANKDATA_LENGTH) {\n let newEventList = bankEventList.slice();\n newEventList.unshift(signalData);\n // chart data limit\n if (newEventList.length > DATA_LIMIT) {\n newEventList.pop();\n }\n // console.log(\"Bank newEventList:\", newEventList.length);\n setBankEventList(newEventList);\n\n // // update bbchart data\n // if (newEventList.length > 0) {\n // getBBChartValuesWithTime(newEventList);\n // } else {\n // setBbValueArray([]);\n // }\n }\n }\n }\n }\n }\n } catch (err) {\n console.log(err);\n }\n };\n\n // start subscribe signal\n getSignalEvent();\n },\n [ signalState.eventData ]\n );\n\n const getBBChartValuesWithTime = (events) => {\n // console.log(\"getBBChartValuesWithTime()\", events[0]);\n\n const names = [\n \"EnqueuedTimeUtc\",\n \"String Voltage(V)\",\n \"String Current(A)\",\n \"Ripple Current(p-pA)\",\n \"Temperature(C)\"\n ];\n\n let bbChartValues = [];\n try {\n names.forEach((keyName, i) => {\n let array = [];\n array.push(keyName);\n\n events.forEach((event, j) => {\n if (i === 0) {\n // time\n // array.push(event[keyName].replace(/T/, \" \").replace(/\\..+/, \"\"));\n array.push(Date.parse(event[keyName]));\n } else {\n // array.push(event.snmpData.value[i - 1]);\n // 20210419 check unavailable value\n if (event.snmpData.value.length < 3) {\n if (process.env.NODE_ENV === \"development\") {\n console.log(\"unavailable value:\", event.snmpData.value);\n // console.log(\"unavailable value:\", event.snmpData.value, event);\n }\n } else {\n array.push(event.snmpData.value[i - 1]);\n }\n }\n });\n\n bbChartValues.push(array);\n });\n // console.log(\"@@ Bank bb values:\", bbChartValues);\n setBbValueArray(bbChartValues);\n } catch (error) {\n console.log(error);\n setBbValueArray([]);\n }\n };\n\n useEffect(\n () => {\n const queryBankData = async () => {\n try {\n setIsLoaded(false);\n let dataList = [];\n let container = \"EventContainer\";\n // console.log(\"selectedMac:\", selectedMac);\n\n let and1 = ` AND c.deviceId = \"${deviceId}\"`;\n let and2 = ` AND c.snmpData.object.cell = \"String\"`;\n let and3 = ` AND c.snmpData.info.mac = \"${selectedMac}\"`;\n // let order = \" ORDER BY c._ts DESC OFFSET 0 LIMIT 50\";\n let order = ` ORDER BY c._ts DESC OFFSET 0 LIMIT ${DATA_LIMIT}`;\n\n const query = defaultQuery + and1 + and2 + and3 + order;\n // console.log(\"query:\", query);\n\n dataList = await queryWithSql(container, query);\n // console.log(\"@ dataList length\", dataList.length);\n // console.log(\"@ dataList\", dataList);\n setBankEventList(dataList);\n\n if (dataList.length > 0) {\n getBBChartValuesWithTime(dataList);\n } else {\n setBbValueArray([]);\n }\n setIsLoaded(true);\n } catch (error) {\n console.log(error);\n }\n };\n\n const queryEachCellData = async () => {\n try {\n setIsCellDataLoaded(false);\n // console.log(\"queryEachCellData()\");\n let container = \"EventContainer\";\n\n // cell index list\n let cellIndexArray = [];\n for (let i = 1; i <= tree.cell; i++) {\n let numStr = i.toString(16).padStart(2, \"0\");\n cellIndexArray.push(numStr);\n }\n // console.log(\"cellIndexArray\", cellIndexArray);\n\n let and1 = ` AND c.deviceId = \"${deviceId}\"`;\n let order = \" ORDER BY c._ts DESC OFFSET 0 LIMIT 1\";\n\n const promiseArray = cellIndexArray.map((cellIndex) => {\n let and2 = ` AND c.snmpData.info.mac = \"${selectedMac}\" AND c.snmpData.object.cell = \"${cellIndex}\"`;\n const query = defaultQuery + and1 + and2 + order;\n // console.log(\"query \", cellIndex, query);\n return new Promise((resolve) => resolve(queryWithSql(container, query)));\n });\n\n let resultArray = await Promise.all(promiseArray);\n if (process.env.NODE_ENV === \"development\") {\n console.log(\"query each cell data result:\", resultArray);\n }\n\n setLatestCellData(resultArray);\n setIsCellDataLoaded(true);\n } catch (error) {\n console.log(error);\n }\n };\n\n if (deviceId.length > 0) {\n // getEvents();\n queryBankData();\n\n queryEachCellData();\n }\n },\n [ deviceId, selectedMac ]\n );\n\n if (!isLoaded || !isCellDataLoaded || bbValueArray === null) {\n return ;\n }\n\n return (\n \n {bbValueArray.length === 0 ? (\n
\n ) : (\n
\n {/*
\n Bank Information\n */}\n
\n \n \n \n \n \n \n \n \n \n {bbValueArray.slice(1).map((bbValue, index) => (\n \n \n \n \n \n \n \n ))}\n \n \n \n
\n \n \n \n \n \n \n \n \n\n {/*
\n {bbValueArray\n .filter(\n (value) => value[0].includes(\"String\") || value[0].includes(\"Ripple\")\n )\n .map((bbValue, index) => (\n \n \n \n \n \n \n \n ))}\n */}\n {/* Total cell data */}\n
\n Cell Overview\n \n
\n {CellKeys.map((cellKey, index) => (\n \n {/* \n {cellKey}\n */}\n \n {latestCellData.map((data, cellIndex) => (\n \n {data.length === 0 ? null : (\n 14.2\n ? \"#ffcccb\"\n : \"\"\n }}\n >\n 14.2 ? (\n \"#ba000d\"\n ) : (\n \"\"\n )\n }\n />\n \n )}\n \n ))}\n \n \n ))}\n \n
\n )}\n
\n );\n};\n\nconst NoData = ({ bankIndex }) => {\n return (\n \n Not found data from Bank {bankIndex} \n
\n );\n};\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n margin: theme.spacing(1)\n },\n title: {\n marginTop: 32,\n marginBottom: 16,\n fontSize: 24,\n fontWeight: 500\n },\n subTitle: {\n marginTop: 10,\n marginBottom: 16,\n fontSize: 20,\n color: \"#141b29\"\n },\n cardRoot: {\n padding: 5,\n marginTop: 10\n // backgroundColor: \"#f2f2f2\"\n },\n cardContentRoot: {\n padding: 5,\n \"&:last-child\": {\n paddingBottom: 10\n }\n },\n paper: {\n border: \"solid 1px #bac3d5\",\n // boxShadow: \"0 0 5px 0 rgba(0, 0, 0, 0.3)\",\n borderRadius: \"10px\",\n padding: 10\n }\n}));\n\nexport default BankDetail;\n","import React, { useState, useEffect, useContext } from \"react\";\nimport { useRecoilValue } from \"recoil\";\nimport {\n makeStyles,\n Card,\n CardContent,\n Grid,\n Typography,\n CircularProgress\n} from \"@material-ui/core\";\n\nimport { SignalContext } from \"contexts/signalContext\";\nimport { BBChart, TextWidget } from \"./widgets\";\nimport { deviceIdState } from \"common/store\";\nimport { queryWithSql } from \"common/apiConfig\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n margin: theme.spacing(1)\n },\n card: {\n display: \"block\",\n width: \"100%\",\n height: \"100%\"\n },\n cardContents: {\n padding: \"15px 15px\"\n }\n}));\n\n// bb chart color\nconst colors = [ \"#1769aa\", \"#009688\", \"#9c27b0\" ];\n\nconst CellDetail = (props) => {\n const { cellIndex, selectedMac } = props;\n const classes = useStyles();\n const signalState = useContext(SignalContext);\n\n const deviceId = useRecoilValue(deviceIdState);\n\n const [ cellEventList, setCellEventList ] = useState([]);\n const [ isLoaded, setIsLoaded ] = useState(false);\n\n const [ bbValueArray, setBbValueArray ] = useState([]);\n\n useEffect(\n () => {\n const getSignalEvent = async () => {\n try {\n // console.log(\"cellEventList 1:\", cellEventList.length, cellEventList[0]);\n const signalData = signalState.eventData;\n if (signalData !== null) {\n if (signalData.messageSource === \"Telemetry\") {\n // node update event check\n if (signalData.hasOwnProperty(\"snmpData\")) {\n let cellIndexHex = Number(cellIndex).toString(16).padStart(2, \"0\");\n if (signalData.snmpData.object.cell === cellIndexHex) {\n // console.log(\"signalData ==>\", signalData.snmpData);\n if (signalData.snmpData.value.length === 3) {\n let newEventList = cellEventList.slice();\n newEventList.unshift(signalData);\n // chart data limit\n if (newEventList.length > 50) {\n newEventList.pop();\n }\n // console.log(\"Cell newEventList:\", newEventList);\n setCellEventList(newEventList);\n\n // update bbchart data\n if (newEventList.length > 0) {\n getBBChartValuesWithTime(newEventList);\n } else {\n setBbValueArray([]);\n }\n }\n }\n }\n }\n }\n } catch (err) {\n console.log(err);\n }\n };\n\n // start subscribe signal\n getSignalEvent();\n },\n [ signalState.eventData ]\n );\n\n useEffect(\n () => {\n const queryCellData = async () => {\n try {\n setIsLoaded(false);\n let dataList = [];\n let container = \"EventContainer\";\n let cellIndexHex = Number(cellIndex).toString(16).padStart(2, \"0\");\n\n let defaultQeury =\n 'SELECT c.EnqueuedTimeUtc, c.message, c.deviceId, c.snmpData FROM c WHERE c.messageSource = \"Telemetry\" AND IS_DEFINED(c.snmpData)';\n let and1 = ` AND c.deviceId = \"${deviceId}\"`;\n let and2 = ` AND c.snmpData.info.mac = \"${selectedMac}\" AND c.snmpData.object.bank = \"01\" AND c.snmpData.object.cell = \"${cellIndexHex}\"`;\n let order = \" ORDER BY c._ts DESC OFFSET 0 LIMIT 100\";\n\n const query = defaultQeury + and1 + and2 + order;\n // console.log(\"query =>\", query);\n\n dataList = await queryWithSql(container, query);\n // console.log(\"[Check] Query complete\");\n // console.log(\"@ dataList\", dataList);\n\n // filtering data\n if (dataList.length > 0) {\n if (selectedMac.length > 0) {\n let filteredEvents = [];\n dataList.forEach((event) => {\n filteredEvents.push(event);\n });\n\n // console.log(\"@ filteredEvents\", selectedMac, filteredEvents);\n if (filteredEvents.length > 0) {\n // getVisChartvalueSingle(filteredEvents);\n getBBChartValuesWithTime(filteredEvents);\n } else {\n setBbValueArray([]);\n // setVisValueArray([]);\n }\n }\n }\n\n setCellEventList(dataList);\n setIsLoaded(true);\n } catch (error) {\n console.log(error);\n }\n };\n if (deviceId.length > 0) {\n queryCellData();\n }\n },\n [ deviceId, cellIndex, selectedMac ]\n );\n\n const getBBChartValuesWithTime = (events) => {\n // console.log(\"getBBChartValuesWithTime\", events);\n\n const names = [\n \"EnqueuedTimeUtc\",\n \"Cell Voltage(V)\",\n \"Cell Internal Resistance(mohm)\",\n \"Cell Temperature(C)\"\n ];\n\n let bbChartValues = [];\n try {\n names.forEach((keyName, i) => {\n let array = [];\n array.push(keyName);\n\n events.forEach((event, j) => {\n if (i === 0) {\n // time data\n array.push(Date.parse(event[keyName]));\n } else {\n // snmp values\n // array.push(event.snmpData.value[i - 1]);\n\n // 20210419 check unavailable value\n if (event.snmpData.value.length < 3) {\n // if (event.snmpData.value.includes(undefined)) {\n // console.log(\"unavailable value:\", event.snmpData.value, event);\n } else {\n array.push(event.snmpData.value[i - 1]);\n }\n }\n });\n\n bbChartValues.push(array);\n });\n // console.log(\"@@ bbChartValues >\", bbChartValues);\n // console.log(\"@@ bbChartValue length:\", bbChartValues.length);\n setBbValueArray(bbChartValues);\n } catch (error) {\n console.log(error);\n setBbValueArray([]);\n }\n };\n\n if (!isLoaded) {\n return ;\n }\n\n return (\n \n {isLoaded && bbValueArray.length === 0 ? (\n
\n ) : (\n
\n \n {bbValueArray\n .filter((value) => value[0].includes(\"Cell\"))\n .map((bbValue, index) => (\n \n \n \n \n \n \n \n ))}\n \n\n \n {bbValueArray\n .filter(\n (value) =>\n value[0].includes(\"Voltage\") ||\n value[0].includes(\"Temperature\") ||\n value[0].includes(\"Resistance\")\n )\n .map((bbValue, index) => (\n \n \n \n \n \n \n \n ))}\n \n {/* react-vis */}\n {/* \n {visValueArray.map((visValue, index) => (\n \n \n \n \n \n \n \n ))}\n */}\n
\n )}\n
\n );\n};\n\nconst NoData = ({ cellIndex }) => {\n return (\n \n Not found data from Cell {cellIndex} \n
\n );\n};\n\nexport default CellDetail;\n","import React, { useState, useEffect } from \"react\";\nimport { useRecoilValue } from \"recoil\";\nimport {\n makeStyles,\n Card,\n CardContent,\n Grid,\n Typography,\n CircularProgress\n} from \"@material-ui/core\";\nimport { deviceIdState } from \"common/store\";\nimport { queryWithSql } from \"common/apiConfig\";\n\nimport { TextWidget } from \"./widgets\";\n\n// const colors = [ \"#1769aa\", \"#009688\", \"#9c27b0\" ];\n\nconst TopDetail = (props) => {\n const { selectedMac } = props;\n const classes = useStyles();\n\n const deviceId = useRecoilValue(deviceIdState);\n\n const [ isLoaded, setIsLoaded ] = useState(false);\n const [ bbValueArray, setBbValueArray ] = useState(null);\n\n // console.log(\"TopDetail:\", selectedMac);\n\n const getBBChartValuesWithTime = (events) => {\n // console.log(\"getBBChartValuesWithTime\", events);\n\n const names = [\n \"EnqueuedTimeUtc\",\n \"String Voltage(V)\",\n \"String Current(A)\",\n \"Ripple Current(p-pA)\"\n ];\n\n let bbChartValues = [];\n try {\n names.forEach((keyName, i) => {\n let array = [];\n array.push(keyName);\n\n events.forEach((event, j) => {\n if (i === 0) {\n // time\n // array.push(event[keyName].replace(/T/, \" \").replace(/\\..+/, \"\"));\n array.push(Date.parse(event[keyName]));\n } else {\n // array.push(event.snmpData.value[i - 1]);\n if (event.snmpData.value.length < 3) {\n // if (event.snmpData.value.includes(undefined)) {\n console.log(\"unavailable value:\", event.snmpData.value, event);\n } else {\n array.push(event.snmpData.value[i - 1]);\n }\n }\n });\n\n bbChartValues.push(array);\n });\n // console.log(\"@@ Top bb values:\", bbChartValues);\n setBbValueArray(bbChartValues);\n } catch (error) {\n console.log(error);\n setBbValueArray([]);\n }\n };\n\n useEffect(\n () => {\n const queryBankData = async () => {\n try {\n setIsLoaded(false);\n let dataList = [];\n let container = \"EventContainer\";\n let cellIndex = \"String\";\n\n let defaultQeury =\n 'SELECT c.EnqueuedTimeUtc, c.message, c.messageSource, c.deviceId, c.snmpData FROM c WHERE c.messageSource = \"Telemetry\" AND IS_DEFINED(c.snmpData)';\n let and1 = ` AND c.deviceId = \"${deviceId}\"`;\n let and2 = ` AND c.snmpData.object.cell = \"${cellIndex}\"`;\n let order = \" ORDER BY c._ts DESC OFFSET 0 LIMIT 50\";\n\n const query = defaultQeury + and1 + and2 + order;\n // console.log(\"query:\", query);\n\n let filtered = [];\n dataList = await queryWithSql(container, query);\n dataList.forEach((event) => {\n if (event.snmpData.info.mac === selectedMac) {\n filtered.push(event);\n }\n });\n // console.log(\"@ dataList\", dataList);\n\n if (filtered.length > 0) {\n getBBChartValuesWithTime(filtered);\n } else {\n setBbValueArray([]);\n }\n // console.log(\"@ filtered\", filtered);\n setIsLoaded(true);\n } catch (error) {\n console.log(error);\n }\n };\n\n if (deviceId.length > 0) {\n queryBankData();\n }\n },\n [ deviceId, selectedMac ]\n );\n\n if (!isLoaded || bbValueArray === null) {\n return ;\n }\n\n return (\n \n {/* Bank {selectedMac} dashboard */}\n {bbValueArray.length === 0 ? (\n
\n ) : (\n
\n \n Node [{selectedMac}] Overview\n \n \n \n Bank 01 \n \n {bbValueArray.slice(1).map((bbValue, index) => (\n \n \n \n \n \n \n \n ))}\n \n
\n )}\n
\n );\n};\n\nconst NoData = ({ selectedMac }) => {\n return (\n \n Not found data from {selectedMac} \n
\n );\n};\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n margin: theme.spacing(1)\n },\n title: {\n marginTop: 20,\n marginBottom: 20,\n fontSize: 18\n }\n}));\n\nexport default TopDetail;\n","import React, { useState } from \"react\";\nimport { useRecoilState } from \"recoil\";\n\nimport {\n makeStyles,\n Typography,\n Button,\n Dialog,\n TextField,\n DialogContent,\n DialogActions\n} from \"@material-ui/core\";\nimport { queryDeviceUpdate } from \"common/apiConfig\";\n\nimport { snackbarState } from \"common/store\";\n// import { ProgressButton } from \"components\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n margin: theme.spacing(2)\n },\n text: {\n marginBottom: theme.spacing(2)\n },\n textField: {\n margin: theme.spacing(1),\n width: 140\n },\n button: {\n backgroundColor: \"#3d516d\"\n }\n}));\n\nconst DashboardConfigForm = (props) => {\n const classes = useStyles();\n const { open, handleClose, device, handleTree, treeConfig } = props;\n\n const [ snackbar, setSnackbar ] = useRecoilState(snackbarState);\n const [ tree, setTree ] = useState(treeConfig);\n // const [ tree, setTree ] = useRecoilState(treeState);\n // const [ loading, setLoading ] = useState(false);\n\n const handleSave = async () => {\n // setLoading(true);\n // document update\n const data = {\n tree: tree\n };\n\n // console.log(\"handleSave data:\", data);\n\n try {\n const resp = await queryDeviceUpdate(device.id, data);\n if (resp.includes(\"OK\")) {\n console.log(\"resp\", resp);\n }\n // setLoading(false);\n // alarm\n setSnackbar({\n ...snackbar,\n open: true,\n message: \"Dashboard configuration updated!\",\n autoHideDuration: 3000,\n severity: \"info\"\n });\n\n handleTree(tree);\n } catch (error) {\n console.log(error);\n // setLoading(false);\n }\n\n handleClose();\n };\n\n const handleChange = (name) => (event) => {\n console.log(\"handleChange()\", name, event.target.value);\n setTree({ ...tree, [name]: parseInt(event.target.value) });\n };\n\n return (\n \n
\n \n \n 시스템 설정 정보를 입력하세요.\n \n \n \n \n \n \n CANCLE\n \n \n SAVE\n \n {/* \n Save and apply\n */}\n \n \n
\n );\n};\n\nexport default DashboardConfigForm;\n","import React, { useState, useEffect } from \"react\";\nimport { Switch, Route, useRouteMatch, useHistory } from \"react-router-dom\";\nimport { useRecoilState, useRecoilValue } from \"recoil\";\nimport { makeStyles, Typography, Grid, Button } from \"@material-ui/core\";\nimport { withStyles } from \"@material-ui/styles\";\nimport { TreeView } from \"@material-ui/lab\";\nimport ExpandMoreIcon from \"@material-ui/icons/ExpandMore\";\nimport ChevronRightIcon from \"@material-ui/icons/ChevronRight\";\nimport MuiTreeItem from \"@material-ui/lab/TreeItem\";\n\nimport { deviceIdState, userDeviceListState, isDeviceLoadedState } from \"common/store\";\nimport SelectUserDevice from \"views/LinkedNode/SelectUserDevice\";\n\nimport BankDetail from \"./BankDetail\";\nimport CellDetail from \"./CellDetail\";\nimport TopDetail from \"./TopDetail\";\nimport DashboardConfigForm from \"./DashboardConfigForm\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n padding: theme.spacing(3)\n },\n treeView: {\n margin: theme.spacing(1)\n }\n}));\n\nconst TreeItem = withStyles({\n root: {\n \"&.MuiTreeItem-root.Mui-selected > .MuiTreeItem-content .MuiTreeItem-label\": {\n backgroundColor: \"#e8eaf6\",\n color: \"#3f51b5\"\n }\n },\n label: { fontSize: 17 }\n})(MuiTreeItem);\n\nconst makeTreeArray = (name, number) => {\n let array = [];\n for (let i = 1; i <= number; i++) {\n let numStr = String(i).padStart(2, \"0\");\n let obj = {\n name: `${name}-${numStr}`,\n key: `${numStr}`\n };\n array.push(obj);\n }\n // console.log(\"array ==>\", array);\n return array;\n};\n\nconst NodeDashboardView = () => {\n const classes = useStyles();\n const history = useHistory();\n const { path, url } = useRouteMatch();\n\n const [ deviceId, setDeviceId ] = useRecoilState(deviceIdState);\n const userDevices = useRecoilValue(userDeviceListState);\n const isDeviceLoaded = useRecoilValue(isDeviceLoadedState);\n\n const [ tree, setTree ] = useState({\n bank: 1,\n cell: 10\n });\n const [ bankArray, setBankArray ] = useState(makeTreeArray(\"Bank\", 1));\n const [ cellArray, setCellArray ] = useState(makeTreeArray(\"Cell\", 10));\n\n const [ selectedMac, setSelectedMac ] = useState(\"\");\n const [ bankIndex, setBankIndex ] = useState(\"00\");\n const [ cellIndex, setCellIndex ] = useState(\"00\");\n\n // const [ nodes, setNodes ] = useState(tempNodeDevices);\n const [ nodes, setNodes ] = useState([]);\n const [ openDialog, setOpenDialog ] = useState(false);\n\n const selectedDevice = userDevices.filter((device) => device.id === deviceId)[0];\n\n // console.log(\"\", selectedDevice);\n\n useEffect(\n () => {\n try {\n const getNodes = () => {\n if (selectedDevice !== undefined) {\n if (selectedDevice.hasOwnProperty(\"properties\")) {\n if (selectedDevice.properties.hasOwnProperty(\"reported\")) {\n if (selectedDevice.properties.reported.hasOwnProperty(\"NodeDevices\")) {\n // Node device list\n let newNodes = selectedDevice.properties.reported.NodeDevices;\n // console.log(\"=> Load Nodes:\", newNodes);\n setNodes(newNodes);\n } else {\n setNodes([]);\n }\n } else {\n setNodes([]);\n }\n } else {\n setNodes([]);\n }\n }\n };\n\n const getTreeInfo = () => {\n if (selectedDevice !== undefined) {\n if (selectedDevice.hasOwnProperty(\"tree\")) {\n console.log(\"Load tree config\", selectedDevice.tree);\n handleTree(selectedDevice.tree);\n setTree(selectedDevice.tree);\n }\n }\n };\n\n // Call function\n getNodes();\n getTreeInfo();\n } catch (error) {\n console.log(error);\n }\n },\n [ deviceId ]\n );\n\n const handleLabelClick = (name) => (event) => {\n event.preventDefault();\n\n // console.log(\"handleLabelClick:\", name);\n let targetUrl = \"\";\n\n let addr = name.split(\"-\");\n\n if (addr.length === 3) {\n // name includes cell number\n setSelectedMac(addr[0]);\n setBankIndex(addr[1]);\n setCellIndex(addr[2]);\n } else if (addr.length === 2) {\n setSelectedMac(addr[0]);\n setBankIndex(addr[1]);\n setCellIndex(\"00\");\n } else {\n setSelectedMac(addr[0]);\n setBankIndex(\"00\");\n setCellIndex(\"00\");\n }\n\n targetUrl = `${url}/${name}`;\n\n // console.log(\"handleLabelClick() targetUrl:\", targetUrl);\n history.push(targetUrl);\n };\n\n const handleSelect = (value) => {\n setDeviceId(value);\n };\n\n useEffect(\n () => {\n // Init url\n history.push(`${url}`);\n // history.push(\"/nodedashboard\");\n return () => {};\n },\n [ deviceId ]\n );\n\n const handleTree = (tree) => {\n try {\n // console.log(\"handleTree()\", tree);\n setTree(tree);\n\n setBankArray(makeTreeArray(\"Bank\", tree.bank));\n setCellArray(makeTreeArray(\"Cell\", tree.cell));\n } catch (error) {\n console.error(error);\n }\n };\n\n return (\n \n {/*
\n Node's Dashboard\n */}\n
\n \n {userDevices.length > 0 ? (\n \n ) : (\n \n There is no registered device.\n \n )}\n \n \n\n {selectedDevice !== undefined ? (\n
\n
setOpenDialog(true)}>\n Config\n \n {nodes.length > 0 ? (\n
\n \n }\n // defaultExpanded={[ \"root\" ]}\n defaultExpandIcon={ }\n >\n {/* ====================> Device list for test */}\n {/* {selectedDevice.nodeDevices.map(({ mac }) => ( */}\n {nodes.map(({ mac }) => (\n \n {bankArray.map((bank) => (\n \n {cellArray.map((cell) => (\n \n ))}\n \n ))}\n \n ))}\n {/* */}\n \n \n \n \n \n {cellIndex !== \"00\" ? (\n \n ) : (\n \n {cellIndex === \"00\" && bankIndex === \"00\" ? (\n \n ) : (\n \n )}\n
\n )}\n \n \n \n \n ) : (\n
\n Can't found Node device.\n \n )}\n\n
setOpenDialog(false)}\n open={openDialog}\n handleTree={handleTree}\n treeConfig={tree}\n />\n \n ) : null}\n
\n );\n};\n\nexport default NodeDashboardView;\n","import React, { useEffect } from \"react\";\n// import Iframe from \"react-iframe\";\n\nimport { docsUrl } from \"common/webConfig\";\n\nconst DocumentView = () => {\n useEffect(() => {}, []);\n\n return (\n \n // \n );\n};\n\nexport default DocumentView;\n","import React from \"react\";\nimport { Switch, Redirect } from \"react-router-dom\";\n\nimport { RouteWithLayout } from \"./components\";\nimport { Main as MainLayout, Minimal as MinimalLayout } from \"./layouts\";\n\nimport {\n // NotFound as NotFoundView,\n UserDevice as UserDeviceView,\n TestPage as TestView,\n DeviceFOTA as DeviceFotaView,\n LinkedNode as LinkedNodeView,\n NodeLog as NodeLogView,\n NodeData as NodeDataView,\n NodeDashboard as NodeDashboardView,\n Document as DocumentView\n} from \"./views\";\n\nconst Routes = () => {\n return (\n \n {/* */}\n \n\n \n \n \n \n \n \n\n \n\n {/* */}\n\n \n\n {/* */}\n {/* */}\n \n );\n};\n\nexport default Routes;\n","import React from \"react\";\nimport { BrowserRouter as Router } from \"react-router-dom\";\nimport { RecoilRoot } from \"recoil\";\n\nimport { createBrowserHistory } from \"history\";\nimport { ThemeProvider } from \"@material-ui/styles\";\n\nimport theme from \"./theme\";\nimport \"react-perfect-scrollbar/dist/css/styles.css\";\n// import \"./assets/scss/index.scss\";\nimport Routes from \"./Routes\";\nimport { SignalProvider } from \"contexts/signalContext\";\nimport { MsalAuthProvider } from \"contexts/msalAuthContext\";\n\n// MSAL imports\nimport { InteractionType } from \"@azure/msal-browser\";\nimport { MsalProvider, MsalAuthenticationTemplate } from \"@azure/msal-react\";\nimport { loginRequest } from \"common/authConfig\";\n\nconst browserHistory = createBrowserHistory();\n\nconst App = ({ pca }) => {\n const authRequest = {\n ...loginRequest\n };\n\n return (\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n );\n};\n\nexport default App;\n","import React from \"react\";\nimport ReactDOM from \"react-dom\";\n\nimport * as serviceWorker from \"./serviceWorker\";\nimport App from \"./App\";\n\nimport { PublicClientApplication } from \"@azure/msal-browser\";\nimport { msalConfig } from \"common/authConfig\";\n\nconst msalInstance = new PublicClientApplication(msalConfig);\n\nReactDOM.render( , document.getElementById(\"root\"));\n\nserviceWorker.unregister();\n"],"sourceRoot":""}