From 2090b55551f21b3edc1163ed2244c1465994cbfb Mon Sep 17 00:00:00 2001 From: Dhruv-J Date: Mon, 11 Dec 2023 14:50:50 -0800 Subject: [PATCH] test and panel file updated Signed-off-by: Dhruv-J --- .../src/TablePanel.test.tsx | 59 ++++++++ .../src/TablePanel.tsx | 136 ++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 plugins/grafana-custom-plugins/grafana-http-table-plugin/src/TablePanel.test.tsx create mode 100644 plugins/grafana-custom-plugins/grafana-http-table-plugin/src/TablePanel.tsx diff --git a/plugins/grafana-custom-plugins/grafana-http-table-plugin/src/TablePanel.test.tsx b/plugins/grafana-custom-plugins/grafana-http-table-plugin/src/TablePanel.test.tsx new file mode 100644 index 00000000..4ab2c03e --- /dev/null +++ b/plugins/grafana-custom-plugins/grafana-http-table-plugin/src/TablePanel.test.tsx @@ -0,0 +1,59 @@ +import { configure } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +import { TablePanel } from './TablePanel'; +import { LoadingState, PanelProps, TimeRange, toDataFrame } from '@grafana/data'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import React from 'react'; + +configure({ adapter: new Adapter() }); + +describe('Table Plugin Test', () => { + it('Should render Table', () => { + let props = {} as PanelProps; + let timeRange = {} as TimeRange; + props.data = { + series: [ + toDataFrame({ + refId: 'A', + fields: [ + { name: 'sourceIP', values: ['10.10.1.4'] }, + { name: 'sourceTransportPort', values: ['42162'] }, + { name: 'destinationIP', values: ['93.184.216.34'] }, + { name: 'destinationTransportPort', values: ['80'] }, + { name: 'httpVals', values: ['{"0":{"hostname":"example.com","url":"/","http_user_agent":"curl/7.88.1","http_content_type":"text/html","http_method":"GET","protocol":"HTTP/1.1","status":200,"length":1256},"1":{"hostname":"example.com","url":"/","http_user_agent":"curl/7.88.1","http_content_type":"text/html","http_method":"GET","protocol":"HTTP/1.1","status":200,"length":1256},"2":{"hostname":"example.com","url":"/","http_user_agent":"curl/7.88.1","http_content_type":"text/html","http_method":"GET","protocol":"HTTP/1.1","status":200,"length":1256}}'] }, + ], + }), + ], + state: LoadingState.Done, + timeRange: timeRange, + }; + props.width = 600, + props.height = 600; + props.options = {}; + let { unmount } = render(); + React.useLayoutEffect = React.useEffect; + + // check each column of the row is in the document and exists three times + expect(screen.getAllByText('10.10.1.4:42162').length).toEqual(3); + expect(screen.getAllByText('10.10.1.4:42162')[0]).toBeInTheDocument(); + expect(screen.getAllByText('93.184.216.34:80').length).toEqual(3); + expect(screen.getAllByText('93.184.216.34:80')[0]).toBeInTheDocument(); + expect(screen.getAllByText('example.com').length).toEqual(3); + expect(screen.getAllByText('example.com')[0]).toBeInTheDocument(); + expect(screen.getAllByText('/').length).toEqual(3); + expect(screen.getAllByText('/')[0]).toBeInTheDocument(); + expect(screen.getAllByText('curl/7.88.1').length).toEqual(3); + expect(screen.getAllByText('curl/7.88.1')[0]).toBeInTheDocument(); + expect(screen.getAllByText('text/html').length).toEqual(3); + expect(screen.getAllByText('text/html')[0]).toBeInTheDocument(); + expect(screen.getAllByText('GET').length).toEqual(3); + expect(screen.getAllByText('GET')[0]).toBeInTheDocument(); + expect(screen.getAllByText('200').length).toEqual(3); + expect(screen.getAllByText('200')[0]).toBeInTheDocument(); + expect(screen.getAllByText('1256').length).toEqual(3); + expect(screen.getAllByText('1256')[0]).toBeInTheDocument(); + + unmount(); + }); +}); diff --git a/plugins/grafana-custom-plugins/grafana-http-table-plugin/src/TablePanel.tsx b/plugins/grafana-custom-plugins/grafana-http-table-plugin/src/TablePanel.tsx new file mode 100644 index 00000000..83d0d950 --- /dev/null +++ b/plugins/grafana-custom-plugins/grafana-http-table-plugin/src/TablePanel.tsx @@ -0,0 +1,136 @@ +import React, { useMemo } from 'react'; +import {config} from '@grafana/runtime' +import { PanelProps } from '@grafana/data'; +import { SimpleOptions } from 'types'; +import { MaterialReactTable, type MRT_ColumnDef} from 'material-react-table'; +import { ThemeProvider, createTheme } from '@mui/material'; + +interface Props extends PanelProps {} + +export const TablePanel: React.FC = ({ options, data, width, height }) => { + const frame = data.series[0]; + const columns = useMemo>>( + () => [ + {header: 'Source', accessorKey: 'source'}, + {header: 'Destination', accessorKey: 'destination'}, + {header: 'Transaction ID', accessorKey: 'txId'}, + {header: 'Hostname', accessorKey: 'hostname'}, + {header: 'URL', accessorKey: 'url'}, + {header: 'HTTP User Agent', accessorKey: 'http_user_agent'}, + {header: 'HTTP Content Type', accessorKey: 'http_content_type'}, + {header: 'HTTP Method', accessorKey: 'http_method'}, + {header: 'Protocol', accessorKey: 'protocol'}, + {header: 'Status', accessorKey: 'status'}, + {header: 'Length', accessorKey: 'length'}, + ], + [], + ); + const sourceIPs = frame.fields.find((field) => field.name === 'sourceIP'); + const destinationIPs = frame.fields.find((field) => field.name === 'destinationIP'); + const sourceTransportPorts = frame.fields.find((field) => field.name === 'sourceTransportPort'); + const destinationTransportPorts = frame.fields.find((field) => field.name === 'destinationTransportPort'); + const httpValsList = frame.fields.find((field) => field.name === 'httpVals'); + const defaultMaterialTheme = createTheme({palette: { + mode: config.theme2.isDark ? 'dark': 'light', + }}); + + let tableData: FlowRow[] = []; + interface FlowRow { + source: string, + destination: string, + txId: number, + hostname: string, + url: string, + http_user_agent: string, + http_content_type: string, + http_method: string, + protocol: string, + status: number, + length: number, + subRows: FlowRow[], + } + for (let i = 0; i < frame.length; i++) { + const sourceIP = sourceIPs?.values.get(i); + const destinationIP = destinationIPs?.values.get(i); + const sourcePort = sourceTransportPorts?.values.get(i); + const destinationPort = destinationTransportPorts?.values.get(i); + const httpVals = httpValsList?.values.get(i); + let httpValsJSON: any; + if (httpVals !== undefined) { + httpValsJSON = JSON.parse(httpVals); + } + const rowData: FlowRow = { + source: '', + destination: '', + txId: 0, + hostname: '', + url: '', + http_user_agent: '', + http_content_type: '', + http_method: '', + protocol: '', + status: 0, + length: 0, + subRows: [], + }; + function setTableRow(source: string, destination: string, txId: number, hostname: string, url: string, http_user_agent: string, http_content_type: string, http_method: string, protocol: string, status: number, length: number) { + if (txId === 0) { + rowData.source = source; + rowData.destination = destination; + rowData.txId = txId; + rowData.hostname = hostname; + rowData.url = url; + rowData.http_user_agent = http_user_agent; + rowData.http_content_type = http_content_type; + rowData.http_method = http_method; + rowData.protocol = protocol; + rowData.status = status; + rowData.length = length; + } else { + const row: FlowRow = { + source: source, + destination: destination, + txId: txId, + hostname: hostname, + url: url, + http_user_agent: http_user_agent, + http_content_type: http_content_type, + http_method: http_method, + protocol: protocol, + status: status, + length: length, + subRows: [], + } + rowData.subRows.push(row); + } + } + for (const txId in httpValsJSON) { + setTableRow(sourceIP+':'+sourcePort, destinationIP+':'+destinationPort, +txId, httpValsJSON[txId].hostname, httpValsJSON[txId].url, httpValsJSON[txId].http_user_agent, httpValsJSON[txId].http_content_type, httpValsJSON[txId].http_method, httpValsJSON[txId].protocol, httpValsJSON[txId].status, httpValsJSON[txId].length); + tableData.push(rowData); + } + } + + return ( +
+ + + +
+ ); +};