Skip to content

Commit

Permalink
refactor(CamelContent): Refactor to use tabs instead of Navigation an…
Browse files Browse the repository at this point in the history
…d routes

tweak styles to stretch content to full height
  • Loading branch information
mmelko committed Apr 17, 2024
1 parent 314b9c8 commit 3ea9106
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 116 deletions.
4 changes: 4 additions & 0 deletions packages/hawtio/src/plugins/camel/Camel.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==');
cursor: col-resize;
}

.camel-content-page {
height: calc(100vh - 85px);
}
2 changes: 1 addition & 1 deletion packages/hawtio/src/plugins/camel/Camel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const Camel: React.FunctionComponent = () => {
<div>
<CamelTreeView />
</div>
<div>
<div className='camel-content-page'>
<CamelContent />
</div>
</Split>
Expand Down
228 changes: 113 additions & 115 deletions packages/hawtio/src/plugins/camel/CamelContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,19 @@ import {
EmptyState,
EmptyStateIcon,
EmptyStateVariant,
Nav,
NavItem,
NavList,
PageGroup,
PageNavigation,
PageSection,
PageSectionVariants,
Tab,
Tabs,
Text,
Title,
} from '@patternfly/react-core'
import { CubesIcon } from '@patternfly/react-icons'
import { Response } from 'jolokia.js'
import React, { useContext, useEffect, useState } from 'react'
import { NavLink, Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom'
import { useNavigate } from 'react-router-dom'
import './CamelContent.css'
import * as camelService from './camel-service'
import { CamelContext } from './context'
Expand All @@ -30,7 +29,7 @@ import { BrowseMessages } from './endpoints/BrowseMessages'
import { EndpointStats } from './endpoints/EndpointsStats'
import { SendMessage } from './endpoints/SendMessage'
import { Exchanges } from './exchanges'
import { log, pluginPath } from './globals'
import { log } from './globals'
import { Profile } from './profile/Profile'
import { Properties } from './properties'
import { RestServices } from './rest-services/RestServices'
Expand All @@ -47,11 +46,90 @@ type NavItem = {
component: JSX.Element
isApplicable: (node: MBeanNode) => boolean
}
/*
* Test if nav should contain general mbean tabs
*/
const isDefaultApplicable = (node: MBeanNode) => {
return (
camelService.hasMBean(node) &&
!camelService.isContextsFolder(node) &&
!camelService.isRoutesFolder(node) &&
!camelService.isRouteXmlNode(node)
)
}

// The order of the items in the following list is the order in will the tabs will be visualized.
// For more info check: https://github.com/hawtio/hawtio-next/issues/237
const allNavItems: NavItem[] = [
{ id: 'attributes', title: 'Attributes', component: <Attributes />, isApplicable: isDefaultApplicable },
{ id: 'operations', title: 'Operations', component: <Operations />, isApplicable: isDefaultApplicable },
{ id: 'contexts', title: 'Contexts', component: <Contexts />, isApplicable: camelService.isContextsFolder },
{ id: 'routes', title: 'Routes', component: <CamelRoutes />, isApplicable: camelService.isRoutesFolder },
{ id: 'endpoints', title: 'Endpoints', component: <Endpoints />, isApplicable: camelService.isEndpointsFolder },
{
id: 'routeDiagram',
title: 'Route Diagram',
component: <RouteDiagram />,
isApplicable: camelService.canViewRouteDiagram,
},
{
id: 'source',
title: 'Source',
component: <Source />,
isApplicable: camelService.canViewSource,
},
{ id: 'properties', title: 'Properties', component: <Properties />, isApplicable: camelService.hasProperties },
{
id: 'send',
title: 'Send',
component: <SendMessage />,
isApplicable: camelService.canSendMessage,
},
{
id: 'browse',
title: 'Browse',
component: <BrowseMessages />,
isApplicable: camelService.canBrowseMessages,
},
{
id: 'endpoint-stats',
title: 'Endpoints (in/out)',
component: <EndpointStats />,
isApplicable: camelService.canViewEndpointStats,
},
{ id: 'exchanges', title: 'Exchanges', component: <Exchanges />, isApplicable: camelService.hasExchange },
{
id: 'rest-services',
title: 'Rest Services',
component: <RestServices />,
isApplicable: camelService.hasRestServices,
},
{
id: 'type-converters',
title: 'Type Converters',
component: <TypeConverters />,
isApplicable: camelService.hasTypeConverter,
},
{ id: 'chart', title: 'Chart', component: <Chart />, isApplicable: isDefaultApplicable },
// Applicable for same criteria as trace
{ id: 'profile', title: 'Profile', component: <Profile />, isApplicable: camelService.canTrace },
{ id: 'trace', title: 'Trace', component: <Trace />, isApplicable: camelService.canTrace },
{ id: 'debug', title: 'Debug', component: <Debug />, isApplicable: camelService.canGetBreakpoints },
]
export const CamelContent: React.FunctionComponent = () => {
const { selectedNode } = useContext(CamelContext)
const routeDiagramContext = useRouteDiagramContext()
const { pathname, search } = useLocation()
const [activeTab, setActiveTab] = useState<string>('')
const [tabItems, setTabItems] = useState<NavItem[]>([])

useEffect(() => {
if (selectedNode) {
/* Filter the nav items to those applicable to the selected node */
const tabItems = allNavItems.filter(nav => nav.isApplicable(selectedNode))
setActiveTab(tabItems[0]?.id ?? '')
setTabItems([...tabItems])
}
}, [selectedNode])

if (!selectedNode) {
return (
Expand All @@ -66,122 +144,42 @@ export const CamelContent: React.FunctionComponent = () => {
)
}

/*
* Test if nav should contain general mbean tabs
*/
const isDefaultApplicable = (node: MBeanNode) => {
return (
camelService.hasMBean(node) &&
!camelService.isContextsFolder(node) &&
!camelService.isRoutesFolder(node) &&
!camelService.isRouteXmlNode(node)
)
}

// The order of the items in the following list is the order in will the tabs will be visualized.
// For more info check: https://github.com/hawtio/hawtio-next/issues/237
const allNavItems: NavItem[] = [
{ id: 'attributes', title: 'Attributes', component: <Attributes />, isApplicable: isDefaultApplicable },
{ id: 'operations', title: 'Operations', component: <Operations />, isApplicable: isDefaultApplicable },
{ id: 'contexts', title: 'Contexts', component: <Contexts />, isApplicable: camelService.isContextsFolder },
{ id: 'routes', title: 'Routes', component: <CamelRoutes />, isApplicable: camelService.isRoutesFolder },
{ id: 'endpoints', title: 'Endpoints', component: <Endpoints />, isApplicable: camelService.isEndpointsFolder },
{
id: 'routeDiagram',
title: 'Route Diagram',
component: (
<RouteDiagramContext.Provider value={routeDiagramContext}>
<RouteDiagram />
</RouteDiagramContext.Provider>
),
isApplicable: camelService.canViewRouteDiagram,
},
{
id: 'source',
title: 'Source',
component: <Source />,
isApplicable: camelService.canViewSource,
},
{ id: 'properties', title: 'Properties', component: <Properties />, isApplicable: camelService.hasProperties },
{
id: 'send',
title: 'Send',
component: <SendMessage />,
isApplicable: camelService.canSendMessage,
},
{
id: 'browse',
title: 'Browse',
component: <BrowseMessages />,
isApplicable: camelService.canBrowseMessages,
},
{
id: 'endpoint-stats',
title: 'Endpoints (in/out)',
component: <EndpointStats />,
isApplicable: camelService.canViewEndpointStats,
},
{ id: 'exchanges', title: 'Exchanges', component: <Exchanges />, isApplicable: camelService.hasExchange },
{
id: 'rest-services',
title: 'Rest Services',
component: <RestServices />,
isApplicable: camelService.hasRestServices,
},
{
id: 'type-converters',
title: 'Type Converters',
component: <TypeConverters />,
isApplicable: camelService.hasTypeConverter,
},
{ id: 'chart', title: 'Chart', component: <Chart />, isApplicable: isDefaultApplicable },
// Applicable for same criteria as trace
{ id: 'profile', title: 'Profile', component: <Profile />, isApplicable: camelService.canTrace },
{ id: 'trace', title: 'Trace', component: <Trace />, isApplicable: camelService.canTrace },
{ id: 'debug', title: 'Debug', component: <Debug />, isApplicable: camelService.canGetBreakpoints },
]

/* Filter the nav items to those applicable to the selected node */
const navItems = allNavItems.filter(nav => nav.isApplicable(selectedNode))

const camelNav = (
<Nav aria-label='Camel Nav' variant='tertiary'>
<NavList>
{navItems.map(nav => (
<NavItem key={nav.id} isActive={pathname === `${pluginPath}/${nav.id}`}>
<NavLink to={{ pathname: nav.id, search }}>{nav.title}</NavLink>
</NavItem>
))}
</NavList>
</Nav>
const camelTabs = (
<Tabs mountOnEnter unmountOnExit activeKey={activeTab} onSelect={(_, eventKey) => setActiveTab(eventKey as string)}>
{tabItems.map(nav => (
<Tab eventKey={nav.id} key={nav.id} title={nav.title}>
{camelService.canViewRouteDiagram(selectedNode) ? (
<RouteDiagramContext.Provider value={routeDiagramContext}>{nav.component}</RouteDiagramContext.Provider>
) : (
nav.component
)}
</Tab>
))}
</Tabs>
)

const camelNavRoutes = navItems.map(nav => <Route key={nav.id} path={nav.id} element={nav.component} />)

return (
<React.Fragment>
<PageGroup>
<PageSection id='camel-content-header' variant={PageSectionVariants.light}>
{camelService.isContext(selectedNode) && <CamelContentContextToolbar />}
<Title headingLevel='h1'>{selectedNode.name}</Title>
{selectedNode.objectName && <Text component='small'>{selectedNode.objectName}</Text>}
</PageSection>
{navItems.length > 1 && <PageNavigation>{camelNav}</PageNavigation>}
</PageGroup>

<PageSection id='camel-content-main'>
{navItems.length > 0 && (
<Routes>
{camelNavRoutes}
<Route key='root' path='/' element={<Navigate to={navItems[0]?.id ?? ''} />} />
</Routes>
<PageGroup style={{ height: '100%' }}>
<PageSection id='camel-content-header' variant={PageSectionVariants.light}>
{camelService.isContext(selectedNode) && <CamelContentContextToolbar />}
<Title headingLevel='h1'>{selectedNode.name}</Title>
{selectedNode.objectName && <Text component='small'>{selectedNode.objectName}</Text>}
</PageSection>

<PageSection id='camel-content-main' variant={PageSectionVariants.light}>
{tabItems.length > 1 && (
<PageSection isFilled type={'tabs'}>
{camelTabs}
</PageSection>
)}
{navItems.length === 0 && !selectedNode.objectName && <JmxContentMBeans />}
{/* Show only the tab content if there is only one tab */}
{tabItems.length === 1 && !selectedNode.objectName && tabItems[0]!.component}

{tabItems.length === 0 && <JmxContentMBeans />}
</PageSection>
</React.Fragment>
</PageGroup>
)
}

const CamelContentContextToolbar: React.FunctionComponent = () => {
const { selectedNode, setSelectedNode } = useContext(CamelContext)
const [contextState, setContextState] = useState<ContextState | null>(null)
Expand Down

0 comments on commit 3ea9106

Please sign in to comment.