-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(Properties View): Implement Properties View for Camel Plugin
* CamelContent * camel-content-service * Adds view to navigation tabs * routes-service * Icons * Implement creation of custom size versions of the icons then cache them * Properties * View that displays schema properties of the route xml nodes Fixes: #387
- Loading branch information
1 parent
7dedd9d
commit 699d8a6
Showing
12 changed files
with
363 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
137 changes: 137 additions & 0 deletions
137
packages/hawtio/src/plugins/camel/properties/Properties.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
import { | ||
Card, | ||
CardBody, | ||
CardHeader, | ||
CardTitle, | ||
Label, | ||
LabelGroup, | ||
Panel, | ||
PanelMain, | ||
PanelMainBody, | ||
Skeleton, | ||
Text, | ||
} from '@patternfly/react-core' | ||
import { InfoCircleIcon } from '@patternfly/react-icons' | ||
import React, { useContext, useEffect, useState } from 'react' | ||
import Logger from 'js-logger' | ||
import { CamelContext } from '../context' | ||
import { log, xmlNodeLocalName } from '../globals' | ||
import { schemaService } from '../schema-service' | ||
import { routesService } from '../routes-service' | ||
import * as pps from './properties-service' | ||
import { PropertiesList } from './PropertiesList' | ||
import { Property } from './property' | ||
import './properties.css' | ||
|
||
export const Properties: React.FunctionComponent = () => { | ||
const { selectedNode } = useContext(CamelContext) | ||
const [isReading, setIsReading] = useState(true) | ||
|
||
const [title, setTitle] = useState('') | ||
const [icon, setIcon] = useState<React.ReactNode>() | ||
const [labels, setLabels] = useState<string[]>([]) | ||
const [description, setDescription] = useState('') | ||
const [definedProperties, setDefinedProperties] = useState<Property[]>([]) | ||
const [defaultProperties, setDefaultProperties] = useState<Property[]>([]) | ||
const [undefinedProperties, setUndefinedProperties] = useState<Property[]>([]) | ||
|
||
useEffect(() => { | ||
if (!selectedNode) return | ||
|
||
setIsReading(true) | ||
|
||
const init = async () => { | ||
const localName: string = selectedNode.getProperty(xmlNodeLocalName) | ||
const schemaKey = localName ? localName : selectedNode.name | ||
const schema = schemaService.getSchema(schemaKey) | ||
|
||
let newTitle = localName | ||
let newIcon = selectedNode.icon | ||
let newDescription = '' | ||
let groups: string[] = [] | ||
|
||
if (schema) { | ||
newTitle = schema['title'] as string | ||
newIcon = routesService.getIcon(schema, 24) | ||
newDescription = schema['description'] as string | ||
const groupStr = schema['group'] as string | ||
groups = groupStr.split(',') | ||
|
||
if (log.enabledFor(Logger.DEBUG)) { | ||
log.debug('Properties - schema:', JSON.stringify(schema, null, ' ')) | ||
} | ||
|
||
const schemaProps = schema['properties'] as Record<string, Record<string, string>> | ||
pps.populateProperties(selectedNode, schemaProps) | ||
|
||
setDefinedProperties(pps.getDefinedProperties(schemaProps)) | ||
setDefaultProperties(pps.getDefaultProperties(schemaProps)) | ||
setUndefinedProperties(pps.getUndefinedProperties(schemaProps)) | ||
} | ||
|
||
setIcon(newIcon) | ||
setTitle(newTitle) | ||
setDescription(newDescription) | ||
setLabels(groups) | ||
|
||
setIsReading(false) | ||
} | ||
|
||
init() | ||
}, [selectedNode]) | ||
|
||
if (!selectedNode) { | ||
return ( | ||
<Card> | ||
<CardBody> | ||
<Text component='p'>No selection has been made</Text> | ||
</CardBody> | ||
</Card> | ||
) | ||
} | ||
|
||
if (isReading) { | ||
return ( | ||
<Card> | ||
<CardBody> | ||
<Skeleton data-testid='loading' screenreaderText='Loading...' /> | ||
</CardBody> | ||
</Card> | ||
) | ||
} | ||
|
||
return ( | ||
<Card isFullHeight> | ||
<CardHeader> | ||
<CardTitle>Properties</CardTitle> | ||
</CardHeader> | ||
<CardBody id='properties-card-body'> | ||
<Panel variant='raised'> | ||
<PanelMain> | ||
<PanelMainBody id='properties-card-title-panel'> | ||
{icon} | ||
<span>{title}</span> | ||
<LabelGroup id='properties-card-title-panel-labelgroup'> | ||
{labels.map(label => ( | ||
<Label key={label} icon={<InfoCircleIcon />}> | ||
{label} | ||
</Label> | ||
))} | ||
</LabelGroup> | ||
</PanelMainBody> | ||
</PanelMain> | ||
</Panel> | ||
{description && ( | ||
<Panel variant='raised'> | ||
<PanelMain> | ||
<PanelMainBody id='properties-card-description-panel'>{description}</PanelMainBody> | ||
</PanelMain> | ||
</Panel> | ||
)} | ||
<PropertiesList title='Defined Properties' values={definedProperties} /> | ||
<PropertiesList title='Default Properties' values={defaultProperties} /> | ||
<PropertiesList title='Undefined Properties' values={undefinedProperties} /> | ||
</CardBody> | ||
</Card> | ||
) | ||
} |
48 changes: 48 additions & 0 deletions
48
packages/hawtio/src/plugins/camel/properties/PropertiesList.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import React from 'react' | ||
import { | ||
DescriptionList, | ||
DescriptionListDescription, | ||
DescriptionListGroup, | ||
DescriptionListTerm, | ||
Panel, | ||
PanelHeader, | ||
PanelMain, | ||
PanelMainBody, | ||
} from '@patternfly/react-core' | ||
import { PropertiesTooltippedName } from './PropertiesTooltippedName' | ||
import { Property } from './property' | ||
import './properties.css' | ||
|
||
interface PropertiesListProps { | ||
title: string | ||
values: Property[] | ||
} | ||
|
||
export const PropertiesList: React.FunctionComponent<PropertiesListProps> = props => { | ||
return ( | ||
<Panel variant='raised' className='properties-list-panel'> | ||
<PanelHeader>{props.title}</PanelHeader> | ||
<PanelMain> | ||
{(!props.values || props.values.length === 0) && ( | ||
<PanelMainBody className='properties-no-properties'>No properties</PanelMainBody> | ||
)} | ||
{props.values && props.values.length > 0 && ( | ||
<PanelMainBody> | ||
<DescriptionList columnModifier={{ default: '2Col' }}> | ||
{props.values.map(p => { | ||
return ( | ||
<DescriptionListGroup key={p.name}> | ||
<DescriptionListTerm> | ||
<PropertiesTooltippedName property={p} /> | ||
</DescriptionListTerm> | ||
<DescriptionListDescription>{p.value}</DescriptionListDescription> | ||
</DescriptionListGroup> | ||
) | ||
})} | ||
</DescriptionList> | ||
</PanelMainBody> | ||
)} | ||
</PanelMain> | ||
</Panel> | ||
) | ||
} |
24 changes: 24 additions & 0 deletions
24
packages/hawtio/src/plugins/camel/properties/PropertiesTooltippedName.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import React from 'react' | ||
import { Tooltip } from '@patternfly/react-core' | ||
import { InfoCircleIcon } from '@patternfly/react-icons' | ||
import { Property } from './property' | ||
import './properties.css' | ||
|
||
interface PropertiesTTNameProps { | ||
property: Property | ||
} | ||
|
||
export const PropertiesTooltippedName: React.FunctionComponent<PropertiesTTNameProps> = props => { | ||
const tooltipRef = React.useRef<HTMLSpanElement>(null) | ||
|
||
return ( | ||
<React.Fragment> | ||
{props.property.name} | ||
|
||
<span ref={tooltipRef} className='properties-name-tooltip-button'> | ||
<InfoCircleIcon /> | ||
</span> | ||
<Tooltip id='tooltip-ref1' reference={tooltipRef} content={<div>{props.property.description}</div>} /> | ||
</React.Fragment> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { Properties } from './Properties' |
74 changes: 74 additions & 0 deletions
74
packages/hawtio/src/plugins/camel/properties/properties-service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { MBeanNode } from '@hawtiosrc/plugins/shared' | ||
import { parseXML } from '@hawtiosrc/util/xml' | ||
import { xmlNodeLocalName } from '../globals' | ||
import { Property } from './property' | ||
|
||
export function populateProperties(node: MBeanNode, schemaProperties: Record<string, Record<string, string>>) { | ||
// Extract the xml fragment from the node's property stash | ||
const xml = node.getProperty('xml') | ||
if (!xml) return | ||
|
||
// Extract the xml tag name from the node's property stash | ||
const localName = node.getProperty(xmlNodeLocalName) | ||
if (!localName) return | ||
|
||
// Parse the xml and find the root element using the localname | ||
const xmlDoc = parseXML(xml) | ||
const elements = xmlDoc.getElementsByTagName(localName) | ||
|
||
// Iterate the elements found (should only be 1) | ||
for (const element of elements) { | ||
// Iterate the element attributes | ||
for (const attribute of element.attributes) { | ||
// If any xml attribute has the same name as a schema property | ||
// then assign the schema property the value, meaning this will | ||
// become a defined property | ||
const property = schemaProperties[attribute.name] | ||
if (!property) continue | ||
|
||
property.value = attribute.value | ||
} | ||
} | ||
} | ||
|
||
export function getDefinedProperties(schemaProperties: Record<string, Record<string, string>>): Property[] { | ||
return Object.keys(schemaProperties) | ||
.filter(key => { | ||
const obj = schemaProperties[key] | ||
return Object.keys(obj).includes('value') | ||
}) | ||
.map(key => { | ||
const propertySchema = schemaProperties[key] | ||
const name = propertySchema['title'] || key | ||
return new Property(name, propertySchema['value'], propertySchema['description']) | ||
}) | ||
.sort(Property.sortByName) | ||
} | ||
|
||
export function getDefaultProperties(schemaProperties: Record<string, Record<string, string>>): Property[] { | ||
return Object.keys(schemaProperties) | ||
.filter(key => { | ||
const obj = schemaProperties[key] | ||
return !Object.keys(obj).includes('value') && Object.keys(obj).includes('defaultValue') | ||
}) | ||
.map(key => { | ||
const propertySchema = schemaProperties[key] | ||
const name = propertySchema['title'] || key | ||
return new Property(name, propertySchema['defaultValue'], propertySchema['description']) | ||
}) | ||
.sort(Property.sortByName) | ||
} | ||
|
||
export function getUndefinedProperties(schemaProperties: Record<string, Record<string, string>>): Property[] { | ||
return Object.keys(schemaProperties) | ||
.filter(key => { | ||
const obj = schemaProperties[key] | ||
return !Object.keys(obj).includes('value') && !Object.keys(obj).includes('defaultValue') | ||
}) | ||
.map(key => { | ||
const propertySchema = schemaProperties[key] | ||
const name = propertySchema['title'] || key | ||
return new Property(name, null, propertySchema['description']) | ||
}) | ||
.sort(Property.sortByName) | ||
} |
25 changes: 25 additions & 0 deletions
25
packages/hawtio/src/plugins/camel/properties/properties.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#properties-card-title-panel img { | ||
margin-right: 1em; | ||
vertical-align: middle; | ||
} | ||
|
||
#properties-card-title-panel-labelgroup { | ||
margin-left: 1em; | ||
} | ||
|
||
.properties-list-panel { | ||
margin-top: 1em !important; | ||
} | ||
|
||
.properties-list-panel .pf-c-panel__header { | ||
color: darkblue; | ||
} | ||
|
||
.properties-no-properties { | ||
font-style: italic !important; | ||
} | ||
|
||
.properties-name-tooltip-button { | ||
margin-left: 0.5em; | ||
color: grey; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export class Property { | ||
constructor(public name: string, public value: string | null, public description: string) {} | ||
|
||
static sortByName(a: Property, b: Property) { | ||
if (a.name < b.name) return -1 | ||
if (a.name > b.name) return 1 | ||
|
||
return 0 | ||
} | ||
} |
Oops, something went wrong.