Merge pull request #310 from jenkinsci/feature/JENKINS-35828-pipeline-card
feature/jenkins 35828 - pipeline card
This commit is contained in:
commit
03a301025c
|
@ -1,12 +1,13 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
max_line_length = 160
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
"skin-deep": "^0.16.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jenkins-cd/design-language": "0.0.58",
|
||||
"@jenkins-cd/design-language": "0.0.60",
|
||||
"@jenkins-cd/js-extensions": "0.0.17-beta-1",
|
||||
"@jenkins-cd/js-modules": "0.0.5",
|
||||
"@jenkins-cd/sse-gateway": "0.0.5",
|
||||
|
|
|
@ -36,7 +36,7 @@ export default class PipelinePage extends Component {
|
|||
<span> / </span>
|
||||
<Link to={activityUrl}>{name}</Link>
|
||||
</h1>
|
||||
<Favorite darkTheme />
|
||||
<Favorite className="dark-yellow" />
|
||||
</Title>
|
||||
<PageTabs base={baseUrl}>
|
||||
<TabLink to="/activity">Activity</TabLink>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
max_line_length = 160
|
|
@ -13,14 +13,9 @@ builder.defineTask('test', function() {
|
|||
var mocha = require('gulp-mocha');
|
||||
var babel = require('babel-core/register');
|
||||
|
||||
// Allow running of a specific test
|
||||
// e.g. gulp test --test pipelines
|
||||
// will run the pipelines-spec.js
|
||||
var filter = builder.args.argvValue('--test', '*');
|
||||
|
||||
builder.gulp.src('src/test/js/' + filter + '-spec.js')
|
||||
builder.gulp.src('src/test/js/**/*-spec.jsx')
|
||||
.pipe(mocha({
|
||||
compilers: {js: babel}
|
||||
compilers: { js: babel },
|
||||
})).on('error', function(e) {
|
||||
if (builder.isRetest()) {
|
||||
// ignore test failures if we are running retest.
|
||||
|
|
|
@ -23,16 +23,18 @@
|
|||
"babel-preset-react": "^6.5.0",
|
||||
"babel-preset-stage-0": "^6.5.0",
|
||||
"chai": "^3.5.0",
|
||||
"enzyme": "^2.2.0",
|
||||
"enzyme": "2.3.0",
|
||||
"eslint": "2.8.0",
|
||||
"eslint-plugin-react": "^5.0.1",
|
||||
"eslint-to-editorconfig": "1.2.0",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-mocha": "^2.2.0",
|
||||
"mocha": "^2.4.5",
|
||||
"nock": "^8.0.0"
|
||||
"nock": "^8.0.0",
|
||||
"react-addons-test-utils": "15.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jenkins-cd/design-language": "0.0.58",
|
||||
"@jenkins-cd/design-language": "0.0.60",
|
||||
"@jenkins-cd/js-extensions": "0.0.17-beta-1",
|
||||
"@jenkins-cd/js-modules": "0.0.5",
|
||||
"@jenkins-cd/sse-gateway": "0.0.5",
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/**
|
||||
* Created by cmeyers on 6/28/16.
|
||||
*/
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { Icon } from 'react-material-icons-blue';
|
||||
import { Favorite, LiveStatusIndicator } from '@jenkins-cd/design-language';
|
||||
|
||||
/**
|
||||
* PipelineCard displays an informational card about a Pipeline and its status.
|
||||
*
|
||||
* Properties:
|
||||
* status: 'result' or 'status' value e.g. 'success', 'failure', etc.
|
||||
* percentage: for status=running, the percent complete
|
||||
* organization: name of org
|
||||
* pipeline: name of pipeline
|
||||
* branch: name of branch
|
||||
* commitId: ID of commit
|
||||
* favorite: whether or not the pipeline is favorited
|
||||
* onRunClick: callback invoked when 'Run Again' is clicked
|
||||
* onFavoriteToggle: callback invokved when favorite checkbox is toggled.
|
||||
*/
|
||||
export class PipelineCard extends Component {
|
||||
|
||||
static _getBackgroundClass(status) {
|
||||
return status !== null && status.length > 0 ?
|
||||
`${status.toLowerCase()}-bg-lite` :
|
||||
'';
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
favorite: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this._updateState(this.props);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.props.favorite !== nextProps.favorite) {
|
||||
this._updateState(nextProps);
|
||||
}
|
||||
}
|
||||
|
||||
_updateState(props) {
|
||||
this.setState({
|
||||
favorite: props.favorite,
|
||||
});
|
||||
}
|
||||
|
||||
_onRunClick() {
|
||||
if (this.props.onRunClick) {
|
||||
this.props.onRunClick();
|
||||
}
|
||||
}
|
||||
|
||||
_onFavoriteToggle() {
|
||||
const value = !this.state.favorite;
|
||||
this.setState({
|
||||
favorite: value,
|
||||
});
|
||||
|
||||
if (this.props.onFavoriteToggle) {
|
||||
this.props.onFavoriteToggle(value);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { status } = this.props;
|
||||
const bgClass = PipelineCard._getBackgroundClass(status);
|
||||
const showRun = status && status.toLowerCase() === 'failure' || status.toLowerCase() === 'aborted';
|
||||
|
||||
return (
|
||||
<div className={`pipeline-card ${bgClass}`}>
|
||||
<LiveStatusIndicator result={this.props.status} width={'20px'} height={'20px'} noBackground />
|
||||
|
||||
<span className="name">
|
||||
{this.props.organization} / {this.props.pipeline}
|
||||
</span>
|
||||
|
||||
{ this.props.branch &&
|
||||
<span className="branch">
|
||||
<span className="octicon octicon-git-branch"></span>
|
||||
<span className="branchText">{this.props.branch}</span>
|
||||
</span>
|
||||
}
|
||||
|
||||
<span className="commit">
|
||||
<span className="octicon octicon-git-commit"></span>
|
||||
<pre className="commitId">#{this.props.commitId}</pre>
|
||||
</span>
|
||||
|
||||
<span className="actions">
|
||||
{ showRun &&
|
||||
<a className="run" title="Run Again" onClick={() => this._onRunClick()}>
|
||||
<Icon size={24} icon="replay" />
|
||||
</a>
|
||||
}
|
||||
|
||||
<Favorite checked={this.state.favorite} className="dark-white"
|
||||
onToggle={() => this._onFavoriteToggle()}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
PipelineCard.propTypes = {
|
||||
status: PropTypes.string,
|
||||
percentage: PropTypes.number, // TODO: might need startTime and estimatedDuration
|
||||
organization: PropTypes.string,
|
||||
pipeline: PropTypes.string,
|
||||
branch: PropTypes.string,
|
||||
commitId: PropTypes.string,
|
||||
favorite: PropTypes.bool,
|
||||
onRunClick: PropTypes.func,
|
||||
onFavoriteToggle: PropTypes.func,
|
||||
};
|
||||
|
||||
PipelineCard.defaultProps = {
|
||||
favorite: false,
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Created by cmeyers on 6/28/16.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { action, storiesOf } from '@kadira/storybook';
|
||||
|
||||
import { PipelineCard } from '../components/PipelineCard';
|
||||
|
||||
const style = { padding: '10px' };
|
||||
const style2 = { paddingBottom: '10px' };
|
||||
|
||||
storiesOf('PipelineCard', module)
|
||||
.add('all states', () => {
|
||||
const states = 'SUCCESS,QUEUED,RUNNING,FAILURE,ABORTED,UNSTABLE,NOT_BUILT,UNKNOWN'.split(',');
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
{ states.map(s =>
|
||||
<div key={s} style={style2}>
|
||||
<PipelineCard status={s} organization="Jenkins" pipeline="blueocean"
|
||||
branch="feature/JENKINS-123" commitId="447d8e1" favorite
|
||||
onRunClick={action('run')} onFavoriteToggle={action('toggle')}
|
||||
/>
|
||||
</div>
|
||||
) }
|
||||
<PipelineCard status="RUNNING" organization="jenkinsci" pipeline="blueocean"
|
||||
commitId="447d8e1" onRunClick={action('run')} onFavoriteToggle={action('toggle')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
|
@ -1,4 +1,5 @@
|
|||
/**
|
||||
* Created by cmeyers on 6/28/16.
|
||||
*/
|
||||
require('./ActionLinkStories.jsx');
|
||||
require('./ActionLinkStories');
|
||||
require('./PipelineCardStories');
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
.pipeline-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
min-width: 400px;
|
||||
padding: 15px;
|
||||
|
||||
.name, .branch, .commit {
|
||||
flex: 1 1 auto;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.branch, .commit {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.name, .branchText, .commitId {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.commitId {
|
||||
margin: 0 0 0 5px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
min-width: 60px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.run {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
// remove empty space to attain centered vertical alignment
|
||||
.run, .actions {
|
||||
> * {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-spinner.running {
|
||||
circle {
|
||||
stroke: #bcd8f1;
|
||||
}
|
||||
path.running {
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-spinner.queued {
|
||||
circle {
|
||||
stroke: white;
|
||||
}
|
||||
circle.inner {
|
||||
stroke: white;
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-spinner.not_built {
|
||||
circle {
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
|
||||
// force "favorite" checkbox to white when on unstable card
|
||||
// FIXME: doesn't work in IE11
|
||||
.checkbox {
|
||||
filter: grayscale(100%) brightness(0%) invert(100%);
|
||||
-webkit-filter: grayscale(100%) brightness(0%) invert(100%);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
@import 'components/pipeline-card';
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* Created by cmeyers on 7/6/16.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { assert } from 'chai';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { PipelineCard } from '../../../main/js/components/PipelineCard';
|
||||
|
||||
describe('PipelineCard', () => {
|
||||
it('renders basic child elements', () => {
|
||||
const status = 'SUCCESS';
|
||||
const wrapper = shallow(
|
||||
<PipelineCard status={status} organization="Jenkins" pipeline="blueocean"
|
||||
branch="feature/JENKINS-123" commitId="447d8e1" favorite
|
||||
/>
|
||||
);
|
||||
|
||||
assert.equal(wrapper.find('LiveStatusIndicator').length, 1);
|
||||
assert.equal(wrapper.find('.name').length, 1);
|
||||
assert.equal(wrapper.find('.name').text(), 'Jenkins / blueocean');
|
||||
assert.equal(wrapper.find('.branch').length, 1);
|
||||
assert.equal(wrapper.find('.branchText').text(), 'feature/JENKINS-123');
|
||||
assert.equal(wrapper.find('.commit').length, 1);
|
||||
assert.equal(wrapper.find('.commitId').text(), '#447d8e1');
|
||||
assert.equal(wrapper.find('Favorite').length, 1);
|
||||
});
|
||||
|
||||
it('renders "run" button after failure', () => {
|
||||
const status = 'FAILURE';
|
||||
const wrapper = shallow(
|
||||
<PipelineCard status={status} organization="Jenkins" pipeline="blueocean"
|
||||
branch="feature/JENKINS-123" commitId="447d8e1" favorite
|
||||
/>
|
||||
);
|
||||
|
||||
assert.equal(wrapper.find('.actions .run').length, 1);
|
||||
});
|
||||
|
||||
it('renders no "run" button after success', () => {
|
||||
const status = 'SUCCESS';
|
||||
const wrapper = shallow(
|
||||
<PipelineCard status={status} organization="Jenkins" pipeline="blueocean"
|
||||
branch="feature/JENKINS-123" commitId="447d8e1" favorite
|
||||
/>
|
||||
);
|
||||
|
||||
assert.equal(wrapper.find('.actions .run').length, 0);
|
||||
});
|
||||
});
|
|
@ -25,7 +25,7 @@
|
|||
"zombie": "^4.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jenkins-cd/design-language": "0.0.58",
|
||||
"@jenkins-cd/design-language": "0.0.60",
|
||||
"@jenkins-cd/js-extensions": "0.0.17-beta-1",
|
||||
"@jenkins-cd/js-modules": "0.0.5",
|
||||
"history": "2.0.2",
|
||||
|
|
Loading…
Reference in New Issue