Commit 994cc699 authored by Patrik Meijer's avatar Patrik Meijer
Browse files

Can add members and minor fixes

parent c281d62c
Loading
Loading
Loading
Loading
+42 −17
Original line number Diff line number Diff line
@@ -8,6 +8,16 @@
 *
 */

const COLORS = {
    EDGE_LABEL: 'rgb(86, 86, 86)',
    POINTER: 'rgb(0,0,255)',
    SET: 'rgb(255,0,255)',
    BASE_POINTER: 'rgb(255,0,0)',
    SELECTED: 'rgba(82, 168, 236, 0.6)',
    VALID_TARGET: 'rgb(139, 255, 135)',
    INVALID_TARGET: 'rgb(255, 135, 135)',
};

const DEFAULT_STYLES = [
    {
        selector: 'node.gme-node[hasChildren]',
@@ -39,13 +49,13 @@ const DEFAULT_STYLES = [
        selector: 'edge.pointer',
        style: {
            content: 'data(label)',
            color: 'rgb(0,0,255)',
            'font-size': 10,
            color: COLORS.EDGE_LABEL,
            'font-size': 7,

            width: 1,
            'line-color': 'rgb(0,0,255)',
            'line-color': COLORS.POINTER,
            'curve-style': 'bezier',
            'target-arrow-color': 'rgb(0,0,255)',
            'target-arrow-color': COLORS.POINTER,
            'target-arrow-shape': 'vee',
        },
    },
@@ -53,13 +63,13 @@ const DEFAULT_STYLES = [
        selector: 'edge.set-member',
        style: {
            content: 'data(label)',
            color: 'rgb(255,0,255)',
            'font-size': 10,
            color: COLORS.EDGE_LABEL,
            'font-size': 7,

            width: 1,
            'curve-style': 'bezier',
            'line-color': 'rgb(255,0,255)',
            'target-arrow-color': 'rgb(255,0,255)',
            'line-color': COLORS.SET,
            'target-arrow-color': COLORS.SET,
            'target-arrow-shape': 'vee',
        },
    },
@@ -67,10 +77,10 @@ const DEFAULT_STYLES = [
        selector: 'edge.base-pointer',
        style: {
            width: 1,
            'line-color': 'rgb(255,0,0)',
            'line-color': COLORS.BASE_POINTER,
            'curve-style': 'bezier',
            'target-arrow-fill': 'hollow',
            'target-arrow-color': 'rgb(255,0,0)',
            'target-arrow-color': COLORS.BASE_POINTER,
            'target-arrow-shape': 'triangle',
        },
    },
@@ -80,34 +90,49 @@ const DEFAULT_STYLES = [
            // 'border-width': '2px',
            'border-style': 'solid',
            'border-opacity': '1',
            'border-color': 'rgba(82, 168, 236, 0.6)',
            'border-color': COLORS.SELECTED,
        },
    },
    {
        selector: 'node[^hasChildren].in-active-selection',
        style: {
            'background-color': 'rgba(82, 168, 236, 0.6)',
            'background-color': COLORS.SELECTED,
        },
    },
    {
        selector: 'edge.in-active-selection',
        style: {
            width: 5,
            'line-color': COLORS.SELECTED,
        },
    },
    {
        selector: 'node.valid-action-target',
        style: {
            'background-color': 'rgba(185, 236, 185, 0.64)',
            'background-color': COLORS.VALID_TARGET,
        },
    },
    {
        selector: 'node.invalid-action-target',
        style: {
            'background-color': 'rgba(236, 150, 185, 0.64)',
            'background-color': COLORS.INVALID_TARGET,
        },
    },
    {
        selector: 'edge.in-active-selection',
        selector: 'edge.valid-action-target',
        style: {
            width: 5,
            'line-color': 'rgba(82, 168, 236, 0.6)',
            width: 4,
            'line-color': COLORS.VALID_TARGET,
        },
    },
    {
        selector: 'edge.invalid-action-target',
        style: {
            width: 4,
            'line-color': COLORS.INVALID_TARGET,
        },
    },

];

export default DEFAULT_STYLES;
+153 −96
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@ export default class GraphEditor extends Component {

    state = {
        showNodeMenu: null,
        // newChildMenuParent: null,
        activeFilters: (() => {
            const {validFilters} = this.props;
            const res = {};
@@ -424,9 +425,22 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
        });
    };

    startNewSetMember = (nodeId, setName) => {
        this.setState({
            showNodeMenu: null,
            creatingNew: {
                type: 'set',
                nodeId,
                id: setName,
                target: null,
                isValid: null,
            },
        });
    };

    startNewConnection = (nodeId, connTypeId) => {
        this.setState({
            showNodeMenu: false,
            showNodeMenu: null,
            creatingNew: {
                type: 'connection',
                nodeId,
@@ -437,6 +451,14 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
        });
    };

    // showNewChildMenu = (nodeId) => {
    //     this.setState({
    //         showNodeMenu: null,
    //         newChildMenuParent: nodeId,
    //         creatingNew: null,
    //     });
    // };

    atLayoutStop = () => {
        this.storePositions(this.cy.nodes('.gme-node')
            .map(ele => ({
@@ -446,41 +468,51 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
    };

    attachCytoscapeHandlers() {
        this.cy.on('dragfree', ({target}) => {
            const {setActiveSelection} = this.props;
            if (typeof target.id === 'function' && target.hasClass('aux-node') === false) {
                const repositions = [
                    {
                        id: target.id(),
                        position: target.position(),
                    },
                ];
        const onMouseOverNodeOrConnection = (nodeId) => {
            const {creatingNew} = this.state;
            const {gmeClient} = this.props;
            const gmeNode = gmeClient.getNode(nodeId);
            if (!gmeNode) {
                return;
            }

                target.descendants('node.gme-node')
                    .forEach(child => repositions.push({
                        id: child.id(),
                        position: child.position(),
                    }));
            if (creatingNew && creatingNew.target !== nodeId) {
                let isValid = false;
                if (creatingNew.type === 'pointer') {
                    isValid = gmeNode.isValidTargetOf(creatingNew.nodeId, creatingNew.id);
                } else if (creatingNew.type === 'set') {
                    isValid = gmeNode.isValidTargetOf(creatingNew.nodeId, creatingNew.id);
                } else if (creatingNew.type === 'connection') {
                    isValid = gmeNode.isValidTargetOf(creatingNew.id, 'dst');
                    if (isValid) {
                        // Check if the new connection can be placed inside common parent.
                        let parentId = gmeNode.getCommonParentId(creatingNew.nodeId);

                this.storePositions(repositions);
                setTimeout(() => {
                    setActiveSelection([target.id()]);
                });
            } else {
                // Free outside of canvas
                setActiveSelection([]);
                        if (parentId === creatingNew.nodeId || parentId === nodeId) {
                            parentId = gmeClient.getNode(parentId)
                                .getParentId();
                        }

                        isValid = gmeNode.isValidChildOf(parentId);
                    }
                }

                this.setState({
                    creatingNew: {
                        type: creatingNew.type,
                        id: creatingNew.id, // connection meta-id, ptr-name or set-name.
                        nodeId: creatingNew.nodeId,
                        target: nodeId,
                        isValid,
                    },
                });
            }
        };

        this.cy.on('vclick', 'node', (e) => {
            const {setActiveSelection, gmeClient} = this.props;
        const onClickNodeOrConnection = (nodeId, orgEvent) => {
            const {creatingNew} = this.state;
            const {gmeClient, setActiveSelection} = this.props;

            // This is async :+1:
            this.setState({creatingNew: null});

            if (typeof e.target.id === 'function') {
                const nodeId = e.target.id();
            if (creatingNew && creatingNew.target === nodeId && creatingNew.isValid) {
                if (creatingNew.type === 'pointer') {
                    gmeClient.setPointer(creatingNew.nodeId, creatingNew.id, creatingNew.target);
@@ -490,11 +522,17 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
                } else if (creatingNew.type === 'connection') {
                    const gmeNode = gmeClient.getNode(nodeId);
                    if (gmeNode) {
                            const commonParentId = gmeNode.getCommonParentId(creatingNew.nodeId);
                        let parentId = gmeNode.getCommonParentId(creatingNew.nodeId);

                        if (parentId === creatingNew.nodeId || parentId === nodeId) {
                            parentId = gmeClient.getNode(parentId)
                                .getParentId();
                        }

                        gmeClient.startTransaction();
                        const connId = gmeClient.createNode({
                            baseId: creatingNew.id,
                                parentId: commonParentId,
                            parentId,
                        });

                        gmeClient.setPointer(connId, 'src', creatingNew.nodeId);
@@ -509,56 +547,73 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
                } else {
                    console.error('Unexpected createNew type', JSON.stringy(creatingNew));
                }
                } else if (e.target.hasClass('aux-node') === false) {
            } else {
                this.setState({
                    showNodeMenu: {
                            id: e.target.id(),
                        id: nodeId,
                        position: {
                                x: e.originalEvent.clientX,
                                y: e.originalEvent.clientY,
                            x: orgEvent.clientX,
                            y: orgEvent.clientY,
                        },
                    },
                });

                setTimeout(() => {
                        setActiveSelection([e.target.id()]);
                    setActiveSelection([nodeId]);
                });
            }
        };

        this.cy.on('dragfree', ({target}) => {
            const {setActiveSelection} = this.props;
            if (typeof target.id === 'function' && target.hasClass('aux-node') === false) {
                const repositions = [
                    {
                        id: target.id(),
                        position: target.position(),
                    },
                ];

                target.descendants('node.gme-node')
                    .forEach(child => repositions.push({
                        id: child.id(),
                        position: child.position(),
                    }));

                this.storePositions(repositions);
                setTimeout(() => {
                    setActiveSelection([target.id()]);
                });
            } else {
                // Free outside of canvas
                setActiveSelection([]);
            }
        });

        this.cy.on('mouseover', 'node', (e) => {
            const {creatingNew} = this.state;
            const {gmeClient} = this.props;
        this.cy.on('vclick', (e) => {
            const {setActiveSelection} = this.props;

            const nodeId = e.target.id();
            const gmeNode = gmeClient.getNode(nodeId);
            if (!gmeNode) {
                return;
            }
            if (e.target === this.cy) {
                console.log('Canvas was clicked!');
                setActiveSelection([]);
            } else if (e.target.hasClass('gme-node') || e.target.hasClass('gme-connection')) {
                onClickNodeOrConnection(e.target.id(), e.originalEvent);
            } else if (e.target.hasClass('pointer') || e.target.hasClass('set-member')) {

            if (creatingNew && creatingNew.target !== nodeId) {
                let isValid = false;
                if (creatingNew.type === 'pointer') {
                    isValid = gmeNode.isValidTargetOf(creatingNew.nodeId, creatingNew.id);
                } else if (creatingNew.type === 'set') {
                    isValid = gmeNode.isValidMemberOf(creatingNew.nodeId, creatingNew.id);
                } else if (creatingNew.type === 'connection') {
                    isValid = gmeNode.isValidTargetOf(creatingNew.id, 'dst');
                setActiveSelection([]);
            } else {
                setActiveSelection([]);
            }

                this.setState({
                    creatingNew: {
                        type: creatingNew.type,
                        id: creatingNew.id, // connection meta-id, ptr-name or set-name.
                        nodeId: creatingNew.nodeId,
                        target: nodeId,
                        isValid,
                    },
            this.setState({creatingNew: null});
        });
            }

        this.cy.on('mouseover', 'node.gme-node', (e) => {
            onMouseOverNodeOrConnection(e.target.id());
        });

        this.cy.on('mouseover', 'edge.gme-connection', (e) => {
            onMouseOverNodeOrConnection(e.target.id());
        });
    }

@@ -641,15 +696,15 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
                                <FullscreenIcon/>
                            </Button>
                        </Tooltip>
                        <Tooltip id="tooltip-show-filters" title="Manage filters">
                            <Button
                                onClick={() => {
                                    this.setState({showFilterSelector: true});
                                }}
                            >
                                <FilterIcon/>
                            </Button>
                        </Tooltip>
                        {/*<Tooltip id="tooltip-show-filters" title="Manage filters">*/}
                            {/*<Button*/}
                                {/*onClick={() => {*/}
                                    {/*this.setState({showFilterSelector: true});*/}
                                {/*}}*/}
                            {/*>*/}
                                {/*<FilterIcon/>*/}
                            {/*</Button>*/}
                        {/*</Tooltip>*/}
                    </span>
                </div>
                <ReactCytoscape
@@ -680,16 +735,18 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
                            }}
                            onSetPointerTarget={this.startNewPointer}
                            onCreateConnection={this.startNewConnection}
                            onAddSetMember={this.startNewSetMember}
                            // onAddChild={this.showNewChildMenu}
                            onSetActiveNode={setActiveNode}
                        />) : null}

                <FilterSelector
                    open={showFilterSelector}
                    validItems={validFilters}
                    activeItems={activeFilters}
                    handleToggle={this.toggleFilter}
                    onClose={(() => this.setState({showFilterSelector: false}))}
                />
                {/*<FilterSelector*/}
                    {/*open={showFilterSelector}*/}
                    {/*validItems={validFilters}*/}
                    {/*activeItems={activeFilters}*/}
                    {/*handleToggle={this.toggleFilter}*/}
                    {/*onClose={(() => this.setState({showFilterSelector: false}))}*/}
                {/*/>*/}
            </div>);
    }
}
+31 −7
Original line number Diff line number Diff line
@@ -29,11 +29,11 @@ export default class SimpleActionMenu extends Component {
        onClose: PropTypes.func.isRequired,

        allowDeletion: PropTypes.bool,
        onAddChild: PropTypes.func,
        onSetActiveNode: PropTypes.func,
        onSetPointerTarget: PropTypes.func,
        onAddSetMember: PropTypes.func,
        onCreateConnection: PropTypes.func,
        onCreateChild: PropTypes.func,
    };

    static defaultProps = {
@@ -43,7 +43,7 @@ export default class SimpleActionMenu extends Component {
        onSetPointerTarget: noop,
        onAddSetMember: noop,
        onCreateConnection: noop,
        onCreateChild: noop,
        onAddChild: noop,
    }

    setActiveNode = () => {
@@ -93,7 +93,7 @@ export default class SimpleActionMenu extends Component {
            onSetPointerTarget,
            onAddSetMember,
            onCreateConnection,
            onCreateChild,
            onAddChild,

            onClose,
        } = this.props;
@@ -105,7 +105,7 @@ export default class SimpleActionMenu extends Component {

        if (onSetActiveNode !== noop) {
            menuItems.push((
                <MenuItem key="open-sub-system" onClick={this.setActiveNode}>
                <MenuItem key="open-node" onClick={this.setActiveNode}>
                    <ListItemIcon>
                        <OpenIcon/>
                    </ListItemIcon>
@@ -124,7 +124,7 @@ export default class SimpleActionMenu extends Component {
                            <PointerIcon/>
                        </ListItemIcon>
                        <ListItemText>
                            {`Create pointer ${name} from here ...`}
                            {`Set pointer ${name} from here ..`}
                        </ListItemText>
                    </MenuItem>));
            });
@@ -140,7 +140,7 @@ export default class SimpleActionMenu extends Component {
                            <SetIcon/>
                        </ListItemIcon>
                        <ListItemText>
                            {`Add new member to set ${name} ...`}
                            {`Add new member to set ${name} ..`}
                        </ListItemText>
                    </MenuItem>));
            });
@@ -157,12 +157,36 @@ export default class SimpleActionMenu extends Component {
                                <ConnectionIcon/>
                            </ListItemIcon>
                            <ListItemText>
                                {`Create connection ${info.name} from here...`}
                                {`Start new connection ${info.name} from here ..`}
                            </ListItemText>
                        </MenuItem>));
                });
        }

        if (onAddChild !== noop && isReadOnly === false) {
            menuItems.push((
                <MenuItem key="add-child" onClick={() => onAddChild(nodeId)}>
                    <ListItemIcon>
                        <NodeIcon/>
                    </ListItemIcon>
                    <ListItemText>
                        Add a new child node ..
                    </ListItemText>
                </MenuItem>));
        }

        if (allowDeletion && isReadOnly === false) {
            menuItems.push((
                <MenuItem key="delete-node" onClick={this.deleteNode}>
                    <ListItemIcon>
                        <DeleteIcon/>
                    </ListItemIcon>
                    <ListItemText>
                        {`Delete ${nodeObj.getAttribute('name')}`}
                    </ListItemText>
                </MenuItem>));
        }

        return (
            <Menu
                id="simple-menu"