Skip to content

Commit

Permalink
Merge pull request #353 from zalando-stups/349-collapsible-filters
Browse files Browse the repository at this point in the history
#349 collapsible filter and general styling
  • Loading branch information
prayerslayer committed Nov 3, 2015
2 parents c1e436e + 9be4b92 commit 3cbf23d
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 180 deletions.
2 changes: 0 additions & 2 deletions client/lib/common/asset/less/common/account-selector.less
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
@import "../variables";

.account-selector {
padding: @padding-small 0;

label {
.transition(background, color);
cursor: pointer;
Expand Down
8 changes: 8 additions & 0 deletions client/lib/common/asset/less/common/collapsible.less
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,13 @@
header {
user-select: none;
cursor: pointer;
border-bottom: 1px solid;
display: inline-block;
margin-top: @padding-tiny;
margin-bottom: @padding-small;
color: @gray;
&:hover {
color: @orange;
}
}
}
13 changes: 10 additions & 3 deletions client/lib/common/asset/less/violation/violation-list.less
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@

.violationList {

.account-selector {
padding-bottom: @padding-big;
.violationList-copy-url {
margin-bottom: @padding-small 0;
}

.violationList-datepicker {
display: flex;
flex-direction: row;
}

.violationList-filter {
margin-bottom: @padding-small;
}

.violationList-btn-group {
> :first-child {
padding-right: @padding-small;
margin-right: 3px;
}
}

Expand Down
3 changes: 2 additions & 1 deletion client/lib/common/src/collapsible.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Collapsible extends React.Component {
}

render() {
return <div className='collapsible' {...this.props}>
return <div className={'collapsible' + (this.state.collapsed ? ' is-collapsed' : '')} {...this.props}>
<header
onClick={this._collapse.bind(this)}>
{this.state.collapsed ?
Expand All @@ -33,6 +33,7 @@ class Collapsible extends React.Component {
Collapsible.displayName = 'Collapsible';
Collapsible.propTypes = {
header: React.PropTypes.object,
initialCollapsed: React.PropTypes.bool,
children: React.PropTypes.oneOf([React.PropTypes.array, React.PropTypes.object])
};
export default Collapsible;
1 change: 0 additions & 1 deletion client/lib/violation/src/account-selector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ class AccountSelector extends React.Component {
activeAccounts = partitionedAccounts[0],
inactiveAccounts = partitionedAccounts[1];
return <div className='account-selector'>
<div>Show violations in accounts:</div>
{!this.state.allSelected ?
<div>
<div>
Expand Down
161 changes: 80 additions & 81 deletions client/lib/violation/src/violation-analysis/violation-analysis.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,89 +55,88 @@ class ViolationAnalysis extends React.Component {
render() {
let {violationCount, violationTypes} = this.props,
chartData = [];
if (violationCount.length) {
violationCount = violationCount.map(c => ({
type: c.type,
typeHelp: violationTypes[c.type].help_text,
typeSeverity: violationTypes[c.type].violation_severity,
account: c.account,
accountName: this.props.accounts[c.account] ? this.props.accounts[c.account].name : '?',
quantity: c.quantity
}));
chartData = this.props.groupByAccount ?
violationCount.filter(c => c.account === this.props.account) :
violationCount.filter(c => c.type === this.props.violationType);

let maxQuantity = chartData.reduce((prev, cur) => prev > cur.quantity ? prev : cur.quantity, 0),
yScale = d3.scale
.linear()
.domain([0, maxQuantity])
.range([225, 0])
.nice();

return <div className='violation-analysis'>
{chartData.length ?
<AutoWidth className='violation-analysis-chart'>
<strong>
{this.props.groupByAccount ?
<span>Account {this.props.accounts[this.props.account] ? this.props.accounts[this.props.account].name : '?'}</span> :
<span>Violation {this.props.violationType}</span>}
</strong>
<Charts.BarChart
data={{
label: 'Violation Count',
values: _.sortByOrder(chartData, ['quantity'], ['desc'])
.map(c => ({ x: this.props.groupByAccount ? c.type : c.accountName, y: c.quantity }))
}}
tooltipHtml={(x, y0, y) => y.toString()}
tooltipMode='element'
height={300}
margin={{top: 50, left: 50, right: 25, bottom: 25}}
yScale={yScale}
yAxis={{label: '# Violations', innerTickSize: -10000}} />
</AutoWidth>
:
null}
<AutoWidth className='violation-analysis-table'>
<SortableTable
helpText='You can search for accounts and violation types.'
filterExprFn={row => `${row.type} ${row.account} ${row.accountName}`.toLowerCase()}
height={Math.min((violationCount.length + 1) * 50 + 2, 1500)}
rows={violationCount}>
<Table.Column
label='ID'
width={160}
cellRenderer={this.accountCellRenderer.bind(this)}
dataKey={'account'} />
<Table.Column
label='Account'
width={200}
cellRenderer={this.accountCellRenderer.bind(this)}
dataKey={'accountName'} />
<Table.Column
label='Violation Type'
width={200}
flexGrow={3}
cellRenderer={this.violationTypeCellRenderer.bind(this)}
dataKey={'type'} />
<Table.Column
label='Severity'
width={100}
flexGrow={1}
cellRenderer={c => <span title={c} className={'sortable-table-align-right ' + 'violation-severity-' + c}>{c}</span>}
dataKey='typeSeverity' />
<Table.Column
label='Count'
width={100}
flexGrow={1}
cellRenderer={c => <span title={c} className='sortable-table-align-right'>{c}</span>}
dataKey={'quantity'} />
</SortableTable>
</AutoWidth>
</div>;
if (!violationCount.length) {
return <div><Icon name='smile-o' /> <span>No violations!</span></div>;
}
violationCount = violationCount.map(c => ({
type: c.type,
typeHelp: violationTypes[c.type].help_text,
typeSeverity: violationTypes[c.type].violation_severity,
account: c.account,
accountName: this.props.accounts[c.account] ? this.props.accounts[c.account].name : '?',
quantity: c.quantity
}));
chartData = this.props.groupByAccount ?
violationCount.filter(c => c.account === this.props.account) :
violationCount.filter(c => c.type === this.props.violationType);

let maxQuantity = chartData.reduce((prev, cur) => prev > cur.quantity ? prev : cur.quantity, 0),
yScale = d3.scale
.linear()
.domain([0, maxQuantity])
.range([225, 0])
.nice();

return <div><Icon name='smile-o' /> <span>No violations!</span></div>;
return <div className='violation-analysis'>
{chartData.length ?
<AutoWidth className='violation-analysis-chart'>
<strong>
{this.props.groupByAccount ?
<span>Account {this.props.accounts[this.props.account] ? this.props.accounts[this.props.account].name : '?'}</span> :
<span>Violation {this.props.violationType}</span>}
</strong>
<Charts.BarChart
data={{
label: 'Violation Count',
values: _.sortByOrder(chartData, ['quantity'], ['desc'])
.map(c => ({ x: this.props.groupByAccount ? c.type : c.accountName, y: c.quantity }))
}}
tooltipHtml={(x, y0, y) => y.toString()}
tooltipMode='element'
height={300}
margin={{top: 50, left: 50, right: 25, bottom: 25}}
yScale={yScale}
yAxis={{label: '# Violations', innerTickSize: -10000}} />
</AutoWidth>
:
null}
<AutoWidth className='violation-analysis-table'>
<SortableTable
helpText='You can search for accounts and violation types.'
filterExprFn={row => `${row.type} ${row.account} ${row.accountName}`.toLowerCase()}
height={Math.min((violationCount.length + 1) * 50 + 2, 1500)}
rows={violationCount}>
<Table.Column
label='ID'
width={160}
cellRenderer={this.accountCellRenderer.bind(this)}
dataKey={'account'} />
<Table.Column
label='Account'
width={200}
cellRenderer={this.accountCellRenderer.bind(this)}
dataKey={'accountName'} />
<Table.Column
label='Violation Type'
width={200}
flexGrow={3}
cellRenderer={this.violationTypeCellRenderer.bind(this)}
dataKey={'type'} />
<Table.Column
label='Severity'
width={100}
flexGrow={1}
cellRenderer={c => <span title={c} className={'sortable-table-align-right ' + 'violation-severity-' + c}>{c}</span>}
dataKey='typeSeverity' />
<Table.Column
label='Count'
width={100}
flexGrow={1}
cellRenderer={c => <span title={c} className='sortable-table-align-right'>{c}</span>}
dataKey={'quantity'} />
</SortableTable>
</AutoWidth>
</div>;
}
}
ViolationAnalysis.displayName = 'ViolationAnalysis';
Expand Down
73 changes: 40 additions & 33 deletions client/lib/violation/src/violation-list/violation-list.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import moment from 'moment';
import lzw from 'lz-string';
import {merge} from 'common/src/util';
import Datepicker from 'common/src/datepicker.jsx';
import Collapsible from 'common/src/collapsible.jsx';
import Clipboard from 'react-copy-to-clipboard';
import AccountOverview from 'violation/src/violation-overview-account/violation-overview-account.jsx';
import AccountSelector from 'violation/src/account-selector.jsx';
Expand Down Expand Up @@ -184,45 +185,51 @@ class ViolationList extends React.Component {
<div className='u-info'>
Violations of the STUPS policy and bad practices in accounts you have access to.
</div>
<div>
Show violations between:
</div>
<div className='violationList-datepicker'>
<Datepicker
onChange={this.showSince.bind(this)}
selectedDay={showingSince} />
<Datepicker
onChange={this.showUntil.bind(this)}
selectedDay={showingUntil} />
</div>
<small>You can filter by resolved or unresolved violations.</small>
<div className='btn-group'>
<div
data-selected={searchParams.showResolved}
onClick={this._toggleShowResolved.bind(this, 'Resolved')}
className='btn btn-default'>
<Icon name='check-circle' /> Show resolved
</div>
<div
data-selected={searchParams.showUnresolved}
onClick={this._toggleShowResolved.bind(this, 'Unresolved')}
className='btn btn-default'>
<Icon name='circle-o' /> Show unresolved
</div>
</div>
<AccountSelector
selectableAccounts={selectableAccounts}
selectedAccounts={selectedAccounts}
activeAccountIds={activeAccountIds}
onToggleAccount={this.toggleAccount.bind(this)} />

<Clipboard
onCopy={this._handleCopy.bind(this)}
text={shareURL}>
<div className='btn btn-default'>
<div className='btn btn-default violationList-copy-url'>
<Icon name='bullhorn' /> Copy sharing URL
</div>
</Clipboard>
<Collapsible
header='Filters'>
<div className='violationList-filter'>
<small>Show violations between:</small>
<div className='violationList-datepicker violationList-btn-group'>
<Datepicker
onChange={this.showSince.bind(this)}
selectedDay={showingSince} />
<Datepicker
onChange={this.showUntil.bind(this)}
selectedDay={showingUntil} />
</div>
</div>
<div className='violationList-filter'>
<small>You can filter by resolved or unresolved violations.</small>
<div className='violationList-btn-group'>
<div
data-selected={searchParams.showResolved}
onClick={this._toggleShowResolved.bind(this, 'Resolved')}
className='btn btn-default'>
<Icon name='check-circle' /> Show resolved
</div>
<div
data-selected={searchParams.showUnresolved}
onClick={this._toggleShowResolved.bind(this, 'Unresolved')}
className='btn btn-default'>
<Icon name='circle-o' /> Show unresolved
</div>
</div>
</div>
<div className='violationList-filter'>
<AccountSelector
selectableAccounts={selectableAccounts}
selectedAccounts={selectedAccounts}
activeAccountIds={activeAccountIds}
onToggleAccount={this.toggleAccount.bind(this)} />
</div>
</Collapsible>

<Tabs.Tabs
onSelect={this._selectTab.bind(this)}
Expand Down
Loading

0 comments on commit 3cbf23d

Please sign in to comment.