diff --git a/client/app/scripts/components/node-details/node-details-health-overflow.js b/client/app/scripts/components/node-details/node-details-health-overflow.js index 32624d631e..45e2c3c4ec 100644 --- a/client/app/scripts/components/node-details/node-details-health-overflow.js +++ b/client/app/scripts/components/node-details/node-details-health-overflow.js @@ -7,11 +7,8 @@ export default class NodeDetailsHealthOverflow extends React.Component { const items = this.props.items.slice(0, 4); return ( -
+
{items.map(item => )} -
- Show more -
); } diff --git a/client/app/scripts/components/node-details/node-details-health.js b/client/app/scripts/components/node-details/node-details-health.js index cb7cf1d4db..d389a653af 100644 --- a/client/app/scripts/components/node-details/node-details-health.js +++ b/client/app/scripts/components/node-details/node-details-health.js @@ -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'; @@ -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}); } @@ -25,17 +25,20 @@ 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 (
- {primeMetrics.map(item => { - return ; - })} - {showOverflow && } - {showLess &&
show less
} +
+ {primeMetrics.map(item => { + return ; + })} + {showOverflow && } +
+ this.handleClickMore()} collection={this.props.metrics} + expanded={this.state.expanded} notShown={notShown} hideNumber />
); } diff --git a/client/app/scripts/components/node-details/node-details-info.js b/client/app/scripts/components/node-details/node-details-info.js index 6df895cded..cf85a58d2f 100644 --- a/client/app/scripts/components/node-details/node-details-info.js +++ b/client/app/scripts/components/node-details/node-details-info.js @@ -1,5 +1,7 @@ import React from 'react'; +import ShowMore from '../show-more'; + export default class NodeDetailsInfo extends React.Component { constructor(props, context) { @@ -10,8 +12,7 @@ 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}); } @@ -19,11 +20,9 @@ export default class NodeDetailsInfo extends React.Component { 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 ( @@ -40,7 +39,8 @@ export default class NodeDetailsInfo extends React.Component {
); })} - {showExpand &&
{expandText}
} + this.handleClickMore()} collection={this.props.rows} + expanded={this.state.expanded} notShown={notShown} /> ); } diff --git a/client/app/scripts/components/node-details/node-details-table.js b/client/app/scripts/components/node-details/node-details-table.js index 7164d471b9..0d18772194 100644 --- a/client/app/scripts/components/node-details/node-details-table.js +++ b/client/app/scripts/components/node-details/node-details-table.js @@ -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'; @@ -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}); } @@ -122,8 +122,8 @@ export default class NodeDetailsTable extends React.Component { 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(); } @@ -151,7 +151,7 @@ export default class NodeDetailsTable extends React.Component { })} - {showLimitAction &&
{limitActionText}
} + this.handleLimitClick()} collection={this.props.nodes} expanded={expanded} notShown={notShown} /> ); } diff --git a/client/app/scripts/components/show-more.js b/client/app/scripts/components/show-more.js new file mode 100644 index 0000000000..8da206f33a --- /dev/null +++ b/client/app/scripts/components/show-more.js @@ -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 ; + } + return ( +
+ {limitActionText} +
+ ); + } +} diff --git a/client/app/styles/main.less b/client/app/styles/main.less index 8ca23f6637..68013cd1ad 100644 --- a/client/app/styles/main.less +++ b/client/app/styles/main.less @@ -570,46 +570,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; @@ -649,17 +630,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; align-items: baseline; @@ -749,21 +719,14 @@ 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; } @@ -932,6 +895,25 @@ h2 { } } +.show-more { + .btn-opacity; + border-top: 1px solid lighten(@text-tertiary-color, 30%); + 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;