Skip to content

Commit

Permalink
Merge pull request #3484 from vikram-raj/odc-1791
Browse files Browse the repository at this point in the history
Bug 1779493: Disabled edit actions if the user has no permission
  • Loading branch information
openshift-merge-robot committed Dec 5, 2019
2 parents 4bd1fb9 + 7dc4725 commit a023f0c
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 67 deletions.
Expand Up @@ -45,6 +45,7 @@ import KnativeService from './components/nodes/KnativeService';
import TrafficLink from './components/edges/TrafficLink';
import ServiceBinding from './components/edges/ServiceBinding';
import RevisionNode from './components/nodes/RevisionNode';
import { withEditReviewAccess } from './withEditReviewAccess';

type NodeProps = {
element: Node;
Expand Down Expand Up @@ -116,13 +117,15 @@ class ComponentFactory {
{ droppable?: boolean; hover?: boolean; canDrop?: boolean },
NodeProps
>(nodeDropTargetSpec)(
withDragNode(nodeDragSourceSpec(type))(
withSelection(false, true)(
withContextMenu(
workloadContextMenu,
document.getElementById('modal-container'),
'odc2-topology-context-menu',
)(WorkloadNode),
withEditReviewAccess()(
withDragNode(nodeDragSourceSpec(type))(
withSelection(false, true)(
withContextMenu(
workloadContextMenu,
document.getElementById('modal-container'),
'odc2-topology-context-menu',
)(WorkloadNode),
),
),
),
),
Expand Down
Expand Up @@ -23,6 +23,7 @@ type GraphProps = {

type NodeProps = {
element: Node;
canEdit?: boolean;
};

type EdgeProps = {
Expand Down Expand Up @@ -73,11 +74,13 @@ const nodeDragSourceSpec = (
allowRegroup: boolean = true,
): DragSourceSpec<DragObjectWithType, Node, {}, NodeProps> => ({
item: { type },
operation: allowRegroup
? {
[Modifiers.SHIFT]: REGROUP_OPERATION,
}
: undefined,
operation: (monitor, props) => {
return props.canEdit && allowRegroup
? {
[Modifiers.SHIFT]: REGROUP_OPERATION,
}
: undefined;
},
canCancel: (monitor) => monitor.getOperation() === REGROUP_OPERATION,
end: async (dropResult, monitor, props) => {
if (!monitor.isCancelled() && monitor.getOperation() === REGROUP_OPERATION) {
Expand Down
@@ -1,6 +1,9 @@
import * as React from 'react';
import * as classNames from 'classnames';
import { referenceFor, modelFor } from '@console/internal/module/k8s';
import { useAccessReview } from '@console/internal/components/utils';
import { Layer, Edge, WithRemoveConnectorProps, observer, useHover } from '@console/topology';
import { getTopologyResourceObject } from '../../../topology/topology-utils';
import './BaseEdge.scss';

type BaseEdgeProps = {
Expand All @@ -20,14 +23,26 @@ const BaseEdge: React.FC<BaseEdgeProps> = ({
const [hover, hoverRef] = useHover();
const startPoint = element.getStartPoint();
const endPoint = element.getEndPoint();
const resourceObj = getTopologyResourceObject(element.getSource().getData());
const resourceModel = modelFor(referenceFor(resourceObj));

const editAccess = useAccessReview({
group: resourceModel && resourceModel.apiGroup,
verb: 'patch',
resource: resourceModel && resourceModel.plural,
name: resourceObj.metadata.name,
namespace: resourceObj.metadata.namespace,
});

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

return (
<Layer id={dragging || hover ? 'top' : undefined}>
Expand Down
Expand Up @@ -14,7 +14,10 @@ import {
observer,
createSvgIdUrl,
} from '@console/topology';
import { modelFor, referenceFor } from '@console/internal/module/k8s';
import { useAccessReview } from '@console/internal/components/utils';
import SvgBoxedText from '../../../svg/SvgBoxedText';
import { getTopologyResourceObject } from '../../../topology/topology-utils';
import NodeShadows, { NODE_SHADOW_FILTER_ID_HOVER, NODE_SHADOW_FILTER_ID } from '../NodeShadows';

import './BaseNode.scss';
Expand Down Expand Up @@ -63,6 +66,15 @@ const BaseNode: React.FC<BaseNodeProps> = ({
useAnchor(EllipseAnchor);
const cx = element.getBounds().width / 2;
const cy = element.getBounds().height / 2;
const resourceObj = getTopologyResourceObject(element.getData());
const resourceModel = modelFor(referenceFor(resourceObj));
const editAccess = useAccessReview({
group: resourceModel.apiGroup,
verb: 'patch',
resource: resourceModel.plural,
name: resourceObj.metadata.name,
namespace: resourceObj.metadata.namespace,
});

const contentsClasses = classNames('odc2-base-node__contents', {
'is-hover': hover || contextMenuOpen,
Expand All @@ -73,20 +85,22 @@ const BaseNode: React.FC<BaseNodeProps> = ({
const refs = useCombineRefs<SVGEllipseElement>(hoverRef, dragNodeRef);

React.useLayoutEffect(() => {
if (hover) {
onShowCreateConnector && onShowCreateConnector();
} else {
onHideCreateConnector && onHideCreateConnector();
if (editAccess) {
if (hover) {
onShowCreateConnector && onShowCreateConnector();
} else {
onHideCreateConnector && onHideCreateConnector();
}
}
}, [hover, onShowCreateConnector, onHideCreateConnector]);
}, [hover, onShowCreateConnector, onHideCreateConnector, editAccess]);

return (
<g className="odc2-base-node">
<NodeShadows />
<g
data-test-id="base-node-handler"
onClick={onSelect}
onContextMenu={onContextMenu}
onContextMenu={editAccess ? onContextMenu : null}
ref={refs}
>
<circle
Expand Down
Expand Up @@ -16,6 +16,9 @@ import {
createSvgIdUrl,
useCombineRefs,
} from '@console/topology';
import { useAccessReview } from '@console/internal/components/utils';
import { modelFor, referenceFor } from '@console/internal/module/k8s';
import { getTopologyResourceObject } from '../../../topology/topology-utils';
import SvgBoxedText from '../../../svg/SvgBoxedText';
import Decorator from '../../../topology/shapes/Decorator';
import RevisionTrafficSourceAnchor from '../anchors/RevisionTrafficSourceAnchor';
Expand Down Expand Up @@ -47,6 +50,15 @@ const KnativeService: React.FC<EventSourceProps> = ({
const nodeRefs = useCombineRefs(innerHoverRef, dragNodeRef);
const { data } = element.getData();
const hasDataUrl = !!data.url;
const resourceObj = getTopologyResourceObject(element.getData());
const resourceModel = modelFor(referenceFor(resourceObj));
const editAccess = useAccessReview({
group: resourceModel.apiGroup,
verb: 'patch',
resource: resourceModel.plural,
name: resourceObj.metadata.name,
namespace: resourceObj.metadata.namespace,
});
useAnchor(
React.useCallback(
(node: Node) => new RevisionTrafficSourceAnchor(node, hasDataUrl ? DECORATOR_RADIUS : 0),
Expand All @@ -59,7 +71,7 @@ const KnativeService: React.FC<EventSourceProps> = ({
const { x, y, width, height } = element.getBounds();

return (
<g ref={hoverRef} onClick={onSelect} onContextMenu={onContextMenu}>
<g ref={hoverRef} onClick={onSelect} onContextMenu={editAccess ? onContextMenu : null}>
<NodeShadows />
<Layer id={dragging && regrouping ? undefined : 'groups2'}>
<rect
Expand Down
@@ -0,0 +1,26 @@
import * as React from 'react';
import { observer } from 'mobx-react';
import { modelFor, referenceFor } from '@console/internal/module/k8s';
import { useAccessReview } from '@console/internal/components/utils';
import { Node } from '@console/topology';
import { getTopologyResourceObject } from '../topology/topology-utils';

type ComponentProps = {
element: Node;
};

export const withEditReviewAccess = () => (WrappedComponent: React.ComponentType) => {
const Component: React.FC<ComponentProps> = (props) => {
const resourceObj = getTopologyResourceObject(props.element.getData());
const resourceModel = modelFor(referenceFor(resourceObj));
const editAccess = useAccessReview({
group: resourceModel.apiGroup,
verb: 'patch',
resource: resourceModel.plural,
name: resourceObj.metadata.name,
namespace: resourceObj.metadata.namespace,
});
return <WrappedComponent {...props as any} canEdit={editAccess} />;
};
return observer(Component);
};
3 changes: 1 addition & 2 deletions frontend/packages/topology/package.json
Expand Up @@ -8,8 +8,7 @@
"@console/shared": "0.0.0-fixed",
"mobx": "^5.14.2",
"mobx-react": "^6.1.4",
"mobx-react-lite": "^1.4.2",
"mobx-utils": "^5.5.2"
"mobx-react-lite": "^1.4.2"
},
"consolePlugin": {
"entry": "src/plugin.tsx"
Expand Down
2 changes: 1 addition & 1 deletion frontend/packages/topology/src/behavior/dnd-types.ts
Expand Up @@ -117,7 +117,7 @@ export interface DragSourceSpec<
Props extends {} = {}
> {
item: DragObject;
operation?: DragSpecOperation;
operation?: ((monitor: DragSourceMonitor, props: Props) => DragSpecOperation) | DragSpecOperation;
begin?: (monitor: DragSourceMonitor, props: Props) => any;
drag?: (event: DragEvent, monitor: DragSourceMonitor, props: Props) => void;
end?: (
Expand Down
53 changes: 32 additions & 21 deletions frontend/packages/topology/src/behavior/useDndDrag.tsx
@@ -1,8 +1,7 @@
import * as React from 'react';
import * as d3 from 'd3';
import { action, computed, comparer } from 'mobx';
import { action, computed, comparer, flow } from 'mobx';
import { observer } from 'mobx-react';
import { actionAsync } from 'mobx-utils';
import ElementContext from '../utils/ElementContext';
import useCallbackRef from '../utils/useCallbackRef';
import {
Expand Down Expand Up @@ -131,10 +130,13 @@ export const useDndDrag = <
React.useCallback(
(node: SVGElement | null) => {
if (node) {
let operationChangeEvents: {
begin: [number, number, number, number];
drag: [number, number, number, number];
} | null = null;
let operationChangeEvents:
| {
begin: [number, number, number, number];
drag: [number, number, number, number];
}
| undefined;
let operation: DragSpecOperation | undefined;
d3.select(node).call(
d3
.drag()
Expand All @@ -147,8 +149,11 @@ export const useDndDrag = <
.node() as any,
)
.on('start', function() {
const updateOperation = actionAsync(async () => {
const { operation } = specRef.current;
operation =
typeof specRef.current.operation === 'function'
? specRef.current.operation(monitor, propsRef.current)
: specRef.current.operation;
const updateOperation = async () => {
if (operation && idRef.current) {
const op = getOperation(operation);
if (dndManager.getOperation() !== op) {
Expand All @@ -171,29 +176,34 @@ export const useDndDrag = <
if (op && operationChangeEvents) {
dndManager.beginDrag(idRef.current, op, ...operationChangeEvents.begin);
dndManager.drag(...operationChangeEvents.drag);
operationChangeEvents = null;
operationChangeEvents = undefined;
}
}
}
});
};
d3.select(node.ownerDocument)
.on(
'keydown.useDndDrag',
actionAsync(async () => {
flow(function*() {
const e = d3.event as KeyboardEvent;
if (e.key === 'Escape') {
if (dndManager.isDragging() && dndManager.cancel()) {
operationChangeEvents = null;
operationChangeEvents = undefined;
d3.select(d3.event.view).on('.drag', null);
d3.select(node.ownerDocument).on('.useDndDrag', null);
await dndManager.endDrag();
yield dndManager.endDrag();
}
} else {
await updateOperation();
yield updateOperation();
}
}),
)
.on('keyup.useDndDrag', updateOperation);
.on(
'keyup.useDndDrag',
flow(function*() {
yield updateOperation();
}),
);
})
.on(
'drag',
Expand All @@ -205,8 +215,8 @@ export const useDndDrag = <
} else if (operationChangeEvents) {
operationChangeEvents.drag = [x, y, pageX, pageY];
} else {
const op = getOperation(specRef.current.operation);
if (op || !hasOperation(specRef.current.operation)) {
const op = getOperation(operation);
if (op || !hasOperation(operation)) {
if (idRef.current) {
dndManager.beginDrag(idRef.current, op, x, y, pageX, pageY);
}
Expand All @@ -221,12 +231,13 @@ export const useDndDrag = <
)
.on(
'end',
actionAsync(async () => {
operationChangeEvents = null;
flow(function*() {
operationChangeEvents = undefined;
operation = undefined;
d3.select(node.ownerDocument).on('.useDndDrag', null);
if (dndManager.isDragging()) {
dndManager.drop();
await dndManager.endDrag();
yield dndManager.endDrag();
}
}),
)
Expand All @@ -240,7 +251,7 @@ export const useDndDrag = <
node && d3.select(node).on('mousedown.drag', null);
};
},
[dndManager],
[dndManager, monitor],
),
);

Expand Down
22 changes: 11 additions & 11 deletions frontend/packages/topology/src/behavior/useDragNode.tsx
Expand Up @@ -42,19 +42,19 @@ export const useDragNode = <
React.useMemo(() => {
const sourceSpec: DragSourceSpec<any, any, any, Props> = {
item: (spec && spec.item) || { type: '#useDragNode#' },
operation: (() => {
if (
spec &&
typeof spec.operation === 'object' &&
Object.keys(spec.operation).length > 0
) {
return {
...defaultOperation,
...spec.operation,
};
operation: (monitor, p) => {
if (spec) {
const operation =
typeof spec.operation === 'function' ? spec.operation(monitor, p) : spec.operation;
if (typeof operation === 'object' && Object.keys(operation).length > 0) {
return {
...defaultOperation,
...operation,
};
}
}
return defaultOperation;
})(),
},
begin: (monitor, p) => {
elementRef.current.raise();
if (elementRef.current.isGroup()) {
Expand Down

0 comments on commit a023f0c

Please sign in to comment.