Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
a0fa5698
Commit
a0fa5698
authored
Mar 17, 2019
by
ryan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
rename reducer to statsCalculator
parent
29695077
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
190 additions
and
248 deletions
+190
-248
packages/grafana-ui/src/components/StatsPicker/StatsPicker.story.tsx
+17
-17
packages/grafana-ui/src/components/StatsPicker/StatsPicker.tsx
+17
-17
packages/grafana-ui/src/utils/statsCalculator.test.ts
+73
-0
packages/grafana-ui/src/utils/statsCalculator.ts
+83
-130
packages/grafana-ui/src/utils/tableReducer.test.ts
+0
-84
No files found.
packages/grafana-ui/src/components/
TableReducePicker/TableReduce
Picker.story.tsx
→
packages/grafana-ui/src/components/
StatsPicker/Stats
Picker.story.tsx
View file @
a0fa5698
...
...
@@ -3,45 +3,45 @@ import React, { PureComponent } from 'react';
import
{
storiesOf
}
from
'@storybook/react'
;
import
{
action
}
from
'@storybook/addon-actions'
;
import
{
withCenteredStory
}
from
'../../utils/storybook/withCenteredStory'
;
import
{
TableReducePicker
}
from
'./TableReduce
Picker'
;
import
{
StatsPicker
}
from
'./Stats
Picker'
;
import
{
text
,
boolean
}
from
'@storybook/addon-knobs'
;
interface
State
{
reducer
s
:
string
[];
stat
s
:
string
[];
}
export
class
WrapperWithState
extends
PureComponent
<
any
,
State
>
{
constructor
(
props
:
any
)
{
super
(
props
);
this
.
state
=
{
reducers
:
this
.
toReducer
sArray
(
props
.
initialReducers
),
stats
:
this
.
toStat
sArray
(
props
.
initialReducers
),
};
}
to
Reducer
sArray
=
(
txt
:
string
):
string
[]
=>
{
to
Stat
sArray
=
(
txt
:
string
):
string
[]
=>
{
return
txt
.
split
(
','
).
map
(
v
=>
v
.
trim
());
};
componentDidUpdate
(
prevProps
:
any
)
{
const
{
initialReducers
}
=
this
.
props
;
if
(
initialReducers
!==
prevProps
.
initialReducers
)
{
this
.
setState
({
reducers
:
this
.
toReducer
sArray
(
initialReducers
)
});
this
.
setState
({
stats
:
this
.
toStat
sArray
(
initialReducers
)
});
}
}
render
()
{
const
{
placeholder
,
default
Reducer
,
allowMultiple
}
=
this
.
props
;
const
{
reducer
s
}
=
this
.
state
;
const
{
placeholder
,
default
Stat
,
allowMultiple
}
=
this
.
props
;
const
{
stat
s
}
=
this
.
state
;
return
(
<
TableReduce
Picker
<
Stats
Picker
placeholder=
{
placeholder
}
default
Reducer=
{
defaultReducer
}
default
Stat=
{
defaultStat
}
allowMultiple=
{
allowMultiple
}
reducers=
{
reducer
s
}
onChange=
{
(
reducer
s
:
string
[])
=>
{
action
(
'Picked:'
)(
reducer
s
);
this
.
setState
({
reducer
s
});
stats=
{
stat
s
}
onChange=
{
(
stat
s
:
string
[])
=>
{
action
(
'Picked:'
)(
stat
s
);
this
.
setState
({
stat
s
});
}
}
/>
);
...
...
@@ -52,16 +52,16 @@ const story = storiesOf('UI/TableReducePicker', module);
story
.
addDecorator
(
withCenteredStory
);
story
.
add
(
'picker'
,
()
=>
{
const
placeholder
=
text
(
'Placeholder Text'
,
''
);
const
default
Reducer
=
text
(
'Default Reducer
'
,
''
);
const
default
Stat
=
text
(
'Default Stat
'
,
''
);
const
allowMultiple
=
boolean
(
'Allow Multiple'
,
false
);
const
initial
Reducers
=
text
(
'Initial Reducer
s'
,
''
);
const
initial
Stats
=
text
(
'Initial Stat
s'
,
''
);
return
(
<
div
>
<
WrapperWithState
placeholder=
{
placeholder
}
default
Reducer=
{
defaultReducer
}
default
Stat=
{
defaultStat
}
allowMultiple=
{
allowMultiple
}
initial
Reducers=
{
initialReducer
s
}
initial
Stats=
{
initialStat
s
}
/>
</
div
>
);
...
...
packages/grafana-ui/src/components/
TableReducePicker/TableReduce
Picker.tsx
→
packages/grafana-ui/src/components/
StatsPicker/Stats
Picker.tsx
View file @
a0fa5698
...
...
@@ -4,19 +4,19 @@ import isArray from 'lodash/isArray';
import
{
Select
}
from
'../index'
;
import
{
get
TableReducers
}
from
'../../utils/tableReduce
r'
;
import
{
get
StatsCalculators
}
from
'../../utils/statsCalculato
r'
;
import
{
SelectOptionItem
}
from
'../Select/Select'
;
interface
Props
{
placeholder
?:
string
;
onChange
:
(
reducer
s
:
string
[])
=>
void
;
reducer
s
:
string
[];
onChange
:
(
stat
s
:
string
[])
=>
void
;
stat
s
:
string
[];
width
?:
number
;
allowMultiple
?:
boolean
;
default
Reducer
?:
string
;
default
Stat
?:
string
;
}
export
class
TableReduce
Picker
extends
PureComponent
<
Props
>
{
export
class
Stats
Picker
extends
PureComponent
<
Props
>
{
static
defaultProps
=
{
width
:
12
,
allowMultiple
:
false
,
...
...
@@ -31,25 +31,25 @@ export class TableReducePicker extends PureComponent<Props> {
}
checkInput
=
()
=>
{
const
{
reducers
,
allowMultiple
,
defaultReducer
,
onChange
}
=
this
.
props
;
const
{
stats
,
allowMultiple
,
defaultStat
,
onChange
}
=
this
.
props
;
// Check that the selected reducers are all real
const
notFound
:
string
[]
=
[];
const
current
=
get
TableReducers
(
reducer
s
,
notFound
);
const
current
=
get
StatsCalculators
(
stat
s
,
notFound
);
if
(
notFound
.
length
>
0
)
{
console
.
warn
(
'Unknown reducers'
,
notFound
,
reducer
s
);
console
.
warn
(
'Unknown reducers'
,
notFound
,
stat
s
);
onChange
(
current
.
map
(
reducer
=>
reducer
.
value
));
}
// Make sure there is only one
if
(
!
allowMultiple
&&
reducer
s
.
length
>
1
)
{
console
.
warn
(
'Removing extra
reducers'
,
reducer
s
);
onChange
([
reducer
s
[
0
]]);
if
(
!
allowMultiple
&&
stat
s
.
length
>
1
)
{
console
.
warn
(
'Removing extra
stat'
,
stat
s
);
onChange
([
stat
s
[
0
]]);
}
// Set the reducer from callback
if
(
default
Reducer
&&
reducer
s
.
length
<
1
)
{
onChange
([
default
Reducer
]);
if
(
default
Stat
&&
stat
s
.
length
<
1
)
{
onChange
([
default
Stat
]);
}
};
...
...
@@ -63,17 +63,17 @@ export class TableReducePicker extends PureComponent<Props> {
};
render
()
{
const
{
width
,
reducers
,
allowMultiple
,
defaultReducer
,
placeholder
}
=
this
.
props
;
const
current
=
get
TableReducers
(
reducer
s
);
const
{
width
,
stats
,
allowMultiple
,
defaultStat
,
placeholder
}
=
this
.
props
;
const
current
=
get
StatsCalculators
(
stat
s
);
return
(
<
Select
width=
{
width
}
value=
{
current
}
isClearable=
{
!
default
Reducer
}
isClearable=
{
!
default
Stat
}
isMulti=
{
allowMultiple
}
isSearchable=
{
true
}
options=
{
get
TableReduce
rs
()
}
options=
{
get
StatsCalculato
rs
()
}
placeholder=
{
placeholder
}
onChange=
{
this
.
onSelectionChange
}
/>
...
...
packages/grafana-ui/src/utils/statsCalculator.test.ts
0 → 100644
View file @
a0fa5698
import
{
parseCSV
}
from
'./processTableData'
;
import
{
getStatsCalculators
,
StatID
,
calculateStats
}
from
'./statsCalculator'
;
describe
(
'Stats Calculators'
,
()
=>
{
const
basicTable
=
parseCSV
(
'a,b,c
\
n10,20,30
\
n20,30,40'
);
it
(
'should load all standard stats'
,
()
=>
{
const
names
=
[
StatID
.
sum
,
StatID
.
max
,
StatID
.
min
,
StatID
.
logmin
,
StatID
.
mean
,
StatID
.
last
,
StatID
.
first
,
StatID
.
count
,
StatID
.
range
,
StatID
.
diff
,
StatID
.
step
,
StatID
.
delta
,
// StatID.allIsZero,
// StatID.allIsNull,
];
const
notFound
:
string
[]
=
[];
const
stats
=
getStatsCalculators
(
names
,
notFound
);
stats
.
forEach
((
stat
,
index
)
=>
{
expect
(
stat
?
stat
.
value
:
'<missing>'
).
toEqual
(
names
[
index
]);
});
expect
(
notFound
.
length
).
toBe
(
0
);
});
it
(
'should fail to load unknown stats'
,
()
=>
{
const
names
=
[
'not a stat'
,
StatID
.
max
,
StatID
.
min
,
'also not a stat'
];
const
notFound
:
string
[]
=
[];
const
stats
=
getStatsCalculators
(
names
,
notFound
);
expect
(
stats
.
length
).
toBe
(
2
);
expect
(
notFound
.
length
).
toBe
(
2
);
});
it
(
'should calculate stats'
,
()
=>
{
const
stats
=
calculateStats
({
data
:
basicTable
,
columnIndex
:
0
,
stats
:
[
'first'
,
'last'
,
'mean'
],
});
// First
expect
(
stats
.
first
).
toEqual
(
10
);
// Last
expect
(
stats
.
last
).
toEqual
(
20
);
// Mean
expect
(
stats
.
mean
).
toEqual
(
15
);
});
it
(
'should support a single stat also'
,
()
=>
{
const
stats
=
calculateStats
({
data
:
basicTable
,
columnIndex
:
0
,
stats
:
[
'first'
,
'last'
,
'mean'
],
});
// First
expect
(
stats
.
first
).
toEqual
(
10
);
// Last
expect
(
stats
.
last
).
toEqual
(
20
);
// Mean
expect
(
stats
.
mean
).
toEqual
(
15
);
});
});
packages/grafana-ui/src/utils/
tableReduce
r.ts
→
packages/grafana-ui/src/utils/
statsCalculato
r.ts
View file @
a0fa5698
...
...
@@ -3,7 +3,7 @@ import isNumber from 'lodash/isNumber';
import
{
TableData
,
NullValueMode
}
from
'../types/index'
;
export
enum
TableReducer
ID
{
export
enum
Stat
ID
{
sum
=
'sum'
,
max
=
'max'
,
min
=
'min'
,
...
...
@@ -21,92 +21,92 @@ export enum TableReducerID {
allIsNull
=
'allIsNull'
,
}
/** Information about the reducing(stats) functions */
export
interface
TableReducerInfo
{
export
interface
ColumnStats
{
[
key
:
string
]:
any
;
}
// Internal function
type
StatCalculator
=
(
data
:
TableData
,
columnIndex
:
number
,
ignoreNulls
:
boolean
,
nullAsZero
:
boolean
)
=>
ColumnStats
;
export
interface
StatCalculatorInfo
{
value
:
string
;
// The ID - value maps directly to select component
label
:
string
;
// The name - label
label
:
string
;
// The name - label
for Select component
description
:
string
;
alias
?:
string
;
// optional secondary key. 'avg' vs 'mean', 'total' vs 'sum'
// Internal details
emptyInputResult
?:
any
;
// typically null, but some things like 'count' & 'sum' should be zero
standard
:
boolean
;
// The most common stats can all be calculated in a single pass
reducer
?:
TableReduce
r
;
calculator
?:
StatCalculato
r
;
}
/**
* Get a list of the known reducing functions
* @param ids list of reducer names or null to get all of them
* @param notFound optional error object that will be filled with the names on unknown reducers
* @param ids list of stat names or null to get all of them
* @param notFound optional error object that will be filled with the names on unknown stats
*/
export
function
get
TableReducers
(
ids
?:
string
[],
notFound
?:
string
[]):
TableReduce
rInfo
[]
{
export
function
get
StatsCalculators
(
ids
?:
string
[],
notFound
?:
string
[]):
StatCalculato
rInfo
[]
{
if
(
ids
===
null
||
ids
===
undefined
)
{
return
listOf
Reducer
s
;
return
listOf
Stat
s
;
}
return
ids
.
reduce
((
list
,
id
)
=>
{
const
reducer
=
getById
(
id
);
if
(
reducer
)
{
list
.
push
(
reducer
);
const
stat
=
getById
(
id
);
if
(
stat
)
{
list
.
push
(
stat
);
}
else
if
(
notFound
&&
id
)
{
notFound
.
push
(
id
);
}
return
list
;
},
new
Array
<
TableReduce
rInfo
>
());
},
new
Array
<
StatCalculato
rInfo
>
());
}
export
interface
TableReducer
Options
{
columnIndexes
?:
number
[]
;
nullValueMode
?:
NullValueMode
;
export
interface
CalculateStats
Options
{
data
:
TableData
;
columnIndex
:
number
;
stats
:
string
[];
// The stats to calculate
nullValueMode
?:
NullValueMode
;
}
export
function
reduceTableData
(
data
:
TableData
,
options
:
TableReducerOptions
):
TableData
[]
{
const
indexes
=
verifyColumns
(
data
,
options
);
const
columns
=
indexes
.
map
(
v
=>
data
.
columns
[
v
]);
/**
* @returns an object with a key for each selected stat
*/
export
function
calculateStats
(
options
:
CalculateStatsOptions
):
ColumnStats
{
const
{
data
,
columnIndex
,
stats
,
nullValueMode
}
=
options
;
const
ignoreNulls
=
options
.
nullValueMode
===
NullValueMode
.
Ignore
;
const
nullAsZero
=
options
.
nullValueMode
===
NullValueMode
.
AsZero
;
if
(
!
stats
||
stats
.
length
<
1
)
{
return
{};
}
const
queue
=
get
TableReducers
(
options
.
stats
);
const
queue
=
get
StatsCalculators
(
stats
);
// Return early for empty tables
// This lets the concrete implementations assume at least one row
if
(
!
data
.
rows
||
data
.
rows
.
length
<
1
)
{
return
queue
.
map
(
stat
=>
{
return
{
columns
,
rows
:
[
indexes
.
map
(
v
=>
stat
.
emptyInputResult
)],
type
:
'table'
,
columnMap
:
{},
};
const
stats
=
{}
as
ColumnStats
;
queue
.
forEach
(
stat
=>
{
stats
[
stat
.
value
]
=
stat
.
emptyInputResult
!==
null
?
stat
.
emptyInputResult
:
null
;
});
return
stats
;
}
const
ignoreNulls
=
nullValueMode
===
NullValueMode
.
Ignore
;
const
nullAsZero
=
nullValueMode
===
NullValueMode
.
AsZero
;
// Avoid calculating all the standard stats if possible
if
(
queue
.
length
===
1
&&
queue
[
0
].
reducer
)
{
return
[
{
columns
,
rows
:
[
queue
[
0
].
reducer
(
data
,
indexes
,
ignoreNulls
,
nullAsZero
)],
type
:
'table'
,
columnMap
:
{},
},
];
if
(
queue
.
length
===
1
&&
queue
[
0
].
calculator
)
{
return
[
queue
[
0
].
calculator
(
data
,
columnIndex
,
ignoreNulls
,
nullAsZero
)];
}
// For now everything can use the standard stats
const
standard
=
standardStatsReducer
(
data
,
indexes
,
ignoreNulls
,
nullAsZero
);
return
queue
.
map
(
calc
=>
{
const
values
=
calc
.
standard
?
standard
.
map
((
s
:
any
)
=>
s
[
calc
.
value
])
:
calc
.
reducer
!
(
data
,
indexes
,
ignoreNulls
,
nullAsZero
);
return
{
columns
,
rows
:
[
values
],
type
:
'table'
,
columnMap
:
{},
let
values
=
standardStatsStat
(
data
,
columnIndex
,
ignoreNulls
,
nullAsZero
);
queue
.
forEach
(
calc
=>
{
if
(
!
values
.
hasOwnProperty
(
calc
.
value
)
&&
calc
.
calculator
)
{
values
=
{
...
values
,
...
calc
.
calculator
(
data
,
columnIndex
,
ignoreNulls
,
nullAsZero
),
};
}
});
return
values
;
}
// ------------------------------------------------------------------------------
...
...
@@ -115,66 +115,64 @@ export function reduceTableData(data: TableData, options: TableReducerOptions):
//
// ------------------------------------------------------------------------------
type
TableReducer
=
(
data
:
TableData
,
columnIndexes
:
number
[],
ignoreNulls
:
boolean
,
nullAsZero
:
boolean
)
=>
any
[];
// private registry of all reducers
interface
TableReducerIndex
{
[
id
:
string
]:
TableReducerInfo
;
// private registry of all stats
interface
TableStatIndex
{
[
id
:
string
]:
StatCalculatorInfo
;
}
const
listOf
Reducers
:
TableReduce
rInfo
[]
=
[];
const
index
:
Table
Reducer
Index
=
{};
const
listOf
Stats
:
StatCalculato
rInfo
[]
=
[];
const
index
:
Table
Stat
Index
=
{};
let
hasBuiltIndex
=
false
;
function
getById
(
id
:
string
):
TableReduce
rInfo
|
undefined
{
function
getById
(
id
:
string
):
StatCalculato
rInfo
|
undefined
{
if
(
!
hasBuiltIndex
)
{
[
{
value
:
TableReducer
ID
.
last
,
value
:
Stat
ID
.
last
,
label
:
'Last'
,
description
:
'Last Value (current)'
,
standard
:
true
,
alias
:
'current'
,
reducer
:
getLastRow
,
stat
:
calculateLast
,
},
{
value
:
TableReducerID
.
first
,
label
:
'First'
,
description
:
'First Value'
,
standard
:
true
,
reducer
:
getFirstRow
},
{
value
:
TableReducer
ID
.
min
,
label
:
'Min'
,
description
:
'Minimum Value'
,
standard
:
true
},
{
value
:
TableReducer
ID
.
max
,
label
:
'Max'
,
description
:
'Maximum Value'
,
standard
:
true
},
{
value
:
TableReducer
ID
.
mean
,
label
:
'Mean'
,
description
:
'Average Value'
,
standard
:
true
,
alias
:
'avg'
},
{
value
:
StatID
.
first
,
label
:
'First'
,
description
:
'First Value'
,
standard
:
true
,
stat
:
calculateFirst
},
{
value
:
Stat
ID
.
min
,
label
:
'Min'
,
description
:
'Minimum Value'
,
standard
:
true
},
{
value
:
Stat
ID
.
max
,
label
:
'Max'
,
description
:
'Maximum Value'
,
standard
:
true
},
{
value
:
Stat
ID
.
mean
,
label
:
'Mean'
,
description
:
'Average Value'
,
standard
:
true
,
alias
:
'avg'
},
{
value
:
TableReducer
ID
.
sum
,
value
:
Stat
ID
.
sum
,
label
:
'Total'
,
description
:
'The sum of all values'
,
emptyInputResult
:
0
,
standard
:
true
,
alias
:
'total'
,
},
{
value
:
TableReducer
ID
.
count
,
label
:
'Count'
,
description
:
'Value Count'
,
emptyInputResult
:
0
,
standard
:
true
},
{
value
:
Stat
ID
.
count
,
label
:
'Count'
,
description
:
'Value Count'
,
emptyInputResult
:
0
,
standard
:
true
},
{
value
:
TableReducer
ID
.
range
,
value
:
Stat
ID
.
range
,
label
:
'Range'
,
description
:
'Difference between minimum and maximum values'
,
standard
:
true
,
},
{
value
:
TableReducer
ID
.
delta
,
value
:
Stat
ID
.
delta
,
label
:
'Delta'
,
description
:
'Cumulative change in value'
,
// HELP! not totally sure what this does
standard
:
true
,
},
{
value
:
TableReducer
ID
.
step
,
value
:
Stat
ID
.
step
,
label
:
'Step'
,
description
:
'Minimum interval between values'
,
standard
:
true
,
},
{
value
:
TableReducer
ID
.
diff
,
value
:
Stat
ID
.
diff
,
label
:
'Difference'
,
description
:
'Difference between first and last values'
,
standard
:
true
,
},
{
value
:
TableReducer
ID
.
logmin
,
value
:
Stat
ID
.
logmin
,
label
:
'Min (above zero)'
,
description
:
'Used for log min scale'
,
standard
:
true
,
...
...
@@ -182,64 +180,29 @@ function getById(id: string): TableReducerInfo | undefined {
].
forEach
(
calc
=>
{
const
{
value
,
alias
}
=
calc
;
if
(
index
.
hasOwnProperty
(
value
))
{
console
.
warn
(
'Duplicate
Reducer
'
,
value
,
calc
,
index
);
console
.
warn
(
'Duplicate
Stat
'
,
value
,
calc
,
index
);
}
index
[
value
]
=
calc
;
if
(
alias
)
{
if
(
index
.
hasOwnProperty
(
alias
))
{
console
.
warn
(
'Duplicate
Reducer
(alias)'
,
alias
,
calc
,
index
);
console
.
warn
(
'Duplicate
Stat
(alias)'
,
alias
,
calc
,
index
);
}
index
[
alias
]
=
calc
;
}
listOf
Reducer
s
.
push
(
calc
);
listOf
Stat
s
.
push
(
calc
);
});
hasBuiltIndex
=
true
;
}
return
index
[
id
];
}
/**
* This will return an array of valid indexes and throw an error if invalid request
*/
function
verifyColumns
(
data
:
TableData
,
options
:
TableReducerOptions
):
number
[]
{
const
{
columnIndexes
}
=
options
;
if
(
!
columnIndexes
)
{
return
data
.
columns
.
map
((
v
,
idx
)
=>
idx
);
}
columnIndexes
.
forEach
(
v
=>
{
if
(
v
<
0
||
v
>=
data
.
columns
.
length
)
{
throw
new
Error
(
'Invalid column selection: '
+
v
);
}
});
return
columnIndexes
;
}
interface
StandardStats
{
sum
:
number
|
null
;
// total
max
:
number
|
null
;
min
:
number
|
null
;
logmin
:
number
;
mean
:
number
|
null
;
// avg
last
:
any
;
// current
first
:
any
;
count
:
number
;
nonNullCount
:
number
;
range
:
number
|
null
;
diff
:
number
|
null
;
delta
:
number
|
null
;
step
:
number
|
null
;
allIsZero
:
boolean
;
allIsNull
:
boolean
;
}
function
standardStatsReducer
(
function
standardStatsStat
(
data
:
TableData
,
columnIndex
es
:
number
[]
,
columnIndex
:
number
,
ignoreNulls
:
boolean
,
nullAsZero
:
boolean
):
StandardStats
[]
{
const
column
=
columnIndexes
.
map
(
idx
=>
{
return
{
):
ColumnStats
{
const
stats
=
{
sum
:
0
,
max
:
-
Number
.
MAX_VALUE
,
min
:
Number
.
MAX_VALUE
,
...
...
@@ -256,15 +219,12 @@ function standardStatsReducer(
delta
:
0
,
step
:
0
,
// Just used for calcutations -- not exposed as a reducer
// Just used for calcutations -- not exposed as a stat
previousDeltaUp
:
true
,
};
});
}
as
ColumnStats
;
for
(
let
i
=
0
;
i
<
data
.
rows
.
length
;
i
++
)
{
for
(
let
x
=
0
;
x
<
column
.
length
;
x
++
)
{
const
stats
=
column
[
x
];
let
currentValue
=
data
.
rows
[
i
][
x
];
let
currentValue
=
data
.
rows
[
i
][
columnIndex
];
if
(
currentValue
===
null
)
{
if
(
ignoreNulls
)
{
...
...
@@ -331,10 +291,6 @@ function standardStatsReducer(
stats
.
last
=
currentValue
;
}
}
}
for
(
let
x
=
0
;
x
<
column
.
length
;
x
++
)
{
const
stats
=
column
[
x
]
as
StandardStats
;
if
(
stats
.
max
===
-
Number
.
MAX_VALUE
)
{
stats
.
max
=
null
;
...
...
@@ -357,17 +313,14 @@ function standardStatsReducer(
stats
.
diff
=
stats
.
last
-
stats
.
first
;
}
}
}
return
column
;
return
stats
;
}
function
getFirstRow
(
data
:
TableData
,
columnIndexes
:
number
[],
ignoreNulls
:
boolean
,
nullAsZero
:
boolean
):
any
[]
{
const
row
=
data
.
rows
[
0
];
return
columnIndexes
.
map
(
idx
=>
row
[
idx
]);
function
calculateFirst
(
data
:
TableData
,
columnIndex
:
number
,
ignoreNulls
:
boolean
,
nullAsZero
:
boolean
):
ColumnStats
{
return
{
first
:
data
.
rows
[
0
][
columnIndex
]
};
}
function
getLastRow
(
data
:
TableData
,
columnIndexes
:
number
[],
ignoreNulls
:
boolean
,
nullAsZero
:
boolean
):
any
[]
{
const
row
=
data
.
rows
[
data
.
rows
.
length
-
1
];
return
columnIndexes
.
map
(
idx
=>
row
[
idx
]);
function
calculateLast
(
data
:
TableData
,
columnIndex
:
number
,
ignoreNulls
:
boolean
,
nullAsZero
:
boolean
):
ColumnStats
{
return
{
last
:
data
.
rows
[
data
.
rows
.
length
-
1
][
columnIndex
]
};
}
packages/grafana-ui/src/utils/tableReducer.test.ts
deleted
100644 → 0
View file @
29695077
import
{
parseCSV
}
from
'./processTableData'
;
import
{
reduceTableData
,
getTableReducers
,
TableReducerID
}
from
'./tableReducer'
;
describe
(
'Table Reducer'
,
()
=>
{
const
basicTable
=
parseCSV
(
'a,b,c
\
n10,20,30
\
n20,30,40'
);
it
(
'should load all standard stats'
,
()
=>
{
const
names
=
[
TableReducerID
.
sum
,
TableReducerID
.
max
,
TableReducerID
.
min
,
TableReducerID
.
logmin
,
TableReducerID
.
mean
,
TableReducerID
.
last
,
TableReducerID
.
first
,
TableReducerID
.
count
,
TableReducerID
.
range
,
TableReducerID
.
diff
,
TableReducerID
.
step
,
TableReducerID
.
delta
,
// TableReducerID.allIsZero,
// TableReducerID.allIsNull,
];
const
notFound
:
string
[]
=
[];
const
reducers
=
getTableReducers
(
names
,
notFound
);
reducers
.
forEach
((
reducer
,
index
)
=>
{
expect
(
reducer
?
reducer
.
value
:
'<missing>'
).
toEqual
(
names
[
index
]);
});
expect
(
notFound
.
length
).
toBe
(
0
);
});
it
(
'should fail to load unknown reducers'
,
()
=>
{
const
names
=
[
'not a reducer'
,
TableReducerID
.
max
,
TableReducerID
.
min
,
'also not a reducer'
];
const
notFound
:
string
[]
=
[];
const
reducers
=
getTableReducers
(
names
,
notFound
);
expect
(
reducers
.
length
).
toBe
(
2
);
expect
(
notFound
.
length
).
toBe
(
2
);
});
it
(
'should calculate stats'
,
()
=>
{
const
reduced
=
reduceTableData
(
basicTable
,
{
columnIndexes
:
[
0
,
1
],
stats
:
[
'first'
,
'last'
,
'mean'
],
});
expect
(
reduced
.
length
).
toBe
(
3
);
// First
expect
(
reduced
[
0
].
rows
[
0
]).
toEqual
([
10
,
20
]);
// Last
expect
(
reduced
[
1
].
rows
[
0
]).
toEqual
([
20
,
30
]);
// Mean
expect
(
reduced
[
2
].
rows
[
0
]).
toEqual
([
15
,
25
]);
});
it
(
'should support a single stat also'
,
()
=>
{
// First
let
reduced
=
reduceTableData
(
basicTable
,
{
columnIndexes
:
[
0
,
1
],
stats
:
[
'first'
],
});
expect
(
reduced
.
length
).
toBe
(
1
);
expect
(
reduced
[
0
].
rows
[
0
]).
toEqual
([
10
,
20
]);
// Last
reduced
=
reduceTableData
(
basicTable
,
{
columnIndexes
:
[
0
,
1
],
stats
:
[
'last'
],
});
expect
(
reduced
.
length
).
toBe
(
1
);
expect
(
reduced
[
0
].
rows
[
0
]).
toEqual
([
20
,
30
]);
// Mean
reduced
=
reduceTableData
(
basicTable
,
{
columnIndexes
:
[
0
,
1
],
stats
:
[
'mean'
],
});
expect
(
reduced
.
length
).
toBe
(
1
);
expect
(
reduced
[
0
].
rows
[
0
]).
toEqual
([
15
,
25
]);
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment