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
fe22d14e
Commit
fe22d14e
authored
Mar 09, 2019
by
ryan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cell builder cleanup
parent
078d8f12
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
374 additions
and
337 deletions
+374
-337
packages/grafana-ui/src/components/Table/Table.story.tsx
+17
-9
packages/grafana-ui/src/components/Table/Table.test.ts
+0
-240
packages/grafana-ui/src/components/Table/Table.tsx
+60
-85
packages/grafana-ui/src/components/Table/TableCellBuilder.tsx
+292
-0
packages/grafana-ui/src/components/Table/TableXXXX.tsx
+0
-0
packages/grafana-ui/src/components/Table/_Table.scss
+1
-0
packages/grafana-ui/src/components/Table/examples.ts
+1
-1
packages/grafana-ui/src/utils/storybook/withFullSizeStory.tsx
+1
-0
public/app/plugins/panel/table/renderer.ts
+1
-1
public/app/plugins/panel/table2/types.ts
+1
-1
No files found.
packages/grafana-ui/src/components/Table/Table.story.tsx
View file @
fe22d14e
...
@@ -5,24 +5,32 @@ import { Table } from './Table';
...
@@ -5,24 +5,32 @@ import { Table } from './Table';
import
{
migratedTestTable
,
migratedTestStyles
,
simpleTable
}
from
'./examples'
;
import
{
migratedTestTable
,
migratedTestStyles
,
simpleTable
}
from
'./examples'
;
import
{
ScopedVars
,
TableData
}
from
'../../types/index'
;
import
{
ScopedVars
,
TableData
}
from
'../../types/index'
;
import
{
withFullSizeStory
}
from
'../../utils/storybook/withFullSizeStory'
;
import
{
withFullSizeStory
}
from
'../../utils/storybook/withFullSizeStory'
;
import
{
number
,
boolean
}
from
'@storybook/addon-knobs'
;
const
replaceVariables
=
(
value
:
any
,
scopedVars
:
ScopedVars
|
undefined
)
=>
{
const
replaceVariables
=
(
value
:
string
,
scopedVars
?:
ScopedVars
)
=>
{
// if (scopedVars) {
if
(
scopedVars
)
{
// // For testing variables replacement in link
// For testing variables replacement in link
// _.each(scopedVars, (val, key) => {
for
(
const
key
in
scopedVars
)
{
// value = value.replace('$' + key, val.value);
const
val
=
scopedVars
[
key
];
// });
value
=
value
.
replace
(
'$'
+
key
,
val
.
value
);
// }
}
}
return
value
;
return
value
;
};
};
storiesOf
(
'UI
- Alpha
/Table'
,
module
)
storiesOf
(
'UI/Table'
,
module
)
.
add
(
'basic'
,
()
=>
{
.
add
(
'basic'
,
()
=>
{
const
showHeader
=
boolean
(
'Show Header'
,
true
);
const
fixedRowCount
=
number
(
'Fixed Rows'
,
1
);
const
fixedColumnCount
=
number
(
'Fixed Columns'
,
1
);
return
withFullSizeStory
(
Table
,
{
return
withFullSizeStory
(
Table
,
{
styles
:
[],
styles
:
[],
data
:
simpleTable
,
data
:
simpleTable
,
replaceVariables
,
replaceVariables
,
showHeader
:
true
,
fixedRowCount
,
fixedColumnCount
,
showHeader
,
});
});
})
})
.
add
(
'Test Configuration'
,
()
=>
{
.
add
(
'Test Configuration'
,
()
=>
{
...
...
packages/grafana-ui/src/components/Table/Table.test.ts
deleted
100644 → 0
View file @
078d8f12
import
_
from
'lodash'
;
import
{
getColorDefinitionByName
}
from
'@grafana/ui'
;
import
{
ScopedVars
}
from
'@grafana/ui/src/types'
;
import
{
getTheme
}
from
'../../themes'
;
import
{
migratedTestTable
,
migratedTestStyles
}
from
'./examples'
;
import
TableXXXX
from
'./TableXXXX'
;
// TODO: this is commented out with *x* describe!
// Essentially all the elements need to replace the <td> with <div>
xdescribe
(
'when rendering table'
,
()
=>
{
const
SemiDarkOrange
=
getColorDefinitionByName
(
'semi-dark-orange'
);
describe
(
'given 13 columns'
,
()
=>
{
// const sanitize = value => {
// return 'sanitized';
// };
const
replaceVariables
=
(
value
:
any
,
scopedVars
:
ScopedVars
|
undefined
)
=>
{
if
(
scopedVars
)
{
// For testing variables replacement in link
_
.
each
(
scopedVars
,
(
val
,
key
)
=>
{
value
=
value
.
replace
(
'$'
+
key
,
val
.
value
);
});
}
return
value
;
};
const
table
=
migratedTestTable
;
const
renderer
=
new
TableXXXX
({
styles
:
migratedTestStyles
,
data
:
migratedTestTable
,
replaceVariables
,
showHeader
:
true
,
width
:
100
,
height
:
100
,
theme
:
getTheme
(),
});
it
(
'time column should be formated'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
0
,
0
,
1388556366666
);
expect
(
html
).
toBe
(
'<td>2014-01-01T06:06:06Z</td>'
);
});
it
(
'time column with epoch as string should be formatted'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
0
,
0
,
'1388556366666'
);
expect
(
html
).
toBe
(
'<td>2014-01-01T06:06:06Z</td>'
);
});
it
(
'time column with RFC2822 date as string should be formatted'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
0
,
0
,
'Sat, 01 Dec 2018 01:00:00 GMT'
);
expect
(
html
).
toBe
(
'<td>2018-12-01T01:00:00Z</td>'
);
});
it
(
'time column with ISO date as string should be formatted'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
0
,
0
,
'2018-12-01T01:00:00Z'
);
expect
(
html
).
toBe
(
'<td>2018-12-01T01:00:00Z</td>'
);
});
it
(
'undefined time column should be rendered as -'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
0
,
0
,
undefined
);
expect
(
html
).
toBe
(
'<td>-</td>'
);
});
it
(
'null time column should be rendered as -'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
0
,
0
,
null
);
expect
(
html
).
toBe
(
'<td>-</td>'
);
});
it
(
'number column with unit specified should ignore style unit'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
5
,
0
,
1230
);
expect
(
html
).
toBe
(
'<td>1.23 kbps</td>'
);
});
it
(
'number column should be formated'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
1
,
0
,
1230
);
expect
(
html
).
toBe
(
'<td>1.230 s</td>'
);
});
it
(
'number style should ignore string values'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
1
,
0
,
'asd'
);
expect
(
html
).
toBe
(
'<td>asd</td>'
);
});
it
(
'colored cell should have style (handles HEX color values)'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
2
,
0
,
40
);
expect
(
html
).
toBe
(
'<td style="color:#00ff00">40.0</td>'
);
});
it
(
'colored cell should have style (handles named color values'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
2
,
0
,
55
);
expect
(
html
).
toBe
(
`<td style="color:
${
SemiDarkOrange
.
variants
.
dark
}
">55.0</td>`
);
});
it
(
'colored cell should have style handles(rgb color values)'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
2
,
0
,
85
);
expect
(
html
).
toBe
(
'<td style="color:rgb(1,0,0)">85.0</td>'
);
});
it
(
'unformated undefined should be rendered as string'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
3
,
0
,
'value'
);
expect
(
html
).
toBe
(
'<td>value</td>'
);
});
it
(
'string style with escape html should return escaped html'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
4
,
0
,
'&breaking <br /> the <br /> row'
);
expect
(
html
).
toBe
(
'<td>&breaking <br /> the <br /> row</td>'
);
});
it
(
'undefined formater should return escaped html'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
3
,
0
,
'&breaking <br /> the <br /> row'
);
expect
(
html
).
toBe
(
'<td>&breaking <br /> the <br /> row</td>'
);
});
it
(
'undefined value should render as -'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
3
,
0
,
undefined
);
expect
(
html
).
toBe
(
'<td></td>'
);
});
it
(
'sanitized value should render as'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
6
,
0
,
'text <a href="http://google.com">link</a>'
);
expect
(
html
).
toBe
(
'<td>sanitized</td>'
);
});
it
(
'Time column title should be Timestamp'
,
()
=>
{
expect
(
table
.
columns
[
0
].
title
).
toBe
(
'Timestamp'
);
});
it
(
'Value column title should be Val'
,
()
=>
{
expect
(
table
.
columns
[
1
].
title
).
toBe
(
'Val'
);
});
it
(
'Colored column title should be Colored'
,
()
=>
{
expect
(
table
.
columns
[
2
].
title
).
toBe
(
'Colored'
);
});
it
(
'link should render as'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
7
,
0
,
'host1'
);
const
expectedHtml
=
`
<td class="table-panel-cell-link">
<a href="/dashboard?param=host1¶m_1=1230¶m_2=40"
target="_blank" data-link-tooltip data-original-title="host1 1230 my.host.com" data-placement="right">
host1
</a>
</td>
`
;
expect
(
normalize
(
html
+
''
)).
toBe
(
normalize
(
expectedHtml
));
});
it
(
'Array column should not use number as formatter'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
8
,
0
,
[
'value1'
,
'value2'
]);
expect
(
html
).
toBe
(
'<td>value1, value2</td>'
);
});
it
(
'numeric value should be mapped to text'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
9
,
0
,
1
);
expect
(
html
).
toBe
(
'<td>on</td>'
);
});
it
(
'string numeric value should be mapped to text'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
9
,
0
,
'0'
);
expect
(
html
).
toBe
(
'<td>off</td>'
);
});
it
(
'string value should be mapped to text'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
9
,
0
,
'HELLO WORLD'
);
expect
(
html
).
toBe
(
'<td>HELLO GRAFANA</td>'
);
});
it
(
'array column value should be mapped to text'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
9
,
0
,
[
'value1'
,
'value2'
]);
expect
(
html
).
toBe
(
'<td>value3, value4</td>'
);
});
it
(
'value should be mapped to text (range)'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
10
,
0
,
2
);
expect
(
html
).
toBe
(
'<td>on</td>'
);
});
it
(
'value should be mapped to text (range)'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
10
,
0
,
5
);
expect
(
html
).
toBe
(
'<td>off</td>'
);
});
it
(
'array column value should not be mapped to text'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
10
,
0
,
[
'value1'
,
'value2'
]);
expect
(
html
).
toBe
(
'<td>value1, value2</td>'
);
});
it
(
'value should be mapped to text and colored cell should have style'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
11
,
0
,
1
);
expect
(
html
).
toBe
(
`<td style="color:
${
SemiDarkOrange
.
variants
.
dark
}
">on</td>`
);
});
it
(
'value should be mapped to text and colored cell should have style'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
11
,
0
,
'1'
);
expect
(
html
).
toBe
(
`<td style="color:
${
SemiDarkOrange
.
variants
.
dark
}
">on</td>`
);
});
it
(
'value should be mapped to text and colored cell should have style'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
11
,
0
,
0
);
expect
(
html
).
toBe
(
'<td style="color:#00ff00">off</td>'
);
});
it
(
'value should be mapped to text and colored cell should have style'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
11
,
0
,
'0'
);
expect
(
html
).
toBe
(
'<td style="color:#00ff00">off</td>'
);
});
it
(
'value should be mapped to text and colored cell should have style'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
11
,
0
,
'2.1'
);
expect
(
html
).
toBe
(
'<td style="color:rgb(1,0,0)">2.1</td>'
);
});
it
(
'value should be mapped to text (range) and colored cell should have style'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
12
,
0
,
0
);
expect
(
html
).
toBe
(
'<td style="color:#00ff00">0</td>'
);
});
it
(
'value should be mapped to text (range) and colored cell should have style'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
12
,
0
,
1
);
expect
(
html
).
toBe
(
'<td style="color:#00ff00">on</td>'
);
});
it
(
'value should be mapped to text (range) and colored cell should have style'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
12
,
0
,
4
);
expect
(
html
).
toBe
(
`<td style="color:
${
SemiDarkOrange
.
variants
.
dark
}
">off</td>`
);
});
it
(
'value should be mapped to text (range) and colored cell should have style'
,
()
=>
{
const
html
=
renderer
.
renderCell
(
12
,
0
,
'7.1'
);
expect
(
html
).
toBe
(
'<td style="color:rgb(1,0,0)">7.1</td>'
);
});
});
});
function
normalize
(
str
:
string
)
{
return
str
.
replace
(
/
\s
+/gm
,
' '
).
trim
();
}
packages/grafana-ui/src/components/Table/Table.tsx
View file @
fe22d14e
// Libraries
// Libraries
import
_
from
'lodash'
;
import
_
from
'lodash'
;
import
React
,
{
Component
,
React
Node
}
from
'react'
;
import
React
,
{
Component
,
React
Element
}
from
'react'
;
import
{
import
{
SortDirectionType
,
SortDirectionType
,
SortIndicator
,
SortIndicator
,
...
@@ -14,49 +14,16 @@ import { Themeable } from '../../types/theme';
...
@@ -14,49 +14,16 @@ import { Themeable } from '../../types/theme';
import
{
sortTableData
}
from
'../../utils/processTimeSeries'
;
import
{
sortTableData
}
from
'../../utils/processTimeSeries'
;
import
{
TableData
,
InterpolateFunction
}
from
'@grafana/ui'
;
import
{
TableData
,
InterpolateFunction
}
from
'@grafana/ui'
;
import
{
ColumnStyle
}
from
'./Table'
;
import
{
TableCellBuilder
,
ColumnStyle
,
getCellBuilder
,
TableCellBuilderOptions
}
from
'./TableCellBuilder'
;
// APP Imports!!!
// import kbn from 'app/core/utils/kbn';
// Made to match the existing (untyped) settings in the angular table
export
interface
ColumnStyle
{
pattern
?:
string
;
alias
?:
string
;
colorMode
?:
'cell'
|
'value'
;
colors
?:
any
[];
decimals
?:
number
;
thresholds
?:
any
[];
type
?:
'date'
|
'number'
|
'string'
|
'hidden'
;
unit
?:
string
;
dateFormat
?:
string
;
sanitize
?:
boolean
;
// not used in react
mappingType
?:
any
;
valueMaps
?:
any
;
rangeMaps
?:
any
;
link
?:
any
;
linkUrl
?:
any
;
linkTooltip
?:
any
;
linkTargetBlank
?:
boolean
;
preserveFormat
?:
boolean
;
}
type
CellFormatter
=
(
v
:
any
,
style
?:
ColumnStyle
)
=>
ReactNode
;
interface
ColumnInfo
{
interface
ColumnInfo
{
index
:
number
;
header
:
string
;
header
:
string
;
accessor
:
string
;
// the field name
builder
:
TableCellBuilder
;
style
?:
ColumnStyle
;
hidden
?:
boolean
;
formatter
:
CellFormatter
;
filterable
?:
boolean
;
}
}
interface
Props
extends
Themeable
{
export
interface
Props
extends
Themeable
{
data
?
:
TableData
;
data
:
TableData
;
showHeader
:
boolean
;
showHeader
:
boolean
;
fixedColumnCount
:
number
;
fixedColumnCount
:
number
;
fixedRowCount
:
number
;
fixedRowCount
:
number
;
...
@@ -70,14 +37,12 @@ interface Props extends Themeable {
...
@@ -70,14 +37,12 @@ interface Props extends Themeable {
interface
State
{
interface
State
{
sortBy
?:
number
;
sortBy
?:
number
;
sortDirection
?:
SortDirectionType
;
sortDirection
?:
SortDirectionType
;
data
?
:
TableData
;
data
:
TableData
;
}
}
export
class
Table
extends
Component
<
Props
,
State
>
{
export
class
Table
extends
Component
<
Props
,
State
>
{
columns
:
ColumnInfo
[]
=
[];
columns
:
ColumnInfo
[];
colorState
:
any
;
measurer
:
CellMeasurerCache
;
_cache
:
CellMeasurerCache
;
static
defaultProps
=
{
static
defaultProps
=
{
showHeader
:
true
,
showHeader
:
true
,
...
@@ -92,12 +57,11 @@ export class Table extends Component<Props, State> {
...
@@ -92,12 +57,11 @@ export class Table extends Component<Props, State> {
data
:
props
.
data
,
data
:
props
.
data
,
};
};
this
.
_cache
=
new
CellMeasurerCache
({
this
.
columns
=
this
.
initColumns
(
props
);
this
.
measurer
=
new
CellMeasurerCache
({
defaultHeight
:
30
,
defaultHeight
:
30
,
defaultWidth
:
150
,
defaultWidth
:
150
,
});
});
this
.
initRenderer
();
}
}
componentDidUpdate
(
prevProps
:
Props
,
prevState
:
State
)
{
componentDidUpdate
(
prevProps
:
Props
,
prevState
:
State
)
{
...
@@ -105,9 +69,14 @@ export class Table extends Component<Props, State> {
...
@@ -105,9 +69,14 @@ export class Table extends Component<Props, State> {
const
{
sortBy
,
sortDirection
}
=
this
.
state
;
const
{
sortBy
,
sortDirection
}
=
this
.
state
;
const
dataChanged
=
data
!==
prevProps
.
data
;
const
dataChanged
=
data
!==
prevProps
.
data
;
// Reset the size cache
if
(
dataChanged
)
{
this
.
measurer
.
clearAll
();
}
// Update the renderer if options change
// Update the renderer if options change
if
(
dataChanged
||
styles
!==
prevProps
.
styles
)
{
if
(
dataChanged
||
styles
!==
prevProps
.
styles
)
{
this
.
initRenderer
(
);
this
.
columns
=
this
.
initColumns
(
this
.
props
);
}
}
// Update the data when data or sort changes
// Update the data when data or sort changes
...
@@ -117,7 +86,32 @@ export class Table extends Component<Props, State> {
...
@@ -117,7 +86,32 @@ export class Table extends Component<Props, State> {
}
}
}
}
initRenderer
()
{}
initColumns
(
props
:
Props
):
ColumnInfo
[]
{
const
{
styles
,
data
}
=
props
;
return
data
.
columns
.
map
((
col
,
index
)
=>
{
let
title
=
col
.
text
;
let
style
:
ColumnStyle
|
null
=
null
;
// ColumnStyle
// Find the style based on the text
for
(
let
i
=
0
;
i
<
styles
.
length
;
i
++
)
{
const
s
=
styles
[
i
];
const
regex
=
'XXX'
;
//kbn.stringToJsRegex(s.pattern);
if
(
title
.
match
(
regex
))
{
style
=
s
;
if
(
s
.
alias
)
{
title
=
title
.
replace
(
regex
,
s
.
alias
);
}
break
;
}
}
return
{
index
,
header
:
title
,
builder
:
getCellBuilder
(
col
,
style
,
this
.
props
),
};
});
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//----------------------------------------------------------------------
...
@@ -136,7 +130,7 @@ export class Table extends Component<Props, State> {
...
@@ -136,7 +130,7 @@ export class Table extends Component<Props, State> {
this
.
setState
({
sortBy
:
sort
,
sortDirection
:
dir
});
this
.
setState
({
sortBy
:
sort
,
sortDirection
:
dir
});
};
};
hand
e
lClick
=
(
rowIndex
:
number
,
columnIndex
:
number
)
=>
{
hand
leCel
lClick
=
(
rowIndex
:
number
,
columnIndex
:
number
)
=>
{
const
{
showHeader
}
=
this
.
props
;
const
{
showHeader
}
=
this
.
props
;
const
{
data
}
=
this
.
state
;
const
{
data
}
=
this
.
state
;
const
realRowIndex
=
rowIndex
-
(
showHeader
?
1
:
0
);
const
realRowIndex
=
rowIndex
-
(
showHeader
?
1
:
0
);
...
@@ -149,14 +143,16 @@ export class Table extends Component<Props, State> {
...
@@ -149,14 +143,16 @@ export class Table extends Component<Props, State> {
}
}
};
};
header
Renderer
=
(
columnIndex
:
number
):
ReactNode
=>
{
header
Builder
=
(
cell
:
TableCellBuilderOptions
):
ReactElement
<
'div'
>
=>
{
const
{
data
,
sortBy
,
sortDirection
}
=
this
.
state
;
const
{
data
,
sortBy
,
sortDirection
}
=
this
.
state
;
const
{
columnIndex
,
rowIndex
,
style
}
=
cell
.
props
;
const
col
=
data
!
.
columns
[
columnIndex
];
const
col
=
data
!
.
columns
[
columnIndex
];
const
sorting
=
sortBy
===
columnIndex
;
const
sorting
=
sortBy
===
columnIndex
;
return
(
return
(
<
div
>
<
div
className=
"gf-table-header"
style=
{
style
}
onClick=
{
()
=>
this
.
handleCellClick
(
rowIndex
,
columnIndex
)
}
>
{
col
.
text
}
{
' '
}
{
col
.
text
}
{
sorting
&&
(
{
sorting
&&
(
<
span
>
<
span
>
{
sortDirection
}
{
sortDirection
}
...
@@ -168,43 +164,22 @@ export class Table extends Component<Props, State> {
...
@@ -168,43 +164,22 @@ export class Table extends Component<Props, State> {
};
};
cellRenderer
=
(
props
:
GridCellProps
):
React
.
ReactNode
=>
{
cellRenderer
=
(
props
:
GridCellProps
):
React
.
ReactNode
=>
{
const
{
rowIndex
,
columnIndex
,
key
,
parent
,
style
}
=
props
;
const
{
rowIndex
,
columnIndex
,
key
,
parent
}
=
props
;
const
{
showHeader
}
=
this
.
props
;
const
{
showHeader
}
=
this
.
props
;
const
{
data
}
=
this
.
state
;
const
{
data
}
=
this
.
state
;
if
(
!
data
)
{
if
(
!
data
)
{
return
<
div
>
?
</
div
>;
return
<
div
>
?
?
</
div
>;
}
}
const
realRowIndex
=
rowIndex
-
(
showHeader
?
1
:
0
);
const
realRowIndex
=
rowIndex
-
(
showHeader
?
1
:
0
);
const
isHeader
=
realRowIndex
<
0
;
let
classNames
=
'gf-table-cell'
;
const
row
=
isHeader
?
(
data
.
columns
as
any
[])
:
data
.
rows
[
realRowIndex
];
let
content
=
null
;
if
(
realRowIndex
<
0
)
{
content
=
this
.
headerRenderer
(
columnIndex
);
classNames
=
'gf-table-header'
;
}
else
{
const
row
=
data
.
rows
[
realRowIndex
];
const
value
=
row
[
columnIndex
];
const
value
=
row
[
columnIndex
];
content
=
(
const
builder
=
isHeader
?
this
.
headerBuilder
:
this
.
columns
[
columnIndex
].
builder
;
<
div
>
{
rowIndex
}
/
{
columnIndex
}
:
{
value
}
</
div
>
);
}
return
(
return
(
<
CellMeasurer
cache=
{
this
.
_cache
}
columnIndex=
{
columnIndex
}
key=
{
key
}
parent=
{
parent
}
rowIndex=
{
rowIndex
}
>
<
CellMeasurer
cache=
{
this
.
measurer
}
columnIndex=
{
columnIndex
}
key=
{
key
}
parent=
{
parent
}
rowIndex=
{
rowIndex
}
>
<
div
{
builder
({
value
,
row
,
table
:
this
,
props
})
}
onClick=
{
()
=>
this
.
handelClick
(
rowIndex
,
columnIndex
)
}
className=
{
classNames
}
style=
{
{
...
style
,
whiteSpace
:
'nowrap'
,
}
}
>
{
content
}
</
div
>
</
CellMeasurer
>
</
CellMeasurer
>
);
);
};
};
...
@@ -218,16 +193,16 @@ export class Table extends Component<Props, State> {
...
@@ -218,16 +193,16 @@ export class Table extends Component<Props, State> {
return
(
return
(
<
MultiGrid
<
MultiGrid
{
{
...
this
.
state
/** Force MultiGrid to update when
any property updat
es */
...
this
.
state
/** Force MultiGrid to update when
data chang
es */
}
}
columnCount=
{
data
.
columns
.
length
}
columnCount=
{
data
.
columns
.
length
}
rowCount=
{
data
.
rows
.
length
+
(
showHeader
?
1
:
0
)
}
rowCount=
{
data
.
rows
.
length
+
(
showHeader
?
1
:
0
)
}
overscanColumnCount=
{
2
}
overscanColumnCount=
{
2
}
overscanRowCount=
{
2
}
overscanRowCount=
{
2
}
columnWidth=
{
this
.
_cache
.
columnWidth
}
columnWidth=
{
this
.
measurer
.
columnWidth
}
deferredMeasurementCache=
{
this
.
_cache
}
deferredMeasurementCache=
{
this
.
measurer
}
cellRenderer=
{
this
.
cellRenderer
}
cellRenderer=
{
this
.
cellRenderer
}
rowHeight=
{
this
.
_cache
.
rowHeight
}
rowHeight=
{
this
.
measurer
.
rowHeight
}
width=
{
width
}
width=
{
width
}
height=
{
height
}
height=
{
height
}
fixedColumnCount=
{
fixedColumnCount
}
fixedColumnCount=
{
fixedColumnCount
}
...
...
packages/grafana-ui/src/components/Table/TableCellBuilder.tsx
0 → 100644
View file @
fe22d14e
// Libraries
import
_
from
'lodash'
;
import
React
,
{
ReactElement
}
from
'react'
;
import
{
GridCellProps
}
from
'react-virtualized'
;
import
{
Table
,
Props
}
from
'./Table'
;
import
moment
from
'moment'
;
import
{
ValueFormatter
}
from
'../../utils/index'
;
import
{
GrafanaTheme
}
from
'../../types/theme'
;
import
{
getValueFormat
,
getColorFromHexRgbOrName
,
Column
}
from
'@grafana/ui'
;
import
{
InterpolateFunction
}
from
'../../types/panel'
;
export
interface
TableCellBuilderOptions
{
value
:
any
;
row
?:
any
[];
table
?:
Table
;
className
?:
string
;
props
:
GridCellProps
;
}
export
type
TableCellBuilder
=
(
cell
:
TableCellBuilderOptions
)
=>
ReactElement
<
'div'
>
;
/** Simplest cell that just spits out the value */
export
const
simpleCellBuilder
:
TableCellBuilder
=
(
cell
:
TableCellBuilderOptions
)
=>
{
const
{
props
,
value
,
className
}
=
cell
;
const
{
style
}
=
props
;
return
(
<
div
style=
{
style
}
className=
{
className
}
>
{
value
}
</
div
>
);
};
// ***************************************************************************
// HERE BE DRAGONS!!!
// ***************************************************************************
//
// The following code has been migrated blindy two times from the angular
// table panel. I don't understand all the options nor do I know if they
// are correct!
//
// ***************************************************************************
// APP Imports!!!
// import kbn from 'app/core/utils/kbn';
// Made to match the existing (untyped) settings in the angular table
export
interface
ColumnStyle
{
pattern
?:
string
;
alias
?:
string
;
colorMode
?:
'cell'
|
'value'
;
colors
?:
any
[];
decimals
?:
number
;
thresholds
?:
any
[];
type
?:
'date'
|
'number'
|
'string'
|
'hidden'
;
unit
?:
string
;
dateFormat
?:
string
;
sanitize
?:
boolean
;
// not used in react
mappingType
?:
any
;
valueMaps
?:
any
;
rangeMaps
?:
any
;
link
?:
any
;
linkUrl
?:
any
;
linkTooltip
?:
any
;
linkTargetBlank
?:
boolean
;
preserveFormat
?:
boolean
;
}
// private mapper:ValueMapper,
// private style:ColumnStyle,
// private theme:GrafanaTheme,
// private column:Column,
// private replaceVariables: InterpolateFunction,
// private fmt?:ValueFormatter) {
export
function
getCellBuilder
(
schema
:
Column
,
style
:
ColumnStyle
|
null
,
props
:
Props
):
TableCellBuilder
{
if
(
!
style
)
{
return
simpleCellBuilder
;
}
if
(
style
.
type
===
'hidden'
)
{
// TODO -- for hidden, we either need to:
// 1. process the Table and remove hidden fields
// 2. do special math to pick the right column skipping hidden fields
throw
new
Error
(
'hidden not supported!'
);
}
if
(
style
.
type
===
'date'
)
{
return
new
CellBuilderWithStyle
(
(
v
:
any
)
=>
{
if
(
v
===
undefined
||
v
===
null
)
{
return
'-'
;
}
if
(
_
.
isArray
(
v
))
{
v
=
v
[
0
];
}
let
date
=
moment
(
v
);
if
(
false
)
{
// TODO?????? this.props.isUTC) {
date
=
date
.
utc
();
}
return
date
.
format
(
style
.
dateFormat
);
},
style
,
props
.
theme
,
schema
,
props
.
replaceVariables
).
build
;
}
if
(
style
.
type
===
'string'
)
{
return
new
CellBuilderWithStyle
(
(
v
:
any
)
=>
{
if
(
_
.
isArray
(
v
))
{
v
=
v
.
join
(
', '
);
}
return
v
;
},
style
,
props
.
theme
,
schema
,
props
.
replaceVariables
).
build
;
// TODO!!!! all the mapping stuff!!!!
}
if
(
style
.
type
===
'number'
)
{
const
valueFormatter
=
getValueFormat
(
style
.
unit
||
schema
.
unit
||
'none'
);
return
new
CellBuilderWithStyle
(
(
v
:
any
)
=>
{
if
(
v
===
null
||
v
===
void
0
)
{
return
'-'
;
}
return
v
;
},
style
,
props
.
theme
,
schema
,
props
.
replaceVariables
,
valueFormatter
).
build
;
}
return
simpleCellBuilder
;
}
type
ValueMapper
=
(
value
:
any
)
=>
any
;
// Runs the value through a formatter and adds colors to the cell properties
class
CellBuilderWithStyle
{
constructor
(
private
mapper
:
ValueMapper
,
private
style
:
ColumnStyle
,
private
theme
:
GrafanaTheme
,
private
column
:
Column
,
private
replaceVariables
:
InterpolateFunction
,
private
fmt
?:
ValueFormatter
)
{
//
}
getColorForValue
=
(
value
:
any
):
string
|
null
=>
{
const
{
thresholds
,
colors
}
=
this
.
style
;
if
(
!
thresholds
||
!
colors
)
{
return
null
;
}
for
(
let
i
=
thresholds
.
length
;
i
>
0
;
i
--
)
{
if
(
value
>=
thresholds
[
i
-
1
])
{
return
getColorFromHexRgbOrName
(
colors
[
i
],
this
.
theme
.
type
);
}
}
return
getColorFromHexRgbOrName
(
_
.
first
(
colors
),
this
.
theme
.
type
);
};
build
=
(
cell
:
TableCellBuilderOptions
)
=>
{
let
{
props
}
=
cell
;
let
value
=
this
.
mapper
(
cell
.
value
);
if
(
_
.
isNumber
(
value
))
{
if
(
this
.
fmt
)
{
value
=
this
.
fmt
(
value
,
this
.
style
.
decimals
);
}
// For numeric values set the color
const
{
colorMode
}
=
this
.
style
;
if
(
colorMode
)
{
const
color
=
this
.
getColorForValue
(
Number
(
value
));
if
(
color
)
{
if
(
colorMode
===
'cell'
)
{
props
=
{
...
props
,
style
:
{
...
props
.
style
,
backgroundColor
:
color
,
color
:
'white'
,
},
};
}
else
if
(
colorMode
===
'value'
)
{
props
=
{
...
props
,
style
:
{
...
props
.
style
,
color
:
color
,
},
};
}
}
}
}
const
cellClasses
=
[];
if
(
this
.
style
.
preserveFormat
)
{
cellClasses
.
push
(
'table-panel-cell-pre'
);
}
if
(
this
.
style
.
link
)
{
// Render cell as link
const
{
row
}
=
cell
;
const
scopedVars
:
any
=
{};
if
(
row
)
{
for
(
let
i
=
0
;
i
<
row
.
length
;
i
++
)
{
scopedVars
[
`__cell_
${
i
}
`
]
=
{
value
:
row
[
i
]
};
}
}
scopedVars
[
'__cell'
]
=
{
value
:
value
};
const
cellLink
=
this
.
replaceVariables
(
this
.
style
.
linkUrl
,
scopedVars
,
encodeURIComponent
);
const
cellLinkTooltip
=
this
.
replaceVariables
(
this
.
style
.
linkTooltip
,
scopedVars
);
const
cellTarget
=
this
.
style
.
linkTargetBlank
?
'_blank'
:
''
;
cellClasses
.
push
(
'table-panel-cell-link'
);
value
=
(
<
a
href=
{
cellLink
}
target=
{
cellTarget
}
data
-
link
-
tooltip
data
-
original
-
title=
{
cellLinkTooltip
}
data
-
placement=
"right"
>
{
value
}
</
a
>
);
}
// ??? I don't think this will still work!
if
(
this
.
column
.
filterable
)
{
cellClasses
.
push
(
'table-panel-cell-filterable'
);
value
=
(
<>
{
value
}
<
span
>
<
a
className=
"table-panel-filter-link"
data
-
link
-
tooltip
data
-
original
-
title=
"Filter out value"
data
-
placement=
"bottom"
data
-
row=
{
props
.
rowIndex
}
data
-
column=
{
props
.
columnIndex
}
data
-
operator=
"!="
>
<
i
className=
"fa fa-search-minus"
/>
</
a
>
<
a
className=
"table-panel-filter-link"
data
-
link
-
tooltip
data
-
original
-
title=
"Filter for value"
data
-
placement=
"bottom"
data
-
row=
{
props
.
rowIndex
}
data
-
column=
{
props
.
columnIndex
}
data
-
operator=
"="
>
<
i
className=
"fa fa-search-plus"
/>
</
a
>
</
span
>
</>
);
}
let
className
;
if
(
cellClasses
.
length
)
{
className
=
cellClasses
.
join
(
' '
);
}
return
simpleCellBuilder
({
value
,
props
,
className
});
};
}
packages/grafana-ui/src/components/Table/TableXXXX.tsx
deleted
100644 → 0
View file @
078d8f12
This diff is collapsed.
Click to expand it.
packages/grafana-ui/src/components/Table/_Table.scss
View file @
fe22d14e
...
@@ -59,6 +59,7 @@
...
@@ -59,6 +59,7 @@
border-bottom
:
2px
solid
$body-bg
;
border-bottom
:
2px
solid
$body-bg
;
cursor
:
pointer
;
cursor
:
pointer
;
white-space
:
nowrap
;
color
:
$blue
;
color
:
$blue
;
}
}
...
...
packages/grafana-ui/src/components/Table/examples.ts
View file @
fe22d14e
import
{
TableData
}
from
'../../types/data'
;
import
{
TableData
}
from
'../../types/data'
;
import
{
ColumnStyle
}
from
'./Table'
;
import
{
ColumnStyle
}
from
'./Table
CellBuilder
'
;
import
{
getColorDefinitionByName
}
from
'@grafana/ui'
;
import
{
getColorDefinitionByName
}
from
'@grafana/ui'
;
...
...
packages/grafana-ui/src/utils/storybook/withFullSizeStory.tsx
View file @
fe22d14e
import
React
from
'react'
;
import
React
from
'react'
;
import
{
AutoSizer
}
from
'react-virtualized'
;
import
{
AutoSizer
}
from
'react-virtualized'
;
/** This will add full size with & height properties */
export
const
withFullSizeStory
=
(
component
:
React
.
ComponentType
<
any
>
,
props
:
any
)
=>
(
export
const
withFullSizeStory
=
(
component
:
React
.
ComponentType
<
any
>
,
props
:
any
)
=>
(
<
div
<
div
style=
{
{
style=
{
{
...
...
public/app/plugins/panel/table/renderer.ts
View file @
fe22d14e
...
@@ -2,7 +2,7 @@ import _ from 'lodash';
...
@@ -2,7 +2,7 @@ import _ from 'lodash';
import
moment
from
'moment'
;
import
moment
from
'moment'
;
import
kbn
from
'app/core/utils/kbn'
;
import
kbn
from
'app/core/utils/kbn'
;
import
{
getValueFormat
,
getColorFromHexRgbOrName
,
GrafanaThemeType
}
from
'@grafana/ui'
;
import
{
getValueFormat
,
getColorFromHexRgbOrName
,
GrafanaThemeType
}
from
'@grafana/ui'
;
import
{
ColumnStyle
}
from
'@grafana/ui/src/components/Table/Table'
;
import
{
ColumnStyle
}
from
'@grafana/ui/src/components/Table/Table
CellBuilder
'
;
export
class
TableRenderer
{
export
class
TableRenderer
{
formatters
:
any
[];
formatters
:
any
[];
...
...
public/app/plugins/panel/table2/types.ts
View file @
fe22d14e
import
{
ColumnStyle
}
from
'@grafana/ui/src/components/Table/Table'
;
import
{
ColumnStyle
}
from
'@grafana/ui/src/components/Table/Table
CellBuilder
'
;
export
interface
Options
{
export
interface
Options
{
showHeader
:
boolean
;
showHeader
:
boolean
;
...
...
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