Skip to content

Commit

Permalink
implemented plugin topology.relationship-provider and contributed rel…
Browse files Browse the repository at this point in the history
…ationship for SBR/kafka connection
  • Loading branch information
invincibleJai committed Aug 11, 2021
1 parent 693f388 commit 50523ea
Show file tree
Hide file tree
Showing 37 changed files with 477 additions and 455 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ export type CreateConnectionGetter = (
target?: Node,
) => CreateConnection;

export type RelationshipProviderProvides = (source: Node, target: Node) => Promise<boolean>;

export type RelationshipProviderCreate = (source: Node, target: Node) => Promise<void>;

export enum TopologyDisplayFilterType {
show = 'show',
expand = 'expand',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {
CreateConnectionGetter,
RelationshipProviderCreate,
RelationshipProviderProvides,
TopologyApplyDisplayOptions,
TopologyDataModelDepicted,
TopologyDataModelGetter,
Expand Down Expand Up @@ -77,6 +79,21 @@ export type TopologyDecoratorProvider = ExtensionDeclaration<
}
>;

/** Topology relationship provider connector extension */
export type TopologyRelationshipProvider = ExtensionDeclaration<
'console.topology/relationship/provider',
{
// use to determine if a connection can be created between the source and target node
provides: CodeRef<RelationshipProviderProvides>;
// tooltip to show when connector operation is hovering over the drop target ex: "Create a Visual Connector"
tooltip: string;
// callback to execute when connector is drop over target node to create a connection
create: CodeRef<RelationshipProviderCreate>;
// priority for relationship, higher will be preferred in case of multiple
priority: number;
}
>;

// Type Guards

export const isTopologyComponentFactory = (e: Extension): e is TopologyComponentFactory =>
Expand All @@ -93,3 +110,6 @@ export const isTopologyDisplayFilters = (e: Extension): e is TopologyDisplayFilt

export const isTopologyDecoratorProvider = (e: Extension): e is TopologyDecoratorProvider =>
e.type === 'console.topology/decorator/provider';

export const isTopologyRelationshipProvider = (e: Extension): e is TopologyRelationshipProvider =>
e.type === 'console.topology/relationship/provider';
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
TopologyDataModelFactory,
TopologyDecoratorProvider,
TopologyDisplayFilters,
TopologyRelationshipProvider,
} from '../extensions/topology';
import { SupportedTopologyDetailsExtensions } from '../extensions/topology-details';
import { YAMLTemplate } from '../extensions/yaml-templates';
Expand Down Expand Up @@ -92,6 +93,7 @@ export type SupportedExtension =
| TopologyDataModelFactory
| TopologyDisplayFilters
| TopologyDecoratorProvider
| TopologyRelationshipProvider
| CreateResource;

/**
Expand Down
20 changes: 14 additions & 6 deletions frontend/packages/dev-console/console-extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@
"type": "console.topology/component/factory",
"properties": {
"getFactory": {
"$codeRef": "topology.componentFactory"
"$codeRef": "topology.getDevConsoleComponentFactory"
}
}
},
Expand All @@ -482,16 +482,24 @@
},
"workloadKeys": ["bindables"],
"getDataModel": {
"$codeRef": "topology.getDataModel"
"$codeRef": "topology.getBindableDevConsoleTopologyDataModel"
}
}
},
{
"type": "console.topology/create/connector",
"type": "console.topology/relationship/provider",
"properties": {
"getCreateConnector": {
"$codeRef": "topology.createConnector"
}
"provides": {
"$codeRef": "topology.providerProvidesServiceBinding"
},
"tooltip": "%devconsole~Create Service Binding%",
"create": {
"$codeRef": "topology.providerCreateServiceBinding"
},
"priority": 100
},
"flags": {
"required": ["ALLOW_SERVICE_BINDING"]
}
}
]
1 change: 1 addition & 0 deletions frontend/packages/dev-console/locales/en/devconsole.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"Search": "Search",
"Project": "Project",
"Builds": "Builds",
"Create Service Binding": "Create Service Binding",
"Container Image": "Container Image",
"From Catalog": "From Catalog",
"Helm Charts": "Helm Charts",
Expand Down
2 changes: 1 addition & 1 deletion frontend/packages/dev-console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"icons": "src/utils/icons.tsx",
"catalog": "src/components/catalog",
"fileUpload": "src/components/jar-file-upload/index.ts",
"topology": "src/components/topology/topology-plugin.ts"
"topology": "src/components/topology"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,44 @@ import {
WithDragNodeProps,
WithSelectionProps,
} from '@patternfly/react-topology';
import { connect } from 'react-redux';
import * as openshiftImg from '@console/internal/imgs/logos/openshift.svg';
import { modelFor, referenceFor, referenceForModel } from '@console/internal/module/k8s';
import { RootState } from '@console/internal/redux';
import { obsOrKafkaConnectionDropTargetSpec } from '@console/rhoas-plugin/src/topology/components/rhoasComponentUtils';
import { calculateRadius } from '@console/shared';
import { TrapezoidBaseNode } from '@console/topology/src/components/graph-view/components/nodes';
import { getServiceBindingStatus, getTopologyResourceObject } from '@console/topology/src/utils';

interface StateProps {
serviceBinding: boolean;
}
import { getTopologyResourceObject } from '@console/topology/src/utils';
import { getRelationshipProvider } from '@console/topology/src/utils/relationship-provider-utils';

type BindableNodeProps = {
element: Node;
tooltipLabel?: string;
} & WithSelectionProps &
WithDragNodeProps &
WithContextMenuProps &
WithCreateConnectorProps &
StateProps;
WithCreateConnectorProps;

const BindableNode: React.FC<BindableNodeProps> = ({
element,
selected,
onSelect,
serviceBinding,
tooltipLabel,
...props
}) => {
const spec = React.useMemo(() => getRelationshipProvider(), []);
const { width, height } = element.getBounds();
const size = Math.min(width, height);
const iconRadius = Math.min(width, height) * 0.25;
const { radius } = calculateRadius(size);
const spec = React.useMemo(() => obsOrKafkaConnectionDropTargetSpec(serviceBinding), [
serviceBinding,
]);
const [dndDropProps, dndDropRef] = useDndDrop(spec, { element, ...props });
const resourceObj = getTopologyResourceObject(element.getData());
const resourceModel = modelFor(referenceFor(resourceObj));
// const kindResource = referenceForModel(resourceModel);
const iconData = element.getData()?.data?.icon || openshiftImg;

// const defaultIcon = getImageForIconClass(`icon-openshift`);
return (
<TrapezoidBaseNode
className="KafkaNode"
className="bindable-node"
tooltipLabel={tooltipLabel}
onSelect={onSelect}
icon={openshiftImg}
icon={iconData}
innerRadius={iconRadius}
selected={selected}
kind={resourceModel && referenceForModel(resourceModel)}
Expand All @@ -69,10 +58,4 @@ const BindableNode: React.FC<BindableNodeProps> = ({
);
};

const mapStateToProps = (state: RootState): StateProps => {
return {
serviceBinding: getServiceBindingStatus(state),
};
};

export default connect(mapStateToProps)(observer(BindableNode));
export default observer(BindableNode);
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { withEditReviewAccess } from '@console/topology/src/utils';
import BindableNode from './BindableNode';
import { TYPE_BINDABLE_NODE } from './const';

export const getDevConsoleComponentFactory = (
const getDevConsoleComponentFactory = (
kind,
type,
): React.ComponentType<{ element: GraphElement }> | undefined => {
Expand All @@ -38,3 +38,5 @@ export const getDevConsoleComponentFactory = (
return undefined;
}
};

export default getDevConsoleComponentFactory;

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
import { Model, NodeModel } from '@patternfly/react-topology';
import { EdgeModel, Model, NodeModel } from '@patternfly/react-topology';
import { K8sResourceKind } from '@console/internal/module/k8s';
import { OverviewItem } from '@console/shared/src';
import { NODE_WIDTH, NODE_HEIGHT, NODE_PADDING } from '@console/topology/src/const';
import { ClusterServiceVersionKind } from '@console/operator-lifecycle-manager/src/types';
import {
getDefaultOperatorIcon,
getImageForCSVIcon,
getOperatorBackedServiceKindMap,
OverviewItem,
} from '@console/shared/src';
import {
NODE_WIDTH,
NODE_HEIGHT,
NODE_PADDING,
TYPE_SERVICE_BINDING,
} from '@console/topology/src/const';
import { getTopologyNodeItem } from '@console/topology/src/data-transforms/transform-utils';
import { edgesFromServiceBinding } from '@console/topology/src/operators/operators-data-transformer';
import { TopologyDataObject, TopologyDataResources } from '@console/topology/src/topology-types';
import { TYPE_BINDABLE_NODE } from './components/const';

Expand All @@ -23,42 +35,94 @@ export const createOverviewItem = (obj: K8sResourceKind): OverviewItem<K8sResour
};
};

export const getTopologyBindableNode = (bindables: K8sResourceKind[]): NodeModel[] => {
export const getTopologyBindableNode = (
bindables: K8sResourceKind[],
typeNode: string,
resources: TopologyDataResources,
): NodeModel[] => {
const nodes = [];
for (const obj of bindables) {
const resKindMap = getOperatorBackedServiceKindMap(
resources?.clusterServiceVersions?.data as ClusterServiceVersionKind[],
);
const csvData = resKindMap?.[obj.kind];
const data: TopologyDataObject = {
id: obj.metadata.uid,
name: obj.metadata.name,
type: TYPE_BINDABLE_NODE,
type: typeNode,
resource: obj,
// resources is poorly named, should be overviewItem, eventually going away.
resources: createOverviewItem(obj),
data: {
resource: obj,
icon: getImageForCSVIcon(csvData?.spec?.icon?.[0]) || getDefaultOperatorIcon(),
},
};
nodes.push(getTopologyNodeItem(obj, TYPE_BINDABLE_NODE, data, BINDABLE_PROPS));
nodes.push(getTopologyNodeItem(obj, typeNode, data, BINDABLE_PROPS));
}

return nodes;
};

export const getBindableDevConsoleTopologyDataModel = (
export const getBindableServiceBindingEdges = (
dc: K8sResourceKind,
rhoasNodes: NodeModel[],
sbrs: K8sResourceKind[],
): EdgeModel[] => {
const edges = [];
if (!sbrs?.length || !rhoasNodes?.length) {
return edges;
}

edgesFromServiceBinding(dc, sbrs).forEach((sbr) => {
sbr.spec.services?.forEach((bss) => {
if (bss) {
const targetNode = rhoasNodes.find(
(node) =>
node.data.resource.kind === bss.kind && node.data.resource.metadata.name === bss.name,
);
if (targetNode) {
const target = targetNode.data.resource.metadata.uid;
const source = dc.metadata.uid;
if (source && target) {
edges.push({
id: `${source}_${target}`,
type: TYPE_SERVICE_BINDING,
source,
target,
resource: sbr,
data: { sbr },
});
}
}
}
});
});

return edges;
};

const getBindableDevConsoleTopologyDataModel = (
namespace: string,
resources: TopologyDataResources,
workloads: K8sResourceKind[],
): Promise<Model> => {
if (!resources.bindables?.data) return Promise.resolve({ nodes: [], edges: [] });
const serviceBindingRequests = resources.serviceBindingRequests?.data;
const bindableDataModel = {
nodes: getTopologyBindableNode(resources.bindables.data),
nodes: getTopologyBindableNode(resources.bindables.data, TYPE_BINDABLE_NODE, resources),
edges: [],
};

if (bindableDataModel.nodes?.length) {
workloads.forEach(() => {
bindableDataModel.edges.push(...[]);
if (bindableDataModel.nodes?.length && serviceBindingRequests?.length) {
workloads.forEach((dc) => {
bindableDataModel.edges.push(
...getBindableServiceBindingEdges(dc, bindableDataModel.nodes, serviceBindingRequests),
);
});
}

return Promise.resolve(bindableDataModel);
};

export default getBindableDevConsoleTopologyDataModel;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export { default as getDevConsoleComponentFactory } from './components/devConsoleComponetFactory';
export { default as getBindableDevConsoleTopologyDataModel } from './dev-console-data-transformer';
export {
providerProvidesServiceBinding,
providerCreateServiceBinding,
} from './relationship-provider';
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Node } from '@patternfly/react-topology';
import { TYPE_WORKLOAD } from '@console/topology/src/const';
import { createServiceBinding } from '@console/topology/src/operators/actions/serviceBindings';
import { getResource } from '@console/topology/src/utils';

export const providerProvidesServiceBinding = (source: Node, target: Node) => {
if (!source || !target) return false;
const sourceObj = getResource(source);
const targetObj = getResource(target);
return (
sourceObj &&
targetObj &&
sourceObj !== targetObj &&
source.getData()?.type === TYPE_WORKLOAD &&
targetObj.metadata?.labels?.['app.kubernetes.io/component'] === 'external-service'
);
};

export const providerCreateServiceBinding = (source: Node, target: Node) => {
const sourceResource = getResource(source);
const targetResource = getResource(target);
return createServiceBinding(sourceResource, targetResource).then(() => null);
};

This file was deleted.

Loading

0 comments on commit 50523ea

Please sign in to comment.