This is an automated email from the ASF dual-hosted git repository.

jbertram pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq-artemis-console.git

commit 904ca3887a4ae647183461d555dc27511902ac28
Author: Grzegorz Grzybek <[email protected]>
AuthorDate: Tue Nov 18 11:42:00 2025 +0100

    ARTEMIS-5743: Handle inaccessible attributes better, when no RBAC metadata 
is available
---
 .../src/artemis-service.test.ts                    |  11 +-
 .../artemis-console-plugin/src/artemis-service.ts  | 206 ++++++++++++++++++---
 .../artemis-console-plugin/src/status/Status.tsx   | 146 +++++++++------
 3 files changed, 282 insertions(+), 81 deletions(-)

diff --git 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/artemis-service.test.ts
 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/artemis-service.test.ts
index 7ff962e..d043919 100644
--- 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/artemis-service.test.ts
+++ 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/artemis-service.test.ts
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 import { beforeAll, describe, expect, test } from "@jest/globals"
-import { artemisService } from "./artemis-service";
+import { artemisService, parseMBeanName } from "./artemis-service";
 import { SortDirection } from './table/ArtemisTable'
 import { userService } from '@hawtio/react'
 
@@ -41,4 +41,13 @@ describe("Artemis Service basic tests", () => {
     await expect(addresses).resolves.toContain("DLQ");
   })
 
+  test("Splitting ObjectNames", () => {
+    const mbean = 
"org.apache.activemq.artemis:broker=\"0.0.0.0:61616\",component=acceptors,filter=\"x,y,z=a\",name=amqp"
+    const parsed = parseMBeanName(mbean)
+    expect(parsed.domain).toEqual("org.apache.activemq.artemis")
+    expect(parsed.properties["broker"]).toEqual("\"0.0.0.0:61616\"")
+    expect(parsed.properties["filter"]).toEqual("\"x,y,z=a\"")
+    expect(parsed.properties["name"]).toEqual("amqp")
+  })
+
 })
diff --git 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/artemis-service.ts
 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/artemis-service.ts
index c25e5b1..aee3de3 100644
--- 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/artemis-service.ts
+++ 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/artemis-service.ts
@@ -15,23 +15,40 @@
  * limitations under the License.
  */
 import { ActiveSort, Filter } from './table/ArtemisTable'
-import { jolokiaService, MBeanNode } from '@hawtio/react'
+import { eventService, jolokiaService, MBeanNode, workspace } from 
'@hawtio/react'
 import { createAddressObjectName, createQueueObjectName } from './util/jmx'
 import { log } from './globals'
 import { Message } from './messages/MessageView'
 import { configManager } from './config-manager'
 
+export type BrokerState = {
+    // loading attempted?
+    loaded: boolean
+    // permission granted?
+    accessible: boolean
+    // possible error message
+    message?: string
+    // if everything is configured correctly, this is fully populated broker 
information
+    info?: BrokerInfo
+}
+// Value returned by Jolokia, when RBAC prevents access
+// see: 
org.jolokia.server.core.service.serializer.ValueFaultHandler.IGNORING_VALUE_FAULT_HANDLER
+export type InaccessibleValue = {
+    ".error": boolean
+    error?: string
+    error_type?: string
+}
 export type BrokerInfo = {
     name: string
     nodeID: string
     objectName: string
-    version: string
-    started: string
-    uptime: string
+    version: string | InaccessibleValue
+    started: string | InaccessibleValue
+    uptime: string | InaccessibleValue
     globalMaxSizeMB: number
     addressMemoryUsage: number
     addressMemoryUsed: number
-    haPolicy: string
+    haPolicy: string | InaccessibleValue
     networkTopology: BrokerNetworkTopology
 }
 
@@ -179,28 +196,55 @@ class ArtemisService {
         const brokerObjectName = await this.brokerObjectName;
         const response = await jolokiaService.readAttribute(brokerObjectName, 
"Name");
         if (response) {
+            if (typeof response === "object" && ".error" in response) {
+                return ""
+            }
             return response as string;
         }
         return null;
     }
 
-    async getBrokerInfo(): Promise<BrokerInfo | null> {
-        return new Promise<BrokerInfo | null>(async (resolve, reject) => {
+    async getBrokerInfo(): Promise<BrokerState> {
+        return new Promise<BrokerState>(async (resolve, _reject) => {
             const brokerObjectName = await this.brokerObjectName;
             if ("" === brokerObjectName) {
-                resolve(null)
+                resolve({ loaded: true, accessible: false, message: "No Broker 
ObjectName available" })
                 return
             }
-            const response = await 
jolokiaService.readAttributes(brokerObjectName).catch(e => null);
+            const brokerMBean = await findMBeanInfo(brokerObjectName)
+            if (!brokerMBean) {
+                resolve({ loaded: true, accessible: false, message: `No Broker 
MBean available for name ${brokerObjectName}` })
+                return
+            }
+            // `canRead` flag is added by jolokia-integration 0.7.1+ and 
ideally it should be checked _before_
+            // getting an attribute (just as `canInvoke` should be checked 
before executing an operation), but
+            // RBAC data may not be complete, so it's still good to be 
prepared (and add relevant `.catch(error => {...})`
+            let permitted = false
+            const nameInfo = brokerMBean.mbean?.attr?.["Name"]
+            if (nameInfo && "canRead" in nameInfo) {
+                permitted = nameInfo["canRead"] as boolean
+            } else if ("canInvoke" in brokerMBean.mbean!) {
+                permitted = brokerMBean.mbean?.["canInvoke"] as boolean
+            }
+            if (!permitted) {
+                resolve({ loaded: true, accessible: false, message: `Access 
not granted to broker ${brokerMBean.objectName}` })
+                return
+            }
+
+            const response = await 
jolokiaService.readAttributes(brokerObjectName).catch(e => {
+                // this is the best (as of Nov 2025) way to handle problems 
when fetching attributes with RBAC enabled
+                eventService.notify({type: 'warning', message: 
jolokiaService.errorMessage(e) })
+                return null
+            });
             if (response) {
                 const name = response.Name as string;
                 const nodeID = response.NodeID as string;
-                const version = response.Version as string;
-                const started = "" + response.Started as string;
+                const version = response.Version as string | InaccessibleValue;
+                const started = response.Started as string | InaccessibleValue;
                 const globalMaxSize = response.GlobalMaxSize as number;
                 const addressMemoryUsage = response.AddressMemoryUsage as 
number;
-                const uptime = response.Uptime as string;
-                const haPolicy = response.HAPolicy as string;
+                const uptime = response.Uptime as string | InaccessibleValue;
+                const haPolicy = response.HAPolicy as string | 
InaccessibleValue;
                 const globalMaxSizeMB = globalMaxSize / 1048576;
                 let used = 0;
                 let addressMemoryUsageMB = 0;
@@ -208,9 +252,13 @@ class ArtemisService {
                     addressMemoryUsageMB = addressMemoryUsage / 1048576;
                     used = addressMemoryUsageMB / globalMaxSizeMB * 100
                 }
-                const topology = await 
jolokiaService.execute(brokerObjectName, LIST_NETWORK_TOPOLOGY_SIG) as string;
+                const topology = await 
jolokiaService.execute(brokerObjectName, LIST_NETWORK_TOPOLOGY_SIG).catch(e => {
+                    eventService.notify({type: 'warning', message: 
jolokiaService.errorMessage(e) })
+                    return "{}"
+                }) as string;
                 const brokerInfo: BrokerInfo = {
-                    name: name, objectName: brokerObjectName,
+                    name: name,
+                    objectName: brokerObjectName,
                     nodeID: nodeID,
                     version: version,
                     started: started,
@@ -221,18 +269,26 @@ class ArtemisService {
                     haPolicy: haPolicy,
                     networkTopology: new 
BrokerNetworkTopology(JSON.parse(topology))
                 };
-                resolve(brokerInfo);
+                resolve({ loaded: true, accessible: true, info: brokerInfo });
+                return
             }
-            resolve(null)
+            resolve({ loaded: true, accessible: false, message: `No 
information available for broker ${brokerMBean.objectName}` })
         });
     }
 
-    async createBrokerTopology(maxAddresses: number, addressFilter: string): 
Promise<BrokerTopology> {
-        return new Promise<BrokerTopology>(async (resolve, reject) => {
+    async createBrokerTopology(maxAddresses: number, addressFilter: string): 
Promise<BrokerTopology | null> {
+        return new Promise<BrokerTopology | null>(async (resolve, reject) => {
             try {
-                const brokerInfo = await this.getBrokerInfo();
+                const state = await this.getBrokerInfo();
+                if (!state || !state.info) {
+                    resolve(null)
+                }
+                const brokerInfo = state.info
                 const brokerObjectName = await this.brokerObjectName;
-                const topology = await 
jolokiaService.execute(brokerObjectName, LIST_NETWORK_TOPOLOGY_SIG) as string;
+                const topology = await 
jolokiaService.execute(brokerObjectName, LIST_NETWORK_TOPOLOGY_SIG).catch(error 
=> {
+                    eventService.notify({ type: "warning", message: 
jolokiaService.errorMessage(error) })
+                    return "[]"
+                }) as string;
                 brokerInfo!.networkTopology =  new 
BrokerNetworkTopology(JSON.parse(topology));
                 const brokerTopology: BrokerTopology = {
                     broker: brokerInfo!,
@@ -242,7 +298,10 @@ class ArtemisService {
                 const max: number = maxAddresses < addresses.length ? 
maxAddresses: addresses.length;
                 addresses = addresses.slice(0, max);
                 for (const address of addresses) {
-                    const queuesJson: string = await 
this.getQueuesForAddress(address);
+                    const queuesJson: string = await 
this.getQueuesForAddress(address).catch(error => {
+                        eventService.notify({ type: "warning", message: 
jolokiaService.errorMessage(error) })
+                        return JSON.stringify({ data: [], count: 0 })
+                    })
                     const queues: Queue[] = JSON.parse(queuesJson).data;
                     brokerTopology.addresses.push({
                         name: address,
@@ -273,7 +332,12 @@ class ArtemisService {
                         .catch((e) => {
                             reject(e)
                         }) as Acceptor;
-                    acceptors.acceptors.push(acceptor);
+                    const validation = isValid(acceptor)
+                    if (validation.valid) {
+                        acceptors.acceptors.push(acceptor);
+                    } else {
+                        eventService.notify({ type: "warning", message: 
`Access not granted to ${search[key]}` })
+                    }
                 }
                 resolve(acceptors);
             }
@@ -296,7 +360,12 @@ class ArtemisService {
                         .catch((e) => {
                             reject(e)
                         }) as ClusterConnection;
-                    
clusterConnections.clusterConnections.push(clusterConnection);
+                    const validation = isValid(clusterConnection)
+                    if (validation.valid) {
+                        
clusterConnections.clusterConnections.push(clusterConnection);
+                    } else {
+                        eventService.notify({ type: "warning", message: 
`Access not granted to ${search[key]}` })
+                    }
                 }
                 resolve(clusterConnections);
             }
@@ -691,4 +760,93 @@ class ArtemisService {
     }
 }
 
+export function parseMBeanName(name: string): { domain: string, properties: 
Record<string, string> } {
+    const colon = name.indexOf(":")
+    if (colon === -1) {
+        throw new Error("Illegal ObjectName")
+    }
+
+    const domain = name.substring(0, colon)
+    const propsString = name.substring(colon + 1)
+
+    let i = 0
+    const len = propsString.length
+    const props: Record<string, string> = {}
+
+    while (i < len) {
+        let key = ""
+        while (i < len && propsString[i] !== "=") {
+            key += propsString[i++]
+        }
+
+        // skip '='
+        i++
+
+        let value = ""
+        if (propsString[i] === '"') {
+            // quoted value - only double quote
+            i++
+            while (i < len) {
+                const ch = propsString[i++]
+                if (ch === '"') {
+                    break
+                }
+                value += ch
+            }
+        } else {
+            // unquoted value can be empty
+            while (i < len && propsString[i] !== ",") {
+                value += propsString[i++]
+            }
+        }
+
+        props[key.trim()] = value.trim()
+
+        if (propsString[i] === ",") {
+            i++
+        }
+    }
+
+    return { domain, properties: props };
+}
+
+export async function findMBeanInfo(brokerObjectName: string): 
Promise<MBeanNode | null> {
+    const tree = await workspace.getTree()
+    const parsed = parseMBeanName(brokerObjectName)
+
+    const matching = tree.findMBeans(parsed.domain, parsed.properties)
+    if (!matching) {
+        return null
+    }
+    if (matching.length == 1) {
+        return matching[0]
+    } else {
+        const more = matching.filter(node => node.objectName === 
brokerObjectName)
+        return more.length > 0 ? more[0] : null
+    }
+}
+
+/**
+ * Jolokia's `getAttributes()` may return an object, where each field is an 
error value (when RBAC is enabled
+ * for example). In this case, the value has special `.error` field. This 
function checks validity of an object
+ * or value.
+ * @param value
+ */
+export function isValid(value: any): { valid: boolean, message: string | null 
} {
+    if (typeof value === "object") {
+        if (".error" in value) {
+            // the value itself is an error value
+            return { valid: false, message: jolokiaService.errorMessage(value) 
}
+        }
+        for (const k in value) {
+            const v = value[k]
+            if (typeof v === "object" && ".error" in v) {
+                // fail fast with an error related to first field of the 
wrapping object
+                return { valid: false, message: jolokiaService.errorMessage(v) 
}
+            }
+        }
+    }
+    return { valid: true, message: null }
+}
+
 export const artemisService = new ArtemisService()
\ No newline at end of file
diff --git 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/status/Status.tsx
 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/status/Status.tsx
index a250f98..3578bc3 100644
--- 
a/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/status/Status.tsx
+++ 
b/artemis-console-extension/artemis-extension/packages/artemis-console-plugin/src/status/Status.tsx
@@ -16,6 +16,7 @@
  */
 import { ChartDonutUtilization } from "@patternfly/react-charts"
 import {
+    Alert,
     Card,
     CardBody,
     CardTitle,
@@ -34,20 +35,25 @@ import {
     Modal,
     ModalVariant,
     DropdownList,
+    MenuToggle,
     MenuToggleElement,
-    MenuToggle
+    PageSection,
+    Spinner,
+    Tooltip
 } from "@patternfly/react-core"
 import { EllipsisVIcon } from 
'@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'
 import { ExclamationCircleIcon } from 
'@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon'
 import { OkIcon } from '@patternfly/react-icons/dist/esm/icons/ok-icon'
-import { Attributes, eventService, Operations } from '@hawtio/react';
-import React, { useContext, useEffect, useState } from "react";
-import { Acceptors, artemisService, BrokerInfo, ClusterConnections } from 
"../artemis-service";
+import { Attributes, eventService, jolokiaService, Operations } from 
'@hawtio/react';
+import React, { ReactNode, useContext, useEffect, useState } from "react";
+import { Acceptors, artemisService, BrokerInfo, BrokerState, 
ClusterConnections } from "../artemis-service";
 import { ArtemisContext } from "../context";
 import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
+import { LockedIcon } from '@patternfly/react-icons'
 
 export const Status: React.FunctionComponent = () => {
 
+    const [brokerState, setBrokerState] = useState<BrokerState>({ loaded: 
false, accessible: false, message: "Loading..." })
     const [brokerInfo, setBrokerInfo] = useState<BrokerInfo>()
     const [acceptors, setAcceptors] = useState<Acceptors>();
     const [clusterConnections, setClusterConnections] = 
useState<ClusterConnections>()
@@ -59,13 +65,14 @@ export const Status: React.FunctionComponent = () => {
     const getBrokerInfo = async () => {
         artemisService.getBrokerInfo()
             .then((brokerInfo) => {
-                setBrokerInfo(brokerInfo ?? undefined)
+                if (brokerInfo.info) {
+                    setBrokerInfo(brokerInfo.info)
+                }
+                setBrokerState({ loaded: brokerInfo.loaded, accessible: 
brokerInfo.accessible, message: brokerInfo.message })
             })
-            .catch((error: string | { [key: string]: any }) => {
-                eventService.notify({
-                    type: 'warning',
-                    message: typeof error === 'object' ? ('error' in error ? 
error.error : JSON.stringify(error)) : error,
-                })
+            .catch((error) => {
+                setBrokerState({ loaded: false, accessible: false, message: 
`Error loading broker: ${jolokiaService.errorMessage(error)}` })
+                eventService.notify({type: 'warning', message: 
jolokiaService.errorMessage(error) })
             });
     }
 
@@ -74,11 +81,8 @@ export const Status: React.FunctionComponent = () => {
             .then((acceptors) => {
                 setAcceptors(acceptors)
             })
-            .catch((error: string | { [key: string]: any }) => {
-                eventService.notify({
-                    type: 'warning',
-                    message: typeof error === 'object' ? ('error' in error ? 
error.error : JSON.stringify(error)) : error,
-                })
+            .catch((error) => {
+                eventService.notify({type: 'warning', message: 
jolokiaService.errorMessage(error) })
             });
     }
 
@@ -87,11 +91,8 @@ export const Status: React.FunctionComponent = () => {
             .then((clusterConnections) => {
                 setClusterConnections(clusterConnections)
             })
-            .catch((error: string | { [key: string]: any }) => {
-                eventService.notify({
-                    type: 'warning',
-                    message: typeof error === 'object' ? ('error' in error ? 
error.error : JSON.stringify(error)) : error,
-                })
+            .catch((error) => {
+                eventService.notify({type: 'warning', message: 
jolokiaService.errorMessage(error) })
             });
     }
 
@@ -118,7 +119,7 @@ export const Status: React.FunctionComponent = () => {
         setIsBrokerInfoOpen(!isBrokerInfoOpen);
     };
 
-    const openAttrubutes = async () => {
+    const openAttributes = async () => {
         const brokerObjectName = await artemisService.getBrokerObjectName();
         findAndSelectNode(brokerObjectName, "");
         setShowAttributesDialog(true);
@@ -144,7 +145,7 @@ export const Status: React.FunctionComponent = () => {
             isOpen={isBrokerInfoOpen}
         >
             <DropdownList>
-                <DropdownItem key="attributes" component="button" onClick={() 
=> openAttrubutes()}>
+                <DropdownItem key="attributes" component="button" onClick={() 
=> openAttributes()}>
                     Attributes
                 </DropdownItem>
                 <DropdownItem key="operations" component="button" onClick={() 
=> openOperations()}>
@@ -154,6 +155,31 @@ export const Status: React.FunctionComponent = () => {
         </Dropdown>
     );
 
+    function actualValue(v: unknown): ReactNode {
+        if (typeof v === 'object' && v && (".error" in v) && v[".error"]) {
+            const msg = "error" in v ? v["error"] as string : "Not accessible"
+            return (
+                <Tooltip content={msg}>
+                    <LockedIcon />
+                </Tooltip>
+            )
+        } else {
+            return (v ? "" + v : "")
+        }
+    }
+
+    if (!brokerState.loaded) {
+        return <Spinner size='lg' />
+    }
+
+    if (!brokerState.accessible) {
+        return (
+            <PageSection id='broker-info' variant='light'>
+                <Alert variant="warning" title={brokerState.message} />
+            </PageSection>
+        )
+    }
+
     return (
         <>
             <Grid hasGutter>
@@ -166,10 +192,10 @@ export const Status: React.FunctionComponent = () => {
                             <Divider />
                             <TextContent>
                                 <TextList isPlain>
-                                    <TextListItem 
component={TextListItemVariants.dd}>Version: 
{brokerInfo?.version}</TextListItem>
-                                    <TextListItem 
component={TextListItemVariants.dd}>Uptime: {brokerInfo?.uptime}</TextListItem>
-                                    <TextListItem 
component={TextListItemVariants.dd}>Started: 
{""+brokerInfo?.started}</TextListItem>
-                                    <TextListItem 
component={TextListItemVariants.dd}>HA Policy: 
{brokerInfo?.haPolicy}</TextListItem>
+                                    <TextListItem 
component={TextListItemVariants.dd}>Version: 
{actualValue(brokerInfo?.version)}</TextListItem>
+                                    <TextListItem 
component={TextListItemVariants.dd}>Uptime: 
{actualValue(brokerInfo?.uptime)}</TextListItem>
+                                    <TextListItem 
component={TextListItemVariants.dd}>Started: 
{actualValue(brokerInfo?.started)}</TextListItem>
+                                    <TextListItem 
component={TextListItemVariants.dd}>HA Policy: 
{actualValue(brokerInfo?.haPolicy)}</TextListItem>
                                 </TextList>
                             </TextContent>
                         </CardBody>
@@ -205,38 +231,46 @@ export const Status: React.FunctionComponent = () => {
             <ExpandableSection toggleTextExpanded="Acceptors" 
toggleTextCollapsed="Acceptors">
                 <Grid hasGutter span={4}>
                     {
-                        acceptors?.acceptors.map((acceptor, index) => (
-                            <GridItem key={index}>
-                                <Card isFullHeight={true} isFlat={true}>
+                        acceptors?.acceptors.map((acceptor, index) => {
+                            if (!(typeof acceptor.Name === 'object' && 
".error" in acceptor.Name)) {
+                                return (
+                                <GridItem key={index}>
+                                    <Card isFullHeight={true} isFlat={true}>
 
-                                    <CardTitle>{acceptor.Name} 
({acceptor.FactoryClassName.indexOf("Netty") === -1?"VM":"TCP"}): 
{acceptor.Started && <OkIcon color="green" />}{!acceptor.Started && 
<ExclamationCircleIcon color="red"/>}</CardTitle>
-                                    <CardBody>
-                                        <Divider />
-                                        <Table variant="compact" 
aria-label="Column Management Table">
-                                        <Thead>
-                                            <Tr 
key={"acceptor-list-param-title"}>
-                                                <Th 
key={"acceptor-list-param-key" + index}>key</Th>
-                                                <Th 
key={"acceptor-list-param-value" + index}>value</Th>
-                                            </Tr>
-                                        </Thead>
-                                        <Tbody>
-                                        {
-                                            
Object.keys(acceptor.Parameters).map((key, index) => {
-                                                return (
-                                                    <Tr 
key={"acceptor-list-param-val-" + index}>
-                                                        <Td 
key={"acceptor-params-key-" + key}>{key}</Td>
-                                                        <Td 
key={"acceptor-params-val-" + key}>{acceptor.Parameters[key]}</Td>
+                                        <CardTitle>{acceptor.Name} ({typeof 
acceptor?.FactoryClassName === 'string' ? 
(acceptor?.FactoryClassName?.indexOf("Netty") === -1 ? "VM" : "TCP") : "?"}): 
{acceptor.Started &&
+                                            <OkIcon color="green" 
/>}{!acceptor.Started &&
+                                            <ExclamationCircleIcon color="red" 
/>}</CardTitle>
+                                        <CardBody>
+                                            <Divider />
+                                            <Table variant="compact" 
aria-label="Column Management Table">
+                                                <Thead>
+                                                    <Tr 
key={"acceptor-list-param-title"}>
+                                                        <Th 
key={"acceptor-list-param-key" + index}>key</Th>
+                                                        <Th 
key={"acceptor-list-param-value" + index}>value</Th>
                                                     </Tr>
+                                                </Thead>
+                                                <Tbody>
+                                                    {
+                                                        
Object.keys(acceptor.Parameters).map((key, index) => {
+                                                            return (
+                                                                <Tr 
key={"acceptor-list-param-val-" + index}>
+                                                                    <Td 
key={"acceptor-params-key-" + key}>{key}</Td>
+                                                                    <Td 
key={"acceptor-params-val-" + key}>{acceptor.Parameters[key]}</Td>
+                                                                </Tr>
 
-                                                )
-                                            })
-                                        }
-                                        </Tbody>
-                                        </Table>
-                                    </CardBody>
-                                </Card>
-                            </GridItem>
-                        ))
+                                                            )
+                                                        })
+                                                    }
+                                                </Tbody>
+                                            </Table>
+                                        </CardBody>
+                                    </Card>
+                                </GridItem>
+                            )} else {
+                                // return 
(<span>{acceptor.Name["message"]}</span>)
+                                return null
+                            }
+                        })
                     }
                 </Grid>
             </ExpandableSection>
@@ -282,7 +316,7 @@ export const Status: React.FunctionComponent = () => {
                 </Grid>
                 <Grid hasGutter>
                     {
-                        brokerInfo?.networkTopology.brokers.map((broker, 
index) => (
+                        brokerInfo?.networkTopology?.brokers?.map?.((broker, 
index) => (
                             <GridItem key={index} span={3}>
                                 <Card isFlat={true}>
                                     <CardTitle>{broker.nodeID}</CardTitle>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information, visit: https://activemq.apache.org/contact


Reply via email to