Skip to content

Commit

Permalink
Expand/collapse Topiology Application Groups
Browse files Browse the repository at this point in the history
  • Loading branch information
jeff-phillips-18 committed Jan 14, 2020
1 parent a5b184f commit fdc6be5
Show file tree
Hide file tree
Showing 14 changed files with 344 additions and 41 deletions.
29 changes: 21 additions & 8 deletions frontend/packages/dev-console/src/components/topology/Topology.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import * as classNames from 'classnames';
import * as _ from 'lodash';
import { action } from 'mobx';
import { connect } from 'react-redux';
import { Button, ToolbarItem, Tooltip } from '@patternfly/react-core';
import {
TopologyView,
Expand All @@ -12,12 +12,12 @@ import {
import {
Visualization,
VisualizationSurface,
GraphElement,
isNode,
Model,
SELECTION_EVENT,
SelectionEventListener,
} from '@console/topology';
import { RootState } from '@console/internal/redux';
import { TopologyIcon } from '@patternfly/react-icons';
import TopologySideBar from './TopologySideBar';
import { TopologyDataModel, TopologyDataObject } from './topology-types';
Expand All @@ -28,8 +28,12 @@ import { layoutFactory, COLA_LAYOUT, COLA_FORCE_LAYOUT } from './layouts/layoutF
import ComponentFactory from './componentFactory';
import { TYPE_APPLICATION_GROUP } from './const';
import TopologyFilterBar from './filters/TopologyFilterBar';
import { getTopologyFilters, TopologyFilters } from './filters/filter-utils';

export interface TopologyProps {
interface StateProps {
filters: TopologyFilters;
}
export interface TopologyProps extends StateProps {
data: TopologyDataModel;
serviceBinding: boolean;
}
Expand All @@ -42,7 +46,7 @@ const graphModel: Model = {
},
};

const Topology: React.FC<TopologyProps> = ({ data, serviceBinding }) => {
const Topology: React.FC<TopologyProps> = ({ data, serviceBinding, filters }) => {
const visRef = React.useRef<Visualization | null>(null);
const componentFactoryRef = React.useRef<ComponentFactory | null>(null);
const [layout, setLayout] = React.useState<string>(graphModel.graph.layout);
Expand Down Expand Up @@ -72,6 +76,12 @@ const Topology: React.FC<TopologyProps> = ({ data, serviceBinding }) => {
componentFactoryRef.current.serviceBinding = serviceBinding;
}, [serviceBinding]);

React.useEffect(() => {
action(() => {
visRef.current.setTypeCollapsed(TYPE_APPLICATION_GROUP, !filters.display.appGrouping);
})();
}, [filters.display.appGrouping]);

React.useEffect(() => {
const newModel = topologyModelFromDataModel(data);
visRef.current.fromModel(newModel);
Expand Down Expand Up @@ -181,9 +191,7 @@ const Topology: React.FC<TopologyProps> = ({ data, serviceBinding }) => {
application={{
id: selectedEntity.getId(),
name: selectedEntity.getLabel(),
resources: _.map(selectedEntity.getChildren(), (node: GraphElement) =>
node.getData(),
),
resources: selectedEntity.getData().resources,
}}
/>
);
Expand Down Expand Up @@ -220,4 +228,9 @@ const Topology: React.FC<TopologyProps> = ({ data, serviceBinding }) => {
);
};

export default Topology;
const TopologyStateToProps = (state: RootState) => {
const filters = getTopologyFilters(state);
return { filters };
};

export default connect(TopologyStateToProps)(Topology);
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
withRemoveConnector,
withContextMenu,
} from '@console/topology';
import ApplicationGroup from './components/nodes/ApplicationGroup';
import Application from './components/nodes/Application';
import ConnectsTo from './components/edges/ConnectsTo';
import EventSource from './components/nodes/EventSource';
import EventSourceLink from './components/edges/EventSourceLink';
Expand Down Expand Up @@ -76,7 +76,7 @@ class ComponentFactory {
groupContextMenu,
document.getElementById('modal-container'),
'odc-topology-context-menu',
)(ApplicationGroup),
)(Application),
),
);
case TYPE_KNATIVE_SERVICE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ import { AbstractAnchor, getEllipseAnchorPoint, Node, Point } from '@console/top
export default class RevisionTrafficTargetAnchor extends AbstractAnchor {
private radius: number;

private offset: number;
private nodeOffset: number;

constructor(node: Node, radius: number) {
super(node);
this.radius = radius;
// TODO align sizing with WorkloadNode
this.offset = radius * 0.7;
this.nodeOffset = radius * 0.7;
}

getLocation(reference: Point): Point {
const bounds = this.getOwner().getBounds();
if (this.radius) {
// location is edge of decorator
const center = new Point(bounds.right() - this.offset, bounds.y + this.offset);
const center = new Point(bounds.right() - this.nodeOffset, bounds.y + this.nodeOffset);
const size = this.radius * 2;
return getEllipseAnchorPoint(center, size, size, reference);
}
Expand All @@ -29,7 +29,7 @@ export default class RevisionTrafficTargetAnchor extends AbstractAnchor {
const bounds = this.getOwner().getBounds();
if (this.radius) {
// reference point is center of decorator
return new Point(bounds.right() - this.offset, bounds.y + this.offset);
return new Point(bounds.right() - this.nodeOffset, bounds.y + this.nodeOffset);
}
// reference point is center of node
return bounds.getCenter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ const BaseEdge: React.FC<BaseEdgeProps> = ({
const startPoint = element.getStartPoint();
const endPoint = element.getEndPoint();
const bendpoints = element.getBendpoints();
const resourceObj = getTopologyResourceObject(element.getSource().getData());
const isCollapsed = element.getSource().isCollapsed() || element.getTarget().isCollapsed();
const resourceObj = getTopologyResourceObject(element.getSource(true).getData());
const resourceModel = modelFor(referenceFor(resourceObj));

const editAccess = useAccessReview({
Expand All @@ -72,14 +73,14 @@ const BaseEdge: React.FC<BaseEdgeProps> = ({
});

React.useLayoutEffect(() => {
if (editAccess) {
if (!isCollapsed && editAccess) {
if (hover && !dragging) {
onShowRemoveConnector && onShowRemoveConnector();
} else {
onHideRemoveConnector && onHideRemoveConnector();
}
}
}, [hover, dragging, onShowRemoveConnector, onHideRemoveConnector, editAccess]);
}, [hover, dragging, onShowRemoveConnector, onHideRemoveConnector, isCollapsed, editAccess]);

const d = `M${startPoint.x} ${startPoint.y} ${bendpoints
.map((b: Point) => `L${b.x} ${b.y} `)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type ConnectsToProps = {
WithRemoveConnectorProps;

const ConnectsTo: React.FC<ConnectsToProps> = ({ element, targetDragRef, children, ...others }) => {
const resourceObj = getTopologyResourceObject(element.getSource().getData());
const resourceObj = getTopologyResourceObject(element.getSource(true).getData());
const resourceModel = modelFor(referenceFor(resourceObj));
const editAccess = useAccessReview({
group: resourceModel.apiGroup,
Expand All @@ -31,10 +31,16 @@ const ConnectsTo: React.FC<ConnectsToProps> = ({ element, targetDragRef, childre
name: resourceObj.metadata.name,
namespace: resourceObj.metadata.namespace,
});
const edgeClasses = classNames('odc-connects-to', { 'odc2-m-editable': editAccess });
const edgeClasses = classNames('odc-connects-to', {
'odc2-m-editable':
editAccess && !element.getSource().isCollapsed() && !element.getTarget().isCollapsed(),
});

return (
<BaseEdge className={edgeClasses} element={element} {...others}>
<EdgeConnectorArrow dragRef={editAccess ? targetDragRef : undefined} edge={element} />
{(!element.getSource().isCollapsed() || !element.getTarget().isCollapsed()) && (
<EdgeConnectorArrow dragRef={editAccess ? targetDragRef : undefined} edge={element} />
)}
{children}
</BaseEdge>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import * as React from 'react';
import { connect } from 'react-redux';
import { RootState } from '@console/internal/redux';
import {
Node,
observer,
useCollapsibleNode,
WithDndDropProps,
WithSelectionProps,
WithContextMenuProps,
} from '@console/topology';
import { getTopologyFilters, TopologyFilters } from '../../filters/filter-utils';
import ApplicationNode from './ApplicationNode';
import ApplicationGroup from './ApplicationGroup';

import './ApplicationGroup.scss';

type ApplicationProps = {
element: Node;
droppable?: boolean;
canDrop?: boolean;
dropTarget?: boolean;
dragging?: boolean;
filters?: TopologyFilters;
} & WithSelectionProps &
WithDndDropProps &
WithContextMenuProps;

const Application: React.FC<ApplicationProps> = ({
element,
selected,
onSelect,
dndDropRef,
droppable,
canDrop,
dropTarget,
onContextMenu,
contextMenuOpen,
dragging,
filters,
}) => {
const { collapsed } = useCollapsibleNode();

if (collapsed) {
return (
<ApplicationNode
element={element}
selected={selected}
onSelect={onSelect}
dndDropRef={dndDropRef}
canDrop={canDrop}
dropTarget={dropTarget}
onContextMenu={onContextMenu}
contextMenuOpen={contextMenuOpen}
dragging={dragging}
filters={filters}
/>
);
}

return (
<ApplicationGroup
element={element}
selected={selected}
onSelect={onSelect}
dndDropRef={dndDropRef}
canDrop={canDrop}
dropTarget={dropTarget}
droppable={droppable}
onContextMenu={onContextMenu}
contextMenuOpen={contextMenuOpen}
dragging={dragging}
filters={filters}
/>
);
};

const ApplicationState = (state: RootState) => {
const filters = getTopologyFilters(state);
return { filters };
};

export default connect(ApplicationState)(observer(Application));
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@
font-size: var(--pf-global--FontSize--sm);
}
}

&__node-title {
cursor: pointer;
font-size: var(--pf-global--FontSize--lg);
font-weight: var(--pf-global--FontWeight--bold);
.odc-m-drag-active & {
cursor: grab;
}
}
&__node-resources {
cursor: pointer;
.odc-m-drag-active & {
cursor: grab;
}
}
}
.odc-m-drag-active {
.odc-application-group {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import * as React from 'react';
import { polygonHull } from 'd3-polygon';
import * as _ from 'lodash';
import { connect } from 'react-redux';
import { RootState } from '@console/internal/redux';
import {
Layer,
Node,
Expand All @@ -21,13 +19,11 @@ import {
hullPath,
} from '@console/topology';
import * as classNames from 'classnames';
import { getTopologyFilters, TopologyFilters } from '../../filters/filter-utils';
import { TopologyFilters } from '../../filters/filter-utils';
import useFilter from '../../filters/useFilter';
import SvgBoxedText from '../../../svg/SvgBoxedText';
import NodeShadows, { NODE_SHADOW_FILTER_ID, NODE_SHADOW_FILTER_ID_HOVER } from '../NodeShadows';

import './ApplicationGroup.scss';

type ApplicationGroupProps = {
element: Node;
droppable?: boolean;
Expand Down Expand Up @@ -166,9 +162,5 @@ const ApplicationGroup: React.FC<ApplicationGroupProps> = ({
</>
);
};
const ApplicationGroupState = (state: RootState) => {
const filters = getTopologyFilters(state);
return { filters };
};

export default connect(ApplicationGroupState)(observer(ApplicationGroup));
export default observer(ApplicationGroup);

0 comments on commit fdc6be5

Please sign in to comment.