diff --git a/locales/en/plugin__gitops-plugin.json b/locales/en/plugin__gitops-plugin.json
index 2e1090283..bf43198f5 100644
--- a/locales/en/plugin__gitops-plugin.json
+++ b/locales/en/plugin__gitops-plugin.json
@@ -116,16 +116,17 @@
"Delete {{x}}": "Delete {{x}}",
"Edit {{x}}": "Edit {{x}}",
"View in Argo CD": "View in Argo CD",
+ "View Details": "View Details",
"Edit Application": "Edit Application",
"Delete Application": "Delete Application",
"Show {{x}}": "Show {{x}}",
"Hide {{x}}": "Hide {{x}}",
+ "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}": "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}",
"Group resources of the same kind into one node": "Group resources of the same kind into one node",
"Group Nodes": "Group Nodes",
"There is no health status for this resource": "There is no health status for this resource",
"Sync Unknown": "Sync Unknown",
"One or more resources are in Progressing state": "One or more resources are in Progressing state",
- "Go to application": "Go to application",
"Step {{x}}": "Step {{x}}",
"Step: unmatched": "Step: unmatched",
"There is no history associated with the application.": "There is no history associated with the application.",
diff --git a/locales/ja/plugin__gitops-plugin.json b/locales/ja/plugin__gitops-plugin.json
index ba4a09539..be8e4aee2 100644
--- a/locales/ja/plugin__gitops-plugin.json
+++ b/locales/ja/plugin__gitops-plugin.json
@@ -116,16 +116,17 @@
"Delete {{x}}": "Delete {{x}}",
"Edit {{x}}": "Edit {{x}}",
"View in Argo CD": "View in Argo CD",
+ "View Details": "View Details",
"Edit Application": "Edit Application",
"Delete Application": "Delete Application",
"Show {{x}}": "Show {{x}}",
"Hide {{x}}": "Hide {{x}}",
+ "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}": "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}",
"Group resources of the same kind into one node": "Group resources of the same kind into one node",
"Group Nodes": "Group Nodes",
"There is no health status for this resource": "There is no health status for this resource",
"Sync Unknown": "Sync Unknown",
"One or more resources are in Progressing state": "One or more resources are in Progressing state",
- "Go to application": "Go to application",
"Step {{x}}": "Step {{x}}",
"Step: unmatched": "Step: unmatched",
"There is no history associated with the application.": "There is no history associated with the application.",
diff --git a/locales/ko/plugin__gitops-plugin.json b/locales/ko/plugin__gitops-plugin.json
index b9a275972..bc0731941 100644
--- a/locales/ko/plugin__gitops-plugin.json
+++ b/locales/ko/plugin__gitops-plugin.json
@@ -116,16 +116,17 @@
"Delete {{x}}": "Delete {{x}}",
"Edit {{x}}": "Edit {{x}}",
"View in Argo CD": "View in Argo CD",
+ "View Details": "View Details",
"Edit Application": "Edit Application",
"Delete Application": "Delete Application",
"Show {{x}}": "Show {{x}}",
"Hide {{x}}": "Hide {{x}}",
+ "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}": "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}",
"Group resources of the same kind into one node": "Group resources of the same kind into one node",
"Group Nodes": "Group Nodes",
"There is no health status for this resource": "There is no health status for this resource",
"Sync Unknown": "Sync Unknown",
"One or more resources are in Progressing state": "One or more resources are in Progressing state",
- "Go to application": "Go to application",
"Step {{x}}": "Step {{x}}",
"Step: unmatched": "Step: unmatched",
"There is no history associated with the application.": "There is no history associated with the application.",
diff --git a/locales/zh/plugin__gitops-plugin.json b/locales/zh/plugin__gitops-plugin.json
index 1d8b344a1..d5211346c 100644
--- a/locales/zh/plugin__gitops-plugin.json
+++ b/locales/zh/plugin__gitops-plugin.json
@@ -116,16 +116,17 @@
"Delete {{x}}": "Delete {{x}}",
"Edit {{x}}": "Edit {{x}}",
"View in Argo CD": "View in Argo CD",
+ "View Details": "View Details",
"Edit Application": "Edit Application",
"Delete Application": "Delete Application",
"Show {{x}}": "Show {{x}}",
"Hide {{x}}": "Hide {{x}}",
+ "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}": "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}",
"Group resources of the same kind into one node": "Group resources of the same kind into one node",
"Group Nodes": "Group Nodes",
"There is no health status for this resource": "There is no health status for this resource",
"Sync Unknown": "Sync Unknown",
"One or more resources are in Progressing state": "One or more resources are in Progressing state",
- "Go to application": "Go to application",
"Step {{x}}": "Step {{x}}",
"Step: unmatched": "Step: unmatched",
"There is no history associated with the application.": "There is no history associated with the application.",
diff --git a/src/gitops/components/application/graph/ApplicationGraphView.scss b/src/gitops/components/application/graph/ApplicationGraphView.scss
index 4a5aa4bd6..34d5cdc64 100644
--- a/src/gitops/components/application/graph/ApplicationGraphView.scss
+++ b/src/gitops/components/application/graph/ApplicationGraphView.scss
@@ -32,7 +32,53 @@
// .pf-topology__edge__background {
// stroke: var(--pf-t--global--dark--background--color--100);
// }
-
+
+ .pf-topology__node.pf-m-selected {
+ .pf-topology__node__label__badge > rect {
+ stroke-width: 1;
+ }
+ .pf-topology__node__action-icon__icon .pf-v6-svg{
+ stroke: var(--pf-topology__node--Color);
+ fill: var(--pf-topology__node__label__background--Stroke);
+ }
+ .gitops-node-layout {
+ .pf-topology__node__action-icon__icon .pf-v6-svg{
+ stroke: var(--pf-t--global--border--color--default);
+ fill: var(--pf-topology__node__action-icon__icon--Color);
+ }
+ }
+ }
+
+ .gitops-resource-node-label-badge-opaque {
+ opacity: 0;
+ }
+
+ .gitops-resource-node-label {
+ .pf-topology__node__separator {
+ opacity: 0;
+ }
+
+ .pf-topology__node__label__background {
+ width: 0px;
+ height: 0px;
+ stroke: var(--pf-topology__node--Color);
+ fill: var(--pf-topology__node--Color);
+ }
+ }
+
+ .gitops-resource-node-menu {
+ transform: translate(243px,10px);
+ }
+
+ .gitops-resource-group-node-menu {
+ transform: translate(243px,25px);
+ }
+
+ .gitops-application-node-menu {
+ transform: translate(263px,25px);
+ fill: var(--pf-topology__node__label__background--Stroke);
+ }
+
.step-edge {
&.step-edge-healthy {
stroke: var(--pf-v5-global--success-color--100);
@@ -74,7 +120,7 @@
padding-right: 6px;
}
- .pf-v6-c-toolbar__item:has(button#setting-owner-reference-layout) {
+ .pf-v6-c-toolbar__item:has(button#toggle-node-layout) {
padding-left: 8px;
border-left: 2px solid var(--pf-t--global--border--color--default);
}
diff --git a/src/gitops/components/application/graph/ApplicationGraphView.tsx b/src/gitops/components/application/graph/ApplicationGraphView.tsx
index f44342ef8..7cc6bef0b 100644
--- a/src/gitops/components/application/graph/ApplicationGraphView.tsx
+++ b/src/gitops/components/application/graph/ApplicationGraphView.tsx
@@ -18,7 +18,7 @@ import {
useUserSettings,
} from '@openshift-console/dynamic-plugin-sdk';
import { useK8sModel } from '@openshift-console/dynamic-plugin-sdk/lib/utils/k8s/hooks/useK8sModel';
-import { ObjectGroupIcon } from '@patternfly/react-icons';
+import { ObjectGroupIcon, ToggleOffIcon, ToggleOnIcon } from '@patternfly/react-icons';
import {
action,
ComponentFactory,
@@ -59,14 +59,19 @@ import { GraphResourceMenuItem } from './hooks/GraphResourceMenuItems';
import { ApplicationNode } from './nodes/ApplicationNode';
import { ResourceGroupNode } from './nodes/ResourceGroupNode';
import { ResourceNode } from './nodes/ResourceNode';
-import { getInitialEdges, getInitialNodes } from './graph-utils';
+import {
+ getInitialEdges,
+ getInitialNodes,
+ getResourceMapKey,
+ getResourcePathForResource,
+} from './graph-utils';
import './ApplicationGraphView.scss';
const customLayoutFactory: LayoutFactory = (type: string, graph: Graph): Layout | undefined => {
return new DagreLayout(graph, {
rankdir: 'LR',
- ranksep: 1,
+ ranksep: 0,
nodesep: 0,
edgesep: 0,
ranker: 'network-simplex',
@@ -122,7 +127,6 @@ const customComponentFactory =
) {
return ;
}
-
// For other actions that don't need resource-specific hooks
return (
{label}
@@ -146,26 +153,14 @@ const customComponentFactory =
graphElement.getData().kind === 'AppProject' ||
graphElement.getData().kind === 'Namespace'
) {
- return createContextMenuItems2(graphElement, [
- t('Edit labels'),
- t('Edit annotations'),
- t('Edit {{x}}', {
- x: graphElement.getData().kind,
- }),
- '-',
- t('View in Argo CD'),
- ]);
+ return createContextMenuItems2(graphElement, [t('View Details'), t('View in Argo CD')]);
} else {
return createContextMenuItems2(graphElement, [
- t('Edit labels'),
- t('Edit annotations'),
- t('Edit {{x}}', {
- x: graphElement.getData().kind,
- }),
t('Delete {{x}}', {
x: graphElement.getData().kind,
}),
'-',
+ t('View Details'),
t('View in Argo CD'),
]);
}
@@ -308,6 +303,11 @@ export const ApplicationGraphView: React.FC<{
false,
false,
);
+ const [resourceNodeLayout, setResourceNodeLayout] = useUserSettings(
+ 'redhat.gitops.resourceNodeLayout',
+ true,
+ false,
+ );
const [argoServer, setArgoServer] = React.useState({ host: '', protocol: '' });
const hrefRef = React.useRef('');
React.useEffect(() => {
@@ -357,12 +357,26 @@ export const ApplicationGraphView: React.FC<{
return newController;
}, []);
+ const resourcePaths = React.useMemo(() => {
+ const map = new Map();
+ resources.forEach((resource) => {
+ const mapKey = getResourceMapKey(resource);
+ if (resource.health?.status !== HealthStatus.MISSING) {
+ map.set(mapKey, getResourcePathForResource(resource, allK8sModels));
+ } else {
+ map.set(mapKey, '');
+ }
+ });
+ return map;
+ }, [resources, allK8sModels]);
const initialNodes = getInitialNodes(
application,
resources,
allK8sModels,
groupNodeState,
groupNodeStates,
+ resourceNodeLayout,
+ resourcePaths,
);
const initialEdges = getInitialEdges(application, initialNodes, groupNodeState);
const nodes = [...initialNodes];
@@ -373,12 +387,16 @@ export const ApplicationGraphView: React.FC<{
// Track the previous node count to detect structural changes
const previousNodeCountRef = React.useRef(0);
const groupNodeRef = React.useRef(groupNodeState);
+ const resourceNodeLayoutRef = React.useRef(resourceNodeLayout);
const currentNodeCount = nodes.length;
const previousNodeCount = previousNodeCountRef.current;
const previousGroupNodeState = groupNodeRef.current;
+ const previousResourceNodeLayout = resourceNodeLayoutRef.current;
const isStructuralChange =
- currentNodeCount !== previousNodeCount || previousGroupNodeState != groupNodeState;
+ currentNodeCount !== previousNodeCount ||
+ previousGroupNodeState != groupNodeState ||
+ previousResourceNodeLayout != resourceNodeLayout;
if (isStructuralChange || previousNodeCount === 0) {
// Structural change: Create model WITH layout
@@ -395,6 +413,7 @@ export const ApplicationGraphView: React.FC<{
controller.fromModel(modelWithLayout, false);
previousNodeCountRef.current = currentNodeCount;
groupNodeRef.current = groupNodeState;
+ resourceNodeLayoutRef.current = resourceNodeLayout;
} else {
// Data change only: Update ONLY changed nodes (no layout, no position changes)
let updateCount = 0;
@@ -462,6 +481,22 @@ export const ApplicationGraphView: React.FC<{
controller.getGraph().layout();
}),
customButtons: [
+ {
+ id: 'toggle-node-layout',
+ icon: resourceNodeLayout ? : ,
+ tooltip: t(
+ 'Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}',
+ { x: resourceNodeLayout ? 'Argo CD' : 'OpenShift' },
+ ),
+ ariaLabel: t(
+ 'Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}',
+ { x: resourceNodeLayout ? 'Argo CD' : 'OpenShift' },
+ ),
+ callback: () => {
+ setResourceNodeLayout(!resourceNodeLayout);
+ controller.getGraph().layout();
+ },
+ },
{
id: 'use-group-nodes',
icon: ,
diff --git a/src/gitops/components/application/graph/graph-utils.tsx b/src/gitops/components/application/graph/graph-utils.tsx
index a457231fc..36b60d30a 100644
--- a/src/gitops/components/application/graph/graph-utils.tsx
+++ b/src/gitops/components/application/graph/graph-utils.tsx
@@ -7,8 +7,13 @@ import {
kindToAbbr,
NODE_DIAMETER,
} from '@gitops/components/graph/utils';
-import { ApplicationKind, ApplicationResourceStatus } from '@gitops/models/ApplicationModel';
+import {
+ ApplicationKind,
+ ApplicationModel,
+ ApplicationResourceStatus,
+} from '@gitops/models/ApplicationModel';
import { HealthStatus, SyncStatus } from '@gitops/utils/constants';
+import { resourcePathFromModel } from '@gitops/utils/utils';
import { K8sModel } from '@openshift-console/dynamic-plugin-sdk';
import {
EdgeStyle,
@@ -24,7 +29,10 @@ const NODE_TYPE_APPLICATION = 'application-node';
const NODE_TYPE_APPLICATION_LABEL = 'Application';
// Map application health status with topology node status
-const createApplicationNode = (application: ApplicationKind): NodeModel => {
+const createApplicationNode = (
+ application: ApplicationKind,
+ resourceNodeLayout: boolean,
+): NodeModel => {
const nodeStatus = getTopologyNodeStatus(application.status?.health?.status);
return {
id:
@@ -34,7 +42,7 @@ const createApplicationNode = (application: ApplicationKind): NodeModel => {
'-' +
application?.metadata?.namespace,
type: NODE_TYPE_APPLICATION,
- label: NODE_TYPE_APPLICATION_LABEL,
+ label: resourceNodeLayout ? ' ' : NODE_TYPE_APPLICATION_LABEL,
status: nodeStatus,
width: APP_NODE_WIDTH,
height: APP_NODE_HEIGHT,
@@ -47,7 +55,9 @@ const createApplicationNode = (application: ApplicationKind): NodeModel => {
badgeBorderColor: RESOURCE_COLORS.get(
RESOURCE_BADGE_COLORS.get('.co-m-resource-' + application?.kind.toLowerCase()),
),
+ badgeTextColor: 'white',
rank: 0,
+ resourceNodeLayout: resourceNodeLayout,
nodeStatus: nodeStatus,
resourceHealthStatus: application?.status?.health?.status,
appHealthStatus: application?.status?.health?.status,
@@ -105,6 +115,7 @@ const createGroupResourceNode = (
resources: ApplicationResourceStatus[],
allK8sModels: { [key: string]: K8sModel },
resourceGroupExpandState: boolean,
+ resourceNodeLayout: boolean,
): Map => {
const resourceCount = resources.filter((res) => res.kind === resource.kind).length;
const resourceHealthyCount = resource.health
@@ -186,7 +197,7 @@ const createGroupResourceNode = (
groupResourceNode = {
id: kind + '-node-group',
type: 'node-group',
- label: allK8sModels[kind]?.labelPlural || kind + 's',
+ label: resourceNodeLayout ? ' ' : allK8sModels[kind]?.labelPlural || kind + 's',
shape: NodeShape.stadium,
status: groupStatus,
width: 280,
@@ -196,6 +207,7 @@ const createGroupResourceNode = (
kind: kind, // Group's kind
kindPlural: allK8sModels[kind]?.labelPlural || kind + 's',
resourceGroupExpandState: resourceGroupExpandState,
+ resourceNodeLayout: resourceNodeLayout,
nodeStatus: groupStatus,
healthStatus: groupStatus,
healthyCount: resourceHealthyCount,
@@ -217,6 +229,7 @@ const createGroupResourceNode = (
badgeColor:
RESOURCE_COLORS.get(RESOURCE_BADGE_COLORS.get('.co-m-resource-' + kind.toLowerCase())) ||
RESOURCE_COLORS.get('color-container-dark'),
+ badgeTextColor: 'white',
icon: kind,
resourceChildrenIds: [],
},
@@ -239,6 +252,27 @@ const createGroupResourceNode = (
return groupResourceNodeMap;
};
+export const getResourceMapKey = (resource: ApplicationResourceStatus): string => {
+ return `${resource.group}-${resource.version}-${resource.kind}-${resource.namespace}-${resource.name}`;
+};
+
+export const getResourcePathForResource = (
+ resource: ApplicationResourceStatus,
+ allK8sModels: { [key: string]: K8sModel },
+): string => {
+ if (resource.kind === ApplicationModel.kind) {
+ return (
+ resourcePathFromModel(ApplicationModel as K8sModel, resource.name, resource.namespace) +
+ '/resources'
+ );
+ }
+ const k8sModel = allK8sModels[resource.kind];
+ if (!k8sModel) {
+ return '';
+ }
+ return resourcePathFromModel(k8sModel, resource.name, resource.namespace);
+};
+
// Application Graph Nodes
export const getInitialNodes = (
application: ApplicationKind,
@@ -246,6 +280,8 @@ export const getInitialNodes = (
allK8sModels: { [key: string]: K8sModel },
showGroupNodes: boolean,
groupNodeStates: string[],
+ resourceNodeLayout: boolean,
+ resourcePaths: Map,
) => {
// This contains all the nodes we want to add to the graph view
const initialNodes: NodeModel[] = [];
@@ -253,7 +289,7 @@ export const getInitialNodes = (
let groupResourceNodeMap = new Map();
// Step 1. Create the Application Node
- initialNodes.push(createApplicationNode(application));
+ initialNodes.push(createApplicationNode(application, resourceNodeLayout));
// Step 2: Proceed with adding more nodes only if the application has resources
// If we use the resource tree in the future, this will change
@@ -261,17 +297,19 @@ export const getInitialNodes = (
// Spacer node to the right of the application node. Fixed.
initialNodes.push(createSpacerNode(1, 'application-node-spacer'));
// Add child resources
- resources.forEach((resource) => {
+ resources.forEach((resource, count) => {
const kind = resource.kind;
const badgeLabel = allK8sModels[kind]?.abbr || kindToAbbr(kind);
const color =
RESOURCE_COLORS.get(
RESOURCE_BADGE_COLORS.get('.co-m-resource-' + resource.kind.toLowerCase()),
) || RESOURCE_COLORS.get('color-container-dark');
- const nodeId = resource.kind + '-' + resource.name + '-' + resource.namespace;
+ const nodeId = count + '-' + resource.kind + '-' + resource.name + '-' + resource.namespace;
const key = resource.kind + 's';
const resourceGroupExpandState = groupNodeStates.includes(key);
+ const resourcePath = resourcePaths.get(getResourceMapKey(resource));
+
if (showGroupNodes && resources.filter((res) => res.kind === resource.kind).length > 1) {
groupResourceNodeMap = createGroupResourceNode(
kind,
@@ -280,6 +318,7 @@ export const getInitialNodes = (
resources,
allK8sModels,
resourceGroupExpandState,
+ resourceNodeLayout,
);
if (!initialNodes.includes(groupResourceNodeMap.get(kind))) {
@@ -295,7 +334,7 @@ export const getInitialNodes = (
initialNodes.push({
id: nodeId,
type: 'node',
- label: resource.kind,
+ label: resourceNodeLayout ? ' ' : resource.kind,
width: 280,
height: NODE_DIAMETER,
labelPosition: LabelPosition.bottom,
@@ -305,6 +344,8 @@ export const getInitialNodes = (
name: resource.name,
group: resource.group,
kind: resource.kind,
+ resourceNodeLayout: resourceNodeLayout,
+ resourcePath: resourcePath,
version: resource.version,
namespace: resource.namespace,
indent: 100,
@@ -313,6 +354,7 @@ export const getInitialNodes = (
syncStatus: resource.status,
rank: 5,
badgeColor: color,
+ badgeTextColor: 'white',
badge: badgeLabel,
icon: kind,
},
@@ -348,7 +390,6 @@ export const getInitialNodes = (
selectable: false,
hideContextMenuKebab: true,
hulledOutline: false,
- style: { padding: 40 },
data: {
kind: groupNode.data.kind,
},
@@ -382,7 +423,6 @@ export const getInitialNodes = (
selectable: false,
hideContextMenuKebab: true,
hulledOutline: false,
- style: { padding: 40 },
};
initialNodes.push(transparentGroupsOfGroups);
}
@@ -420,7 +460,7 @@ export const getInitialEdges = (
target: node.id,
edgeStyle: EdgeStyle.dotted,
data: {
- indent: 100,
+ indent: 0,
},
});
}
@@ -432,7 +472,7 @@ export const getInitialEdges = (
target: node.data.kind + '-node-spacer',
edgeStyle: EdgeStyle.dotted,
data: {
- indent: 100,
+ indent: 0,
},
});
}
@@ -445,17 +485,18 @@ export const getInitialEdges = (
if (node.type === 'node') {
const b =
nodes.filter(
- (res) => res.type === 'node-group' && res.id === node.label + '-node-group',
+ (res) => res.type === 'node-group' && res.id === node.data.kind + '-node-group',
).length > 0;
initialEdges.push({
- id: 'e-' + node.label + '-' + index,
+ id: 'e-' + node.data.kind + '-' + index,
type: 'edge',
nodeSeparation: 0,
- source: showGroupNodes && b ? node.label + '-node-spacer' : 'application-node-spacer',
+ source:
+ showGroupNodes && b ? node.data.kind + '-node-spacer' : 'application-node-spacer',
target: node.id,
edgeStyle: EdgeStyle.default,
data: {
- indent: 100,
+ indent: 0,
},
});
}
diff --git a/src/gitops/components/application/graph/icons/resource-icons.tsx b/src/gitops/components/application/graph/icons/resource-icons.tsx
index a3b169686..c16d56e2f 100644
--- a/src/gitops/components/application/graph/icons/resource-icons.tsx
+++ b/src/gitops/components/application/graph/icons/resource-icons.tsx
@@ -31,12 +31,17 @@ import {
interface ResourceIconProps {
kind: string;
badge: string;
+ badgeIconTransform?: string;
}
const iconHeight = 21;
const iconWidth = 21;
-export const ResourceSvgIcon: React.FC = ({ kind, badge }) => {
+export const ResourceSvgIcon: React.FC = ({
+ kind,
+ badge,
+ badgeIconTransform,
+}) => {
let targetIcon: React.ReactNode;
switch (kind) {
case 'Namespace':
@@ -77,14 +82,10 @@ export const ResourceSvgIcon: React.FC = ({ kind, badge }) =>
break;
default:
targetIcon = (
-
-
+
+
+
+
{badge}
diff --git a/src/gitops/components/application/graph/nodes/ApplicationNode.tsx b/src/gitops/components/application/graph/nodes/ApplicationNode.tsx
index 1e795f7d3..2180cbf76 100644
--- a/src/gitops/components/application/graph/nodes/ApplicationNode.tsx
+++ b/src/gitops/components/application/graph/nodes/ApplicationNode.tsx
@@ -19,7 +19,10 @@ import {
PauseIcon,
} from '@patternfly/react-icons';
import {
+ BadgeLocation,
DefaultNode,
+ LabelBadge,
+ LabelPosition,
Node,
RectAnchor,
ShapeProps,
@@ -122,8 +125,8 @@ const ApplicationSyncStatusIcon = ({ status }: { status: SyncStatus }) => {
);
};
-const ApplicationShape: React.FunctionComponent = observer(
- ({ element, className, width, height, filter, dndDropRef }) => {
+const ApplicationShape: React.FunctionComponent =
+ observer(({ element, className, width, height, filter, dndDropRef, resourceNodeLayout }) => {
useAnchor(RectAnchor);
const data = element.getData();
const anchorRef = useSvgAnchor();
@@ -148,7 +151,7 @@ const ApplicationShape: React.FunctionComponent = observer(
= observer(
);
- },
-);
+ });
export const ApplicationNode: React.FC<
CustomNodeProps & WithSelectionProps & WithContextMenuProps
> = observer(({ element, onContextMenu, contextMenuOpen, onSelect, selected }) => {
const data = element.getData();
+ const resourceNodeLayout = data.resourceNodeLayout as boolean;
+
return (
{
- return ApplicationShape;
+ return (props: ShapeProps) => (
+
+ );
}}
- />
+ >
+ {resourceNodeLayout && (
+ <>
+
+
+
+ >
+ )}
+
);
});
diff --git a/src/gitops/components/application/graph/nodes/ResourceGroupNode.tsx b/src/gitops/components/application/graph/nodes/ResourceGroupNode.tsx
index d8e89f3f1..2e1e0279e 100644
--- a/src/gitops/components/application/graph/nodes/ResourceGroupNode.tsx
+++ b/src/gitops/components/application/graph/nodes/ResourceGroupNode.tsx
@@ -13,7 +13,10 @@ import {
QuestionCircleIcon,
} from '@patternfly/react-icons';
import {
+ BadgeLocation,
DefaultNode,
+ LabelBadge,
+ LabelPosition,
Node as TopologyNode,
WithContextMenuProps,
WithSelectionProps,
@@ -31,6 +34,15 @@ export const ResourceGroupNode: React.FC<
const data = element.getData();
// const Icon = data.icon ? data.icon : null;
const kind = data.icon as string;
+ const resourceNodeLayout = data.resourceNodeLayout as boolean;
+ const truncatedBadge = data.badge.length > 3 ? data.badge.slice(0, 3) : data.badge;
+ let dx = 8;
+ if (truncatedBadge.length === 1) {
+ dx = 17;
+ } else if (truncatedBadge.length === 2) {
+ dx = 12;
+ }
+ const transform = resourceNodeLayout ? `scale(0.6) translate(8, 6)` : '';
return (
{kind !== null ? (
-
-
+
+
) : (
@@ -71,6 +91,22 @@ export const ResourceGroupNode: React.FC<
)}
+ {resourceNodeLayout && (
+ <>
+
+
+
+ >
+ )}
+