mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui.git
				synced 2025-11-03 20:27:59 +00:00 
			
		
		
		
	Compare commits
	
		
			15 Commits
		
	
	
		
			v3.1.0
			...
			release/v3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					f7a7b8aa9d | ||
| 
						 | 
					0a08bfca60 | ||
| 
						 | 
					1958de15be | ||
| 
						 | 
					01008dc1aa | ||
| 
						 | 
					26b90cfdba | ||
| 
						 | 
					c7bf7ad1dc | ||
| 
						 | 
					e0cf06b437 | ||
| 
						 | 
					b218051104 | ||
| 
						 | 
					a2fa93938f | ||
| 
						 | 
					c220d11dd0 | ||
| 
						 | 
					40d533ecc5 | ||
| 
						 | 
					460ba9eee7 | ||
| 
						 | 
					788e1f59bd | ||
| 
						 | 
					d1a1c96e74 | ||
| 
						 | 
					1a18985c0d | 
@@ -8,7 +8,7 @@ fullnameOverride: ""
 | 
				
			|||||||
images:
 | 
					images:
 | 
				
			||||||
  owgwui:
 | 
					  owgwui:
 | 
				
			||||||
    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw-ui
 | 
					    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw-ui
 | 
				
			||||||
    tag: v3.1.0
 | 
					    tag: v3.2.1
 | 
				
			||||||
    pullPolicy: Always
 | 
					    pullPolicy: Always
 | 
				
			||||||
 | 
					
 | 
				
			||||||
services:
 | 
					services:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										32
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -1,12 +1,12 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "ucentral-client",
 | 
					  "name": "ucentral-client",
 | 
				
			||||||
  "version": "3.1.0(5)",
 | 
					  "version": "3.2.0",
 | 
				
			||||||
  "lockfileVersion": 3,
 | 
					  "lockfileVersion": 3,
 | 
				
			||||||
  "requires": true,
 | 
					  "requires": true,
 | 
				
			||||||
  "packages": {
 | 
					  "packages": {
 | 
				
			||||||
    "": {
 | 
					    "": {
 | 
				
			||||||
      "name": "ucentral-client",
 | 
					      "name": "ucentral-client",
 | 
				
			||||||
      "version": "3.1.0(5)",
 | 
					      "version": "3.2.0",
 | 
				
			||||||
      "license": "ISC",
 | 
					      "license": "ISC",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@chakra-ui/anatomy": "^2.1.1",
 | 
					        "@chakra-ui/anatomy": "^2.1.1",
 | 
				
			||||||
@@ -3540,7 +3540,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@jridgewell/resolve-uri": {
 | 
					    "node_modules/@jridgewell/resolve-uri": {
 | 
				
			||||||
      "version": "3.1.0",
 | 
					      "version": "3.1.0",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">=6.0.0"
 | 
					        "node": ">=6.0.0"
 | 
				
			||||||
@@ -3548,7 +3548,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@jridgewell/set-array": {
 | 
					    "node_modules/@jridgewell/set-array": {
 | 
				
			||||||
      "version": "1.1.2",
 | 
					      "version": "1.1.2",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">=6.0.0"
 | 
					        "node": ">=6.0.0"
 | 
				
			||||||
@@ -3556,7 +3556,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@jridgewell/source-map": {
 | 
					    "node_modules/@jridgewell/source-map": {
 | 
				
			||||||
      "version": "0.3.2",
 | 
					      "version": "0.3.2",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@jridgewell/gen-mapping": "^0.3.0",
 | 
					        "@jridgewell/gen-mapping": "^0.3.0",
 | 
				
			||||||
@@ -3565,7 +3565,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": {
 | 
					    "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": {
 | 
				
			||||||
      "version": "0.3.2",
 | 
					      "version": "0.3.2",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@jridgewell/set-array": "^1.0.1",
 | 
					        "@jridgewell/set-array": "^1.0.1",
 | 
				
			||||||
@@ -3578,12 +3578,12 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@jridgewell/sourcemap-codec": {
 | 
					    "node_modules/@jridgewell/sourcemap-codec": {
 | 
				
			||||||
      "version": "1.4.14",
 | 
					      "version": "1.4.14",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@jridgewell/trace-mapping": {
 | 
					    "node_modules/@jridgewell/trace-mapping": {
 | 
				
			||||||
      "version": "0.3.17",
 | 
					      "version": "0.3.17",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@jridgewell/resolve-uri": "3.1.0",
 | 
					        "@jridgewell/resolve-uri": "3.1.0",
 | 
				
			||||||
@@ -4374,7 +4374,7 @@
 | 
				
			|||||||
      "version": "18.15.11",
 | 
					      "version": "18.15.11",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
 | 
				
			||||||
      "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==",
 | 
					      "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==",
 | 
				
			||||||
      "devOptional": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@types/parse-json": {
 | 
					    "node_modules/@types/parse-json": {
 | 
				
			||||||
      "version": "4.0.0",
 | 
					      "version": "4.0.0",
 | 
				
			||||||
@@ -4419,7 +4419,7 @@
 | 
				
			|||||||
      "version": "18.0.11",
 | 
					      "version": "18.0.11",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz",
 | 
				
			||||||
      "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==",
 | 
					      "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@types/react": "*"
 | 
					        "@types/react": "*"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -4753,7 +4753,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/acorn": {
 | 
					    "node_modules/acorn": {
 | 
				
			||||||
      "version": "8.8.0",
 | 
					      "version": "8.8.0",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "bin": {
 | 
					      "bin": {
 | 
				
			||||||
        "acorn": "bin/acorn"
 | 
					        "acorn": "bin/acorn"
 | 
				
			||||||
@@ -5174,7 +5174,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/buffer-from": {
 | 
					    "node_modules/buffer-from": {
 | 
				
			||||||
      "version": "1.1.2",
 | 
					      "version": "1.1.2",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/builtin-modules": {
 | 
					    "node_modules/builtin-modules": {
 | 
				
			||||||
@@ -9781,7 +9781,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/source-map-support": {
 | 
					    "node_modules/source-map-support": {
 | 
				
			||||||
      "version": "0.5.21",
 | 
					      "version": "0.5.21",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "buffer-from": "^1.0.0",
 | 
					        "buffer-from": "^1.0.0",
 | 
				
			||||||
@@ -9790,7 +9790,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/source-map-support/node_modules/source-map": {
 | 
					    "node_modules/source-map-support/node_modules/source-map": {
 | 
				
			||||||
      "version": "0.6.1",
 | 
					      "version": "0.6.1",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "BSD-3-Clause",
 | 
					      "license": "BSD-3-Clause",
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">=0.10.0"
 | 
					        "node": ">=0.10.0"
 | 
				
			||||||
@@ -10080,7 +10080,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/terser": {
 | 
					    "node_modules/terser": {
 | 
				
			||||||
      "version": "5.15.1",
 | 
					      "version": "5.15.1",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "BSD-2-Clause",
 | 
					      "license": "BSD-2-Clause",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@jridgewell/source-map": "^0.3.2",
 | 
					        "@jridgewell/source-map": "^0.3.2",
 | 
				
			||||||
@@ -10097,7 +10097,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/terser/node_modules/commander": {
 | 
					    "node_modules/terser/node_modules/commander": {
 | 
				
			||||||
      "version": "2.20.3",
 | 
					      "version": "2.20.3",
 | 
				
			||||||
      "devOptional": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/text-table": {
 | 
					    "node_modules/text-table": {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "ucentral-client",
 | 
					  "name": "ucentral-client",
 | 
				
			||||||
  "version": "3.1.0(5)",
 | 
					  "version": "3.2.1",
 | 
				
			||||||
  "description": "",
 | 
					  "description": "",
 | 
				
			||||||
  "private": true,
 | 
					  "private": true,
 | 
				
			||||||
  "main": "index.tsx",
 | 
					  "main": "index.tsx",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										257
									
								
								src/components/Modals/CableDiagnosticsModal/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								src/components/Modals/CableDiagnosticsModal/index.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,257 @@
 | 
				
			|||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Modal,
 | 
				
			||||||
 | 
					  Text,
 | 
				
			||||||
 | 
					  ModalOverlay,
 | 
				
			||||||
 | 
					  ModalContent,
 | 
				
			||||||
 | 
					  ModalBody,
 | 
				
			||||||
 | 
					  Center,
 | 
				
			||||||
 | 
					  Spinner,
 | 
				
			||||||
 | 
					  Checkbox,
 | 
				
			||||||
 | 
					  Stack,
 | 
				
			||||||
 | 
					  Table,
 | 
				
			||||||
 | 
					  Thead,
 | 
				
			||||||
 | 
					  Tbody,
 | 
				
			||||||
 | 
					  Tr,
 | 
				
			||||||
 | 
					  Th,
 | 
				
			||||||
 | 
					  Td,
 | 
				
			||||||
 | 
					} from '@chakra-ui/react';
 | 
				
			||||||
 | 
					import { PlugsConnected } from '@phosphor-icons/react';
 | 
				
			||||||
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
 | 
					import { CloseButton } from 'components/Buttons/CloseButton';
 | 
				
			||||||
 | 
					import { ResponsiveButton } from 'components/Buttons/ResponsiveButton';
 | 
				
			||||||
 | 
					import { ModalHeader } from 'components/Containers/Modal/ModalHeader';
 | 
				
			||||||
 | 
					import { useCableDiagnostics } from 'hooks/Network/Devices';
 | 
				
			||||||
 | 
					import { ModalProps } from 'models/Modal';
 | 
				
			||||||
 | 
					import Button from 'theme/components/button';
 | 
				
			||||||
 | 
					import { DataGridColumn, useDataGrid } from 'components/DataTables/DataGrid/useDataGrid';
 | 
				
			||||||
 | 
					import { DataGrid } from 'components/DataTables/DataGrid';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type CableDiagnosticsModalProps = {
 | 
				
			||||||
 | 
					  modalProps: ModalProps;
 | 
				
			||||||
 | 
					  serialNumber: string;
 | 
				
			||||||
 | 
					  port: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DiagnosticsRow = {
 | 
				
			||||||
 | 
					  port: string;
 | 
				
			||||||
 | 
					  linkStatus: string;
 | 
				
			||||||
 | 
					  pairA: string;
 | 
				
			||||||
 | 
					  pairB: string;
 | 
				
			||||||
 | 
					  pairC: string;
 | 
				
			||||||
 | 
					  pairD: string;
 | 
				
			||||||
 | 
					  type: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type OpticalRow = {
 | 
				
			||||||
 | 
					  port: string;
 | 
				
			||||||
 | 
					  vendorName: string;
 | 
				
			||||||
 | 
					  formFactor: string;
 | 
				
			||||||
 | 
					  partNumber: string;
 | 
				
			||||||
 | 
					  serialNumber: string;
 | 
				
			||||||
 | 
					  temperature: string;
 | 
				
			||||||
 | 
					  txPower: string;
 | 
				
			||||||
 | 
					  rxPower: string;
 | 
				
			||||||
 | 
					  revision: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const CableDiagnosticsModal = ({
 | 
				
			||||||
 | 
					  modalProps: { isOpen, onClose },
 | 
				
			||||||
 | 
					  serialNumber,
 | 
				
			||||||
 | 
					  port,
 | 
				
			||||||
 | 
					}: CableDiagnosticsModalProps) => {
 | 
				
			||||||
 | 
					  const { t } = useTranslation();
 | 
				
			||||||
 | 
					  const [selectedPorts, setSelectedPorts] = React.useState<string[]>([]);
 | 
				
			||||||
 | 
					  const [diagnosticsResult, setDiagnosticsResult] = React.useState<any>(null);
 | 
				
			||||||
 | 
					  const { mutateAsync: diagnose, isLoading } = useCableDiagnostics({ serialNumber });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handlePortToggle = (port: string) => {
 | 
				
			||||||
 | 
					    setSelectedPorts((prev) => (prev.includes(port) ? prev.filter((p) => p !== port) : [...prev, port]));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleDiagnose = async () => {
 | 
				
			||||||
 | 
					    if (port) {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        const result = await diagnose([port]);
 | 
				
			||||||
 | 
					        setDiagnosticsResult(result);
 | 
				
			||||||
 | 
					      } catch (error) {
 | 
				
			||||||
 | 
					        console.error('Error diagnosing cable:', error);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const tableController = useDataGrid({
 | 
				
			||||||
 | 
					    tableSettingsId: 'cable.diagnostics.table',
 | 
				
			||||||
 | 
					    defaultOrder: ['port', 'linkStatus', 'pairA', 'pairB', 'pairC', 'pairD', 'type'],
 | 
				
			||||||
 | 
					    showAllRows: true,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const columns: DataGridColumn<DiagnosticsRow | OpticalRow>[] = React.useMemo(() => {
 | 
				
			||||||
 | 
					    const data = diagnosticsResult?.results?.status?.text?.[port];
 | 
				
			||||||
 | 
					    const isOpticalData = data && 'form-factor' in data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return isOpticalData
 | 
				
			||||||
 | 
					      ? [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'vendorName',
 | 
				
			||||||
 | 
					            header: 'Vendor Name',
 | 
				
			||||||
 | 
					            accessorKey: 'vendorName',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'formFactor',
 | 
				
			||||||
 | 
					            header: 'Form Factor',
 | 
				
			||||||
 | 
					            accessorKey: 'formFactor',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'partNumber',
 | 
				
			||||||
 | 
					            header: 'Part Number',
 | 
				
			||||||
 | 
					            accessorKey: 'partNumber',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'serialNumber',
 | 
				
			||||||
 | 
					            header: 'Serial Number',
 | 
				
			||||||
 | 
					            accessorKey: 'serialNumber',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'temperature',
 | 
				
			||||||
 | 
					            header: 'Temperature',
 | 
				
			||||||
 | 
					            accessorKey: 'temperature',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'txPower',
 | 
				
			||||||
 | 
					            header: 'TX Power',
 | 
				
			||||||
 | 
					            accessorKey: 'txPower',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'rxPower',
 | 
				
			||||||
 | 
					            header: 'RX Power',
 | 
				
			||||||
 | 
					            accessorKey: 'rxPower',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'revision',
 | 
				
			||||||
 | 
					            header: 'Revision',
 | 
				
			||||||
 | 
					            accessorKey: 'revision',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      : [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'port',
 | 
				
			||||||
 | 
					            header: 'Port',
 | 
				
			||||||
 | 
					            accessorKey: 'port',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'linkStatus',
 | 
				
			||||||
 | 
					            header: 'Link Status',
 | 
				
			||||||
 | 
					            accessorKey: 'linkStatus',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'pairA',
 | 
				
			||||||
 | 
					            header: 'Pair A',
 | 
				
			||||||
 | 
					            accessorKey: 'pairA',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'pairB',
 | 
				
			||||||
 | 
					            header: 'Pair B',
 | 
				
			||||||
 | 
					            accessorKey: 'pairB',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'pairC',
 | 
				
			||||||
 | 
					            header: 'Pair C',
 | 
				
			||||||
 | 
					            accessorKey: 'pairC',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'pairD',
 | 
				
			||||||
 | 
					            header: 'Pair D',
 | 
				
			||||||
 | 
					            accessorKey: 'pairD',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 'type',
 | 
				
			||||||
 | 
					            header: 'Type',
 | 
				
			||||||
 | 
					            accessorKey: 'type',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					  }, [diagnosticsResult]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const formatDiagnosticsData = (result: any): (DiagnosticsRow | OpticalRow)[] => {
 | 
				
			||||||
 | 
					    if (!result?.results?.status?.text?.[port]) return [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const data = result.results.status.text[port];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (data['form-factor']) {
 | 
				
			||||||
 | 
					      return [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          port,
 | 
				
			||||||
 | 
					          vendorName: data['vendor-name'] || 'N/A',
 | 
				
			||||||
 | 
					          formFactor: data['form-factor'] || 'N/A',
 | 
				
			||||||
 | 
					          partNumber: data['part-number'] || 'N/A',
 | 
				
			||||||
 | 
					          serialNumber: data['serial-number'] || 'N/A',
 | 
				
			||||||
 | 
					          temperature: data.temperature ? `${data.temperature.toFixed(2)}` : 'N/A',
 | 
				
			||||||
 | 
					          txPower: data['tx-optical-power'] ? `${data['tx-optical-power']}` : 'N/A',
 | 
				
			||||||
 | 
					          rxPower: data['rx-optical-power'] ? `${data['rx-optical-power']}` : 'N/A',
 | 
				
			||||||
 | 
					          revision: data.revision || 'N/A',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        port,
 | 
				
			||||||
 | 
					        linkStatus: data['link-status'],
 | 
				
			||||||
 | 
					        pairA: `${data['pair-A'].meters} (${data['pair-A'].status})`,
 | 
				
			||||||
 | 
					        pairB: `${data['pair-B'].meters} (${data['pair-B'].status})`,
 | 
				
			||||||
 | 
					        pairC: `${data['pair-C'].meters} (${data['pair-C'].status})`,
 | 
				
			||||||
 | 
					        pairD: `${data['pair-D'].meters} (${data['pair-D'].status})`,
 | 
				
			||||||
 | 
					        type: data.type,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Modal onClose={onClose} isOpen={isOpen} size="xl">
 | 
				
			||||||
 | 
					      <ModalOverlay />
 | 
				
			||||||
 | 
					      <ModalContent maxW="50vw">
 | 
				
			||||||
 | 
					        <ModalHeader title={t('commands.cable_diagnostics')} right={<CloseButton onClick={onClose} />} />
 | 
				
			||||||
 | 
					        <ModalBody pb={6}>
 | 
				
			||||||
 | 
					          {isLoading ? (
 | 
				
			||||||
 | 
					            <Center my={4} flexDirection="column" gap={4}>
 | 
				
			||||||
 | 
					              <Spinner size="lg" />
 | 
				
			||||||
 | 
					              <Text>Please wait...</Text>
 | 
				
			||||||
 | 
					              <Text fontSize="sm" color="gray.500">
 | 
				
			||||||
 | 
					                Please do not close this window. This may take a few seconds.
 | 
				
			||||||
 | 
					              </Text>
 | 
				
			||||||
 | 
					            </Center>
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            <Center flexDirection="column" gap={4}>
 | 
				
			||||||
 | 
					              <ResponsiveButton
 | 
				
			||||||
 | 
					                color="blue"
 | 
				
			||||||
 | 
					                icon={<PlugsConnected size={20} />}
 | 
				
			||||||
 | 
					                label={`${
 | 
				
			||||||
 | 
					                  diagnosticsResult && formatDiagnosticsData(diagnosticsResult).length > 0 ? 'Retake' : 'Start'
 | 
				
			||||||
 | 
					                } Test for Port ${port}`}
 | 
				
			||||||
 | 
					                onClick={handleDiagnose}
 | 
				
			||||||
 | 
					                isLoading={isLoading}
 | 
				
			||||||
 | 
					                isDisabled={!port}
 | 
				
			||||||
 | 
					                isCompact={false}
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					              {diagnosticsResult && formatDiagnosticsData(diagnosticsResult).length > 0 && (
 | 
				
			||||||
 | 
					                <DataGrid<DiagnosticsRow | OpticalRow>
 | 
				
			||||||
 | 
					                  controller={tableController}
 | 
				
			||||||
 | 
					                  header={{
 | 
				
			||||||
 | 
					                    title: '',
 | 
				
			||||||
 | 
					                    objectListed: 'Cable Diagnostics',
 | 
				
			||||||
 | 
					                  }}
 | 
				
			||||||
 | 
					                  columns={columns}
 | 
				
			||||||
 | 
					                  isLoading={isLoading}
 | 
				
			||||||
 | 
					                  data={formatDiagnosticsData(diagnosticsResult)}
 | 
				
			||||||
 | 
					                  options={{
 | 
				
			||||||
 | 
					                    isHidingControls: true,
 | 
				
			||||||
 | 
					                  }}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              )}
 | 
				
			||||||
 | 
					            </Center>
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					        </ModalBody>
 | 
				
			||||||
 | 
					      </ModalContent>
 | 
				
			||||||
 | 
					    </Modal>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -377,6 +377,40 @@ export const useWifiScanDevice = ({ serialNumber }: { serialNumber: string }) =>
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useCableDiagnostics = ({ serialNumber }: { serialNumber: string }) => {
 | 
				
			||||||
 | 
					  const toast = useToast();
 | 
				
			||||||
 | 
					  const { t } = useTranslation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return useMutation(
 | 
				
			||||||
 | 
					    (ports: string[]): Promise<unknown> =>
 | 
				
			||||||
 | 
					      axiosGw
 | 
				
			||||||
 | 
					        .post(`device/${serialNumber}/cable-diagnostics`, {
 | 
				
			||||||
 | 
					          serial: serialNumber,
 | 
				
			||||||
 | 
					          ports,
 | 
				
			||||||
 | 
					          when: 0,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .then(({ data }) => data),
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      onSuccess: (data) => {
 | 
				
			||||||
 | 
					        console.log('Success data: ', data);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      onError: (e: AxiosError) => {
 | 
				
			||||||
 | 
					        toast({
 | 
				
			||||||
 | 
					          id: uuid(),
 | 
				
			||||||
 | 
					          title: t('common.error'),
 | 
				
			||||||
 | 
					          description: t('commands.cablediagnostics_error', {
 | 
				
			||||||
 | 
					            e: e?.response?.data?.ErrorDescription,
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					          status: 'error',
 | 
				
			||||||
 | 
					          duration: 5000,
 | 
				
			||||||
 | 
					          isClosable: true,
 | 
				
			||||||
 | 
					          position: 'top-right',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useGetDeviceRtty = ({ serialNumber, extraId }: { serialNumber: string; extraId: string | number }) => {
 | 
					export const useGetDeviceRtty = ({ serialNumber, extraId }: { serialNumber: string; extraId: string | number }) => {
 | 
				
			||||||
  const { t } = useTranslation();
 | 
					  const { t } = useTranslation();
 | 
				
			||||||
  const toast = useToast();
 | 
					  const toast = useToast();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,19 @@
 | 
				
			|||||||
import * as React from 'react';
 | 
					import * as React from 'react';
 | 
				
			||||||
import { IconButton, Tooltip, useToast } from '@chakra-ui/react';
 | 
					import { IconButton, Tooltip, useToast } from '@chakra-ui/react';
 | 
				
			||||||
import { Power } from '@phosphor-icons/react';
 | 
					import { Power, PlugsConnected } from '@phosphor-icons/react';
 | 
				
			||||||
import { useTranslation } from 'react-i18next';
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
import { usePowerCycle } from 'hooks/Network/Devices';
 | 
					import { usePowerCycle } from 'hooks/Network/Devices';
 | 
				
			||||||
import { useNotification } from 'hooks/useNotification';
 | 
					import { useNotification } from 'hooks/useNotification';
 | 
				
			||||||
import { DeviceLinkState } from 'hooks/Network/Statistics';
 | 
					import { DeviceLinkState } from 'hooks/Network/Statistics';
 | 
				
			||||||
 | 
					import { CableDiagnosticsModalProps } from 'components/Modals/CableDiagnosticsModal';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
  state: DeviceLinkState & { name: string };
 | 
					  state: DeviceLinkState & { name: string };
 | 
				
			||||||
  deviceSerialNumber: string;
 | 
					  deviceSerialNumber: string;
 | 
				
			||||||
 | 
					  onOpenCableDiagnostics: (port: string) => void;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const LinkStateTableActions = ({ state, deviceSerialNumber }: Props) => {
 | 
					const LinkStateTableActions = ({ state, deviceSerialNumber, onOpenCableDiagnostics }: Props) => {
 | 
				
			||||||
  const { t } = useTranslation();
 | 
					  const { t } = useTranslation();
 | 
				
			||||||
  const powerCycle = usePowerCycle();
 | 
					  const powerCycle = usePowerCycle();
 | 
				
			||||||
  const toast = useToast();
 | 
					  const toast = useToast();
 | 
				
			||||||
@@ -54,6 +56,7 @@ const LinkStateTableActions = ({ state, deviceSerialNumber }: Props) => {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
      <Tooltip label="Power Cycle" placement="auto-start">
 | 
					      <Tooltip label="Power Cycle" placement="auto-start">
 | 
				
			||||||
        <IconButton
 | 
					        <IconButton
 | 
				
			||||||
          aria-label="Power Cycle"
 | 
					          aria-label="Power Cycle"
 | 
				
			||||||
@@ -64,6 +67,16 @@ const LinkStateTableActions = ({ state, deviceSerialNumber }: Props) => {
 | 
				
			|||||||
          size="xs"
 | 
					          size="xs"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </Tooltip>
 | 
					      </Tooltip>
 | 
				
			||||||
 | 
					      <Tooltip label="Cable Diagnostics" placement="auto-start">
 | 
				
			||||||
 | 
					        <IconButton
 | 
				
			||||||
 | 
					          aria-label="Cable Diagnostics"
 | 
				
			||||||
 | 
					          icon={<PlugsConnected size={20} />}
 | 
				
			||||||
 | 
					          colorScheme="blue"
 | 
				
			||||||
 | 
					          onClick={() => onOpenCableDiagnostics(state.name)}
 | 
				
			||||||
 | 
					          size="xs"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </Tooltip>
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,8 +9,12 @@ import LinkStateTableActions from './Actions';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type Row = DeviceLinkState & { name: string };
 | 
					type Row = DeviceLinkState & { name: string };
 | 
				
			||||||
const dataCell = (v: number) => <DataCell bytes={v} />;
 | 
					const dataCell = (v: number) => <DataCell bytes={v} />;
 | 
				
			||||||
const actionCell = (row: Row, serialNumber: string) => (
 | 
					const actionCell = (row: Row, serialNumber: string, onOpenCableDiagnostics: (port: string) => void) => (
 | 
				
			||||||
  <LinkStateTableActions state={row} deviceSerialNumber={serialNumber} />
 | 
					  <LinkStateTableActions
 | 
				
			||||||
 | 
					    state={row}
 | 
				
			||||||
 | 
					    deviceSerialNumber={serialNumber}
 | 
				
			||||||
 | 
					    onOpenCableDiagnostics={onOpenCableDiagnostics}
 | 
				
			||||||
 | 
					  />
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
@@ -19,9 +23,10 @@ type Props = {
 | 
				
			|||||||
  isFetching: boolean;
 | 
					  isFetching: boolean;
 | 
				
			||||||
  type: 'upstream' | 'downstream';
 | 
					  type: 'upstream' | 'downstream';
 | 
				
			||||||
  serialNumber: string;
 | 
					  serialNumber: string;
 | 
				
			||||||
 | 
					  onOpenCableDiagnostics: (port: string) => void;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const LinkStateTable = ({ statistics, refetch, isFetching, type, serialNumber }: Props) => {
 | 
					const LinkStateTable = ({ statistics, refetch, isFetching, type, serialNumber, onOpenCableDiagnostics }: Props) => {
 | 
				
			||||||
  const tableController = useDataGrid({
 | 
					  const tableController = useDataGrid({
 | 
				
			||||||
    tableSettingsId: 'switch.link-state.table',
 | 
					    tableSettingsId: 'switch.link-state.table',
 | 
				
			||||||
    defaultOrder: [
 | 
					    defaultOrder: [
 | 
				
			||||||
@@ -157,10 +162,16 @@ const LinkStateTable = ({ statistics, refetch, isFetching, type, serialNumber }:
 | 
				
			|||||||
        id: 'actions',
 | 
					        id: 'actions',
 | 
				
			||||||
        header: '',
 | 
					        header: '',
 | 
				
			||||||
        accessorKey: '',
 | 
					        accessorKey: '',
 | 
				
			||||||
        cell: ({ cell }) => actionCell(cell.row.original, serialNumber),
 | 
					        cell: ({ cell }) => (
 | 
				
			||||||
 | 
					          <LinkStateTableActions
 | 
				
			||||||
 | 
					            state={cell.row.original}
 | 
				
			||||||
 | 
					            deviceSerialNumber={serialNumber}
 | 
				
			||||||
 | 
					            onOpenCableDiagnostics={onOpenCableDiagnostics}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    [],
 | 
					    [onOpenCableDiagnostics],
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!statistics || statistics?.length === 0) {
 | 
					  if (!statistics || statistics?.length === 0) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@ import SwitchInterfaceTable from './SwitchInterfaceTable';
 | 
				
			|||||||
import { DeviceLinkState, useGetDeviceLastStats } from 'hooks/Network/Statistics';
 | 
					import { DeviceLinkState, useGetDeviceLastStats } from 'hooks/Network/Statistics';
 | 
				
			||||||
import { Card } from 'components/Containers/Card';
 | 
					import { Card } from 'components/Containers/Card';
 | 
				
			||||||
import { CardBody } from 'components/Containers/Card/CardBody';
 | 
					import { CardBody } from 'components/Containers/Card/CardBody';
 | 
				
			||||||
 | 
					import { CableDiagnosticsModal } from 'components/Modals/CableDiagnosticsModal';
 | 
				
			||||||
 | 
					import { useDisclosure } from '@chakra-ui/react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
  serialNumber: string;
 | 
					  serialNumber: string;
 | 
				
			||||||
@@ -12,6 +14,8 @@ type Props = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const SwitchPortExamination = ({ serialNumber }: Props) => {
 | 
					const SwitchPortExamination = ({ serialNumber }: Props) => {
 | 
				
			||||||
  const [tabIndex, setTabIndex] = React.useState(0);
 | 
					  const [tabIndex, setTabIndex] = React.useState(0);
 | 
				
			||||||
 | 
					  const [selectedPort, setSelectedPort] = React.useState<string>('');
 | 
				
			||||||
 | 
					  const cableDiagnosticsModalProps = useDisclosure();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleTabsChange = React.useCallback((index: number) => {
 | 
					  const handleTabsChange = React.useCallback((index: number) => {
 | 
				
			||||||
    setTabIndex(index);
 | 
					    setTabIndex(index);
 | 
				
			||||||
@@ -35,7 +39,13 @@ const SwitchPortExamination = ({ serialNumber }: Props) => {
 | 
				
			|||||||
    }));
 | 
					    }));
 | 
				
			||||||
  }, [getStats.data]);
 | 
					  }, [getStats.data]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleOpenCableDiagnostics = React.useCallback((port: string) => {
 | 
				
			||||||
 | 
					    setSelectedPort(port);
 | 
				
			||||||
 | 
					    cableDiagnosticsModalProps.onOpen();
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
      <Card p={0} mb={4}>
 | 
					      <Card p={0} mb={4}>
 | 
				
			||||||
        <CardBody p={0} display="block">
 | 
					        <CardBody p={0} display="block">
 | 
				
			||||||
          <Tabs index={tabIndex} onChange={handleTabsChange} variant="enclosed" w="100%">
 | 
					          <Tabs index={tabIndex} onChange={handleTabsChange} variant="enclosed" w="100%">
 | 
				
			||||||
@@ -70,6 +80,7 @@ const SwitchPortExamination = ({ serialNumber }: Props) => {
 | 
				
			|||||||
                    isFetching={getStats.isFetching}
 | 
					                    isFetching={getStats.isFetching}
 | 
				
			||||||
                    type="upstream"
 | 
					                    type="upstream"
 | 
				
			||||||
                    serialNumber={serialNumber}
 | 
					                    serialNumber={serialNumber}
 | 
				
			||||||
 | 
					                    onOpenCableDiagnostics={handleOpenCableDiagnostics}
 | 
				
			||||||
                  />
 | 
					                  />
 | 
				
			||||||
                ) : (
 | 
					                ) : (
 | 
				
			||||||
                  <Spinner size="xl" />
 | 
					                  <Spinner size="xl" />
 | 
				
			||||||
@@ -83,6 +94,7 @@ const SwitchPortExamination = ({ serialNumber }: Props) => {
 | 
				
			|||||||
                    isFetching={getStats.isFetching}
 | 
					                    isFetching={getStats.isFetching}
 | 
				
			||||||
                    type="downstream"
 | 
					                    type="downstream"
 | 
				
			||||||
                    serialNumber={serialNumber}
 | 
					                    serialNumber={serialNumber}
 | 
				
			||||||
 | 
					                    onOpenCableDiagnostics={handleOpenCableDiagnostics}
 | 
				
			||||||
                  />
 | 
					                  />
 | 
				
			||||||
                ) : (
 | 
					                ) : (
 | 
				
			||||||
                  <Spinner size="xl" />
 | 
					                  <Spinner size="xl" />
 | 
				
			||||||
@@ -92,6 +104,8 @@ const SwitchPortExamination = ({ serialNumber }: Props) => {
 | 
				
			|||||||
          </Tabs>
 | 
					          </Tabs>
 | 
				
			||||||
        </CardBody>
 | 
					        </CardBody>
 | 
				
			||||||
      </Card>
 | 
					      </Card>
 | 
				
			||||||
 | 
					      <CableDiagnosticsModal modalProps={cableDiagnosticsModalProps} serialNumber={serialNumber} port={selectedPort} />
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,6 +68,7 @@ const DevicePageWrapper = ({ serialNumber }: Props) => {
 | 
				
			|||||||
  const getHealth = useGetDeviceHealthChecks({ serialNumber, limit: 1 });
 | 
					  const getHealth = useGetDeviceHealthChecks({ serialNumber, limit: 1 });
 | 
				
			||||||
  const { isOpen: isDeleteOpen, onOpen: onDeleteOpen, onClose: onDeleteClose } = useDisclosure();
 | 
					  const { isOpen: isDeleteOpen, onOpen: onDeleteOpen, onClose: onDeleteClose } = useDisclosure();
 | 
				
			||||||
  const scanModalProps = useDisclosure();
 | 
					  const scanModalProps = useDisclosure();
 | 
				
			||||||
 | 
					  const cableDiagnosticsModalProps = useDisclosure();
 | 
				
			||||||
  const resetModalProps = useDisclosure();
 | 
					  const resetModalProps = useDisclosure();
 | 
				
			||||||
  const eventQueueProps = useDisclosure();
 | 
					  const eventQueueProps = useDisclosure();
 | 
				
			||||||
  const configureModalProps = useDisclosure();
 | 
					  const configureModalProps = useDisclosure();
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user