Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace Show More buttons with carets w/ counts #1029

Merged
merged 2 commits into from
Feb 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions client/app/scripts/components/node-details.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ export default class NodeDetails extends React.Component {

renderDetails() {
const details = this.props.details;
const showSummary = (details.metadata || details.metrics || details.docker_labels) !== undefined;
const showControls = details.controls && details.controls.length > 0;
const nodeColor = getNodeColorDark(details.rank, details.label, details.pseudo);
const {error, pending} = (this.props.nodeControlStatus || {});
Expand Down Expand Up @@ -166,10 +165,13 @@ export default class NodeDetails extends React.Component {
</div>}

<div className="node-details-content">
{showSummary && <div className="node-details-content-section">
{details.metrics && <div className="node-details-content-section">
<div className="node-details-content-section-header">Status</div>
{details.metrics && <NodeDetailsHealth metrics={details.metrics} />}
{details.metadata && <NodeDetailsInfo rows={details.metadata} />}
<NodeDetailsHealth metrics={details.metrics} />
</div>}
{details.metadata && <div className="node-details-content-section">
<div className="node-details-content-section-header">Info</div>
<NodeDetailsInfo rows={details.metadata} />
</div>}

{details.children && details.children.map(children => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,23 @@ import React from 'react';
import NodeDetailsHealthOverflowItem from './node-details-health-overflow-item';

export default class NodeDetailsHealthOverflow extends React.Component {

constructor(props, context) {
super(props, context);
this.handleClick = this.handleClick.bind(this);
}

handleClick(ev) {
ev.preventDefault();
this.props.handleClick();
}

render() {
const items = this.props.items.slice(0, 4);

return (
<div className="node-details-health-overflow" onClick={this.props.handleClickMore}>
<div className="node-details-health-overflow" onClick={this.handleClick}>
{items.map(item => <NodeDetailsHealthOverflowItem key={item.id} {...item} />)}
<div className="node-details-health-overflow-expand">
Show more
</div>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';

import ShowMore from '../show-more';
import NodeDetailsHealthOverflow from './node-details-health-overflow';
import NodeDetailsHealthItem from './node-details-health-item';

Expand All @@ -13,8 +14,7 @@ export default class NodeDetailsHealth extends React.Component {
this.handleClickMore = this.handleClickMore.bind(this);
}

handleClickMore(ev) {
ev.preventDefault();
handleClickMore() {
const expanded = !this.state.expanded;
this.setState({expanded});
}
Expand All @@ -25,17 +25,21 @@ export default class NodeDetailsHealth extends React.Component {
const primeMetrics = metrics.slice(0, primeCutoff);
const overflowMetrics = metrics.slice(primeCutoff);
const showOverflow = overflowMetrics.length > 0 && !this.state.expanded;
const showLess = this.state.expanded;
const flexWrap = showOverflow || !this.state.expanded ? 'nowrap' : 'wrap';
const justifyContent = showOverflow || !this.state.expanded ? 'space-around' : 'flex-start';
const notShown = overflowMetrics.length;

return (
<div className="node-details-health" style={{flexWrap, justifyContent}}>
{primeMetrics.map(item => {
return <NodeDetailsHealthItem key={item.id} {...item} />;
})}
{showOverflow && <NodeDetailsHealthOverflow items={overflowMetrics} handleClickMore={this.handleClickMore} />}
{showLess && <div className="node-details-health-expand" onClick={this.handleClickMore}>show less</div>}
<div className="node-details-health-wrapper">
{primeMetrics.map(item => {
return <NodeDetailsHealthItem key={item.id} {...item} />;
})}
{showOverflow && <NodeDetailsHealthOverflow items={overflowMetrics}
handleClick={() => this.handleClickMore()} />}
</div>
<ShowMore handleClick={() => this.handleClickMore()} collection={this.props.metrics}
expanded={this.state.expanded} notShown={notShown} hideNumber />
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';

import ShowMore from '../show-more';

export default class NodeDetailsInfo extends React.Component {

constructor(props, context) {
Expand All @@ -10,20 +12,17 @@ export default class NodeDetailsInfo extends React.Component {
this.handleClickMore = this.handleClickMore.bind(this);
}

handleClickMore(ev) {
ev.preventDefault();
handleClickMore() {
const expanded = !this.state.expanded;
this.setState({expanded});
}

render() {
let rows = (this.props.rows || []);
const prime = rows.filter(row => row.prime);
let expandText = 'Show less';
let showExpand = this.state.expanded;
let notShown = 0;
if (!this.state.expanded && prime.length < rows.length) {
expandText = 'Show more';
showExpand = true;
notShown = rows.length - prime.length;
rows = prime;
}
return (
Expand All @@ -40,7 +39,8 @@ export default class NodeDetailsInfo extends React.Component {
</div>
);
})}
{showExpand && <div className="node-details-info-expand" onClick={this.handleClickMore}>{expandText}</div>}
<ShowMore handleClick={() => this.handleClickMore()} collection={this.props.rows}
expanded={this.state.expanded} notShown={notShown} />
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import _ from 'lodash';
import React from 'react';

import ShowMore from '../show-more';
import NodeDetailsTableNodeLink from './node-details-table-node-link';
import NodeDetailsTableNodeMetric from './node-details-table-node-metric';

Expand All @@ -25,8 +26,7 @@ export default class NodeDetailsTable extends React.Component {
this.setState({sortBy, sortedDesc});
}

handleLimitClick(ev) {
ev.preventDefault();
handleLimitClick() {
const limit = this.state.limit ? 0 : this.DEFAULT_LIMIT;
this.setState({limit});
}
Expand Down Expand Up @@ -115,15 +115,17 @@ export default class NodeDetailsTable extends React.Component {
}
return <NodeDetailsTableNodeMetric key={field.id} {...field} />;
}
// empty cell to complete the row for proper hover
return <td className="node-details-table-node-value" key={id} />;
});
}

render() {
const headers = this.renderHeaders();
let nodes = _.sortByAll(this.props.nodes, this.getValueForSortBy, 'label', this.getMetaDataSorters());
const limited = nodes && this.state.limit > 0 && nodes.length > this.state.limit;
const showLimitAction = nodes && (limited || (this.state.limit === 0 && nodes.length > this.DEFAULT_LIMIT));
const limitActionText = limited ? 'Show more' : 'Show less';
const expanded = this.state.limit === 0;
const notShown = nodes.length - this.DEFAULT_LIMIT;
if (this.state.sortedDesc) {
nodes.reverse();
}
Expand Down Expand Up @@ -151,7 +153,7 @@ export default class NodeDetailsTable extends React.Component {
})}
</tbody>
</table>
{showLimitAction && <div className="node-details-table-more" onClick={this.handleLimitClick}>{limitActionText}</div>}
<ShowMore handleClick={() => this.handleLimitClick()} collection={this.props.nodes} expanded={expanded} notShown={notShown} />
</div>
);
}
Expand Down
30 changes: 30 additions & 0 deletions client/app/scripts/components/show-more.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';

export default class ShowMore extends React.Component {

constructor(props, context) {
super(props, context);
this.handleClick = this.handleClick.bind(this);
}

handleClick(ev) {
ev.preventDefault();
this.props.handleClick();
}

render() {
const { collection, notShown, expanded, hideNumber } = this.props;
const showLimitAction = collection && (expanded || notShown > 0);
const limitActionText = !hideNumber && !expanded && notShown > 0 ? `+${notShown}` : '';
const limitActionIcon = !expanded && notShown > 0 ? 'fa fa-caret-down' : 'fa fa-caret-up';

if (!showLimitAction) {
return <span/>;
}
return (
<div className="show-more" onClick={this.handleClick}>
{limitActionText} <span className={'show-more-icon ' + limitActionIcon}/>
</div>
);
}
}
89 changes: 33 additions & 56 deletions client/app/styles/main.less
Original file line number Diff line number Diff line change
Expand Up @@ -546,10 +546,6 @@ h2 {
padding: 0 36px 0 36px;
overflow-y: auto;

&-info {
margin-top: 16px;
}

&-loading {
margin-top: 48px;
text-align: center;
Expand All @@ -570,46 +566,27 @@ h2 {
}

&-health {
display: flex;
justify-content: space-around;
align-content: center;
text-align: center;

&-expand {
.btn-opacity;
margin: 4px 16px 0;
border-top: 1px solid @border-light-color;
text-transform: uppercase;
font-size: 80%;
color: @text-secondary-color;
width: 100%;
cursor: pointer;
opacity: @link-opacity-default;
&-wrapper {
display: flex;
justify-content: space-around;
align-content: center;
text-align: center;
flex-wrap: wrap;
}

&-overflow {
.btn-opacity;
flex-basis: 33%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
border-left: 1px solid @border-light-color;
opacity: 0.85;
cursor: pointer;
position: relative;
padding-bottom: 16px;

&-expand {
text-transform: uppercase;
font-size: 70%;
color: @text-secondary-color;
position: absolute;
bottom: -2px;
left: 0;
right: 0;
font-weight: bold;
}

&-item {
padding: 4px 8px;
line-height: 1.2;
Expand Down Expand Up @@ -647,18 +624,6 @@ h2 {
}

&-info {
margin: 16px 0;

&-expand {
.btn-opacity;
text-align: center;
text-transform: uppercase;
font-size: 80%;
cursor: pointer;
color: @text-secondary-color;
padding: 2px 0;
font-weight: bold;
}

&-field {
display: flex;
Expand Down Expand Up @@ -724,7 +689,7 @@ h2 {
table-layout: fixed;

&-wrapper {
margin: 24px 0;
margin: 24px -4px;
}

&-header {
Expand All @@ -733,7 +698,7 @@ h2 {
font-size: 90%;
text-align: right;
cursor: pointer;
padding: 0;
padding: 0 4px;

&-sorted {
color: @text-secondary-color;
Expand All @@ -749,23 +714,16 @@ h2 {
}
}

&-more {
.btn-opacity;
padding: 2px 0;
text-align: center;
text-transform: uppercase;
cursor: pointer;
color: @text-secondary-color;
font-size: 80%;
font-weight: bold;
}

&-node {
font-size: 105%;
line-height: 1.5;

&:hover {
background-color: lighten(@background-color, 5%);
}

> * {
padding: 0;
padding: 0 4px;
}

&-link {
Expand Down Expand Up @@ -932,6 +890,25 @@ h2 {
}
}

.show-more {
.btn-opacity;
border-top: 1px dotted @border-light-color;
padding: 0px 0;
margin-top: 4px;
text-align: right;
text-transform: uppercase;
cursor: pointer;
color: @text-secondary-color;
font-size: 90%;

&-icon {
color: @text-tertiary-color;
font-size: 120%;
position: relative;
top: 1px;
}
}

.status {
text-transform: uppercase;

Expand Down