Skip to content

Commit

Permalink
Merge e7c30bb into 87f0e55
Browse files Browse the repository at this point in the history
  • Loading branch information
ZitaNemeckova committed Feb 19, 2018
2 parents 87f0e55 + e7c30bb commit 8b28df5
Show file tree
Hide file tree
Showing 7 changed files with 368 additions and 0 deletions.
10 changes: 10 additions & 0 deletions sass/patternfly-react/_patternfly-react.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/**
Patternfly React Partials
*/
.label-strong {
font-weight: 600;
}
.display-inline-block {
display: inline-block;
}
.label-text {
font-size: 12px !important;
color: black;
}
145 changes: 145 additions & 0 deletions src/components/UtilizationBar/UtilizationBar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { ProgressBar } from '../ProgressBar';
import ClassNames from 'classnames';
import PropTypes from 'prop-types';
import { OverlayTrigger } from '../OverlayTrigger';
import { Tooltip } from '../Tooltip';
import React from 'react';

const randomId = () => {
return Date.now();
};

const AvailableTooltipFunction = (max, now) => {
return <Tooltip id={randomId()}>Available {max - now} %</Tooltip>;
};

const UsedTooltipFunction = now => {
return <Tooltip id={randomId()}>Used {now} %</Tooltip>;
};

const UtilizationBar = props => {
const barStyle = () => {
if (props.thresholdWarning && props.thresholdError) {
let style = 'success';
if (props.thresholdWarning <= props.now) {
style = 'warning';
}
if (props.thresholdError <= props.now) {
style = 'danger';
}
return style;
} else {
return null;
}
};

const labelClasses = top => {
return ClassNames(
{ 'progress-label-top-right': top, 'progress-label-right': !top },
'pull-right',
'label-text',
'display-inline-block'
);
};

const mainDivClasses = (onSide, mainDivClasses) => {
return ClassNames({
'progress-container': onSide && props.description,
'progress-description-left': onSide && props.description,
'progress-label-right': onSide && props.label,
mainDivClasses: mainDivClasses
});
};

return (
<div
className={mainDivClasses(
!props.descriptionPlacementTop,
props.mainDivClasses
)}
>
<div className={props.descriptionPlacementTop ? null : 'progress-bar'}>
{props.label && (
<span className={labelClasses(props.descriptionPlacementTop)}>
<strong className="label-strong label-text">
{props.now + ' of ' + props.max}
</strong>{' '}
{props.label}
</span>
)}
{props.description && (
<div className="progress-description label-text">
{props.description}
</div>
)}
</div>
<div className="progress">
<OverlayTrigger
overlay={props.usedTooltipFunction(props.now)}
placement="top"
trigger={['hover', 'focus']}
rootClose={false}
>
<ProgressBar
bsStyle={barStyle()}
min={props.min}
max={props.max}
now={props.now}
key={1}
isChild
/>
</OverlayTrigger>
<OverlayTrigger
overlay={props.availableTooltipFunction(props.max, props.now)}
placement="top"
trigger={['hover', 'focus']}
rootClose={false}
>
<ProgressBar
min={props.min}
max={props.max}
now={props.max - props.now}
key={2}
bsClass="progress-bar progress-bar-remaining"
isChild
/>
</OverlayTrigger>
</div>
</div>
);
};

UtilizationBar.propTypes = {
/** Minimal value */
min: PropTypes.number,
/** Maximal value */
max: PropTypes.number,
/** Current value */
now: PropTypes.number.isRequired,
/** Threshold value. Bar will change value to orange if it's surpassed. */
thresholdWarning: PropTypes.number,
/** Threshold value. Bar will change value to red if it's surpassed. */
thresholdError: PropTypes.number,
/** Function that renders tooltip for available part of bar. */
availableTooltipFunction: PropTypes.func,
/** Function that renders tooltip for used part of bar. */
usedTooltipFunction: PropTypes.func,
/** Classes for main div */
mainDivClasses: PropTypes.string,
/** Description that is displayed on the right side */
description: PropTypes.string,
/** Units */
label: PropTypes.string,
/** If set labels will be placed above utilization bar */
descriptionPlacementTop: PropTypes.bool
};

UtilizationBar.defaultProps = {
min: 0,
max: 100,
availableTooltipFunction: AvailableTooltipFunction,
usedTooltipFunction: UsedTooltipFunction,
descriptionPlacementTop: false
};

export default UtilizationBar;
31 changes: 31 additions & 0 deletions src/components/UtilizationBar/UtilizationBar.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import { defaultTemplate } from '../../../storybook/decorators/storyTemplates';
import { withKnobs, number, boolean, text } from '@storybook/addon-knobs';
import { UtilizationBar } from './index';

const stories = storiesOf('UtilizationBar', module);
stories.addDecorator(withKnobs);
stories.addDecorator(
defaultTemplate({
title: 'Utilization Bar',
documentationLink:
'http://www.patternfly.org/pattern-library/cards/utilization-bar-card/'
})
);

stories.addWithInfo('Utilization Bar', 'Utilization Bar', () => (
<div>
<h1>Utilization bar</h1>
<UtilizationBar
now={number('Actual value', 70)}
min={number('Minimal value', 0)}
max={number('Maximal value', 100)}
thresholdWarning={number('Warning threshold value', 40)}
thresholdError={number('Error threshold value', 80)}
description={text('Description', 'Label')}
label={text('Label', '%')}
descriptionPlacementTop={boolean('Description placement', false)}
/>
</div>
));
35 changes: 35 additions & 0 deletions src/components/UtilizationBar/UtilizationBar.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* eslint-env jest */

import React from 'react';
import renderer from 'react-test-renderer';

import UtilizationBar from './UtilizationBar';

test('basic UtilizationBar renders properly', () => {
const component = renderer.create(<UtilizationBar now={60} />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

test('UtilizationBar with custom tooltips renders properly', () => {
const overriddenTooltip = () => {
return <strong>This tooltip is overridden.</strong>;
};
const component = renderer.create(
<UtilizationBar
now={60}
availableTooltipFunction={overriddenTooltip}
usedTooltipFunction={overriddenTooltip}
/>
);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

test('UtilizationBar with thresholds renders properly', () => {
const component = renderer.create(
<UtilizationBar now={60} thresholdWarning={10} thresholdError={40} />
);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`UtilizationBar with custom tooltips renders properly 1`] = `
<div
className=""
>
<div
className="progress-bar"
/>
<div
className="progress"
>
<div
aria-valuemax={100}
aria-valuemin={0}
aria-valuenow={60}
className="progress-bar"
onBlur={[Function]}
onClick={null}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
role="progressbar"
style={
Object {
"width": "60%",
}
}
/>
<div
aria-valuemax={100}
aria-valuemin={0}
aria-valuenow={40}
className="progress-bar progress-bar-remaining"
onBlur={[Function]}
onClick={null}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
role="progressbar"
style={
Object {
"width": "40%",
}
}
/>
</div>
</div>
`;

exports[`UtilizationBar with thresholds renders properly 1`] = `
<div
className=""
>
<div
className="progress-bar"
/>
<div
className="progress"
>
<div
aria-valuemax={100}
aria-valuemin={0}
aria-valuenow={60}
className="progress-bar progress-bar-danger"
onBlur={[Function]}
onClick={null}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
role="progressbar"
style={
Object {
"width": "60%",
}
}
/>
<div
aria-valuemax={100}
aria-valuemin={0}
aria-valuenow={40}
className="progress-bar progress-bar-remaining"
onBlur={[Function]}
onClick={null}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
role="progressbar"
style={
Object {
"width": "40%",
}
}
/>
</div>
</div>
`;

exports[`basic UtilizationBar renders properly 1`] = `
<div
className=""
>
<div
className="progress-bar"
/>
<div
className="progress"
>
<div
aria-valuemax={100}
aria-valuemin={0}
aria-valuenow={60}
className="progress-bar"
onBlur={[Function]}
onClick={null}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
role="progressbar"
style={
Object {
"width": "60%",
}
}
/>
<div
aria-valuemax={100}
aria-valuemin={0}
aria-valuenow={40}
className="progress-bar progress-bar-remaining"
onBlur={[Function]}
onClick={null}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
role="progressbar"
style={
Object {
"width": "40%",
}
}
/>
</div>
</div>
`;
1 change: 1 addition & 0 deletions src/components/UtilizationBar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as UtilizationBar } from './UtilizationBar';
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export * from './components/ToastNotification';
export * from './components/Toolbar';
export * from './components/Tooltip';
export * from './components/TreeView';
export * from './components/UtilizationBar';
export * from './components/Wizard';
export * from './components/VerticalNav';
export { patternfly } from './common/patternfly';
Expand Down

0 comments on commit 8b28df5

Please sign in to comment.