mirror of https://github.com/grafana/grafana
commit
ad9c96abb5
@ -1,6 +1,6 @@ |
||||
import React from 'react'; |
||||
import renderer from 'react-test-renderer'; |
||||
import { ColorPalette } from '../components/colorpicker/ColorPalette'; |
||||
import { ColorPalette } from './ColorPalette'; |
||||
|
||||
describe('CollorPalette', () => { |
||||
it('renders correctly', () => { |
@ -0,0 +1,11 @@ |
||||
import React, { SFC } from 'react'; |
||||
|
||||
interface LoadingPlaceholderProps { |
||||
text: string; |
||||
} |
||||
|
||||
export const LoadingPlaceholder: SFC<LoadingPlaceholderProps> = ({ text }) => ( |
||||
<div className="gf-form-group"> |
||||
{text} <i className="fa fa-spinner fa-spin" /> |
||||
</div> |
||||
); |
@ -0,0 +1,15 @@ |
||||
import React, { SFC } from 'react'; |
||||
|
||||
interface Props { |
||||
cols?: number; |
||||
children: JSX.Element[] | JSX.Element; |
||||
} |
||||
|
||||
export const PanelOptionsGrid: SFC<Props> = ({ children }) => { |
||||
|
||||
return ( |
||||
<div className="panel-options-grid"> |
||||
{children} |
||||
</div> |
||||
); |
||||
}; |
@ -0,0 +1,10 @@ |
||||
.panel-options-grid { |
||||
display: grid; |
||||
grid-template-columns: repeat(1, 1fr); |
||||
grid-row-gap: 10px; |
||||
grid-column-gap: 10px; |
||||
|
||||
@include media-breakpoint-up(lg) { |
||||
grid-template-columns: repeat(3, 1fr); |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
.panel-options-group { |
||||
margin-bottom: 10px; |
||||
border: $panel-options-group-border; |
||||
border-radius: $border-radius; |
||||
background: $page-bg; |
||||
} |
||||
|
||||
.panel-options-group__header { |
||||
padding: 4px 20px; |
||||
font-size: 1.1rem; |
||||
background: $panel-options-group-header-bg; |
||||
position: relative; |
||||
|
||||
.btn { |
||||
position: absolute; |
||||
right: 0; |
||||
top: 0px; |
||||
} |
||||
} |
||||
|
||||
.panel-options-group__body { |
||||
padding: 20px; |
||||
|
||||
&--queries { |
||||
min-height: 200px; |
||||
} |
||||
} |
@ -1,7 +1,10 @@ |
||||
import React from 'react'; |
||||
|
||||
// Ignoring because I couldn't get @types/react-select work wih Torkel's fork
|
||||
// @ts-ignore
|
||||
import { components } from '@torkelo/react-select'; |
||||
|
||||
export const IndicatorsContainer = props => { |
||||
export const IndicatorsContainer = (props: any) => { |
||||
const isOpen = props.selectProps.menuIsOpen; |
||||
return ( |
||||
<components.IndicatorsContainer {...props}> |
@ -1,5 +1,9 @@ |
||||
import React from 'react'; |
||||
|
||||
// Ignoring because I couldn't get @types/react-select work wih Torkel's fork
|
||||
// @ts-ignore
|
||||
import { components } from '@torkelo/react-select'; |
||||
// @ts-ignore
|
||||
import { OptionProps } from '@torkelo/react-select/lib/components/Option'; |
||||
|
||||
export interface Props { |
@ -1,7 +1,12 @@ |
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
||||
exports[`PickerOption renders correctly 1`] = ` |
||||
<div> |
||||
exports[`SelectOption renders correctly 1`] = ` |
||||
<div |
||||
id="" |
||||
onClick={[MockFunction]} |
||||
onMouseOver={[MockFunction]} |
||||
tabIndex={1} |
||||
> |
||||
<div |
||||
className="gf-form-select-box__desc-option" |
||||
> |
@ -0,0 +1,27 @@ |
||||
export default function resetSelectStyles() { |
||||
return { |
||||
clearIndicator: () => ({}), |
||||
container: () => ({}), |
||||
control: () => ({}), |
||||
dropdownIndicator: () => ({}), |
||||
group: () => ({}), |
||||
groupHeading: () => ({}), |
||||
indicatorsContainer: () => ({}), |
||||
indicatorSeparator: () => ({}), |
||||
input: () => ({}), |
||||
loadingIndicator: () => ({}), |
||||
loadingMessage: () => ({}), |
||||
menu: () => ({}), |
||||
menuList: ({ maxHeight }: { maxHeight: number }) => ({ |
||||
maxHeight, |
||||
}), |
||||
multiValue: () => ({}), |
||||
multiValueLabel: () => ({}), |
||||
multiValueRemove: () => ({}), |
||||
noOptionsMessage: () => ({}), |
||||
option: () => ({}), |
||||
placeholder: () => ({}), |
||||
singleValue: () => ({}), |
||||
valueContainer: () => ({}), |
||||
}; |
||||
} |
@ -0,0 +1,99 @@ |
||||
import React from 'react'; |
||||
import * as PopperJS from 'popper.js'; |
||||
import { Themes } from './Popper'; |
||||
|
||||
type PopperContent = string | (() => JSX.Element); |
||||
|
||||
export interface UsingPopperProps { |
||||
show?: boolean; |
||||
placement?: PopperJS.Placement; |
||||
content: PopperContent; |
||||
children: JSX.Element; |
||||
renderContent?: (content: PopperContent) => JSX.Element; |
||||
theme?: Themes; |
||||
} |
||||
|
||||
type PopperControllerRenderProp = ( |
||||
showPopper: () => void, |
||||
hidePopper: () => void, |
||||
popperProps: { |
||||
show: boolean; |
||||
placement: PopperJS.Placement; |
||||
content: string | ((props: any) => JSX.Element); |
||||
renderContent: (content: any) => any; |
||||
theme?: Themes; |
||||
} |
||||
) => JSX.Element; |
||||
|
||||
interface Props { |
||||
placement?: PopperJS.Placement; |
||||
content: PopperContent; |
||||
className?: string; |
||||
children: PopperControllerRenderProp; |
||||
theme?: Themes; |
||||
} |
||||
|
||||
interface State { |
||||
placement: PopperJS.Placement; |
||||
show: boolean; |
||||
} |
||||
|
||||
class PopperController extends React.Component<Props, State> { |
||||
constructor(props: Props) { |
||||
super(props); |
||||
|
||||
this.state = { |
||||
placement: this.props.placement || 'auto', |
||||
show: false, |
||||
}; |
||||
} |
||||
|
||||
componentWillReceiveProps(nextProps: Props) { |
||||
if (nextProps.placement && nextProps.placement !== this.state.placement) { |
||||
this.setState((prevState: State) => { |
||||
return { |
||||
...prevState, |
||||
placement: nextProps.placement || 'auto', |
||||
}; |
||||
}); |
||||
} |
||||
} |
||||
|
||||
showPopper = () => { |
||||
this.setState(prevState => ({ |
||||
...prevState, |
||||
show: true, |
||||
})); |
||||
}; |
||||
|
||||
hidePopper = () => { |
||||
this.setState(prevState => ({ |
||||
...prevState, |
||||
show: false, |
||||
})); |
||||
}; |
||||
|
||||
renderContent(content: PopperContent) { |
||||
if (typeof content === 'function') { |
||||
// If it's a function we assume it's a React component
|
||||
const ReactComponent = content; |
||||
return <ReactComponent />; |
||||
} |
||||
return content; |
||||
} |
||||
|
||||
render() { |
||||
const { children, content, theme } = this.props; |
||||
const { show, placement } = this.state; |
||||
|
||||
return children(this.showPopper, this.hidePopper, { |
||||
show, |
||||
placement, |
||||
content, |
||||
renderContent: this.renderContent, |
||||
theme, |
||||
}); |
||||
} |
||||
} |
||||
|
||||
export default PopperController; |
@ -0,0 +1,12 @@ |
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
||||
exports[`Tooltip renders correctly 1`] = ` |
||||
<a |
||||
className="test-class" |
||||
href="http://www.grafana.com" |
||||
onMouseEnter={[Function]} |
||||
onMouseLeave={[Function]} |
||||
> |
||||
Link with tooltip |
||||
</a> |
||||
`; |
@ -1 +1,7 @@ |
||||
@import 'CustomScrollbar/CustomScrollbar'; |
||||
@import 'DeleteButton/DeleteButton'; |
||||
@import 'ThresholdsEditor/ThresholdsEditor'; |
||||
@import 'Tooltip/Tooltip'; |
||||
@import 'Select/Select'; |
||||
@import 'PanelOptionsGroup/PanelOptionsGroup'; |
||||
@import 'PanelOptionsGrid/PanelOptionsGrid'; |
||||
|
@ -1 +1,20 @@ |
||||
export { DeleteButton } from './DeleteButton/DeleteButton'; |
||||
export { Tooltip } from './Tooltip/Tooltip'; |
||||
export { Portal } from './Portal/Portal'; |
||||
export { CustomScrollbar } from './CustomScrollbar/CustomScrollbar'; |
||||
|
||||
// Select
|
||||
export { Select, AsyncSelect, SelectOptionItem } from './Select/Select'; |
||||
export { IndicatorsContainer } from './Select/IndicatorsContainer'; |
||||
export { NoOptionsMessage } from './Select/NoOptionsMessage'; |
||||
export { default as resetSelectStyles } from './Select/resetSelectStyles'; |
||||
|
||||
export { LoadingPlaceholder } from './LoadingPlaceholder/LoadingPlaceholder'; |
||||
export { ColorPicker } from './ColorPicker/ColorPicker'; |
||||
export { SeriesColorPickerPopover } from './ColorPicker/SeriesColorPickerPopover'; |
||||
export { SeriesColorPicker } from './ColorPicker/SeriesColorPicker'; |
||||
export { ThresholdsEditor } from './ThresholdsEditor/ThresholdsEditor'; |
||||
export { GfFormLabel } from './GfFormLabel/GfFormLabel'; |
||||
export { Graph } from './Graph/Graph'; |
||||
export { PanelOptionsGroup } from './PanelOptionsGroup/PanelOptionsGroup'; |
||||
export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid'; |
||||
|
@ -1 +0,0 @@ |
||||
export { GfFormLabel } from './GfFormLabel/GfFormLabel'; |
@ -0,0 +1,16 @@ |
||||
import { RangeMap, Threshold, ValueMap } from './panel'; |
||||
|
||||
export interface GaugeOptions { |
||||
baseColor: string; |
||||
decimals: number; |
||||
mappings: Array<RangeMap | ValueMap>; |
||||
maxValue: number; |
||||
minValue: number; |
||||
prefix: string; |
||||
showThresholdLabels: boolean; |
||||
showThresholdMarkers: boolean; |
||||
stat: string; |
||||
suffix: string; |
||||
thresholds: Threshold[]; |
||||
unit: string; |
||||
} |
@ -1,3 +1,4 @@ |
||||
export * from './series'; |
||||
export * from './time'; |
||||
export * from './panel'; |
||||
export * from './gauge'; |
||||
|
@ -0,0 +1,93 @@ |
||||
import _ from 'lodash'; |
||||
import tinycolor from 'tinycolor2'; |
||||
|
||||
export const PALETTE_ROWS = 4; |
||||
export const PALETTE_COLUMNS = 14; |
||||
export const DEFAULT_ANNOTATION_COLOR = 'rgba(0, 211, 255, 1)'; |
||||
export const OK_COLOR = 'rgba(11, 237, 50, 1)'; |
||||
export const ALERTING_COLOR = 'rgba(237, 46, 24, 1)'; |
||||
export const NO_DATA_COLOR = 'rgba(150, 150, 150, 1)'; |
||||
export const PENDING_COLOR = 'rgba(247, 149, 32, 1)'; |
||||
export const REGION_FILL_ALPHA = 0.09; |
||||
|
||||
export const colors = [ |
||||
'#7EB26D', // 0: pale green
|
||||
'#EAB839', // 1: mustard
|
||||
'#6ED0E0', // 2: light blue
|
||||
'#EF843C', // 3: orange
|
||||
'#E24D42', // 4: red
|
||||
'#1F78C1', // 5: ocean
|
||||
'#BA43A9', // 6: purple
|
||||
'#705DA0', // 7: violet
|
||||
'#508642', // 8: dark green
|
||||
'#CCA300', // 9: dark sand
|
||||
'#447EBC', |
||||
'#C15C17', |
||||
'#890F02', |
||||
'#0A437C', |
||||
'#6D1F62', |
||||
'#584477', |
||||
'#B7DBAB', |
||||
'#F4D598', |
||||
'#70DBED', |
||||
'#F9BA8F', |
||||
'#F29191', |
||||
'#82B5D8', |
||||
'#E5A8E2', |
||||
'#AEA2E0', |
||||
'#629E51', |
||||
'#E5AC0E', |
||||
'#64B0C8', |
||||
'#E0752D', |
||||
'#BF1B00', |
||||
'#0A50A1', |
||||
'#962D82', |
||||
'#614D93', |
||||
'#9AC48A', |
||||
'#F2C96D', |
||||
'#65C5DB', |
||||
'#F9934E', |
||||
'#EA6460', |
||||
'#5195CE', |
||||
'#D683CE', |
||||
'#806EB7', |
||||
'#3F6833', |
||||
'#967302', |
||||
'#2F575E', |
||||
'#99440A', |
||||
'#58140C', |
||||
'#052B51', |
||||
'#511749', |
||||
'#3F2B5B', |
||||
'#E0F9D7', |
||||
'#FCEACA', |
||||
'#CFFAFF', |
||||
'#F9E2D2', |
||||
'#FCE2DE', |
||||
'#BADFF4', |
||||
'#F9D9F9', |
||||
'#DEDAF7', |
||||
]; |
||||
|
||||
function sortColorsByHue(hexColors: string[]) { |
||||
const hslColors = _.map(hexColors, hexToHsl); |
||||
|
||||
const sortedHSLColors = _.sortBy(hslColors, ['h']); |
||||
const chunkedHSLColors = _.chunk(sortedHSLColors, PALETTE_ROWS); |
||||
const sortedChunkedHSLColors = _.map(chunkedHSLColors, chunk => { |
||||
return _.sortBy(chunk, 'l'); |
||||
}); |
||||
const flattenedZippedSortedChunkedHSLColors = _.flattenDeep(_.zip(...sortedChunkedHSLColors)); |
||||
|
||||
return _.map(flattenedZippedSortedChunkedHSLColors, hslToHex); |
||||
} |
||||
|
||||
function hexToHsl(color: string) { |
||||
return tinycolor(color).toHsl(); |
||||
} |
||||
|
||||
function hslToHex(color: any) { |
||||
return tinycolor(color).toHexString(); |
||||
} |
||||
|
||||
export let sortedColors = sortColorsByHue(colors); |
@ -1 +1,3 @@ |
||||
export * from './processTimeSeries'; |
||||
export * from './valueFormats/valueFormats'; |
||||
export * from './colors'; |
||||
|
@ -0,0 +1,40 @@ |
||||
import { toHex, toHex0x } from './arithmeticFormatters'; |
||||
|
||||
describe('hex', () => { |
||||
it('positive integer', () => { |
||||
const str = toHex(100, 0); |
||||
expect(str).toBe('64'); |
||||
}); |
||||
it('negative integer', () => { |
||||
const str = toHex(-100, 0); |
||||
expect(str).toBe('-64'); |
||||
}); |
||||
it('positive float', () => { |
||||
const str = toHex(50.52, 1); |
||||
expect(str).toBe('32.8'); |
||||
}); |
||||
it('negative float', () => { |
||||
const str = toHex(-50.333, 2); |
||||
expect(str).toBe('-32.547AE147AE14'); |
||||
}); |
||||
}); |
||||
|
||||
describe('hex 0x', () => { |
||||
it('positive integeter', () => { |
||||
const str = toHex0x(7999, 0); |
||||
expect(str).toBe('0x1F3F'); |
||||
}); |
||||
it('negative integer', () => { |
||||
const str = toHex0x(-584, 0); |
||||
expect(str).toBe('-0x248'); |
||||
}); |
||||
|
||||
it('positive float', () => { |
||||
const str = toHex0x(74.443, 3); |
||||
expect(str).toBe('0x4A.716872B020C4'); |
||||
}); |
||||
it('negative float', () => { |
||||
const str = toHex0x(-65.458, 1); |
||||
expect(str).toBe('-0x41.8'); |
||||
}); |
||||
}); |
@ -0,0 +1,42 @@ |
||||
import { toFixed } from './valueFormats'; |
||||
|
||||
export function toPercent(size: number, decimals: number) { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
return toFixed(size, decimals) + '%'; |
||||
} |
||||
|
||||
export function toPercentUnit(size: number, decimals: number) { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
return toFixed(100 * size, decimals) + '%'; |
||||
} |
||||
|
||||
export function toHex0x(value: number, decimals: number) { |
||||
if (value == null) { |
||||
return ''; |
||||
} |
||||
const hexString = toHex(value, decimals); |
||||
if (hexString.substring(0, 1) === '-') { |
||||
return '-0x' + hexString.substring(1); |
||||
} |
||||
return '0x' + hexString; |
||||
} |
||||
|
||||
export function toHex(value: number, decimals: number) { |
||||
if (value == null) { |
||||
return ''; |
||||
} |
||||
return parseFloat(toFixed(value, decimals)) |
||||
.toString(16) |
||||
.toUpperCase(); |
||||
} |
||||
|
||||
export function sci(value: number, decimals: number) { |
||||
if (value == null) { |
||||
return ''; |
||||
} |
||||
return value.toExponential(decimals); |
||||
} |
@ -0,0 +1,322 @@ |
||||
import { locale, scaledUnits, simpleCountUnit, toFixed, toFixedUnit, ValueFormatCategory } from './valueFormats'; |
||||
import { |
||||
dateTimeAsIso, |
||||
dateTimeAsUS, |
||||
dateTimeFromNow, |
||||
toClockMilliseconds, |
||||
toClockSeconds, |
||||
toDays, |
||||
toDurationInHoursMinutesSeconds, |
||||
toDurationInMilliseconds, |
||||
toDurationInSeconds, |
||||
toHours, |
||||
toMicroSeconds, |
||||
toMilliSeconds, |
||||
toMinutes, |
||||
toNanoSeconds, |
||||
toSeconds, |
||||
toTimeTicks, |
||||
} from './dateTimeFormatters'; |
||||
import { toHex, sci, toHex0x, toPercent, toPercentUnit } from './arithmeticFormatters'; |
||||
import { binarySIPrefix, currency, decimalSIPrefix } from './symbolFormatters'; |
||||
|
||||
export const getCategories = (): ValueFormatCategory[] => [ |
||||
{ |
||||
name: 'Misc', |
||||
formats: [ |
||||
{ name: 'none', id: 'none', fn: toFixed }, |
||||
{ |
||||
name: 'short', |
||||
id: 'short', |
||||
fn: scaledUnits(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Quadr', ' Quint', ' Sext', ' Sept']), |
||||
}, |
||||
{ name: 'percent (0-100)', id: 'percent', fn: toPercent }, |
||||
{ name: 'percent (0.0-1.0)', id: 'percentunit', fn: toPercentUnit }, |
||||
{ name: 'Humidity (%H)', id: 'humidity', fn: toFixedUnit('%H') }, |
||||
{ name: 'decibel', id: 'dB', fn: toFixedUnit('dB') }, |
||||
{ name: 'hexadecimal (0x)', id: 'hex0x', fn: toHex0x }, |
||||
{ name: 'hexadecimal', id: 'hex', fn: toHex }, |
||||
{ name: 'scientific notation', id: 'sci', fn: sci }, |
||||
{ name: 'locale format', id: 'locale', fn: locale }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Acceleration', |
||||
formats: [ |
||||
{ name: 'Meters/sec²', id: 'accMS2', fn: toFixedUnit('m/sec²') }, |
||||
{ name: 'Feet/sec²', id: 'accFS2', fn: toFixedUnit('f/sec²') }, |
||||
{ name: 'G unit', id: 'accG', fn: toFixedUnit('g') }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Angle', |
||||
formats: [ |
||||
{ name: 'Degrees (°)', id: 'degree', fn: toFixedUnit('°') }, |
||||
{ name: 'Radians', id: 'radian', fn: toFixedUnit('rad') }, |
||||
{ name: 'Gradian', id: 'grad', fn: toFixedUnit('grad') }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Area', |
||||
formats: [ |
||||
{ name: 'Square Meters (m²)', id: 'areaM2', fn: toFixedUnit('m²') }, |
||||
{ name: 'Square Feet (ft²)', id: 'areaF2', fn: toFixedUnit('ft²') }, |
||||
{ name: 'Square Miles (mi²)', id: 'areaMI2', fn: toFixedUnit('mi²') }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Computation', |
||||
formats: [ |
||||
{ name: 'FLOP/s', id: 'flops', fn: decimalSIPrefix('FLOP/s') }, |
||||
{ name: 'MFLOP/s', id: 'mflops', fn: decimalSIPrefix('FLOP/s', 2) }, |
||||
{ name: 'GFLOP/s', id: 'gflops', fn: decimalSIPrefix('FLOP/s', 3) }, |
||||
{ name: 'TFLOP/s', id: 'tflops', fn: decimalSIPrefix('FLOP/s', 4) }, |
||||
{ name: 'PFLOP/s', id: 'pflops', fn: decimalSIPrefix('FLOP/s', 5) }, |
||||
{ name: 'EFLOP/s', id: 'eflops', fn: decimalSIPrefix('FLOP/s', 6) }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Concentration', |
||||
formats: [ |
||||
{ name: 'parts-per-million (ppm)', id: 'ppm', fn: toFixedUnit('ppm') }, |
||||
{ name: 'parts-per-billion (ppb)', id: 'conppb', fn: toFixedUnit('ppb') }, |
||||
{ name: 'nanogram per cubic meter (ng/m³)', id: 'conngm3', fn: toFixedUnit('ng/m³') }, |
||||
{ name: 'nanogram per normal cubic meter (ng/Nm³)', id: 'conngNm3', fn: toFixedUnit('ng/Nm³') }, |
||||
{ name: 'microgram per cubic meter (μg/m³)', id: 'conμgm3', fn: toFixedUnit('μg/m³') }, |
||||
{ name: 'microgram per normal cubic meter (μg/Nm³)', id: 'conμgNm3', fn: toFixedUnit('μg/Nm³') }, |
||||
{ name: 'milligram per cubic meter (mg/m³)', id: 'conmgm3', fn: toFixedUnit('mg/m³') }, |
||||
{ name: 'milligram per normal cubic meter (mg/Nm³)', id: 'conmgNm3', fn: toFixedUnit('mg/Nm³') }, |
||||
{ name: 'gram per cubic meter (g/m³)', id: 'congm3', fn: toFixedUnit('g/m³') }, |
||||
{ name: 'gram per normal cubic meter (g/Nm³)', id: 'congNm3', fn: toFixedUnit('g/Nm³') }, |
||||
{ name: 'milligrams per decilitre (mg/dL)', id: 'conmgdL', fn: toFixedUnit('mg/dL') }, |
||||
{ name: 'millimoles per litre (mmol/L)', id: 'conmmolL', fn: toFixedUnit('mmol/L') }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Currency', |
||||
formats: [ |
||||
{ name: 'Dollars ($)', id: 'currencyUSD', fn: currency('$') }, |
||||
{ name: 'Pounds (£)', id: 'currencyGBP', fn: currency('£') }, |
||||
{ name: 'Euro (€)', id: 'currencyEUR', fn: currency('€') }, |
||||
{ name: 'Yen (¥)', id: 'currencyJPY', fn: currency('¥') }, |
||||
{ name: 'Rubles (₽)', id: 'currencyRUB', fn: currency('₽') }, |
||||
{ name: 'Hryvnias (₴)', id: 'currencyUAH', fn: currency('₴') }, |
||||
{ name: 'Real (R$)', id: 'currencyBRL', fn: currency('R$') }, |
||||
{ name: 'Danish Krone (kr)', id: 'currencyDKK', fn: currency('kr') }, |
||||
{ name: 'Icelandic Króna (kr)', id: 'currencyISK', fn: currency('kr') }, |
||||
{ name: 'Norwegian Krone (kr)', id: 'currencyNOK', fn: currency('kr') }, |
||||
{ name: 'Swedish Krona (kr)', id: 'currencySEK', fn: currency('kr') }, |
||||
{ name: 'Czech koruna (czk)', id: 'currencyCZK', fn: currency('czk') }, |
||||
{ name: 'Swiss franc (CHF)', id: 'currencyCHF', fn: currency('CHF') }, |
||||
{ name: 'Polish Złoty (PLN)', id: 'currencyPLN', fn: currency('PLN') }, |
||||
{ name: 'Bitcoin (฿)', id: 'currencyBTC', fn: currency('฿') }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Data (IEC)', |
||||
formats: [ |
||||
{ name: 'bits', id: 'bits', fn: binarySIPrefix('b') }, |
||||
{ name: 'bytes', id: 'bytes', fn: binarySIPrefix('B') }, |
||||
{ name: 'kibibytes', id: 'kbytes', fn: binarySIPrefix('B', 1) }, |
||||
{ name: 'mebibytes', id: 'mbytes', fn: binarySIPrefix('B', 2) }, |
||||
{ name: 'gibibytes', id: 'gbytes', fn: binarySIPrefix('B', 3) }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Data (Metric)', |
||||
formats: [ |
||||
{ name: 'bits', id: 'decbits', fn: decimalSIPrefix('d') }, |
||||
{ name: 'bytes', id: 'decbytes', fn: decimalSIPrefix('B') }, |
||||
{ name: 'kilobytes', id: 'deckbytes', fn: decimalSIPrefix('B', 1) }, |
||||
{ name: 'megabytes', id: 'decmbytes', fn: decimalSIPrefix('B', 2) }, |
||||
{ name: 'gigabytes', id: 'decgbytes', fn: decimalSIPrefix('B', 3) }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Data Rate', |
||||
formats: [ |
||||
{ name: 'packets/sec', id: 'pps', fn: decimalSIPrefix('pps') }, |
||||
{ name: 'bits/sec', id: 'bps', fn: decimalSIPrefix('bps') }, |
||||
{ name: 'bytes/sec', id: 'Bps', fn: decimalSIPrefix('B/s') }, |
||||
{ name: 'kilobytes/sec', id: 'KBs', fn: decimalSIPrefix('Bs', 1) }, |
||||
{ name: 'kilobits/sec', id: 'Kbits', fn: decimalSIPrefix('bps', 1) }, |
||||
{ name: 'megabytes/sec', id: 'MBs', fn: decimalSIPrefix('Bs', 2) }, |
||||
{ name: 'megabits/sec', id: 'Mbits', fn: decimalSIPrefix('bps', 2) }, |
||||
{ name: 'gigabytes/sec', id: 'GBs', fn: decimalSIPrefix('Bs', 3) }, |
||||
{ name: 'gigabits/sec', id: 'Gbits', fn: decimalSIPrefix('bps', 3) }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Date & Time', |
||||
formats: [ |
||||
{ name: 'YYYY-MM-DD HH:mm:ss', id: 'dateTimeAsIso', fn: dateTimeAsIso }, |
||||
{ name: 'DD/MM/YYYY h:mm:ss a', id: 'dateTimeAsUS', fn: dateTimeAsUS }, |
||||
{ name: 'From Now', id: 'dateTimeFromNow', fn: dateTimeFromNow }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Energy', |
||||
formats: [ |
||||
{ name: 'Watt (W)', id: 'watt', fn: decimalSIPrefix('W') }, |
||||
{ name: 'Kilowatt (kW)', id: 'kwatt', fn: decimalSIPrefix('W', 1) }, |
||||
{ name: 'Milliwatt (mW)', id: 'mwatt', fn: decimalSIPrefix('W', -1) }, |
||||
{ name: 'Watt per square meter (W/m²)', id: 'Wm2', fn: toFixedUnit('W/m²') }, |
||||
{ name: 'Volt-ampere (VA)', id: 'voltamp', fn: decimalSIPrefix('VA') }, |
||||
{ name: 'Kilovolt-ampere (kVA)', id: 'kvoltamp', fn: decimalSIPrefix('VA', 1) }, |
||||
{ name: 'Volt-ampere reactive (var)', id: 'voltampreact', fn: decimalSIPrefix('var') }, |
||||
{ name: 'Kilovolt-ampere reactive (kvar)', id: 'kvoltampreact', fn: decimalSIPrefix('var', 1) }, |
||||
{ name: 'Watt-hour (Wh)', id: 'watth', fn: decimalSIPrefix('Wh') }, |
||||
{ name: 'Kilowatt-hour (kWh)', id: 'kwatth', fn: decimalSIPrefix('Wh', 1) }, |
||||
{ name: 'Kilowatt-min (kWm)', id: 'kwattm', fn: decimalSIPrefix('W/Min', 1) }, |
||||
{ name: 'Joule (J)', id: 'joule', fn: decimalSIPrefix('J') }, |
||||
{ name: 'Electron volt (eV)', id: 'ev', fn: decimalSIPrefix('eV') }, |
||||
{ name: 'Ampere (A)', id: 'amp', fn: decimalSIPrefix('A') }, |
||||
{ name: 'Kiloampere (kA)', id: 'kamp', fn: decimalSIPrefix('A', 1) }, |
||||
{ name: 'Milliampere (mA)', id: 'mamp', fn: decimalSIPrefix('A', -1) }, |
||||
{ name: 'Volt (V)', id: 'volt', fn: decimalSIPrefix('V') }, |
||||
{ name: 'Kilovolt (kV)', id: 'kvolt', fn: decimalSIPrefix('V', 1) }, |
||||
{ name: 'Millivolt (mV)', id: 'mvolt', fn: decimalSIPrefix('V', -1) }, |
||||
{ name: 'Decibel-milliwatt (dBm)', id: 'dBm', fn: decimalSIPrefix('dBm') }, |
||||
{ name: 'Ohm (Ω)', id: 'ohm', fn: decimalSIPrefix('Ω') }, |
||||
{ name: 'Lumens (Lm)', id: 'lumens', fn: decimalSIPrefix('Lm') }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Flow', |
||||
formats: [ |
||||
{ name: 'Gallons/min (gpm)', id: 'flowgpm', fn: toFixedUnit('gpm') }, |
||||
{ name: 'Cubic meters/sec (cms)', id: 'flowcms', fn: toFixedUnit('cms') }, |
||||
{ name: 'Cubic feet/sec (cfs)', id: 'flowcfs', fn: toFixedUnit('cfs') }, |
||||
{ name: 'Cubic feet/min (cfm)', id: 'flowcfm', fn: toFixedUnit('cfm') }, |
||||
{ name: 'Litre/hour', id: 'litreh', fn: toFixedUnit('l/h') }, |
||||
{ name: 'Litre/min (l/min)', id: 'flowlpm', fn: toFixedUnit('l/min') }, |
||||
{ name: 'milliLitre/min (mL/min)', id: 'flowmlpm', fn: toFixedUnit('mL/min') }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Force', |
||||
formats: [ |
||||
{ name: 'Newton-meters (Nm)', id: 'forceNm', fn: decimalSIPrefix('Nm') }, |
||||
{ name: 'Kilonewton-meters (kNm)', id: 'forcekNm', fn: decimalSIPrefix('Nm', 1) }, |
||||
{ name: 'Newtons (N)', id: 'forceN', fn: decimalSIPrefix('N') }, |
||||
{ name: 'Kilonewtons (kN)', id: 'forcekN', fn: decimalSIPrefix('N', 1) }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Hash Rate', |
||||
formats: [ |
||||
{ name: 'hashes/sec', id: 'Hs', fn: decimalSIPrefix('H/s') }, |
||||
{ name: 'kilohashes/sec', id: 'KHs', fn: decimalSIPrefix('H/s', 1) }, |
||||
{ name: 'megahashes/sec', id: 'MHs', fn: decimalSIPrefix('H/s', 2) }, |
||||
{ name: 'gigahashes/sec', id: 'GHs', fn: decimalSIPrefix('H/s', 3) }, |
||||
{ name: 'terahashes/sec', id: 'THs', fn: decimalSIPrefix('H/s', 4) }, |
||||
{ name: 'petahashes/sec', id: 'PHs', fn: decimalSIPrefix('H/s', 5) }, |
||||
{ name: 'exahashes/sec', id: 'EHs', fn: decimalSIPrefix('H/s', 6) }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Mass', |
||||
formats: [ |
||||
{ name: 'milligram (mg)', id: 'massmg', fn: decimalSIPrefix('g', -1) }, |
||||
{ name: 'gram (g)', id: 'massg', fn: decimalSIPrefix('g') }, |
||||
{ name: 'kilogram (kg)', id: 'masskg', fn: decimalSIPrefix('g', 1) }, |
||||
{ name: 'metric ton (t)', id: 'masst', fn: toFixedUnit('t') }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'length', |
||||
formats: [ |
||||
{ name: 'millimetre (mm)', id: 'lengthmm', fn: decimalSIPrefix('m', -1) }, |
||||
{ name: 'feet (ft)', id: 'lengthft', fn: toFixedUnit('ft') }, |
||||
{ name: 'meter (m)', id: 'lengthm', fn: decimalSIPrefix('m') }, |
||||
{ name: 'kilometer (km)', id: 'lengthkm', fn: decimalSIPrefix('m', 1) }, |
||||
{ name: 'mile (mi)', id: 'lengthmi', fn: toFixedUnit('mi') }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Pressure', |
||||
formats: [ |
||||
{ name: 'Millibars', id: 'pressurembar', fn: decimalSIPrefix('bar', -1) }, |
||||
{ name: 'Bars', id: 'pressurebar', fn: decimalSIPrefix('bar') }, |
||||
{ name: 'Kilobars', id: 'pressurekbar', fn: decimalSIPrefix('bar', 1) }, |
||||
{ name: 'Hectopascals', id: 'pressurehpa', fn: toFixedUnit('hPa') }, |
||||
{ name: 'Kilopascals', id: 'pressurekpa', fn: toFixedUnit('kPa') }, |
||||
{ name: 'Inches of mercury', id: 'pressurehg', fn: toFixedUnit('"Hg') }, |
||||
{ name: 'PSI', id: 'pressurepsi', fn: scaledUnits(1000, ['psi', 'ksi', 'Mpsi']) }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Radiation', |
||||
formats: [ |
||||
{ name: 'Becquerel (Bq)', id: 'radbq', fn: decimalSIPrefix('Bq') }, |
||||
{ name: 'curie (Ci)', id: 'radci', fn: decimalSIPrefix('Ci') }, |
||||
{ name: 'Gray (Gy)', id: 'radgy', fn: decimalSIPrefix('Gy') }, |
||||
{ name: 'rad', id: 'radrad', fn: decimalSIPrefix('rad') }, |
||||
{ name: 'Sievert (Sv)', id: 'radsv', fn: decimalSIPrefix('Sv') }, |
||||
{ name: 'rem', id: 'radrem', fn: decimalSIPrefix('rem') }, |
||||
{ name: 'Exposure (C/kg)', id: 'radexpckg', fn: decimalSIPrefix('C/kg') }, |
||||
{ name: 'roentgen (R)', id: 'radr', fn: decimalSIPrefix('R') }, |
||||
{ name: 'Sievert/hour (Sv/h)', id: 'radsvh', fn: decimalSIPrefix('Sv/h') }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Temperature', |
||||
formats: [ |
||||
{ name: 'Celsius (°C)', id: 'celsius', fn: toFixedUnit('°C') }, |
||||
{ name: 'Farenheit (°F)', id: 'farenheit', fn: toFixedUnit('°F') }, |
||||
{ name: 'Kelvin (K)', id: 'kelvin', fn: toFixedUnit('K') }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Time', |
||||
formats: [ |
||||
{ name: 'Hertz (1/s)', id: 'hertz', fn: decimalSIPrefix('Hz') }, |
||||
{ name: 'nanoseconds (ns)', id: 'ns', fn: toNanoSeconds }, |
||||
{ name: 'microseconds (µs)', id: 'µs', fn: toMicroSeconds }, |
||||
{ name: 'milliseconds (ms)', id: 'ms', fn: toMilliSeconds }, |
||||
{ name: 'seconds (s)', id: 's', fn: toSeconds }, |
||||
{ name: 'minutes (m)', id: 'm', fn: toMinutes }, |
||||
{ name: 'hours (h)', id: 'h', fn: toHours }, |
||||
{ name: 'days (d)', id: 'd', fn: toDays }, |
||||
{ name: 'duration (ms)', id: 'dtdurationms', fn: toDurationInMilliseconds }, |
||||
{ name: 'duration (s)', id: 'dtdurations', fn: toDurationInSeconds }, |
||||
{ name: 'duration (hh:mm:ss)', id: 'dthms', fn: toDurationInHoursMinutesSeconds }, |
||||
{ name: 'Timeticks (s/100)', id: 'timeticks', fn: toTimeTicks }, |
||||
{ name: 'clock (ms)', id: 'clockms', fn: toClockMilliseconds }, |
||||
{ name: 'clock (s)', id: 'clocks', fn: toClockSeconds }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Throughput', |
||||
formats: [ |
||||
{ name: 'ops/sec (ops)', id: 'ops', fn: simpleCountUnit('ops') }, |
||||
{ name: 'requests/sec (rps)', id: 'reqps', fn: simpleCountUnit('reqps') }, |
||||
{ name: 'reads/sec (rps)', id: 'rps', fn: simpleCountUnit('rps') }, |
||||
{ name: 'writes/sec (wps)', id: 'wps', fn: simpleCountUnit('wps') }, |
||||
{ name: 'I/O ops/sec (iops)', id: 'iops', fn: simpleCountUnit('iops') }, |
||||
{ name: 'ops/min (opm)', id: 'opm', fn: simpleCountUnit('opm') }, |
||||
{ name: 'reads/min (rpm)', id: 'rpm', fn: simpleCountUnit('rpm') }, |
||||
{ name: 'writes/min (wpm)', id: 'wpm', fn: simpleCountUnit('wpm') }, |
||||
], |
||||
}, |
||||
{ |
||||
name: 'Velocity', |
||||
formats: [ |
||||
{ name: 'metres/second (m/s)', id: 'velocityms', fn: toFixedUnit('m/s') }, |
||||
{ name: 'kilometers/hour (km/h)', id: 'velocitykmh', fn: toFixedUnit('km/h') }, |
||||
{ name: 'miles/hour (mph)', id: 'velocitymph', fn: toFixedUnit('mph') }, |
||||
{ name: 'knot (kn)', id: 'velocityknot', fn: toFixedUnit('kn') }, |
||||
] |
||||
}, |
||||
{ |
||||
name: 'Volume', |
||||
formats: [ |
||||
{ name: 'millilitre (mL)', id: 'mlitre', fn: decimalSIPrefix('L', -1) }, |
||||
{ name: 'litre (L)', id: 'litre', fn: decimalSIPrefix('L') }, |
||||
{ name: 'cubic metre', id: 'm3', fn: toFixedUnit('m³') }, |
||||
{ name: 'Normal cubic metre', id: 'Nm3', fn: toFixedUnit('Nm³') }, |
||||
{ name: 'cubic decimetre', id: 'dm3', fn: toFixedUnit('dm³') }, |
||||
{ name: 'gallons', id: 'gallons', fn: toFixedUnit('gal') }, |
||||
], |
||||
} |
||||
]; |
@ -0,0 +1,231 @@ |
||||
import moment from 'moment'; |
||||
import { |
||||
dateTimeAsIso, |
||||
dateTimeAsUS, |
||||
dateTimeFromNow, |
||||
Interval, |
||||
toClock, |
||||
toDuration, |
||||
toDurationInMilliseconds, |
||||
toDurationInSeconds, |
||||
} from './dateTimeFormatters'; |
||||
|
||||
describe('date time formats', () => { |
||||
const epoch = 1505634997920; |
||||
const utcTime = moment.utc(epoch); |
||||
const browserTime = moment(epoch); |
||||
|
||||
it('should format as iso date', () => { |
||||
const expected = browserTime.format('YYYY-MM-DD HH:mm:ss'); |
||||
const actual = dateTimeAsIso(epoch, 0, 0, false); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as iso date (in UTC)', () => { |
||||
const expected = utcTime.format('YYYY-MM-DD HH:mm:ss'); |
||||
const actual = dateTimeAsIso(epoch, 0, 0, true); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as iso date and skip date when today', () => { |
||||
const now = moment(); |
||||
const expected = now.format('HH:mm:ss'); |
||||
const actual = dateTimeAsIso(now.valueOf(), 0, 0, false); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as iso date (in UTC) and skip date when today', () => { |
||||
const now = moment.utc(); |
||||
const expected = now.format('HH:mm:ss'); |
||||
const actual = dateTimeAsIso(now.valueOf(), 0, 0, true); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as US date', () => { |
||||
const expected = browserTime.format('MM/DD/YYYY h:mm:ss a'); |
||||
const actual = dateTimeAsUS(epoch, 0, 0, false); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as US date (in UTC)', () => { |
||||
const expected = utcTime.format('MM/DD/YYYY h:mm:ss a'); |
||||
const actual = dateTimeAsUS(epoch, 0, 0, true); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as US date and skip date when today', () => { |
||||
const now = moment(); |
||||
const expected = now.format('h:mm:ss a'); |
||||
const actual = dateTimeAsUS(now.valueOf(), 0, 0, false); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as US date (in UTC) and skip date when today', () => { |
||||
const now = moment.utc(); |
||||
const expected = now.format('h:mm:ss a'); |
||||
const actual = dateTimeAsUS(now.valueOf(), 0, 0, true); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as from now with days', () => { |
||||
const daysAgo = moment().add(-7, 'd'); |
||||
const expected = '7 days ago'; |
||||
const actual = dateTimeFromNow(daysAgo.valueOf(), 0, 0, false); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as from now with days (in UTC)', () => { |
||||
const daysAgo = moment.utc().add(-7, 'd'); |
||||
const expected = '7 days ago'; |
||||
const actual = dateTimeFromNow(daysAgo.valueOf(), 0, 0, true); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as from now with minutes', () => { |
||||
const daysAgo = moment().add(-2, 'm'); |
||||
const expected = '2 minutes ago'; |
||||
const actual = dateTimeFromNow(daysAgo.valueOf(), 0, 0, false); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as from now with minutes (in UTC)', () => { |
||||
const daysAgo = moment.utc().add(-2, 'm'); |
||||
const expected = '2 minutes ago'; |
||||
const actual = dateTimeFromNow(daysAgo.valueOf(), 0, 0, true); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
}); |
||||
|
||||
describe('duration', () => { |
||||
it('0 milliseconds', () => { |
||||
const str = toDurationInMilliseconds(0, 0); |
||||
expect(str).toBe('0 milliseconds'); |
||||
}); |
||||
it('1 millisecond', () => { |
||||
const str = toDurationInMilliseconds(1, 0); |
||||
expect(str).toBe('1 millisecond'); |
||||
}); |
||||
it('-1 millisecond', () => { |
||||
const str = toDurationInMilliseconds(-1, 0); |
||||
expect(str).toBe('1 millisecond ago'); |
||||
}); |
||||
it('seconds', () => { |
||||
const str = toDurationInSeconds(1, 0); |
||||
expect(str).toBe('1 second'); |
||||
}); |
||||
it('minutes', () => { |
||||
const str = toDuration(1, 0, Interval.Minute); |
||||
expect(str).toBe('1 minute'); |
||||
}); |
||||
it('hours', () => { |
||||
const str = toDuration(1, 0, Interval.Hour); |
||||
expect(str).toBe('1 hour'); |
||||
}); |
||||
it('days', () => { |
||||
const str = toDuration(1, 0, Interval.Day); |
||||
expect(str).toBe('1 day'); |
||||
}); |
||||
it('weeks', () => { |
||||
const str = toDuration(1, 0, Interval.Week); |
||||
expect(str).toBe('1 week'); |
||||
}); |
||||
it('months', () => { |
||||
const str = toDuration(1, 0, Interval.Month); |
||||
expect(str).toBe('1 month'); |
||||
}); |
||||
it('years', () => { |
||||
const str = toDuration(1, 0, Interval.Year); |
||||
expect(str).toBe('1 year'); |
||||
}); |
||||
it('decimal days', () => { |
||||
const str = toDuration(1.5, 2, Interval.Day); |
||||
expect(str).toBe('1 day, 12 hours, 0 minutes'); |
||||
}); |
||||
it('decimal months', () => { |
||||
const str = toDuration(1.5, 3, Interval.Month); |
||||
expect(str).toBe('1 month, 2 weeks, 1 day, 0 hours'); |
||||
}); |
||||
it('no decimals', () => { |
||||
const str = toDuration(38898367008, 0, Interval.Millisecond); |
||||
expect(str).toBe('1 year'); |
||||
}); |
||||
it('1 decimal', () => { |
||||
const str = toDuration(38898367008, 1, Interval.Millisecond); |
||||
expect(str).toBe('1 year, 2 months'); |
||||
}); |
||||
it('too many decimals', () => { |
||||
const str = toDuration(38898367008, 20, Interval.Millisecond); |
||||
expect(str).toBe('1 year, 2 months, 3 weeks, 4 days, 5 hours, 6 minutes, 7 seconds, 8 milliseconds'); |
||||
}); |
||||
it('floating point error', () => { |
||||
const str = toDuration(36993906007, 8, Interval.Millisecond); |
||||
expect(str).toBe('1 year, 2 months, 0 weeks, 3 days, 4 hours, 5 minutes, 6 seconds, 7 milliseconds'); |
||||
}); |
||||
}); |
||||
|
||||
describe('clock', () => { |
||||
it('size less than 1 second', () => { |
||||
const str = toClock(999, 0); |
||||
expect(str).toBe('999ms'); |
||||
}); |
||||
describe('size less than 1 minute', () => { |
||||
it('default', () => { |
||||
const str = toClock(59999); |
||||
expect(str).toBe('59s:999ms'); |
||||
}); |
||||
it('decimals equals 0', () => { |
||||
const str = toClock(59999, 0); |
||||
expect(str).toBe('59s'); |
||||
}); |
||||
}); |
||||
describe('size less than 1 hour', () => { |
||||
it('default', () => { |
||||
const str = toClock(3599999); |
||||
expect(str).toBe('59m:59s:999ms'); |
||||
}); |
||||
it('decimals equals 0', () => { |
||||
const str = toClock(3599999, 0); |
||||
expect(str).toBe('59m'); |
||||
}); |
||||
it('decimals equals 1', () => { |
||||
const str = toClock(3599999, 1); |
||||
expect(str).toBe('59m:59s'); |
||||
}); |
||||
}); |
||||
describe('size greater than or equal 1 hour', () => { |
||||
it('default', () => { |
||||
const str = toClock(7199999); |
||||
expect(str).toBe('01h:59m:59s:999ms'); |
||||
}); |
||||
it('decimals equals 0', () => { |
||||
const str = toClock(7199999, 0); |
||||
expect(str).toBe('01h'); |
||||
}); |
||||
it('decimals equals 1', () => { |
||||
const str = toClock(7199999, 1); |
||||
expect(str).toBe('01h:59m'); |
||||
}); |
||||
it('decimals equals 2', () => { |
||||
const str = toClock(7199999, 2); |
||||
expect(str).toBe('01h:59m:59s'); |
||||
}); |
||||
}); |
||||
describe('size greater than or equal 1 day', () => { |
||||
it('default', () => { |
||||
const str = toClock(89999999); |
||||
expect(str).toBe('24h:59m:59s:999ms'); |
||||
}); |
||||
it('decimals equals 0', () => { |
||||
const str = toClock(89999999, 0); |
||||
expect(str).toBe('24h'); |
||||
}); |
||||
it('decimals equals 1', () => { |
||||
const str = toClock(89999999, 1); |
||||
expect(str).toBe('24h:59m'); |
||||
}); |
||||
it('decimals equals 2', () => { |
||||
const str = toClock(89999999, 2); |
||||
expect(str).toBe('24h:59m:59s'); |
||||
}); |
||||
}); |
||||
}); |
@ -0,0 +1,312 @@ |
||||
import { toFixed, toFixedScaled } from './valueFormats'; |
||||
import moment from 'moment'; |
||||
|
||||
interface IntervalsInSeconds { |
||||
[interval: string]: number; |
||||
} |
||||
|
||||
export enum Interval { |
||||
Year = 'year', |
||||
Month = 'month', |
||||
Week = 'week', |
||||
Day = 'day', |
||||
Hour = 'hour', |
||||
Minute = 'minute', |
||||
Second = 'second', |
||||
Millisecond = 'millisecond', |
||||
} |
||||
|
||||
const INTERVALS_IN_SECONDS: IntervalsInSeconds = { |
||||
[Interval.Year]: 31536000, |
||||
[Interval.Month]: 2592000, |
||||
[Interval.Week]: 604800, |
||||
[Interval.Day]: 86400, |
||||
[Interval.Hour]: 3600, |
||||
[Interval.Minute]: 60, |
||||
[Interval.Second]: 1, |
||||
[Interval.Millisecond]: 0.001, |
||||
}; |
||||
|
||||
export function toNanoSeconds(size: number, decimals: number, scaledDecimals: number) { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
|
||||
if (Math.abs(size) < 1000) { |
||||
return toFixed(size, decimals) + ' ns'; |
||||
} else if (Math.abs(size) < 1000000) { |
||||
return toFixedScaled(size / 1000, decimals, scaledDecimals, 3, ' µs'); |
||||
} else if (Math.abs(size) < 1000000000) { |
||||
return toFixedScaled(size / 1000000, decimals, scaledDecimals, 6, ' ms'); |
||||
} else if (Math.abs(size) < 60000000000) { |
||||
return toFixedScaled(size / 1000000000, decimals, scaledDecimals, 9, ' s'); |
||||
} else { |
||||
return toFixedScaled(size / 60000000000, decimals, scaledDecimals, 12, ' min'); |
||||
} |
||||
} |
||||
|
||||
export function toMicroSeconds(size: number, decimals: number, scaledDecimals: number) { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
|
||||
if (Math.abs(size) < 1000) { |
||||
return toFixed(size, decimals) + ' µs'; |
||||
} else if (Math.abs(size) < 1000000) { |
||||
return toFixedScaled(size / 1000, decimals, scaledDecimals, 3, ' ms'); |
||||
} else { |
||||
return toFixedScaled(size / 1000000, decimals, scaledDecimals, 6, ' s'); |
||||
} |
||||
} |
||||
|
||||
export function toMilliSeconds(size: number, decimals: number, scaledDecimals: number) { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
|
||||
if (Math.abs(size) < 1000) { |
||||
return toFixed(size, decimals) + ' ms'; |
||||
} else if (Math.abs(size) < 60000) { |
||||
// Less than 1 min
|
||||
return toFixedScaled(size / 1000, decimals, scaledDecimals, 3, ' s'); |
||||
} else if (Math.abs(size) < 3600000) { |
||||
// Less than 1 hour, divide in minutes
|
||||
return toFixedScaled(size / 60000, decimals, scaledDecimals, 5, ' min'); |
||||
} else if (Math.abs(size) < 86400000) { |
||||
// Less than one day, divide in hours
|
||||
return toFixedScaled(size / 3600000, decimals, scaledDecimals, 7, ' hour'); |
||||
} else if (Math.abs(size) < 31536000000) { |
||||
// Less than one year, divide in days
|
||||
return toFixedScaled(size / 86400000, decimals, scaledDecimals, 8, ' day'); |
||||
} |
||||
|
||||
return toFixedScaled(size / 31536000000, decimals, scaledDecimals, 10, ' year'); |
||||
} |
||||
|
||||
export function toSeconds(size: number, decimals: number, scaledDecimals: number) { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
|
||||
// Less than 1 µs, divide in ns
|
||||
if (Math.abs(size) < 0.000001) { |
||||
return toFixedScaled(size * 1e9, decimals, scaledDecimals - decimals, -9, ' ns'); |
||||
} |
||||
// Less than 1 ms, divide in µs
|
||||
if (Math.abs(size) < 0.001) { |
||||
return toFixedScaled(size * 1e6, decimals, scaledDecimals - decimals, -6, ' µs'); |
||||
} |
||||
// Less than 1 second, divide in ms
|
||||
if (Math.abs(size) < 1) { |
||||
return toFixedScaled(size * 1e3, decimals, scaledDecimals - decimals, -3, ' ms'); |
||||
} |
||||
|
||||
if (Math.abs(size) < 60) { |
||||
return toFixed(size, decimals) + ' s'; |
||||
} else if (Math.abs(size) < 3600) { |
||||
// Less than 1 hour, divide in minutes
|
||||
return toFixedScaled(size / 60, decimals, scaledDecimals, 1, ' min'); |
||||
} else if (Math.abs(size) < 86400) { |
||||
// Less than one day, divide in hours
|
||||
return toFixedScaled(size / 3600, decimals, scaledDecimals, 4, ' hour'); |
||||
} else if (Math.abs(size) < 604800) { |
||||
// Less than one week, divide in days
|
||||
return toFixedScaled(size / 86400, decimals, scaledDecimals, 5, ' day'); |
||||
} else if (Math.abs(size) < 31536000) { |
||||
// Less than one year, divide in week
|
||||
return toFixedScaled(size / 604800, decimals, scaledDecimals, 6, ' week'); |
||||
} |
||||
|
||||
return toFixedScaled(size / 3.15569e7, decimals, scaledDecimals, 7, ' year'); |
||||
} |
||||
|
||||
export function toMinutes(size: number, decimals: number, scaledDecimals: number) { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
|
||||
if (Math.abs(size) < 60) { |
||||
return toFixed(size, decimals) + ' min'; |
||||
} else if (Math.abs(size) < 1440) { |
||||
return toFixedScaled(size / 60, decimals, scaledDecimals, 2, ' hour'); |
||||
} else if (Math.abs(size) < 10080) { |
||||
return toFixedScaled(size / 1440, decimals, scaledDecimals, 3, ' day'); |
||||
} else if (Math.abs(size) < 604800) { |
||||
return toFixedScaled(size / 10080, decimals, scaledDecimals, 4, ' week'); |
||||
} else { |
||||
return toFixedScaled(size / 5.25948e5, decimals, scaledDecimals, 5, ' year'); |
||||
} |
||||
} |
||||
|
||||
export function toHours(size: number, decimals: number, scaledDecimals: number) { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
|
||||
if (Math.abs(size) < 24) { |
||||
return toFixed(size, decimals) + ' hour'; |
||||
} else if (Math.abs(size) < 168) { |
||||
return toFixedScaled(size / 24, decimals, scaledDecimals, 2, ' day'); |
||||
} else if (Math.abs(size) < 8760) { |
||||
return toFixedScaled(size / 168, decimals, scaledDecimals, 3, ' week'); |
||||
} else { |
||||
return toFixedScaled(size / 8760, decimals, scaledDecimals, 4, ' year'); |
||||
} |
||||
} |
||||
|
||||
export function toDays(size: number, decimals: number, scaledDecimals: number) { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
|
||||
if (Math.abs(size) < 7) { |
||||
return toFixed(size, decimals) + ' day'; |
||||
} else if (Math.abs(size) < 365) { |
||||
return toFixedScaled(size / 7, decimals, scaledDecimals, 2, ' week'); |
||||
} else { |
||||
return toFixedScaled(size / 365, decimals, scaledDecimals, 3, ' year'); |
||||
} |
||||
} |
||||
|
||||
export function toDuration(size: number, decimals: number, timeScale: Interval): string { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
if (size === 0) { |
||||
return '0 ' + timeScale + 's'; |
||||
} |
||||
if (size < 0) { |
||||
return toDuration(-size, decimals, timeScale) + ' ago'; |
||||
} |
||||
|
||||
const units = [ |
||||
{ long: Interval.Year }, |
||||
{ long: Interval.Month }, |
||||
{ long: Interval.Week }, |
||||
{ long: Interval.Day }, |
||||
{ long: Interval.Hour }, |
||||
{ long: Interval.Minute }, |
||||
{ long: Interval.Second }, |
||||
{ long: Interval.Millisecond }, |
||||
]; |
||||
// convert $size to milliseconds
|
||||
// intervals_in_seconds uses seconds (duh), convert them to milliseconds here to minimize floating point errors
|
||||
size *= INTERVALS_IN_SECONDS[timeScale] * 1000; |
||||
|
||||
const strings = []; |
||||
// after first value >= 1 print only $decimals more
|
||||
let decrementDecimals = false; |
||||
for (let i = 0; i < units.length && decimals >= 0; i++) { |
||||
const interval = INTERVALS_IN_SECONDS[units[i].long] * 1000; |
||||
const value = size / interval; |
||||
if (value >= 1 || decrementDecimals) { |
||||
decrementDecimals = true; |
||||
const floor = Math.floor(value); |
||||
const unit = units[i].long + (floor !== 1 ? 's' : ''); |
||||
strings.push(floor + ' ' + unit); |
||||
size = size % interval; |
||||
decimals--; |
||||
} |
||||
} |
||||
|
||||
return strings.join(', '); |
||||
} |
||||
|
||||
export function toClock(size: number, decimals?: number) { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
|
||||
// < 1 second
|
||||
if (size < 1000) { |
||||
return moment.utc(size).format('SSS\\m\\s'); |
||||
} |
||||
|
||||
// < 1 minute
|
||||
if (size < 60000) { |
||||
let format = 'ss\\s:SSS\\m\\s'; |
||||
if (decimals === 0) { |
||||
format = 'ss\\s'; |
||||
} |
||||
return moment.utc(size).format(format); |
||||
} |
||||
|
||||
// < 1 hour
|
||||
if (size < 3600000) { |
||||
let format = 'mm\\m:ss\\s:SSS\\m\\s'; |
||||
if (decimals === 0) { |
||||
format = 'mm\\m'; |
||||
} else if (decimals === 1) { |
||||
format = 'mm\\m:ss\\s'; |
||||
} |
||||
return moment.utc(size).format(format); |
||||
} |
||||
|
||||
let format = 'mm\\m:ss\\s:SSS\\m\\s'; |
||||
|
||||
const hours = `${('0' + Math.floor(moment.duration(size, 'milliseconds').asHours())).slice(-2)}h`; |
||||
|
||||
if (decimals === 0) { |
||||
format = ''; |
||||
} else if (decimals === 1) { |
||||
format = 'mm\\m'; |
||||
} else if (decimals === 2) { |
||||
format = 'mm\\m:ss\\s'; |
||||
} |
||||
|
||||
return format ? `${hours}:${moment.utc(size).format(format)}` : hours; |
||||
} |
||||
|
||||
export function toDurationInMilliseconds(size: number, decimals: number) { |
||||
return toDuration(size, decimals, Interval.Millisecond); |
||||
} |
||||
|
||||
export function toDurationInSeconds(size: number, decimals: number) { |
||||
return toDuration(size, decimals, Interval.Second); |
||||
} |
||||
|
||||
export function toDurationInHoursMinutesSeconds(size: number) { |
||||
const strings = []; |
||||
const numHours = Math.floor(size / 3600); |
||||
const numMinutes = Math.floor((size % 3600) / 60); |
||||
const numSeconds = Math.floor((size % 3600) % 60); |
||||
numHours > 9 ? strings.push('' + numHours) : strings.push('0' + numHours); |
||||
numMinutes > 9 ? strings.push('' + numMinutes) : strings.push('0' + numMinutes); |
||||
numSeconds > 9 ? strings.push('' + numSeconds) : strings.push('0' + numSeconds); |
||||
return strings.join(':'); |
||||
} |
||||
|
||||
export function toTimeTicks(size: number, decimals: number, scaledDecimals: number) { |
||||
return toSeconds(size, decimals, scaledDecimals); |
||||
} |
||||
|
||||
export function toClockMilliseconds(size: number, decimals: number) { |
||||
return toClock(size, decimals); |
||||
} |
||||
|
||||
export function toClockSeconds(size: number, decimals: number) { |
||||
return toClock(size * 1000, decimals); |
||||
} |
||||
|
||||
export function dateTimeAsIso(value: number, decimals: number, scaledDecimals: number, isUtc: boolean) { |
||||
const time = isUtc ? moment.utc(value) : moment(value); |
||||
|
||||
if (moment().isSame(value, 'day')) { |
||||
return time.format('HH:mm:ss'); |
||||
} |
||||
return time.format('YYYY-MM-DD HH:mm:ss'); |
||||
} |
||||
|
||||
export function dateTimeAsUS(value: number, decimals: number, scaledDecimals: number, isUtc: boolean) { |
||||
const time = isUtc ? moment.utc(value) : moment(value); |
||||
|
||||
if (moment().isSame(value, 'day')) { |
||||
return time.format('h:mm:ss a'); |
||||
} |
||||
return time.format('MM/DD/YYYY h:mm:ss a'); |
||||
} |
||||
|
||||
export function dateTimeFromNow(value: number, decimals: number, scaledDecimals: number, isUtc: boolean) { |
||||
const time = isUtc ? moment.utc(value) : moment(value); |
||||
return time.fromNow(); |
||||
} |
@ -0,0 +1,7 @@ |
||||
import { currency } from './symbolFormatters'; |
||||
|
||||
describe('Currency', () => { |
||||
it('should format as usd', () => { |
||||
expect(currency('$')(1532.82, 1, -1)).toEqual('$1.53K'); |
||||
}); |
||||
}); |
@ -0,0 +1,30 @@ |
||||
import { scaledUnits } from './valueFormats'; |
||||
|
||||
export function currency(symbol: string) { |
||||
const units = ['', 'K', 'M', 'B', 'T']; |
||||
const scaler = scaledUnits(1000, units); |
||||
return (size: number, decimals: number, scaledDecimals: number) => { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
const scaled = scaler(size, decimals, scaledDecimals); |
||||
return symbol + scaled; |
||||
}; |
||||
} |
||||
|
||||
export function binarySIPrefix(unit: string, offset = 0) { |
||||
const prefixes = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'].slice(offset); |
||||
const units = prefixes.map(p => { |
||||
return ' ' + p + unit; |
||||
}); |
||||
return scaledUnits(1024, units); |
||||
} |
||||
|
||||
export function decimalSIPrefix(unit: string, offset = 0) { |
||||
let prefixes = ['n', 'µ', 'm', '', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; |
||||
prefixes = prefixes.slice(3 + (offset || 0)); |
||||
const units = prefixes.map(p => { |
||||
return ' ' + p + unit; |
||||
}); |
||||
return scaledUnits(1000, units); |
||||
} |
@ -0,0 +1,166 @@ |
||||
import { getCategories } from './categories'; |
||||
|
||||
type ValueFormatter = (value: number, decimals?: number, scaledDecimals?: number, isUtc?: boolean) => string; |
||||
|
||||
interface ValueFormat { |
||||
name: string; |
||||
id: string; |
||||
fn: ValueFormatter; |
||||
} |
||||
|
||||
export interface ValueFormatCategory { |
||||
name: string; |
||||
formats: ValueFormat[]; |
||||
} |
||||
|
||||
interface ValueFormatterIndex { |
||||
[id: string]: ValueFormatter; |
||||
} |
||||
|
||||
// Globals & formats cache
|
||||
let categories: ValueFormatCategory[] = []; |
||||
const index: ValueFormatterIndex = {}; |
||||
let hasBuiltIndex = false; |
||||
|
||||
export function toFixed(value: number, decimals?: number): string { |
||||
if (value === null) { |
||||
return ''; |
||||
} |
||||
|
||||
const factor = decimals ? Math.pow(10, Math.max(0, decimals)) : 1; |
||||
const formatted = String(Math.round(value * factor) / factor); |
||||
|
||||
// if exponent return directly
|
||||
if (formatted.indexOf('e') !== -1 || value === 0) { |
||||
return formatted; |
||||
} |
||||
|
||||
// If tickDecimals was specified, ensure that we have exactly that
|
||||
// much precision; otherwise default to the value's own precision.
|
||||
if (decimals != null) { |
||||
const decimalPos = formatted.indexOf('.'); |
||||
const precision = decimalPos === -1 ? 0 : formatted.length - decimalPos - 1; |
||||
if (precision < decimals) { |
||||
return (precision ? formatted : formatted + '.') + String(factor).substr(1, decimals - precision); |
||||
} |
||||
} |
||||
|
||||
return formatted; |
||||
} |
||||
|
||||
export function toFixedScaled( |
||||
value: number, |
||||
decimals: number, |
||||
scaledDecimals: number, |
||||
additionalDecimals: number, |
||||
ext: string |
||||
) { |
||||
if (scaledDecimals === null) { |
||||
return toFixed(value, decimals) + ext; |
||||
} else { |
||||
return toFixed(value, scaledDecimals + additionalDecimals) + ext; |
||||
} |
||||
} |
||||
|
||||
export function toFixedUnit(unit: string) { |
||||
return (size: number, decimals: number) => { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
return toFixed(size, decimals) + ' ' + unit; |
||||
}; |
||||
} |
||||
|
||||
// Formatter which scales the unit string geometrically according to the given
|
||||
// numeric factor. Repeatedly scales the value down by the factor until it is
|
||||
// less than the factor in magnitude, or the end of the array is reached.
|
||||
export function scaledUnits(factor: number, extArray: string[]) { |
||||
return (size: number, decimals: number, scaledDecimals: number) => { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
|
||||
let steps = 0; |
||||
const limit = extArray.length; |
||||
|
||||
while (Math.abs(size) >= factor) { |
||||
steps++; |
||||
size /= factor; |
||||
|
||||
if (steps >= limit) { |
||||
return 'NA'; |
||||
} |
||||
} |
||||
|
||||
if (steps > 0 && scaledDecimals !== null) { |
||||
decimals = scaledDecimals + 3 * steps; |
||||
} |
||||
|
||||
return toFixed(size, decimals) + extArray[steps]; |
||||
}; |
||||
} |
||||
|
||||
export function locale(value: number, decimals: number) { |
||||
if (value == null) { |
||||
return ''; |
||||
} |
||||
return value.toLocaleString(undefined, { maximumFractionDigits: decimals }); |
||||
} |
||||
|
||||
export function simpleCountUnit(symbol: string) { |
||||
const units = ['', 'K', 'M', 'B', 'T']; |
||||
const scaler = scaledUnits(1000, units); |
||||
return (size: number, decimals: number, scaledDecimals: number) => { |
||||
if (size === null) { |
||||
return ''; |
||||
} |
||||
const scaled = scaler(size, decimals, scaledDecimals); |
||||
return scaled + ' ' + symbol; |
||||
}; |
||||
} |
||||
|
||||
function buildFormats() { |
||||
categories = getCategories(); |
||||
|
||||
for (const cat of categories) { |
||||
for (const format of cat.formats) { |
||||
index[format.id] = format.fn; |
||||
} |
||||
} |
||||
|
||||
hasBuiltIndex = true; |
||||
} |
||||
|
||||
export function getValueFormat(id: string): ValueFormatter { |
||||
if (!hasBuiltIndex) { |
||||
buildFormats(); |
||||
} |
||||
|
||||
return index[id]; |
||||
} |
||||
|
||||
export function getValueFormatterIndex(): ValueFormatterIndex { |
||||
if (!hasBuiltIndex) { |
||||
buildFormats(); |
||||
} |
||||
|
||||
return index; |
||||
} |
||||
|
||||
export function getValueFormats() { |
||||
if (!hasBuiltIndex) { |
||||
buildFormats(); |
||||
} |
||||
|
||||
return categories.map(cat => { |
||||
return { |
||||
text: cat.name, |
||||
submenu: cat.formats.map(format => { |
||||
return { |
||||
text: format.name, |
||||
value: format.id, |
||||
}; |
||||
}), |
||||
}; |
||||
}); |
||||
} |
@ -1 +0,0 @@ |
||||
export { Graph } from './Graph/Graph'; |
@ -1,25 +1,49 @@ |
||||
#!/bin/sh |
||||
|
||||
_grafana_tag=$1 |
||||
_grafana_tag=${1:-} |
||||
_docker_repo=${2:-grafana/grafana} |
||||
|
||||
# If the tag starts with v, treat this as a official release |
||||
if echo "$_grafana_tag" | grep -q "^v"; then |
||||
_grafana_version=$(echo "${_grafana_tag}" | cut -d "v" -f 2) |
||||
_docker_repo=${2:-grafana/grafana} |
||||
else |
||||
_grafana_version=$_grafana_tag |
||||
_docker_repo=${2:-grafana/grafana-dev} |
||||
fi |
||||
|
||||
echo "Building ${_docker_repo}:${_grafana_version}" |
||||
|
||||
docker build \ |
||||
--tag "${_docker_repo}:${_grafana_version}" \ |
||||
--no-cache=true . |
||||
export DOCKER_CLI_EXPERIMENTAL=enabled |
||||
|
||||
# Build grafana image for a specific arch |
||||
docker_build () { |
||||
base_image=$1 |
||||
grafana_tgz=$2 |
||||
tag=$3 |
||||
|
||||
docker build \ |
||||
--build-arg BASE_IMAGE=${base_image} \ |
||||
--build-arg GRAFANA_TGZ=${grafana_tgz} \ |
||||
--tag "${tag}" \ |
||||
--no-cache=true . |
||||
} |
||||
|
||||
# Tag docker images of all architectures |
||||
docker_tag_all () { |
||||
repo=$1 |
||||
tag=$2 |
||||
docker tag "${_docker_repo}:${_grafana_version}" "${repo}:${tag}" |
||||
docker tag "${_docker_repo}-arm32v7-linux:${_grafana_version}" "${repo}-arm32v7-linux:${tag}" |
||||
docker tag "${_docker_repo}-arm64v8-linux:${_grafana_version}" "${repo}-arm64v8-linux:${tag}" |
||||
} |
||||
|
||||
docker_build "debian:stretch-slim" "grafana-latest.linux-x64.tar.gz" "${_docker_repo}:${_grafana_version}" |
||||
docker_build "arm32v7/debian:stretch-slim" "grafana-latest.linux-armv7.tar.gz" "${_docker_repo}-arm32v7-linux:${_grafana_version}" |
||||
docker_build "arm64v8/debian:stretch-slim" "grafana-latest.linux-arm64.tar.gz" "${_docker_repo}-arm64v8-linux:${_grafana_version}" |
||||
|
||||
# Tag as 'latest' for official release; otherwise tag as grafana/grafana:master |
||||
if echo "$_grafana_tag" | grep -q "^v"; then |
||||
docker tag "${_docker_repo}:${_grafana_version}" "${_docker_repo}:latest" |
||||
docker_tag_all "${_docker_repo}" "latest" |
||||
else |
||||
docker tag "${_docker_repo}:${_grafana_version}" "grafana/grafana:master" |
||||
docker_tag_all "${_docker_repo}" "master" |
||||
docker tag "${_docker_repo}:${_grafana_version}" "grafana/grafana-dev:${_grafana_version}" |
||||
fi |
||||
|
@ -1,24 +1,46 @@ |
||||
#!/bin/sh |
||||
set -e |
||||
|
||||
_grafana_tag=$1 |
||||
_grafana_tag=${1:-} |
||||
_docker_repo=${2:-grafana/grafana} |
||||
|
||||
# If the tag starts with v, treat this as a official release |
||||
if echo "$_grafana_tag" | grep -q "^v"; then |
||||
_grafana_version=$(echo "${_grafana_tag}" | cut -d "v" -f 2) |
||||
_docker_repo=${2:-grafana/grafana} |
||||
else |
||||
_grafana_version=$_grafana_tag |
||||
_docker_repo=${2:-grafana/grafana-dev} |
||||
fi |
||||
|
||||
export DOCKER_CLI_EXPERIMENTAL=enabled |
||||
|
||||
echo "pushing ${_docker_repo}:${_grafana_version}" |
||||
docker push "${_docker_repo}:${_grafana_version}" |
||||
|
||||
|
||||
docker_push_all () { |
||||
repo=$1 |
||||
tag=$2 |
||||
|
||||
# Push each image individually |
||||
docker push "${repo}:${tag}" |
||||
docker push "${repo}-arm32v7-linux:${tag}" |
||||
docker push "${repo}-arm64v8-linux:${tag}" |
||||
|
||||
# Create and push a multi-arch manifest |
||||
docker manifest create "${repo}:${tag}" \ |
||||
"${repo}:${tag}" \ |
||||
"${repo}-arm32v7-linux:${tag}" \ |
||||
"${repo}-arm64v8-linux:${tag}" |
||||
|
||||
docker manifest push "${repo}:${tag}" |
||||
} |
||||
|
||||
if echo "$_grafana_tag" | grep -q "^v" && echo "$_grafana_tag" | grep -vq "beta"; then |
||||
echo "pushing ${_docker_repo}:latest" |
||||
docker push "${_docker_repo}:latest" |
||||
docker_push_all "${_docker_repo}" "latest" |
||||
docker_push_all "${_docker_repo}" "${_grafana_version}" |
||||
elif echo "$_grafana_tag" | grep -q "^v" && echo "$_grafana_tag" | grep -q "beta"; then |
||||
docker_push_all "${_docker_repo}" "${_grafana_version}" |
||||
elif echo "$_grafana_tag" | grep -q "master"; then |
||||
echo "pushing grafana/grafana:master" |
||||
docker push grafana/grafana:master |
||||
docker_push_all "${_docker_repo}" "master" |
||||
docker push "grafana/grafana-dev:${_grafana_version}" |
||||
fi |
||||
|
@ -1,78 +0,0 @@ |
||||
import React from 'react'; |
||||
import baron from 'baron'; |
||||
|
||||
export interface Props { |
||||
children: any; |
||||
className: string; |
||||
} |
||||
|
||||
export default class ScrollBar extends React.Component<Props, any> { |
||||
private container: any; |
||||
private scrollbar: baron; |
||||
|
||||
constructor(props) { |
||||
super(props); |
||||
} |
||||
|
||||
componentDidMount() { |
||||
this.scrollbar = baron({ |
||||
root: this.container.parentElement, |
||||
scroller: this.container, |
||||
bar: '.baron__bar', |
||||
barOnCls: '_scrollbar', |
||||
scrollingCls: '_scrolling', |
||||
track: '.baron__track', |
||||
}); |
||||
} |
||||
|
||||
componentDidUpdate() { |
||||
this.scrollbar.update(); |
||||
} |
||||
|
||||
componentWillUnmount() { |
||||
this.scrollbar.dispose(); |
||||
} |
||||
|
||||
// methods can be invoked by outside
|
||||
setScrollTop(top) { |
||||
if (this.container) { |
||||
this.container.scrollTop = top; |
||||
this.scrollbar.update(); |
||||
|
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
setScrollLeft(left) { |
||||
if (this.container) { |
||||
this.container.scrollLeft = left; |
||||
this.scrollbar.update(); |
||||
|
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
update() { |
||||
this.scrollbar.update(); |
||||
} |
||||
|
||||
handleRef = ref => { |
||||
this.container = ref; |
||||
}; |
||||
|
||||
render() { |
||||
return ( |
||||
<div className="baron baron__root baron__clipper"> |
||||
<div className={this.props.className + ' baron__scroller'} ref={this.handleRef}> |
||||
{this.props.children} |
||||
</div> |
||||
|
||||
<div className="baron__track"> |
||||
<div className="baron__bar" /> |
||||
</div> |
||||
</div> |
||||
); |
||||
} |
||||
} |
@ -1,25 +0,0 @@ |
||||
export default { |
||||
clearIndicator: () => ({}), |
||||
container: () => ({}), |
||||
control: () => ({}), |
||||
dropdownIndicator: () => ({}), |
||||
group: () => ({}), |
||||
groupHeading: () => ({}), |
||||
indicatorsContainer: () => ({}), |
||||
indicatorSeparator: () => ({}), |
||||
input: () => ({}), |
||||
loadingIndicator: () => ({}), |
||||
loadingMessage: () => ({}), |
||||
menu: () => ({}), |
||||
menuList: ({ maxHeight }: { maxHeight: number }) => ({ |
||||
maxHeight, |
||||
}), |
||||
multiValue: () => ({}), |
||||
multiValueLabel: () => ({}), |
||||
multiValueRemove: () => ({}), |
||||
noOptionsMessage: () => ({}), |
||||
option: () => ({}), |
||||
placeholder: () => ({}), |
||||
singleValue: () => ({}), |
||||
valueContainer: () => ({}), |
||||
}; |
@ -1,16 +0,0 @@ |
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
||||
exports[`Popover renders correctly 1`] = ` |
||||
<div |
||||
className="popper__manager test-class" |
||||
onClick={[Function]} |
||||
> |
||||
<div |
||||
className="popper_ref " |
||||
> |
||||
<button> |
||||
Button with Popover |
||||
</button> |
||||
</div> |
||||
</div> |
||||
`; |
@ -1,19 +0,0 @@ |
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
||||
exports[`Tooltip renders correctly 1`] = ` |
||||
<div |
||||
className="popper__manager test-class" |
||||
onMouseEnter={[Function]} |
||||
onMouseLeave={[Function]} |
||||
> |
||||
<div |
||||
className="popper_ref " |
||||
> |
||||
<a |
||||
href="http://www.grafana.com" |
||||
> |
||||
Link with tooltip |
||||
</a> |
||||
</div> |
||||
</div> |
||||
`; |
@ -1,89 +0,0 @@ |
||||
import React from 'react'; |
||||
import { Themes } from './Popper'; |
||||
export interface UsingPopperProps { |
||||
showPopper: (prevState: object) => void; |
||||
hidePopper: (prevState: object) => void; |
||||
renderContent: (content: any) => any; |
||||
show: boolean; |
||||
placement?: string; |
||||
content: string | ((props: any) => JSX.Element); |
||||
className?: string; |
||||
refClassName?: string; |
||||
theme?: Themes; |
||||
} |
||||
|
||||
interface Props { |
||||
placement?: string; |
||||
className?: string; |
||||
refClassName?: string; |
||||
content: string | ((props: any) => JSX.Element); |
||||
theme?: Themes; |
||||
} |
||||
|
||||
interface State { |
||||
placement: string; |
||||
show: boolean; |
||||
} |
||||
|
||||
export default function withPopper(WrappedComponent) { |
||||
return class extends React.Component<Props, State> { |
||||
constructor(props) { |
||||
super(props); |
||||
this.setState = this.setState.bind(this); |
||||
this.state = { |
||||
placement: this.props.placement || 'auto', |
||||
show: false, |
||||
}; |
||||
} |
||||
|
||||
componentWillReceiveProps(nextProps) { |
||||
if (nextProps.placement && nextProps.placement !== this.state.placement) { |
||||
this.setState(prevState => { |
||||
return { |
||||
...prevState, |
||||
placement: nextProps.placement, |
||||
}; |
||||
}); |
||||
} |
||||
} |
||||
|
||||
showPopper = () => { |
||||
this.setState(prevState => ({ |
||||
...prevState, |
||||
show: true, |
||||
})); |
||||
}; |
||||
|
||||
hidePopper = () => { |
||||
this.setState(prevState => ({ |
||||
...prevState, |
||||
show: false, |
||||
})); |
||||
}; |
||||
|
||||
renderContent(content) { |
||||
if (typeof content === 'function') { |
||||
// If it's a function we assume it's a React component
|
||||
const ReactComponent = content; |
||||
return <ReactComponent />; |
||||
} |
||||
return content; |
||||
} |
||||
|
||||
render() { |
||||
const { show, placement } = this.state; |
||||
const className = this.props.className || ''; |
||||
return ( |
||||
<WrappedComponent |
||||
{...this.props} |
||||
showPopper={this.showPopper} |
||||
hidePopper={this.hidePopper} |
||||
renderContent={this.renderContent} |
||||
show={show} |
||||
placement={placement} |
||||
className={className} |
||||
/> |
||||
); |
||||
} |
||||
}; |
||||
} |
@ -0,0 +1,8 @@ |
||||
import getFactors from 'app/core/utils/factors'; |
||||
|
||||
describe('factors', () => { |
||||
it('should return factors for 12', () => { |
||||
const factors = getFactors(12); |
||||
expect(factors).toEqual([1, 2, 3, 4, 6, 12]); |
||||
}); |
||||
}); |
@ -1,493 +0,0 @@ |
||||
import kbn from '../utils/kbn'; |
||||
import * as dateMath from '../utils/datemath'; |
||||
import moment from 'moment'; |
||||
|
||||
describe('unit format menu', () => { |
||||
const menu = kbn.getUnitFormats(); |
||||
menu.map(submenu => { |
||||
describe('submenu ' + submenu.text, () => { |
||||
it('should have a title', () => { |
||||
expect(typeof submenu.text).toBe('string'); |
||||
}); |
||||
|
||||
it('should have a submenu', () => { |
||||
expect(Array.isArray(submenu.submenu)).toBe(true); |
||||
}); |
||||
|
||||
submenu.submenu.map(entry => { |
||||
describe('entry ' + entry.text, () => { |
||||
it('should have a title', () => { |
||||
expect(typeof entry.text).toBe('string'); |
||||
}); |
||||
it('should have a format', () => { |
||||
expect(typeof entry.value).toBe('string'); |
||||
}); |
||||
it('should have a valid format', () => { |
||||
expect(typeof kbn.valueFormats[entry.value]).toBe('function'); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
function describeValueFormat(desc, value, tickSize, tickDecimals, result) { |
||||
describe('value format: ' + desc, () => { |
||||
it('should translate ' + value + ' as ' + result, () => { |
||||
const scaledDecimals = tickDecimals - Math.floor(Math.log(tickSize) / Math.LN10); |
||||
const str = kbn.valueFormats[desc](value, tickDecimals, scaledDecimals); |
||||
expect(str).toBe(result); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
describeValueFormat('ms', 0.0024, 0.0005, 4, '0.0024 ms'); |
||||
describeValueFormat('ms', 100, 1, 0, '100 ms'); |
||||
describeValueFormat('ms', 1250, 10, 0, '1.25 s'); |
||||
describeValueFormat('ms', 1250, 300, 0, '1.3 s'); |
||||
describeValueFormat('ms', 65150, 10000, 0, '1.1 min'); |
||||
describeValueFormat('ms', 6515000, 1500000, 0, '1.8 hour'); |
||||
describeValueFormat('ms', 651500000, 150000000, 0, '8 day'); |
||||
|
||||
describeValueFormat('none', 2.75e-10, 0, 10, '3e-10'); |
||||
describeValueFormat('none', 0, 0, 2, '0'); |
||||
describeValueFormat('dB', 10, 1000, 2, '10.00 dB'); |
||||
|
||||
describeValueFormat('percent', 0, 0, 0, '0%'); |
||||
describeValueFormat('percent', 53, 0, 1, '53.0%'); |
||||
describeValueFormat('percentunit', 0.0, 0, 0, '0%'); |
||||
describeValueFormat('percentunit', 0.278, 0, 1, '27.8%'); |
||||
describeValueFormat('percentunit', 1.0, 0, 0, '100%'); |
||||
|
||||
describeValueFormat('currencyUSD', 7.42, 10000, 2, '$7.42'); |
||||
describeValueFormat('currencyUSD', 1532.82, 1000, 1, '$1.53K'); |
||||
describeValueFormat('currencyUSD', 18520408.7, 10000000, 0, '$19M'); |
||||
|
||||
describeValueFormat('bytes', -1.57e308, -1.57e308, 2, 'NA'); |
||||
|
||||
describeValueFormat('ns', 25, 1, 0, '25 ns'); |
||||
describeValueFormat('ns', 2558, 50, 0, '2.56 µs'); |
||||
|
||||
describeValueFormat('ops', 123, 1, 0, '123 ops'); |
||||
describeValueFormat('rps', 456000, 1000, -1, '456K rps'); |
||||
describeValueFormat('rps', 123456789, 1000000, 2, '123.457M rps'); |
||||
describeValueFormat('wps', 789000000, 1000000, -1, '789M wps'); |
||||
describeValueFormat('iops', 11000000000, 1000000000, -1, '11B iops'); |
||||
|
||||
describeValueFormat('s', 1.23456789e-7, 1e-10, 8, '123.5 ns'); |
||||
describeValueFormat('s', 1.23456789e-4, 1e-7, 5, '123.5 µs'); |
||||
describeValueFormat('s', 1.23456789e-3, 1e-6, 4, '1.235 ms'); |
||||
describeValueFormat('s', 1.23456789e-2, 1e-5, 3, '12.35 ms'); |
||||
describeValueFormat('s', 1.23456789e-1, 1e-4, 2, '123.5 ms'); |
||||
describeValueFormat('s', 24, 1, 0, '24 s'); |
||||
describeValueFormat('s', 246, 1, 0, '4.1 min'); |
||||
describeValueFormat('s', 24567, 100, 0, '6.82 hour'); |
||||
describeValueFormat('s', 24567890, 10000, 0, '40.62 week'); |
||||
describeValueFormat('s', 24567890000, 1000000, 0, '778.53 year'); |
||||
|
||||
describeValueFormat('m', 24, 1, 0, '24 min'); |
||||
describeValueFormat('m', 246, 10, 0, '4.1 hour'); |
||||
describeValueFormat('m', 6545, 10, 0, '4.55 day'); |
||||
describeValueFormat('m', 24567, 100, 0, '2.44 week'); |
||||
describeValueFormat('m', 24567892, 10000, 0, '46.7 year'); |
||||
|
||||
describeValueFormat('h', 21, 1, 0, '21 hour'); |
||||
describeValueFormat('h', 145, 1, 0, '6.04 day'); |
||||
describeValueFormat('h', 1234, 100, 0, '7.3 week'); |
||||
describeValueFormat('h', 9458, 1000, 0, '1.08 year'); |
||||
|
||||
describeValueFormat('d', 3, 1, 0, '3 day'); |
||||
describeValueFormat('d', 245, 100, 0, '35 week'); |
||||
describeValueFormat('d', 2456, 10, 0, '6.73 year'); |
||||
|
||||
describe('date time formats', () => { |
||||
const epoch = 1505634997920; |
||||
const utcTime = moment.utc(epoch); |
||||
const browserTime = moment(epoch); |
||||
|
||||
it('should format as iso date', () => { |
||||
const expected = browserTime.format('YYYY-MM-DD HH:mm:ss'); |
||||
const actual = kbn.valueFormats.dateTimeAsIso(epoch); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as iso date (in UTC)', () => { |
||||
const expected = utcTime.format('YYYY-MM-DD HH:mm:ss'); |
||||
const actual = kbn.valueFormats.dateTimeAsIso(epoch, true); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as iso date and skip date when today', () => { |
||||
const now = moment(); |
||||
const expected = now.format('HH:mm:ss'); |
||||
const actual = kbn.valueFormats.dateTimeAsIso(now.valueOf(), false); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as iso date (in UTC) and skip date when today', () => { |
||||
const now = moment.utc(); |
||||
const expected = now.format('HH:mm:ss'); |
||||
const actual = kbn.valueFormats.dateTimeAsIso(now.valueOf(), true); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as US date', () => { |
||||
const expected = browserTime.format('MM/DD/YYYY h:mm:ss a'); |
||||
const actual = kbn.valueFormats.dateTimeAsUS(epoch, false); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as US date (in UTC)', () => { |
||||
const expected = utcTime.format('MM/DD/YYYY h:mm:ss a'); |
||||
const actual = kbn.valueFormats.dateTimeAsUS(epoch, true); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as US date and skip date when today', () => { |
||||
const now = moment(); |
||||
const expected = now.format('h:mm:ss a'); |
||||
const actual = kbn.valueFormats.dateTimeAsUS(now.valueOf(), false); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as US date (in UTC) and skip date when today', () => { |
||||
const now = moment.utc(); |
||||
const expected = now.format('h:mm:ss a'); |
||||
const actual = kbn.valueFormats.dateTimeAsUS(now.valueOf(), true); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as from now with days', () => { |
||||
const daysAgo = moment().add(-7, 'd'); |
||||
const expected = '7 days ago'; |
||||
const actual = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), false); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as from now with days (in UTC)', () => { |
||||
const daysAgo = moment.utc().add(-7, 'd'); |
||||
const expected = '7 days ago'; |
||||
const actual = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), true); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as from now with minutes', () => { |
||||
const daysAgo = moment().add(-2, 'm'); |
||||
const expected = '2 minutes ago'; |
||||
const actual = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), false); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
|
||||
it('should format as from now with minutes (in UTC)', () => { |
||||
const daysAgo = moment.utc().add(-2, 'm'); |
||||
const expected = '2 minutes ago'; |
||||
const actual = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), true); |
||||
expect(actual).toBe(expected); |
||||
}); |
||||
}); |
||||
|
||||
describe('kbn.toFixed and negative decimals', () => { |
||||
it('should treat as zero decimals', () => { |
||||
const str = kbn.toFixed(186.123, -2); |
||||
expect(str).toBe('186'); |
||||
}); |
||||
}); |
||||
|
||||
describe('kbn ms format when scaled decimals is null do not use it', () => { |
||||
it('should use specified decimals', () => { |
||||
const str = kbn.valueFormats['ms'](10000086.123, 1, null); |
||||
expect(str).toBe('2.8 hour'); |
||||
}); |
||||
}); |
||||
|
||||
describe('kbn kbytes format when scaled decimals is null do not use it', () => { |
||||
it('should use specified decimals', () => { |
||||
const str = kbn.valueFormats['kbytes'](10000000, 3, null); |
||||
expect(str).toBe('9.537 GiB'); |
||||
}); |
||||
}); |
||||
|
||||
describe('kbn deckbytes format when scaled decimals is null do not use it', () => { |
||||
it('should use specified decimals', () => { |
||||
const str = kbn.valueFormats['deckbytes'](10000000, 3, null); |
||||
expect(str).toBe('10.000 GB'); |
||||
}); |
||||
}); |
||||
|
||||
describe('kbn roundValue', () => { |
||||
it('should should handle null value', () => { |
||||
const str = kbn.roundValue(null, 2); |
||||
expect(str).toBe(null); |
||||
}); |
||||
it('should round value', () => { |
||||
const str = kbn.roundValue(200.877, 2); |
||||
expect(str).toBe(200.88); |
||||
}); |
||||
}); |
||||
|
||||
describe('calculateInterval', () => { |
||||
it('1h 100 resultion', () => { |
||||
const range = { from: dateMath.parse('now-1h'), to: dateMath.parse('now') }; |
||||
const res = kbn.calculateInterval(range, 100, null); |
||||
expect(res.interval).toBe('30s'); |
||||
}); |
||||
|
||||
it('10m 1600 resolution', () => { |
||||
const range = { from: dateMath.parse('now-10m'), to: dateMath.parse('now') }; |
||||
const res = kbn.calculateInterval(range, 1600, null); |
||||
expect(res.interval).toBe('500ms'); |
||||
expect(res.intervalMs).toBe(500); |
||||
}); |
||||
|
||||
it('fixed user min interval', () => { |
||||
const range = { from: dateMath.parse('now-10m'), to: dateMath.parse('now') }; |
||||
const res = kbn.calculateInterval(range, 1600, '10s'); |
||||
expect(res.interval).toBe('10s'); |
||||
expect(res.intervalMs).toBe(10000); |
||||
}); |
||||
|
||||
it('short time range and user low limit', () => { |
||||
const range = { from: dateMath.parse('now-10m'), to: dateMath.parse('now') }; |
||||
const res = kbn.calculateInterval(range, 1600, '>10s'); |
||||
expect(res.interval).toBe('10s'); |
||||
}); |
||||
|
||||
it('large time range and user low limit', () => { |
||||
const range = { from: dateMath.parse('now-14d'), to: dateMath.parse('now') }; |
||||
const res = kbn.calculateInterval(range, 1000, '>10s'); |
||||
expect(res.interval).toBe('20m'); |
||||
}); |
||||
|
||||
it('10s 900 resolution and user low limit in ms', () => { |
||||
const range = { from: dateMath.parse('now-10s'), to: dateMath.parse('now') }; |
||||
const res = kbn.calculateInterval(range, 900, '>15ms'); |
||||
expect(res.interval).toBe('15ms'); |
||||
}); |
||||
|
||||
it('1d 1 resolution', () => { |
||||
const range = { from: dateMath.parse('now-1d'), to: dateMath.parse('now') }; |
||||
const res = kbn.calculateInterval(range, 1, null); |
||||
expect(res.interval).toBe('1d'); |
||||
expect(res.intervalMs).toBe(86400000); |
||||
}); |
||||
|
||||
it('86399s 1 resolution', () => { |
||||
const range = { |
||||
from: dateMath.parse('now-86390s'), |
||||
to: dateMath.parse('now'), |
||||
}; |
||||
const res = kbn.calculateInterval(range, 1, null); |
||||
expect(res.interval).toBe('12h'); |
||||
expect(res.intervalMs).toBe(43200000); |
||||
}); |
||||
}); |
||||
|
||||
describe('hex', () => { |
||||
it('positive integer', () => { |
||||
const str = kbn.valueFormats.hex(100, 0); |
||||
expect(str).toBe('64'); |
||||
}); |
||||
it('negative integer', () => { |
||||
const str = kbn.valueFormats.hex(-100, 0); |
||||
expect(str).toBe('-64'); |
||||
}); |
||||
it('null', () => { |
||||
const str = kbn.valueFormats.hex(null, 0); |
||||
expect(str).toBe(''); |
||||
}); |
||||
it('positive float', () => { |
||||
const str = kbn.valueFormats.hex(50.52, 1); |
||||
expect(str).toBe('32.8'); |
||||
}); |
||||
it('negative float', () => { |
||||
const str = kbn.valueFormats.hex(-50.333, 2); |
||||
expect(str).toBe('-32.547AE147AE14'); |
||||
}); |
||||
}); |
||||
|
||||
describe('hex 0x', () => { |
||||
it('positive integeter', () => { |
||||
const str = kbn.valueFormats.hex0x(7999, 0); |
||||
expect(str).toBe('0x1F3F'); |
||||
}); |
||||
it('negative integer', () => { |
||||
const str = kbn.valueFormats.hex0x(-584, 0); |
||||
expect(str).toBe('-0x248'); |
||||
}); |
||||
it('null', () => { |
||||
const str = kbn.valueFormats.hex0x(null, 0); |
||||
expect(str).toBe(''); |
||||
}); |
||||
it('positive float', () => { |
||||
const str = kbn.valueFormats.hex0x(74.443, 3); |
||||
expect(str).toBe('0x4A.716872B020C4'); |
||||
}); |
||||
it('negative float', () => { |
||||
const str = kbn.valueFormats.hex0x(-65.458, 1); |
||||
expect(str).toBe('-0x41.8'); |
||||
}); |
||||
}); |
||||
|
||||
describe('duration', () => { |
||||
it('null', () => { |
||||
const str = kbn.toDuration(null, 0, 'millisecond'); |
||||
expect(str).toBe(''); |
||||
}); |
||||
it('0 milliseconds', () => { |
||||
const str = kbn.toDuration(0, 0, 'millisecond'); |
||||
expect(str).toBe('0 milliseconds'); |
||||
}); |
||||
it('1 millisecond', () => { |
||||
const str = kbn.toDuration(1, 0, 'millisecond'); |
||||
expect(str).toBe('1 millisecond'); |
||||
}); |
||||
it('-1 millisecond', () => { |
||||
const str = kbn.toDuration(-1, 0, 'millisecond'); |
||||
expect(str).toBe('1 millisecond ago'); |
||||
}); |
||||
it('seconds', () => { |
||||
const str = kbn.toDuration(1, 0, 'second'); |
||||
expect(str).toBe('1 second'); |
||||
}); |
||||
it('minutes', () => { |
||||
const str = kbn.toDuration(1, 0, 'minute'); |
||||
expect(str).toBe('1 minute'); |
||||
}); |
||||
it('hours', () => { |
||||
const str = kbn.toDuration(1, 0, 'hour'); |
||||
expect(str).toBe('1 hour'); |
||||
}); |
||||
it('days', () => { |
||||
const str = kbn.toDuration(1, 0, 'day'); |
||||
expect(str).toBe('1 day'); |
||||
}); |
||||
it('weeks', () => { |
||||
const str = kbn.toDuration(1, 0, 'week'); |
||||
expect(str).toBe('1 week'); |
||||
}); |
||||
it('months', () => { |
||||
const str = kbn.toDuration(1, 0, 'month'); |
||||
expect(str).toBe('1 month'); |
||||
}); |
||||
it('years', () => { |
||||
const str = kbn.toDuration(1, 0, 'year'); |
||||
expect(str).toBe('1 year'); |
||||
}); |
||||
it('decimal days', () => { |
||||
const str = kbn.toDuration(1.5, 2, 'day'); |
||||
expect(str).toBe('1 day, 12 hours, 0 minutes'); |
||||
}); |
||||
it('decimal months', () => { |
||||
const str = kbn.toDuration(1.5, 3, 'month'); |
||||
expect(str).toBe('1 month, 2 weeks, 1 day, 0 hours'); |
||||
}); |
||||
it('no decimals', () => { |
||||
const str = kbn.toDuration(38898367008, 0, 'millisecond'); |
||||
expect(str).toBe('1 year'); |
||||
}); |
||||
it('1 decimal', () => { |
||||
const str = kbn.toDuration(38898367008, 1, 'millisecond'); |
||||
expect(str).toBe('1 year, 2 months'); |
||||
}); |
||||
it('too many decimals', () => { |
||||
const str = kbn.toDuration(38898367008, 20, 'millisecond'); |
||||
expect(str).toBe('1 year, 2 months, 3 weeks, 4 days, 5 hours, 6 minutes, 7 seconds, 8 milliseconds'); |
||||
}); |
||||
it('floating point error', () => { |
||||
const str = kbn.toDuration(36993906007, 8, 'millisecond'); |
||||
expect(str).toBe('1 year, 2 months, 0 weeks, 3 days, 4 hours, 5 minutes, 6 seconds, 7 milliseconds'); |
||||
}); |
||||
}); |
||||
|
||||
describe('clock', () => { |
||||
it('null', () => { |
||||
const str = kbn.toClock(null, 0); |
||||
expect(str).toBe(''); |
||||
}); |
||||
it('size less than 1 second', () => { |
||||
const str = kbn.toClock(999, 0); |
||||
expect(str).toBe('999ms'); |
||||
}); |
||||
describe('size less than 1 minute', () => { |
||||
it('default', () => { |
||||
const str = kbn.toClock(59999); |
||||
expect(str).toBe('59s:999ms'); |
||||
}); |
||||
it('decimals equals 0', () => { |
||||
const str = kbn.toClock(59999, 0); |
||||
expect(str).toBe('59s'); |
||||
}); |
||||
}); |
||||
describe('size less than 1 hour', () => { |
||||
it('default', () => { |
||||
const str = kbn.toClock(3599999); |
||||
expect(str).toBe('59m:59s:999ms'); |
||||
}); |
||||
it('decimals equals 0', () => { |
||||
const str = kbn.toClock(3599999, 0); |
||||
expect(str).toBe('59m'); |
||||
}); |
||||
it('decimals equals 1', () => { |
||||
const str = kbn.toClock(3599999, 1); |
||||
expect(str).toBe('59m:59s'); |
||||
}); |
||||
}); |
||||
describe('size greater than or equal 1 hour', () => { |
||||
it('default', () => { |
||||
const str = kbn.toClock(7199999); |
||||
expect(str).toBe('01h:59m:59s:999ms'); |
||||
}); |
||||
it('decimals equals 0', () => { |
||||
const str = kbn.toClock(7199999, 0); |
||||
expect(str).toBe('01h'); |
||||
}); |
||||
it('decimals equals 1', () => { |
||||
const str = kbn.toClock(7199999, 1); |
||||
expect(str).toBe('01h:59m'); |
||||
}); |
||||
it('decimals equals 2', () => { |
||||
const str = kbn.toClock(7199999, 2); |
||||
expect(str).toBe('01h:59m:59s'); |
||||
}); |
||||
}); |
||||
describe('size greater than or equal 1 day', () => { |
||||
it('default', () => { |
||||
const str = kbn.toClock(89999999); |
||||
expect(str).toBe('24h:59m:59s:999ms'); |
||||
}); |
||||
it('decimals equals 0', () => { |
||||
const str = kbn.toClock(89999999, 0); |
||||
expect(str).toBe('24h'); |
||||
}); |
||||
it('decimals equals 1', () => { |
||||
const str = kbn.toClock(89999999, 1); |
||||
expect(str).toBe('24h:59m'); |
||||
}); |
||||
it('decimals equals 2', () => { |
||||
const str = kbn.toClock(89999999, 2); |
||||
expect(str).toBe('24h:59m:59s'); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
describe('volume', () => { |
||||
it('1000m3', () => { |
||||
const str = kbn.valueFormats['m3'](1000, 1, null); |
||||
expect(str).toBe('1000.0 m³'); |
||||
}); |
||||
}); |
||||
|
||||
describe('hh:mm:ss', () => { |
||||
it('00:04:06', () => { |
||||
const str = kbn.valueFormats['dthms'](246, 1); |
||||
expect(str).toBe('00:04:06'); |
||||
}); |
||||
it('24:00:00', () => { |
||||
const str = kbn.valueFormats['dthms'](86400, 1); |
||||
expect(str).toBe('24:00:00'); |
||||
}); |
||||
it('6824413:53:20', () => { |
||||
const str = kbn.valueFormats['dthms'](24567890000, 1); |
||||
expect(str).toBe('6824413:53:20'); |
||||
}); |
||||
}); |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue