mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui.git
				synced 2025-10-31 10:47:55 +00:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 460ba9eee7 | ||
|   | 788e1f59bd | 
							
								
								
									
										1
									
								
								.env
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.env
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | VITE_UCENTRALSEC_URL="https://ucentral.dpaas.arilia.com:16001" | ||||||
							
								
								
									
										2
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -20,7 +20,7 @@ defaults: | |||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   docker: |   docker: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-20.04 | ||||||
|     env: |     env: | ||||||
|       DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io |       DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||||
|       DOCKER_REGISTRY_USERNAME: ucentral |       DOCKER_REGISTRY_USERNAME: ucentral | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -11,7 +11,7 @@ defaults: | |||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   helm-package: |   helm-package: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-20.04 | ||||||
|     env: |     env: | ||||||
|       HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ |       HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ | ||||||
|       HELM_REPO_USERNAME: ucentral |       HELM_REPO_USERNAME: ucentral | ||||||
|   | |||||||
| @@ -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: main |     tag: v3.2.0 | ||||||
|     pullPolicy: Always |     pullPolicy: Always | ||||||
|  |  | ||||||
| services: | services: | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,12 +1,12 @@ | |||||||
| { | { | ||||||
|   "name": "ucentral-client", |   "name": "ucentral-client", | ||||||
|   "version": "4.1.0", |   "version": "3.1.0(5)", | ||||||
|   "lockfileVersion": 3, |   "lockfileVersion": 3, | ||||||
|   "requires": true, |   "requires": true, | ||||||
|   "packages": { |   "packages": { | ||||||
|     "": { |     "": { | ||||||
|       "name": "ucentral-client", |       "name": "ucentral-client", | ||||||
|       "version": "4.1.0", |       "version": "3.1.0(5)", | ||||||
|       "license": "ISC", |       "license": "ISC", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@chakra-ui/anatomy": "^2.1.1", |         "@chakra-ui/anatomy": "^2.1.1", | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "ucentral-client", |   "name": "ucentral-client", | ||||||
|   "version": "4.1.0", |   "version": "3.2.0", | ||||||
|   "description": "", |   "description": "", | ||||||
|   "private": true, |   "private": true, | ||||||
|   "main": "index.tsx", |   "main": "index.tsx", | ||||||
|   | |||||||
| @@ -514,10 +514,6 @@ | |||||||
| 			"started_upgrade": "{{serialNumber}} just shut down to start the upgrade!", | 			"started_upgrade": "{{serialNumber}} just shut down to start the upgrade!", | ||||||
| 			"trace": "Trace", | 			"trace": "Trace", | ||||||
| 			"trace_description": "Launch a remote trace of this device for either a specific duration or a number of packets", | 			"trace_description": "Launch a remote trace of this device for either a specific duration or a number of packets", | ||||||
|       "re_enroll": "Re-enroll", |  | ||||||
|       "re_enroll_initiated": "Re-enrollment initiated for device {{serialNumber}}", |  | ||||||
|       "re_enroll_warning": "This will renew the operational certificate for device {{serialNumber}}.", |  | ||||||
|       "confirm_re_enroll": "Renew Certificate for {{serialNumber}}", |  | ||||||
| 			"update_success": "Device updated!", | 			"update_success": "Device updated!", | ||||||
| 			"updated_blacklist": "Updated Blacklist!" | 			"updated_blacklist": "Updated Blacklist!" | ||||||
| 		}, | 		}, | ||||||
| @@ -626,7 +622,6 @@ | |||||||
| 		"all": "All", | 		"all": "All", | ||||||
| 		"associations": "Associations", | 		"associations": "Associations", | ||||||
| 		"certificate_expires_in": "Certificate Expiry", | 		"certificate_expires_in": "Certificate Expiry", | ||||||
|     "certificate_issuer": "Certificate Issuer", |  | ||||||
| 		"certificate_expiry": "Cert. Expires In", | 		"certificate_expiry": "Cert. Expires In", | ||||||
| 		"connected": "Connected", | 		"connected": "Connected", | ||||||
| 		"crash_logs": "Crash Logs", | 		"crash_logs": "Crash Logs", | ||||||
|   | |||||||
| @@ -32,7 +32,6 @@ interface Props { | |||||||
|   onOpenTelemetryModal: (serialNumber: string) => void; |   onOpenTelemetryModal: (serialNumber: string) => void; | ||||||
|   onOpenScriptModal: (device: GatewayDevice) => void; |   onOpenScriptModal: (device: GatewayDevice) => void; | ||||||
|   onOpenRebootModal: (serialNumber: string) => void; |   onOpenRebootModal: (serialNumber: string) => void; | ||||||
|   onOpenReEnrollModal?: (serialNumber: string) => void; |  | ||||||
|   size?: 'sm' | 'md' | 'lg'; |   size?: 'sm' | 'md' | 'lg'; | ||||||
|   isCompact?: boolean; |   isCompact?: boolean; | ||||||
| } | } | ||||||
| @@ -50,7 +49,6 @@ const DeviceActionDropdown = ({ | |||||||
|   onOpenConfigureModal, |   onOpenConfigureModal, | ||||||
|   onOpenScriptModal, |   onOpenScriptModal, | ||||||
|   onOpenRebootModal, |   onOpenRebootModal, | ||||||
|   onOpenReEnrollModal, |  | ||||||
|   size, |   size, | ||||||
|   isCompact, |   isCompact, | ||||||
| }: Props) => { | }: Props) => { | ||||||
| @@ -236,11 +234,6 @@ const DeviceActionDropdown = ({ | |||||||
|             <MenuItem onClick={handleRebootClick} hidden={!isCompact}> |             <MenuItem onClick={handleRebootClick} hidden={!isCompact}> | ||||||
|               {t('commands.reboot')} |               {t('commands.reboot')} | ||||||
|             </MenuItem> |             </MenuItem> | ||||||
|             {onOpenReEnrollModal && ( |  | ||||||
|               <MenuItem onClick={() => onOpenReEnrollModal(device.serialNumber)}> |  | ||||||
|                 {t('controller.devices.re_enroll')} |  | ||||||
|               </MenuItem> |  | ||||||
|             )} |  | ||||||
|             <MenuItem onClick={handleOpenTelemetry}>{t('controller.telemetry.title')}</MenuItem> |             <MenuItem onClick={handleOpenTelemetry}>{t('controller.telemetry.title')}</MenuItem> | ||||||
|             <MenuItem onClick={handleOpenScript}>{t('script.one')}</MenuItem> |             <MenuItem onClick={handleOpenScript}>{t('script.one')}</MenuItem> | ||||||
|             <MenuItem onClick={handleOpenTrace}>{t('controller.devices.trace')}</MenuItem> |             <MenuItem onClick={handleOpenTrace}>{t('controller.devices.trace')}</MenuItem> | ||||||
|   | |||||||
| @@ -1,257 +0,0 @@ | |||||||
| 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> |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
| @@ -1,50 +0,0 @@ | |||||||
| import React from 'react'; |  | ||||||
| import { Center, Spinner, Alert, Button } from '@chakra-ui/react'; |  | ||||||
| import { useTranslation } from 'react-i18next'; |  | ||||||
| import { Modal } from '../Modal'; |  | ||||||
| import { useReEnroll } from 'hooks/Network/ReEnroll'; |  | ||||||
| import { ModalProps } from 'models/Modal'; |  | ||||||
|  |  | ||||||
| interface Props { |  | ||||||
|   modalProps: ModalProps; |  | ||||||
|   serialNumber: string; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const ReEnrollModal = ({ modalProps: { isOpen, onClose }, serialNumber }: Props) => { |  | ||||||
|   const { t } = useTranslation(); |  | ||||||
|   const { mutate: reEnroll, isLoading } = useReEnroll({ serialNumber }); |  | ||||||
|  |  | ||||||
|   const submit = () => { |  | ||||||
|     reEnroll( |  | ||||||
|       { serialNumber, when: 0 }, |  | ||||||
|       { |  | ||||||
|         onSuccess: () => { |  | ||||||
|           onClose(); |  | ||||||
|         }, |  | ||||||
|       } |  | ||||||
|     ); |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   return ( |  | ||||||
|     <Modal isOpen={isOpen} onClose={onClose} title={t('controller.devices.re_enroll')}> |  | ||||||
|       {isLoading ? ( |  | ||||||
|         <Center> |  | ||||||
|           <Spinner size="lg" /> |  | ||||||
|         </Center> |  | ||||||
|       ) : ( |  | ||||||
|         <> |  | ||||||
|           <Alert colorScheme="blue" mb={6}> |  | ||||||
|             {t('controller.devices.re_enroll_warning', { serialNumber })} |  | ||||||
|           </Alert> |  | ||||||
|           <Center mb={6}> |  | ||||||
|             <Button size="lg" colorScheme="blue" onClick={submit} fontWeight="bold"> |  | ||||||
|               {t('controller.devices.confirm_re_enroll', { serialNumber })} |  | ||||||
|             </Button> |  | ||||||
|           </Center> |  | ||||||
|         </> |  | ||||||
|       )} |  | ||||||
|     </Modal> |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export default ReEnrollModal; |  | ||||||
| @@ -166,7 +166,6 @@ export type DeviceStatus = { | |||||||
|   connected: boolean; |   connected: boolean; | ||||||
|   connectReason?: string; |   connectReason?: string; | ||||||
|   certificateExpiryDate: number; |   certificateExpiryDate: number; | ||||||
|   certificateIssuerName?: string; |  | ||||||
|   connectionCompletionTime: number; |   connectionCompletionTime: number; | ||||||
|   firmware: string; |   firmware: string; | ||||||
|   ipAddress: string; |   ipAddress: string; | ||||||
| @@ -378,40 +377,6 @@ 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,78 +0,0 @@ | |||||||
| import { useToast } from '@chakra-ui/react'; |  | ||||||
| import { useMutation, useQueryClient } from '@tanstack/react-query'; |  | ||||||
| import { useTranslation } from 'react-i18next'; |  | ||||||
| import { axiosGw } from 'constants/axiosInstances'; |  | ||||||
|  |  | ||||||
| export type ReEnrollRequest = { |  | ||||||
|   serialNumber: string; |  | ||||||
|   when?: number; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export type ReEnrollResponse = { |  | ||||||
|   UUID: string; |  | ||||||
|   command: 're-enroll' | 'reenroll'; |  | ||||||
|   completed: number; |  | ||||||
|   custom: number; |  | ||||||
|   details: { |  | ||||||
|     serial: string; |  | ||||||
|     when: number; |  | ||||||
|   }; |  | ||||||
|   errorCode: number; |  | ||||||
|   errorText: string; |  | ||||||
|   executed: number; |  | ||||||
|   executionTime: number; |  | ||||||
|   results: { |  | ||||||
|     serial: string; |  | ||||||
|     status: { |  | ||||||
|       error: number; |  | ||||||
|       resultCode: number; |  | ||||||
|       resultText: string; |  | ||||||
|       text: string; |  | ||||||
|     }; |  | ||||||
|   }; |  | ||||||
|   serialNumber: string; |  | ||||||
|   status: string; |  | ||||||
|   submitted: number; |  | ||||||
|   submittedBy: string; |  | ||||||
|   when: number; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const reEnrollDevice = async ({ serialNumber, when = 0 }: ReEnrollRequest) => |  | ||||||
|   axiosGw.post<ReEnrollResponse>(`device/${serialNumber}/reenroll`, { |  | ||||||
|     serial: serialNumber, |  | ||||||
|     when, |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
| export const useReEnroll = ({ serialNumber }: { serialNumber: string }) => { |  | ||||||
|   const queryClient = useQueryClient(); |  | ||||||
|   const { t } = useTranslation(); |  | ||||||
|   const toast = useToast(); |  | ||||||
|  |  | ||||||
|   return useMutation(reEnrollDevice, { |  | ||||||
|     onSuccess: () => { |  | ||||||
|       queryClient.invalidateQueries(['commands', serialNumber]); |  | ||||||
|       queryClient.invalidateQueries(['device', serialNumber]); |  | ||||||
|       queryClient.invalidateQueries(['device-status', serialNumber]); |  | ||||||
|       toast({ |  | ||||||
|         id: `re-enroll-success-${serialNumber}`, |  | ||||||
|         title: t('common.success'), |  | ||||||
|         description: t('controller.devices.re_enroll_initiated', { serialNumber }), |  | ||||||
|         status: 'success', |  | ||||||
|         duration: 5000, |  | ||||||
|         isClosable: true, |  | ||||||
|         position: 'top-right', |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|     onError: (error: any) => { |  | ||||||
|       toast({ |  | ||||||
|         id: `re-enroll-error-${serialNumber}`, |  | ||||||
|         title: t('common.error'), |  | ||||||
|         description: error?.response?.data?.ErrorDescription || t('common.error'), |  | ||||||
|         status: 'error', |  | ||||||
|         duration: 5000, |  | ||||||
|         isClosable: true, |  | ||||||
|         position: 'top-right', |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
| @@ -171,12 +171,6 @@ const DeviceSummary = ({ serialNumber }: Props) => { | |||||||
|                 '-' |                 '-' | ||||||
|               )} |               )} | ||||||
|             </GridItem> |             </GridItem> | ||||||
|             <GridItem colSpan={1} alignContent="center" alignItems="center"> |  | ||||||
|               <Heading size="sm">{t('devices.certificate_issuer')}:</Heading> |  | ||||||
|             </GridItem> |  | ||||||
|             <GridItem colSpan={1}> |  | ||||||
|               {getStatus.data?.certificateIssuerName ? getStatus.data.certificateIssuerName.split('CN=')[1] : '-'} |  | ||||||
|             </GridItem> |  | ||||||
|             <GridItem colSpan={1} alignContent="center" alignItems="center"> |             <GridItem colSpan={1} alignContent="center" alignItems="center"> | ||||||
|               <Heading size="sm">Connect Reason:</Heading> |               <Heading size="sm">Connect Reason:</Heading> | ||||||
|             </GridItem> |             </GridItem> | ||||||
|   | |||||||
| @@ -1,19 +1,17 @@ | |||||||
| 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, PlugsConnected } from '@phosphor-icons/react'; | import { Power } 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, onOpenCableDiagnostics }: Props) => { | const LinkStateTableActions = ({ state, deviceSerialNumber }: Props) => { | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const powerCycle = usePowerCycle(); |   const powerCycle = usePowerCycle(); | ||||||
|   const toast = useToast(); |   const toast = useToast(); | ||||||
| @@ -56,7 +54,6 @@ const LinkStateTableActions = ({ state, deviceSerialNumber, onOpenCableDiagnosti | |||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   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" | ||||||
| @@ -67,16 +64,6 @@ const LinkStateTableActions = ({ state, deviceSerialNumber, onOpenCableDiagnosti | |||||||
|         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,12 +9,8 @@ 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, onOpenCableDiagnostics: (port: string) => void) => ( | const actionCell = (row: Row, serialNumber: string) => ( | ||||||
|   <LinkStateTableActions |   <LinkStateTableActions state={row} deviceSerialNumber={serialNumber} /> | ||||||
|     state={row} |  | ||||||
|     deviceSerialNumber={serialNumber} |  | ||||||
|     onOpenCableDiagnostics={onOpenCableDiagnostics} |  | ||||||
|   /> |  | ||||||
| ); | ); | ||||||
|  |  | ||||||
| type Props = { | type Props = { | ||||||
| @@ -23,10 +19,9 @@ 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, onOpenCableDiagnostics }: Props) => { | const LinkStateTable = ({ statistics, refetch, isFetching, type, serialNumber }: Props) => { | ||||||
|   const tableController = useDataGrid({ |   const tableController = useDataGrid({ | ||||||
|     tableSettingsId: 'switch.link-state.table', |     tableSettingsId: 'switch.link-state.table', | ||||||
|     defaultOrder: [ |     defaultOrder: [ | ||||||
| @@ -162,16 +157,10 @@ const LinkStateTable = ({ statistics, refetch, isFetching, type, serialNumber, o | |||||||
|         id: 'actions', |         id: 'actions', | ||||||
|         header: '', |         header: '', | ||||||
|         accessorKey: '', |         accessorKey: '', | ||||||
|         cell: ({ cell }) => ( |         cell: ({ cell }) => actionCell(cell.row.original, serialNumber), | ||||||
|           <LinkStateTableActions |  | ||||||
|             state={cell.row.original} |  | ||||||
|             deviceSerialNumber={serialNumber} |  | ||||||
|             onOpenCableDiagnostics={onOpenCableDiagnostics} |  | ||||||
|           /> |  | ||||||
|         ), |  | ||||||
|       }, |       }, | ||||||
|     ], |     ], | ||||||
|     [onOpenCableDiagnostics], |     [], | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   if (!statistics || statistics?.length === 0) { |   if (!statistics || statistics?.length === 0) { | ||||||
|   | |||||||
| @@ -5,8 +5,6 @@ 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; | ||||||
| @@ -14,8 +12,6 @@ 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); | ||||||
| @@ -39,13 +35,7 @@ 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%"> | ||||||
| @@ -80,7 +70,6 @@ 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" /> | ||||||
| @@ -94,7 +83,6 @@ 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" /> | ||||||
| @@ -104,8 +92,6 @@ const SwitchPortExamination = ({ serialNumber }: Props) => { | |||||||
|         </Tabs> |         </Tabs> | ||||||
|       </CardBody> |       </CardBody> | ||||||
|     </Card> |     </Card> | ||||||
|       <CableDiagnosticsModal modalProps={cableDiagnosticsModalProps} serialNumber={serialNumber} port={selectedPort} /> |  | ||||||
|     </> |  | ||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -41,7 +41,6 @@ import { EventQueueModal } from 'components/Modals/EventQueueModal'; | |||||||
| import FactoryResetModal from 'components/Modals/FactoryResetModal'; | import FactoryResetModal from 'components/Modals/FactoryResetModal'; | ||||||
| import { FirmwareUpgradeModal } from 'components/Modals/FirmwareUpgradeModal'; | import { FirmwareUpgradeModal } from 'components/Modals/FirmwareUpgradeModal'; | ||||||
| import { RebootModal } from 'components/Modals/RebootModal'; | import { RebootModal } from 'components/Modals/RebootModal'; | ||||||
| import ReEnrollModal from 'components/Modals/ReEnrollModal'; |  | ||||||
| import { useScriptModal } from 'components/Modals/ScriptModal/useScriptModal'; | import { useScriptModal } from 'components/Modals/ScriptModal/useScriptModal'; | ||||||
| import ethernetConnected from './ethernetIconConnected.svg?react'; | import ethernetConnected from './ethernetIconConnected.svg?react'; | ||||||
| import ethernetDisconnected from './ethernetIconDisconnected.svg?react'; | import ethernetDisconnected from './ethernetIconDisconnected.svg?react'; | ||||||
| @@ -69,7 +68,6 @@ 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(); | ||||||
| @@ -77,7 +75,6 @@ const DevicePageWrapper = ({ serialNumber }: Props) => { | |||||||
|   const telemetryModalProps = useDisclosure(); |   const telemetryModalProps = useDisclosure(); | ||||||
|   const traceModalProps = useDisclosure(); |   const traceModalProps = useDisclosure(); | ||||||
|   const rebootModalProps = useDisclosure(); |   const rebootModalProps = useDisclosure(); | ||||||
|   const reEnrollModalProps = useDisclosure(); |  | ||||||
|   const scriptModal = useScriptModal(); |   const scriptModal = useScriptModal(); | ||||||
|   // Sticky-top styles |   // Sticky-top styles | ||||||
|   const isCompact = breakpoint === 'base' || breakpoint === 'sm' || breakpoint === 'md'; |   const isCompact = breakpoint === 'base' || breakpoint === 'sm' || breakpoint === 'md'; | ||||||
| @@ -218,7 +215,6 @@ const DevicePageWrapper = ({ serialNumber }: Props) => { | |||||||
|                   onOpenTelemetryModal={telemetryModalProps.onOpen} |                   onOpenTelemetryModal={telemetryModalProps.onOpen} | ||||||
|                   onOpenScriptModal={scriptModal.openModal} |                   onOpenScriptModal={scriptModal.openModal} | ||||||
|                   onOpenRebootModal={rebootModalProps.onOpen} |                   onOpenRebootModal={rebootModalProps.onOpen} | ||||||
|                   onOpenReEnrollModal={reEnrollModalProps.onOpen} |  | ||||||
|                   size="md" |                   size="md" | ||||||
|                   isCompact |                   isCompact | ||||||
|                 /> |                 /> | ||||||
| @@ -271,7 +267,6 @@ const DevicePageWrapper = ({ serialNumber }: Props) => { | |||||||
|                     onOpenTelemetryModal={telemetryModalProps.onOpen} |                     onOpenTelemetryModal={telemetryModalProps.onOpen} | ||||||
|                     onOpenRebootModal={rebootModalProps.onOpen} |                     onOpenRebootModal={rebootModalProps.onOpen} | ||||||
|                     onOpenScriptModal={scriptModal.openModal} |                     onOpenScriptModal={scriptModal.openModal} | ||||||
|                     onOpenReEnrollModal={reEnrollModalProps.onOpen} |  | ||||||
|                     size="md" |                     size="md" | ||||||
|                   /> |                   /> | ||||||
|                 )} |                 )} | ||||||
| @@ -315,7 +310,6 @@ const DevicePageWrapper = ({ serialNumber }: Props) => { | |||||||
|       <ConfigureModal serialNumber={serialNumber} modalProps={configureModalProps} /> |       <ConfigureModal serialNumber={serialNumber} modalProps={configureModalProps} /> | ||||||
|       <TelemetryModal serialNumber={serialNumber} modalProps={telemetryModalProps} /> |       <TelemetryModal serialNumber={serialNumber} modalProps={telemetryModalProps} /> | ||||||
|       <RebootModal serialNumber={serialNumber} modalProps={rebootModalProps} /> |       <RebootModal serialNumber={serialNumber} modalProps={rebootModalProps} /> | ||||||
|       <ReEnrollModal serialNumber={serialNumber} modalProps={reEnrollModalProps} /> |  | ||||||
|       {scriptModal.modal} |       {scriptModal.modal} | ||||||
|       <Box mt={isCompact ? '0px' : '68px'}> |       <Box mt={isCompact ? '0px' : '68px'}> | ||||||
|         <Masonry |         <Masonry | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user