<commit_before>import React, { Component, PropTypes } from 'react';
import {
    ModalView,
    ModalBody,
    ModalHeader,
    PipelineResult,
    PageTabs,
    TabLink,
} from '@jenkins-cd/design-language';

import {
    actions,
    currentRuns as runsSelector,
    isMultiBranch as isMultiBranchSelector,
    createSelector,
    connect,
} from '../redux';

const { func, object, array, any } = PropTypes;

/**
 * Trim the last path element off a URL. Handles trailing slashes nicely.
 * @param url
 * @returns {string}
 */
function cleanBaseUrl(url) {
    const paths = url.split('/').filter(path => (path.length > 0));
    paths.pop();
    return paths.join('/');
}

class RunDetails extends Component {
    componentWillMount() {
        if (this.context.config && this.context.params) {
            const {
                params: {
                    pipeline,
                },
                config = {},
            } = this.context;
            config.pipeline = pipeline;
            this.props.fetchRunsIfNeeded(config);
            this.props.setPipeline(config);
        }
    }
    render() {
        // early out
        if (!this.context.params
            || !this.props.runs
            || this.props.isMultiBranch === null
        ) {
            return null;
        }
        const {
            context: {
                router,
                params: {
                    branch,
                    runId,
                    pipeline: name,
                },
            },
        } = this;

        const baseUrl = cleanBaseUrl(this.context.location.pathname);

        const result = this.props.runs.filter(
            (run) => run.id === runId && decodeURIComponent(run.pipeline) === branch)[0];

        result.name = name;

        const afterClose = () => {
            router.goBack();
        };

        return (<ModalView
          isVisible
          result={result.result}
          {...{ afterClose }}
        >
            <ModalHeader>
                <div>
                    <PipelineResult data={result} />
                    <PageTabs base={baseUrl}>
                        <TabLink to="/logs">Pipeline</TabLink>
                        <TabLink to="/changes">Changes</TabLink>
                        <TabLink to="/tests">Tests</TabLink>
                        <TabLink to="/artifacts">Artifacts</TabLink>
                    </PageTabs>
                    </div>
            </ModalHeader>
            <ModalBody>
                <div>
                    {React.cloneElement(this.props.children, { ...this.props })}
                </div>
            </ModalBody>
        </ModalView>);
    }
}

RunDetails.contextTypes = {
    config: object.isRequired,
    params: object,
    location: object,
    router: object.isRequired, // From react-router
};

RunDetails.propTypes = {
    children: PropTypes.node,
    runs: array,
    isMultiBranch: any,
    fetchIfNeeded: func,
    fetchRunsIfNeeded: func,
    setPipeline: func,
    getPipeline: func,
};

const selectors = createSelector(
    [runsSelector, isMultiBranchSelector],
    (runs, isMultiBranch) => ({ runs, isMultiBranch }));

export default connect(selectors, actions)(RunDetails);
<commit_msg>[UX-76] navigate to Changes tab when author list is clicked<commit_after>import React, { Component, PropTypes } from 'react';
import {
    ModalView,
    ModalBody,
    ModalHeader,
    PipelineResult,
    PageTabs,
    TabLink,
} from '@jenkins-cd/design-language';

import {
    actions,
    currentRuns as runsSelector,
    isMultiBranch as isMultiBranchSelector,
    createSelector,
    connect,
} from '../redux';

const { func, object, array, any } = PropTypes;

/**
 * Trim the last path element off a URL. Handles trailing slashes nicely.
 * @param url
 * @returns {string}
 */
function cleanBaseUrl(url) {
    const paths = url.split('/').filter(path => (path.length > 0));
    paths.pop();
    return paths.join('/');
}

class RunDetails extends Component {
    constructor(props) {
        super(props);

        this.navigateToChanges = this.navigateToChanges.bind(this);
    }
    componentWillMount() {
        if (this.context.config && this.context.params) {
            const {
                params: {
                    pipeline,
                },
                config = {},
            } = this.context;
            config.pipeline = pipeline;
            this.props.fetchRunsIfNeeded(config);
            this.props.setPipeline(config);
        }
    }
    navigateToChanges() {
        const changesUrl = `${cleanBaseUrl(this.context.location.pathname)}/changes`;
        this.context.router.push(changesUrl);
    }
    render() {
        // early out
        if (!this.context.params
            || !this.props.runs
            || this.props.isMultiBranch === null
        ) {
            return null;
        }
        const {
            context: {
                router,
                params: {
                    branch,
                    runId,
                    pipeline: name,
                },
            },
        } = this;

        const baseUrl = cleanBaseUrl(this.context.location.pathname);

        const result = this.props.runs.filter(
            (run) => run.id === runId && decodeURIComponent(run.pipeline) === branch)[0];

        result.name = name;

        const afterClose = () => {
            router.goBack();
        };

        return (<ModalView
          isVisible
          result={result.result}
          {...{ afterClose }}
        >
            <ModalHeader>
                <div>
                    <PipelineResult data={result}
                      onAuthorsClick={this.navigateToChanges}
                    />
                    <PageTabs base={baseUrl}>
                        <TabLink to="/logs">Pipeline</TabLink>
                        <TabLink to="/changes">Changes</TabLink>
                        <TabLink to="/tests">Tests</TabLink>
                        <TabLink to="/artifacts">Artifacts</TabLink>
                    </PageTabs>
                    </div>
            </ModalHeader>
            <ModalBody>
                <div>
                    {React.cloneElement(this.props.children, { ...this.props })}
                </div>
            </ModalBody>
        </ModalView>);
    }
}

RunDetails.contextTypes = {
    config: object.isRequired,
    params: object,
    location: object,
    router: object.isRequired, // From react-router
};

RunDetails.propTypes = {
    children: PropTypes.node,
    runs: array,
    isMultiBranch: any,
    fetchIfNeeded: func,
    fetchRunsIfNeeded: func,
    setPipeline: func,
    getPipeline: func,
};

const selectors = createSelector(
    [runsSelector, isMultiBranchSelector],
    (runs, isMultiBranch) => ({ runs, isMultiBranch }));

export default connect(selectors, actions)(RunDetails);

{'fraction_non_alphanumeric': 0.11989498249708284, 'fraction_numerical': 0.0008751458576429405, 'mean_word_length': 1.6121904761904762, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 55, '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': '5522155', 'n_tokens_mistral': 1887, 'n_tokens_neox': 1854, 'n_words': 377}