From fa499b875f8241dcf4d018b9ed01dc3baec7d68b Mon Sep 17 00:00:00 2001 From: Tadayoshi Sato Date: Thu, 28 Sep 2023 16:47:34 +0900 Subject: [PATCH] refactor(runtime): polish Runtime plugin --- .../hawtio/src/plugins/runtime/Metrics.tsx | 2 +- .../hawtio/src/plugins/runtime/Runtime.tsx | 30 +-- .../hawtio/src/plugins/runtime/SysProps.tsx | 166 ++++++------ .../src/plugins/runtime/ThreadInfoModal.tsx | 47 ++-- .../hawtio/src/plugins/runtime/Threads.tsx | 236 +++++++++--------- 5 files changed, 248 insertions(+), 233 deletions(-) diff --git a/packages/hawtio/src/plugins/runtime/Metrics.tsx b/packages/hawtio/src/plugins/runtime/Metrics.tsx index cfad5617..8eb7a17c 100644 --- a/packages/hawtio/src/plugins/runtime/Metrics.tsx +++ b/packages/hawtio/src/plugins/runtime/Metrics.tsx @@ -1,8 +1,8 @@ +import { ChartBullet } from '@patternfly/react-charts' import { Card, CardBody, CardHeader, Grid, GridItem, Title } from '@patternfly/react-core' import React, { useEffect, useState } from 'react' import { runtimeService } from './runtime-service' import { Metric } from './types' -import { ChartBullet } from '@patternfly/react-charts' export const Metrics: React.FunctionComponent = () => { const [metrics, setMetrics] = useState>({}) diff --git a/packages/hawtio/src/plugins/runtime/Runtime.tsx b/packages/hawtio/src/plugins/runtime/Runtime.tsx index cc385f33..66232252 100644 --- a/packages/hawtio/src/plugins/runtime/Runtime.tsx +++ b/packages/hawtio/src/plugins/runtime/Runtime.tsx @@ -1,19 +1,9 @@ -import { - PageSection, - PageSectionVariants, - NavItem, - Title, - PageGroup, - PageNavigation, - Nav, - NavList, - Card, -} from '@patternfly/react-core' +import { Nav, NavItem, NavList, PageGroup, PageNavigation, PageSection, Title } from '@patternfly/react-core' import React from 'react' -import { SysProps } from './SysProps' import { Navigate, NavLink, Route, Routes, useLocation } from 'react-router-dom' import { Metrics } from './Metrics' +import { SysProps } from './SysProps' import { Threads } from './Threads' type NavItem = { @@ -32,7 +22,7 @@ export const Runtime: React.FunctionComponent = () => { return ( - + Runtime @@ -49,14 +39,12 @@ export const Runtime: React.FunctionComponent = () => { - - - {navItems.map(navItem => ( - - ))} - } /> - - + + {navItems.map(navItem => ( + + ))} + } /> + ) diff --git a/packages/hawtio/src/plugins/runtime/SysProps.tsx b/packages/hawtio/src/plugins/runtime/SysProps.tsx index 64e5251e..4c326371 100644 --- a/packages/hawtio/src/plugins/runtime/SysProps.tsx +++ b/packages/hawtio/src/plugins/runtime/SysProps.tsx @@ -1,9 +1,8 @@ -import React, { useEffect, useState } from 'react' +import { objectSorter } from '@hawtiosrc/util/objects' import { Bullseye, Button, Card, - CardBody, Dropdown, DropdownItem, DropdownToggle, @@ -19,10 +18,10 @@ import { ToolbarGroup, ToolbarItem, } from '@patternfly/react-core' -import { TableComposable, Tbody, Td, Th, Thead, ThProps, Tr } from '@patternfly/react-table' import { SearchIcon } from '@patternfly/react-icons' +import { TableComposable, Tbody, Td, Th, ThProps, Thead, Tr } from '@patternfly/react-table' +import React, { useEffect, useState } from 'react' import { runtimeService } from './runtime-service' -import { objectSorter } from '@hawtiosrc/util/objects' import { SystemProperty } from './types' export const SysProps: React.FunctionComponent = () => { @@ -137,6 +136,7 @@ export const SysProps: React.FunctionComponent = () => { }, columnIndex: sortColumn, }) + const sortProperties = (): SystemProperty[] => { let sortedProps = filteredProperties if (sortIndex >= 0) { @@ -149,86 +149,88 @@ export const SysProps: React.FunctionComponent = () => { return sortedProps } + + const tableToolbar = ( + + + + setIsDropdownOpen(false)} + defaultValue='name' + toggle={ + + {attributes.find(att => att.key === attributeMenuItem)?.value} + + } + isOpen={isDropdownOpen} + dropdownItems={dropdownItems} + /> + onDeleteFilter(filter as string)} + deleteChipGroup={clearFilters} + categoryName='Filters' + > + handleSearch(value, attributeMenuItem, filters)} + aria-label='Search input' + /> + + + + + + + + + + ) + return ( - - - - - setIsDropdownOpen(false)} - defaultValue='name' - toggle={ - - {attributes.find(att => att.key === attributeMenuItem)?.value} - - } - isOpen={isDropdownOpen} - dropdownItems={dropdownItems} - /> - onDeleteFilter(filter as string)} - deleteChipGroup={clearFilters} - categoryName='Filters' - > - handleSearch(value, attributeMenuItem, filters)} - aria-label='Search input' - /> - - - - - - - - - - - {sortProperties().length > 0 && ( - - - - - - Property Name - - - Property Value - - - - - {getPageProperties().map((prop, index) => { - return ( - - {prop.key} - {prop.value} - - ) - })} - - - - )} - {filteredProperties.length === 0 && ( - - - - No results found. - - - )} - + {tableToolbar} + {sortProperties().length > 0 && ( + + + + + + Property Name + + + Property Value + + + + + {getPageProperties().map((prop, index) => { + return ( + + {prop.key} + {prop.value} + + ) + })} + + + + )} + {filteredProperties.length === 0 && ( + + + + No results found. + + + )} ) } diff --git a/packages/hawtio/src/plugins/runtime/ThreadInfoModal.tsx b/packages/hawtio/src/plugins/runtime/ThreadInfoModal.tsx index 8c279f35..abfdd7df 100644 --- a/packages/hawtio/src/plugins/runtime/ThreadInfoModal.tsx +++ b/packages/hawtio/src/plugins/runtime/ThreadInfoModal.tsx @@ -3,27 +3,14 @@ import { Thread } from '@hawtiosrc/plugins/runtime/types' import { Grid, GridItem, Modal, ModalVariant } from '@patternfly/react-core' export const ThreadInfoModal: React.FunctionComponent<{ - thread: Thread + thread?: Thread isOpen: boolean setIsOpen: (open: boolean) => void }> = ({ thread, isOpen, setIsOpen }) => { - const CustomItem: React.FunctionComponent<{ itemName: string; itemValue: string | number | null | undefined }> = ({ - itemName, - itemValue, - }) => { - if (itemValue) { - if ((typeof itemValue === 'number' && itemValue > -1) || (typeof itemValue === 'string' && itemValue !== '')) - return ( - <> - - {itemName} - - {itemValue} - - ) - } - return <> + if (!thread) { + return null } + return ( ) } + +const CustomItem: React.FunctionComponent<{ + itemName: string + itemValue: string | number | null +}> = ({ itemName, itemValue }) => { + if (!itemValue) { + return null + } + + if (typeof itemValue === 'number' && itemValue < 0) { + return null + } + + if (typeof itemValue === 'string' && itemValue === '') { + return null + } + + return ( + <> + + {itemName} + + {itemValue} + + ) +} diff --git a/packages/hawtio/src/plugins/runtime/Threads.tsx b/packages/hawtio/src/plugins/runtime/Threads.tsx index e4d8ff19..3fd29683 100644 --- a/packages/hawtio/src/plugins/runtime/Threads.tsx +++ b/packages/hawtio/src/plugins/runtime/Threads.tsx @@ -1,9 +1,7 @@ -import React, { useEffect, useState } from 'react' import { Bullseye, Button, Card, - CardBody, CodeBlock, CodeBlockCode, Dropdown, @@ -14,7 +12,6 @@ import { EmptyStateIcon, FormGroup, Modal, - ModalVariant, Pagination, SearchInput, Toolbar, @@ -23,19 +20,21 @@ import { ToolbarGroup, ToolbarItem, } from '@patternfly/react-core' +import React, { useEffect, useState } from 'react' -import { TableComposable, Tbody, Td, Th, Thead, ThProps, Tr } from '@patternfly/react-table' +import { Thread } from '@hawtiosrc/plugins/runtime/types' +import { objectSorter } from '@hawtiosrc/util/objects' import { SearchIcon } from '@patternfly/react-icons' +import { TableComposable, Tbody, Td, Th, Thead, ThProps, Tr } from '@patternfly/react-table' import { runtimeService } from './runtime-service' -import { objectSorter } from '@hawtiosrc/util/objects' -import { Thread } from '@hawtiosrc/plugins/runtime/types' import { ThreadInfoModal } from './ThreadInfoModal' const ThreadsDumpModal: React.FunctionComponent<{ isOpen: boolean setIsOpen: (opened: boolean) => void }> = ({ isOpen, setIsOpen }) => { - const [threadsDump, setThreadsDump] = useState('') + const [threadsDump, setThreadsDump] = useState('') + useEffect(() => { const readThreadDump = async () => { const threadsDump = await runtimeService.dumpThreads() @@ -51,7 +50,7 @@ const ThreadsDumpModal: React.FunctionComponent<{ bodyAriaLabel='Thread Dump' tabIndex={0} isOpen={isOpen} - variant={ModalVariant.large} + variant='large' title='Thread Dump' onClose={() => setIsOpen(false)} > @@ -85,7 +84,7 @@ export const Threads: React.FunctionComponent = () => { setThreads(threads) setFilteredThreads(threads) setThreadConnectionMonitoring(await runtimeService.isThreadContentionMonitoringEnabled()) - await runtimeService.registerLoadThreadsRequest(threads => { + runtimeService.registerLoadThreadsRequest(threads => { setThreads(threads) setFilteredThreads(threads) }) @@ -104,6 +103,7 @@ export const Threads: React.FunctionComponent = () => { setFilters([...filters, `${attributeMenuItem}:${searchTerm}`]) setSearchTerm('') } + const clearFilters = () => { setFilters([]) setSearchTerm('') @@ -131,6 +131,7 @@ export const Threads: React.FunctionComponent = () => { const end = start + perPage return filteredThreads.slice(start, end) } + const handleSearch = (value: string, key: string, filters: string[]) => { setSearchTerm(value) //filter with findTerm @@ -192,10 +193,12 @@ export const Threads: React.FunctionComponent = () => { State , ] + const getIndexedThread = (thread: Thread): (string | number)[] => { const { suspended, blockedTime, inNative, threadId, threadName, threadState, waitedTime } = thread return [threadId, threadState, threadName, waitedTime, blockedTime, String(inNative), String(suspended)] } + const getSortParams = (sortColumn: number): ThProps['sort'] => ({ sortBy: { index: sortIndex, @@ -208,6 +211,7 @@ export const Threads: React.FunctionComponent = () => { }, columnIndex: sortColumn, }) + const sortThreads = (): Thread[] => { let sortedThreads = filteredThreads if (sortIndex >= 0) { @@ -220,117 +224,125 @@ export const Threads: React.FunctionComponent = () => { return sortedThreads } - function onThreadDumpClick() { + const onThreadDumpClick = () => { setIsThreadsDumpModalOpen(true) } - async function handleConnectionThreadMonitoring() { - runtimeService.enableThreadContentionMonitoring(!threadConnectionMonitoring) + const handleConnectionThreadMonitoring = async () => { + await runtimeService.enableThreadContentionMonitoring(!threadConnectionMonitoring) setThreadConnectionMonitoring(!threadConnectionMonitoring) } + const tableToolbar = ( + + + + setIsDropdownOpen(false)} + defaultValue='Name' + toggle={ + + {tableColumns.find(att => att.value === attributeMenuItem)?.value} + + } + isOpen={isDropdownOpen} + dropdownItems={dropdownItems} + /> + onDeleteFilter(filter as string)} + deleteChipGroup={clearFilters} + categoryName='Filters' + > + handleSearch(value, attributeMenuItem, filters)} + aria-label='Search input' + /> + + + + + + + + + + + + + + + + + + + + + ) + return ( - - {isThreadsDumpModalOpen && ( - - )} - {isThreadDetailsOpen && currentThread && ( - - )} - - - - setIsDropdownOpen(false)} - defaultValue='Name' - toggle={ - - {tableColumns.find(att => att.value === attributeMenuItem)?.value} - - } - isOpen={isDropdownOpen} - dropdownItems={dropdownItems} - /> - onDeleteFilter(filter as string)} - deleteChipGroup={clearFilters} - categoryName='Filters' - > - handleSearch(value, attributeMenuItem, filters)} - aria-label='Search input' - /> - - - - - - - - - - - - {sortThreads().length > 0 && ( - - - - - {tableColumns.map((att, index) => ( - - {att.value} - - ))} - Actions - - - - {getThreadsPage().map((thread, index) => { - return ( - - {tableColumns.map((att, column) => ( - {getIndexedThread(thread)[column]} - ))} - - - - - ) - })} - - - - )} - {filteredThreads.length === 0 && ( - - - - No results found. - - - )} - + + + {tableToolbar} + {sortThreads().length > 0 && ( + + + + + {tableColumns.map((att, index) => ( + + {att.value} + + ))} + Actions + + + + {getThreadsPage().map((thread, index) => { + return ( + + {tableColumns.map((att, column) => ( + {getIndexedThread(thread)[column]} + ))} + + + + + ) + })} + + + + )} + {filteredThreads.length === 0 && ( + + + + No results found. + + + )} ) }