<commit_before>import React, { Component, PropTypes } from 'react';
import {describeArcAsPath, polarToCartesian} from './SVG.jsx';

export const pipelineStageState = {
    // See: io.jenkins.blueocean.rest.model.BlueRun.BlueRunState
    queued: "queued", // May run in future
    running: "running",
    // See: io.jenkins.blueocean.rest.model.BlueRun.BlueRunResult
    success: "success",
    failure: "failure",
    notBuilt: "not_built" // Not run, and will not be
};

// Dimensions used for layout, px
const nodeSpacingH = 120;
const nodeSpacingV = 70;
const nodeRadius = 12;
const curveRadius = 12;
const connectorStrokeWidth = 4;

const labelWidth = nodeSpacingH;
const labelOffsetH = Math.floor(labelWidth * -0.5);
const labelOffsetV = 25;

const smallLabelWidth = nodeSpacingH - (2 * curveRadius); // Fit between lines
const smallLabelOffsetH = Math.floor(smallLabelWidth * -0.5);
const smallLabelOffsetV = 20;

const outlineNodeRadius = nodeRadius - (connectorStrokeWidth / 2);

const mouseTargetRadius = nodeRadius + (2 * connectorStrokeWidth); // Slightly bigger than visual nodes

// Colours. FIXME: Probably want to migrate these to stylesheets somehow
const connectorColor = "#979797";

const nodeColorSuccess = "#5BA504";
const nodeColorFailure = "#D54C53";
const nodeColorRunningTrack = "#a9c6e6";
const nodeColorRunningProgress = "#4a90e2";
const nodeColorNotBuilt = connectorColor;
const nodeColorUnexpected = "#ff00ff";

// These are about layout more than appearance, so they should probably remain inline
const bigLabelStyle = {
    position: "absolute",
    width: labelWidth,
    textAlign: "center",
    marginLeft: labelOffsetH,
    marginBottom: labelOffsetV
};

const smallLabelStyle = {
    position: "absolute",
    width: smallLabelWidth,
    textAlign: "center",
    fontSize: "80%",
    marginLeft: smallLabelOffsetH,
    marginTop: smallLabelOffsetV
};

const outerDivStyle = {
    position: "relative",
    overflow: "visible"
};

// Get the outgoing/rhs connection point from a node
function nodeConnectorFrom(fromNode) {
    return {
        x: fromNode.x + nodeRadius - (connectorStrokeWidth / 2),
        y: fromNode.y
    };
}

// Get the incoming/lhs connection point from a node
function nodeConnectorTo(toNode) {
    return {
        x: toNode.x - nodeRadius + (connectorStrokeWidth / 2),
        y: toNode.y
    };
}

export default class PipelineGraph extends Component {

    constructor(props) {
        super(props);
        this.state = {
            nodes: [],
            connections: [],
            bigLabels: [],
            smallLabels: [],
            measuredWidth: 0,
            measuredHeight: 0
        };
    }

    componentWillMount() {
        this.stagesUpdated(this.props.stages);
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.stages !== this.props.stages) {
            this.stagesUpdated(nextProps.stages);
        }
    }

    addConnectionDetails(connections, previousNodes, columnNodes) {

        if (false && previousNodes.length == 1 && columnNodes.length == 1) {
            // Just a simple single connection
            connections.push([previousNodes[0], columnNodes[0]]);

        } else {

            // Connect to top of previous/next column. Curves added when creating SVG

            // Collapse from previous node(s) to top column node
            for (let previousNode of previousNodes) {
                connections.push([previousNode, columnNodes[0]]);
            }

            // Expand from top previous node to column node(s) - first one done already above
            for (let columnNode of columnNodes.slice(1)) {
                connections.push([previousNodes[0], columnNode]);
            }

        }
    }

    stagesUpdated(newStages = []) {
        var nodes = [];
        var connections = [];
        var bigLabels = [];
        var smallLabels = [];

        // FIXME: Should we calculate based on expected text size guesstimate?
        const ypStart = 50;

        // next node position
        var xp = nodeSpacingH / 2;
        var yp;

        var previousNodes = [];
        var mostColumnNodes = 0;

        // For reach top-level stage we have a column of node(s)
        for (let topStage of newStages) {

            yp = ypStart;

            // Always have a single bigLabel per top-level stage
            bigLabels.push({
                x: xp,
                y: yp,<commit_msg>feature/UX-74-PipelineGraph * Re-do a small clean-up that I must have undone during a revert<commit_after>import React, { Component, PropTypes } from 'react';
import {describeArcAsPath, polarToCartesian} from './SVG.jsx';

export const pipelineStageState = {
    // See: io.jenkins.blueocean.rest.model.BlueRun.BlueRunState
    queued: "queued", // May run in future
    running: "running",
    // See: io.jenkins.blueocean.rest.model.BlueRun.BlueRunResult
    success: "success",
    failure: "failure",
    notBuilt: "not_built" // Not run, and will not be
};

// Dimensions used for layout, px
const nodeSpacingH = 120;
const nodeSpacingV = 70;
const nodeRadius = 12;
const curveRadius = 12;
const connectorStrokeWidth = 4;

const labelWidth = nodeSpacingH;
const labelOffsetH = Math.floor(labelWidth * -0.5);
const labelOffsetV = 25;

const smallLabelWidth = nodeSpacingH - (2 * curveRadius); // Fit between lines
const smallLabelOffsetH = Math.floor(smallLabelWidth * -0.5);
const smallLabelOffsetV = 20;

const outlineNodeRadius = nodeRadius - (connectorStrokeWidth / 2);

const mouseTargetRadius = nodeRadius + (2 * connectorStrokeWidth); // Slightly bigger than visual nodes

// Colours. FIXME: Probably want to migrate these to stylesheets somehow
const connectorColor = "#979797";

const nodeColorSuccess = "#5BA504";
const nodeColorFailure = "#D54C53";
const nodeColorRunningTrack = "#a9c6e6";
const nodeColorRunningProgress = "#4a90e2";
const nodeColorNotBuilt = connectorColor;
const nodeColorUnexpected = "#ff00ff";

// These are about layout more than appearance, so they should probably remain inline
const bigLabelStyle = {
    position: "absolute",
    width: labelWidth,
    textAlign: "center",
    marginLeft: labelOffsetH,
    marginBottom: labelOffsetV
};

const smallLabelStyle = {
    position: "absolute",
    width: smallLabelWidth,
    textAlign: "center",
    fontSize: "80%",
    marginLeft: smallLabelOffsetH,
    marginTop: smallLabelOffsetV
};

const outerDivStyle = {
    position: "relative",
    overflow: "visible"
};

// Get the outgoing/rhs connection point from a node
function nodeConnectorFrom(fromNode) {
    return {
        x: fromNode.x + nodeRadius - (connectorStrokeWidth / 2),
        y: fromNode.y
    };
}

// Get the incoming/lhs connection point from a node
function nodeConnectorTo(toNode) {
    return {
        x: toNode.x - nodeRadius + (connectorStrokeWidth / 2),
        y: toNode.y
    };
}

export default class PipelineGraph extends Component {

    constructor(props) {
        super(props);
        this.state = {
            nodes: [],
            connections: [],
            bigLabels: [],
            smallLabels: [],
            measuredWidth: 0,
            measuredHeight: 0
        };
    }

    componentWillMount() {
        this.stagesUpdated(this.props.stages);
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.stages !== this.props.stages) {
            this.stagesUpdated(nextProps.stages);
        }
    }

    addConnectionDetails(connections, previousNodes, columnNodes) {
        // Connect to top of previous/next column. Curves added when creating SVG

        // Collapse from previous node(s) to top column node
        for (let previousNode of previousNodes) {
            connections.push([previousNode, columnNodes[0]]);
        }

        // Expand from top previous node to column node(s) - first one done already above
        for (let columnNode of columnNodes.slice(1)) {
            connections.push([previousNodes[0], columnNode]);
        }
    }

    stagesUpdated(newStages = []) {
        var nodes = [];
        var connections = [];
        var bigLabels = [];
        var smallLabels = [];

        // FIXME: Should we calculate based on expected text size guesstimate?
        const ypStart = 50;

        // next node position
        var xp = nodeSpacingH / 2;
        var yp;

        var previousNodes = [];
        var mostColumnNodes = 0;

        // For reach top-level stage we have a column of node(s)
        for (let topStage of newStages) {

            yp = ypStart;

            // Always have a single bigLabel per top-level stage
            bigLabels.push({
                x: xp,
                y: yp,
{'fraction_non_alphanumeric': 0.10089944649446494, 'fraction_numerical': 0.013837638376383764, 'mean_word_length': 2.621294363256785, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4422542', 'n_tokens_mistral': 2550, 'n_tokens_neox': 2433, 'n_words': 723}