[ux-412] Working version after merge

This commit is contained in:
Thorsten Scherler 2016-05-27 21:13:08 +02:00
parent 15c67cc1fb
commit fceb1763a8
17 changed files with 83 additions and 59 deletions

View File

@ -2,7 +2,7 @@ root = true
[*]
indent_style = space
indent_size = 2
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true

View File

@ -1,5 +1,11 @@
import React, { Component, PropTypes } from 'react';
import { actions, pipelines as pipelinesSelector, connect, createSelector } from './redux';
import {
actions,
pipelines as pipelinesSelector,
isMultiBranch as isMultiBranchSelector,
connect,
createSelector,
} from './redux';
import * as sse from '@jenkins-cd/sse-gateway';
import * as pushEventUtil from './util/push-event-util';
@ -12,6 +18,7 @@ sse.connect('jenkins_blueocean');
class OrganisationPipelines extends Component {
// FIXME: IMO the following should be droped
getChildContext() {
const {
params,
@ -36,8 +43,14 @@ class OrganisationPipelines extends Component {
}
componentWillMount() {
if (this.context.config) {
this.props.fetchPipelinesIfNeeded(this.context.config);
const config = this.context.config;
if (config) {
this.props.fetchPipelinesIfNeeded(config);
if (this.props.params.pipeline) {
const { pipeline } = this.props.params;
config.pipeline = pipeline;
this.props.setPipeline(config);
}
const _this = this;
// Subscribe for job channel push events
@ -71,15 +84,29 @@ class OrganisationPipelines extends Component {
});
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.params.pipeline !== this.props.params.pipeline) {
const config = this.context.config;
const { pipeline } = nextProps.params;
config.pipeline = pipeline;
this.props.setPipeline(config);
}
}
componentWillUnmount() {
if (this.jobListener) {
sse.unsubscribe(this.jobListener);
delete this.jobListener;
}
}
/*
FIXME we should use clone here, this way we could pass all actions and reducer down to all
components and get rid of the seperate connect in each subcomponents -> see RunDetailsPipeline
*/
render() {
return this.props.children; // Set by router
return this.props.children;
}
}
@ -90,6 +117,7 @@ OrganisationPipelines.contextTypes = {
OrganisationPipelines.propTypes = {
fetchPipelinesIfNeeded: func.isRequired,
setPipeline: func,
processJobQueuedEvent: func.isRequired,
updateRunState: func.isRequired,
params: object, // From react-router
@ -105,6 +133,7 @@ OrganisationPipelines.childContextTypes = {
location: object, // From react-router
};
const selectors = createSelector([pipelinesSelector], (pipelines) => ({ pipelines }));
const selectors = createSelector([pipelinesSelector, isMultiBranchSelector],
(pipelines, isMultiBranch) => ({ pipelines, isMultiBranch }));
export default connect(selectors, actions)(OrganisationPipelines);

View File

@ -1,5 +1,6 @@
import React, { Component, PropTypes } from 'react';
import { Icon } from 'react-material-icons-blue';
import { StatusIndicator } from '@jenkins-cd/design-language';
import moment from 'moment';
import { calculateLogUrl } from '../redux';
@ -7,22 +8,6 @@ import LogConsole from './LogConsole';
const { object, func, string } = PropTypes;
function iconFromResult(result) {
switch (result) {
case 'SUCCESS':
case 'UNSTABLE':
return 'done';
case 'FAILURE':
case 'ABORTED':
case 'NOT_BUILT':
return 'close';
case 'RUNNING':
return 'track_changes';
default:
return 'close';
}
}
export default class Node extends Component {
constructor(props) {
super(props);
@ -40,22 +25,22 @@ export default class Node extends Component {
render() {
const { node, logs, nodesBaseUrl, fetchLog } = this.props;
const { isVisible } = this.state;
// Early out
// Early out
if (!node || !fetchLog) {
return null;
}
const { config = {} } = this.context;
const {
key,
title,
durationInMillis,
result,
state,
} = node;
key,
title,
durationInMillis,
result,
state,
} = node;
const newVar = result === 'UNKNOWN' || !result ? state : result;
const resultRun = result === 'UNKNOWN' || !result ? state : result;
const duration = moment.duration(
Number(durationInMillis), 'milliseconds').humanize();
Number(durationInMillis), 'milliseconds').humanize();
const log = logs ? logs[calculateLogUrl({ ...config, node, nodesBaseUrl })] : null;
const getLogForNode = () => {
@ -68,7 +53,12 @@ export default class Node extends Component {
return (<div>
<div className="nodes" key={key} onClick={getLogForNode}>
<div className="nodes__section">
<div className="result"><Icon {...{ icon: iconFromResult(newVar) }} /></div>
<div className="result"><StatusIndicator result={resultRun} /></div>
<div className="state">
{ this.state.isVisible ?
<Icon {...{ icon: 'keyboard_arrow_down' }} /> :
<Icon {...{ icon: 'keyboard_arrow_right' }} />}
</div>
<div className="title">{title}</div>
</div>
<div className="nodes__section">

View File

@ -19,6 +19,7 @@ export default class Nodes extends Component {
key={index}
node={item}
nodesBaseUrl={nodesBaseUrl}
{...this.props}
/>)
}
</div>);

View File

@ -40,14 +40,13 @@ class RunDetails extends Component {
componentWillMount() {
if (this.context.config && this.context.params) {
const {
params: {
pipeline,
},
config = {},
} = this.context;
params: {
pipeline,
},
config = {},
} = this.context;
config.pipeline = pipeline;
this.props.fetchRunsIfNeeded(config);
this.props.setPipeline(config);
}
}

View File

@ -26,36 +26,38 @@ export class RunDetailsPipeline extends Component {
generateConfig() {
const {
params: {
pipeline: name, branch, runId,
},
config = {},
} = this.context;
params: { pipeline: name, branch, runId },
config = {},
} = this.context;
const { isMultiBranch } = this.props;
const mergedConfig = { ...config, name, branch, runId, isMultiBranch };
return mergedConfig;
}
render() {
const { pipeline: name, branch, runId } = this.context.params;
const { isMultiBranch, nodes } = this.props;
if (!nodes) {
return null;
}
const mergedConfig = this.generateConfig();
const key = calculateNodeBaseUrl(mergedConfig);
const logGeneral = calculateRunLogURLObject(mergedConfig);
return (
<div>
<ExtensionPoint name="jenkins.pipeline.run.result"
pipelineName={name}
branchName={isMultiBranch ? branch : undefined}
runId={runId}
/>
<LogToolbar fileName={logGeneral.fileName} url={logGeneral.url} />
{ nodes && <Nodes
nodeInformation={nodes[key]}
/>
}
</div>
<div>
<ExtensionPoint name="jenkins.pipeline.run.result"
pipelineName={name}
branchName={isMultiBranch ? branch : undefined}
runId={runId}
/>
<LogToolbar fileName={logGeneral.fileName} url={logGeneral.url} />
{ nodes && <Nodes
nodeInformation={nodes[key]}
{...this.props}
/>
}
</div>
);
}
}

View File

@ -78,7 +78,8 @@ export const actionHandlers = {
if (!pipelines) {
return state.set('pipeline', null);
}
const pipeline = pipelines.filter(item => item.name === id);
// [].slice(0) returns a clone, we do need it for uniqueness
const pipeline = pipelines.slice(0).filter(item => item.name === id);
return state.set('pipeline', pipeline[0] ? pipeline[0] : null);
},
[ACTION_TYPES.CLEAR_CURRENT_RUN_DATA](state) {
@ -198,6 +199,7 @@ export const actions = {
dispatch({ type: ACTION_TYPES.CLEAR_PIPELINE_DATA });
const pipelines = getState().adminStore.pipelines;
if (!pipelines) {
return dispatch(actions.fetchPipelinesIfNeeded(config))
.then(() => dispatch({ id: config.pipeline, type: ACTION_TYPES.SET_PIPELINE }));
@ -536,7 +538,7 @@ export const actions = {
},
/*
Get a specific log for a node, fetch it only if needed.
key for cache: nodesBaseUrl + nodeId
key for cache: logUrl = calculateLogUrl
*/
fetchLog(config) {
return (dispatch, getState) => {

View File

@ -16,6 +16,7 @@ export const nodes = createSelector([adminStore], store => store.nodes);
export const currentBranches = createSelector([adminStore], store => store.currentBranches);
export const isMultiBranch = createSelector(
[pipeline], (pipe) => {
console.log('dammit');
if (pipe && pipe.organization) {
return !!pipe.branchNames;
}