[ 
https://issues.apache.org/jira/browse/ARTEMIS-4680?focusedWorklogId=917106&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-917106
 ]

ASF GitHub Bot logged work on ARTEMIS-4680:
-------------------------------------------

                Author: ASF GitHub Bot
            Created on: 01/May/24 06:47
            Start Date: 01/May/24 06:47
    Worklog Time Spent: 10m 
      Work Description: andytaylor commented on code in PR #2:
URL: 
https://github.com/apache/activemq-artemis-console/pull/2#discussion_r1585945469


##########
artemis-console-extension/artemis-extension/src/artemis-extension/artemis/brokers/BrokerTopology.tsx:
##########
@@ -0,0 +1,671 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import * as React from 'react';
+
+import { RegionsIcon as Icon1 } from '@patternfly/react-icons';
+import { FolderOpenIcon as Icon2 } from '@patternfly/react-icons';
+import { ClusterIcon } from '@patternfly/react-icons';
+
+import {
+  ColaLayout,
+  ComponentFactory,
+  DefaultEdge,
+  DefaultGroup,
+  DefaultNode,
+  DragObjectWithType,
+  Edge,
+  EdgeModel,
+  EdgeStyle,
+  Graph,
+  GraphComponent,
+  graphDropTargetSpec,
+  GRAPH_LAYOUT_END_EVENT,
+  groupDropTargetSpec,
+  Layout,
+  LayoutFactory,
+  Model,
+  ModelKind,
+  Node,
+  nodeDragSourceSpec,
+  nodeDropTargetSpec,
+  NodeModel,
+  NodeShape,
+  NodeStatus,
+  observer,
+  SELECTION_EVENT,
+  TopologyView,
+  Visualization,
+  VisualizationProvider,
+  VisualizationSurface,
+  withDndDrop,
+  WithDndDropProps,
+  withDragNode,
+  WithDragNodeProps,
+  withPanZoom,
+  withSelection,
+  WithSelectionProps,
+  withTargetDrag
+} from '@patternfly/react-topology';
+import { useEffect, useState } from 'react';
+import { artemisService, BrokerInfo } from '../artemis-service';
+import { eventService } from '@hawtio/react';
+import { ToolbarItem, Select, SelectVariant, SelectOption } from 
'@patternfly/react-core';
+
+
+const BadgeColors = [
+  {
+    name: 'A',
+    badgeColor: '#ace12e',
+    badgeTextColor: '#0f280d',
+    badgeBorderColor: '#486b00'
+  },
+  {
+    name: 'B',
+    badgeColor: '#F2F0FC',
+    badgeTextColor: '#5752d1',
+    badgeBorderColor: '#CBC1FF'
+  },
+  {
+    name: 'Broker',
+    badgeColor: '#c12766',
+    badgeTextColor: 'white',
+    badgeBorderColor: '#CBC1FF'
+  },
+  {
+    name: 'Address',
+    badgeColor: '#3e489f',
+    badgeTextColor: 'white',
+    badgeBorderColor: '#CBC1FF'
+  },
+  {
+    name: 'Queue',
+    badgeColor: '#50621d',
+    badgeTextColor: 'white',
+    badgeBorderColor: '#CBC1FF'
+  },
+  {
+    name: 'Internal Address',
+    badgeColor: 'white',
+    badgeTextColor: 'black',
+    badgeBorderColor: '#CBC1FF'
+  },
+  {
+    name: 'Internal Queue',
+    badgeColor: 'white',
+    badgeTextColor: 'black',
+    badgeBorderColor: '#CBC1FF'
+  }
+];
+
+interface ControllerState {
+  selectedIds: string[];
+  viewOptions: ViewOptions;
+}
+
+type CustomNodeProps = {
+  element: Node;
+} & WithDragNodeProps;
+
+const CustomNode: React.FC<CustomNodeProps & WithSelectionProps & 
WithDragNodeProps & WithDndDropProps> = ({ element, onSelect, selected, ...rest 
 }) => {
+
+  const data = element.getData();
+  const Icon = data.isAlternate ? Icon2 : Icon1;
+  const badgeColors = BadgeColors.find(badgeColor => badgeColor.name === 
data.badge);
+
+  return (  
+    <DefaultNode
+      element={element}
+      showStatusDecorator
+      badgeColor={badgeColors?.badgeColor}
+      badgeTextColor={badgeColors?.badgeTextColor}
+      badgeBorderColor={badgeColors?.badgeBorderColor} 
+      className="artemisBroker"
+      onSelect={onSelect}
+      selected={selected}
+      {...rest}
+    >
+      <g transform={`translate(25, 25)`}>
+        <Icon style={{ color: '#393F44' }} width={25} height={25} />
+      </g>
+    </DefaultNode>
+  );
+};
+
+const BrokerCustomNode: React.FC<CustomNodeProps & WithSelectionProps & 
WithDragNodeProps & WithDndDropProps> = observer(({ element, onSelect, 
selected, ...rest }) => {
+  const data = element.getData();
+  const Icon = ClusterIcon;
+  const badgeColors = BadgeColors.find(badgeColor => badgeColor.name === 
data.badge);
+  const { viewOptions } = element.getController().getState<ControllerState>();
+
+  return (
+    <DefaultNode
+      element={element}
+      showStatusDecorator
+      badge={data.badge}
+      badgeColor={badgeColors?.badgeColor}
+      badgeTextColor={badgeColors?.badgeTextColor}
+      badgeBorderColor={badgeColors?.badgeBorderColor}
+      showLabel={viewOptions.showLabels}
+      className="artemisBroker"
+      onSelect={onSelect}
+      selected={selected}
+      {...rest}
+    >
+      <g transform={`translate(25, 25)`}>
+        <Icon style={{ color: '#393F44' }} width={25} height={25} />
+      </g>
+    </DefaultNode>
+  );
+});
+
+const AddressCustomNode: React.FC<CustomNodeProps & WithSelectionProps & 
WithDragNodeProps & WithDndDropProps> = ({ element, onSelect, selected, ...rest 
 }) => {
+  const data = element.getData();
+  const badgeColors = BadgeColors.find(badgeColor => badgeColor.name === 
data.badge);
+  const { viewOptions } = element.getController().getState<ControllerState>();
+
+  return (
+    <DefaultNode
+      element={element}
+      showStatusDecorator
+      badge={data.badge}
+      badgeColor={badgeColors?.badgeColor}
+      badgeTextColor={badgeColors?.badgeTextColor}
+      badgeBorderColor={badgeColors?.badgeBorderColor} 
+      showLabel={viewOptions.showLabels}
+      onSelect={onSelect}
+      selected={selected}
+      className="artemisAddress"
+      {...rest}
+    >
+    </DefaultNode>
+  );
+};
+
+const InternalAddressCustomNode: React.FC<CustomNodeProps & WithSelectionProps 
& WithDragNodeProps & WithDndDropProps> = ({ element, onSelect, selected, 
...rest  }) => {
+  const data = element.getData();
+  const badgeColors = BadgeColors.find(badgeColor => badgeColor.name === 
data.badge);
+  const { viewOptions } = element.getController().getState<ControllerState>();
+
+  return (
+    <DefaultNode
+      element={element}
+      showStatusDecorator
+      badge={data.badge}
+      badgeColor={badgeColors?.badgeColor}
+      badgeTextColor={badgeColors?.badgeTextColor}
+      badgeBorderColor={badgeColors?.badgeBorderColor} 
+      showLabel={viewOptions.showLabels}
+      className="artemisInternalAddress"
+      onSelect={onSelect}
+      selected={selected}
+      {...rest}
+    >
+    </DefaultNode>
+  );
+};
+
+
+const QueueCustomNode: React.FC<CustomNodeProps & WithSelectionProps & 
WithDragNodeProps & WithDndDropProps> = ({ element, onSelect, selected, ...rest 
 }) => {
+  const data = element.getData();
+  const badgeColors = BadgeColors.find(badgeColor => badgeColor.name === 
data.badge);
+  const { viewOptions } = element.getController().getState<ControllerState>();
+
+  return (
+    <DefaultNode
+      element={element}
+      showStatusDecorator
+      badge={data.badge}
+      badgeColor={badgeColors?.badgeColor}
+      badgeTextColor={badgeColors?.badgeTextColor}
+      badgeBorderColor={badgeColors?.badgeBorderColor}
+      showLabel={viewOptions.showLabels} 
+      className="artemisQueue"
+      onSelect={onSelect}
+      selected={selected}
+      {...rest}
+    >
+    </DefaultNode>
+  );
+};
+
+const InternalQueueCustomNode: React.FC<CustomNodeProps & WithSelectionProps & 
WithDragNodeProps & WithDndDropProps> = ({ element, onSelect, selected, ...rest 
 }) => {
+  const data = element.getData();
+  const badgeColors = BadgeColors.find(badgeColor => badgeColor.name === 
data.badge);
+  const { viewOptions } = element.getController().getState<ControllerState>();
+
+  return (
+    <DefaultNode
+      element={element}
+      showStatusDecorator
+      badge={data.badge}
+      badgeColor={badgeColors?.badgeColor}
+      badgeTextColor={badgeColors?.badgeTextColor}
+      badgeBorderColor={badgeColors?.badgeBorderColor}
+      showLabel={viewOptions.showLabels} 
+      className="artemisInternalQueue"
+      onSelect={onSelect}
+      selected={selected}
+      {...rest}
+    >
+    </DefaultNode>
+  );
+};
+
+const customLayoutFactory: LayoutFactory = (type: string, graph: Graph): 
Layout | undefined => {
+  switch (type) {
+    case 'Cola':
+      return new ColaLayout(graph);
+    default:
+      return new ColaLayout(graph, { layoutOnDrag: true });
+  }
+};
+
+const CONNECTOR_TARGET_DROP = 'connector-target-drop';
+
+const customComponentFactory: ComponentFactory = (kind: ModelKind, type: 
string): any => {
+  switch (type) {
+    case 'group':
+      return 
withDndDrop(groupDropTargetSpec)(withDragNode(nodeDragSourceSpec('group'))(withSelection()(DefaultGroup)));
+    default:
+      switch (kind) {
+        case ModelKind.graph:
+          return 
withDndDrop(graphDropTargetSpec())(withPanZoom()(GraphComponent));
+        case ModelKind.node:
+          switch(type) {
+            case 'broker':
+              return withDndDrop(nodeDropTargetSpec([CONNECTOR_TARGET_DROP]))(
+                withDragNode(nodeDragSourceSpec('node', true, 
true))(BrokerCustomNode));
+            case 'address':
+              return withDndDrop(nodeDropTargetSpec([CONNECTOR_TARGET_DROP]))(
+                withDragNode(nodeDragSourceSpec('node', true, 
true))(AddressCustomNode));
+            case 'queue':
+              return withDndDrop(nodeDropTargetSpec([CONNECTOR_TARGET_DROP]))(
+                withDragNode(nodeDragSourceSpec('node', true, 
true))(QueueCustomNode));
+            case 'internalAddress':
+              return withDndDrop(nodeDropTargetSpec([CONNECTOR_TARGET_DROP]))(
+                withDragNode(nodeDragSourceSpec('node', true, 
true))(InternalAddressCustomNode));
+            case 'internalQueue':
+              return withDndDrop(nodeDropTargetSpec([CONNECTOR_TARGET_DROP]))(
+                withDragNode(nodeDragSourceSpec('node', true, 
true))(InternalQueueCustomNode));
+            default:
+              return withDndDrop(nodeDropTargetSpec([CONNECTOR_TARGET_DROP]))(
+                withDragNode(nodeDragSourceSpec('node', true, 
true))(CustomNode));
+          }
+        case ModelKind.edge:
+          return withTargetDrag<
+            DragObjectWithType,
+            Node,
+            { dragging?: boolean },
+            {
+              element: Edge;
+            }
+          >({
+            item: { type: CONNECTOR_TARGET_DROP },
+            begin: (monitor, props) => {
+              props.element.raise();
+              return props.element;
+            },
+            drag: (event, monitor, props) => {
+              props.element.setEndPoint(event.x, event.y);
+            },
+            end: (dropResult, monitor, props) => {
+              if (monitor.didDrop() && dropResult && props) {
+                props.element.setTarget(dropResult);
+              }
+              props.element.setEndPoint();
+            },
+            collect: monitor => ({
+              dragging: monitor.isDragging()
+            })
+            // @ts-ignore
+          })(DefaultEdge);
+        default:
+          return undefined;
+      }
+  }
+};
+
+const BROKER_NODE_DIAMETER = 75;
+const ADDRESS_NODE_DIAMETER = 50;
+const QUEUE_NODE_DIAMETER = 50;
+
+const NODES: NodeModel[] = [];
+const EDGES: EdgeModel[] = [];
+
+interface ViewOptions {
+  showLabels: boolean;
+  showAddresses: boolean;
+  showQueues: boolean;
+  showInternalAddresses: boolean;
+  showInternalQueues: boolean;
+  showConnectors: boolean;
+}
+
+export const DefaultViewOptions: ViewOptions = {
+  showLabels: false,

Review Comment:
   I have enabled labels by default. 





Issue Time Tracking
-------------------

    Worklog Id:     (was: 917106)
    Time Spent: 8h 50m  (was: 8h 40m)

> Upgrade the console to use HawtIO 4
> -----------------------------------
>
>                 Key: ARTEMIS-4680
>                 URL: https://issues.apache.org/jira/browse/ARTEMIS-4680
>             Project: ActiveMQ Artemis
>          Issue Type: Improvement
>          Components: Web Console
>            Reporter: Andy Taylor
>            Assignee: Andy Taylor
>            Priority: Major
>          Time Spent: 8h 50m
>  Remaining Estimate: 0h
>
> The current console is based upon HawtIO 1 which in turn is built on 
> Bootstrap. Bootstrap is old and no longer actively being maintained.
>  
> This improvement is to migrate the current console to use HawtIO 4 which i 
> based on Typescript, react and Patternfly.
>  
> A WIP can be found 
> [here|https://github.com/andytaylor/activemq-artemis/tree/artemis-console-ng]



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to