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
72c15d7a
Unverified
Commit
72c15d7a
authored
Sep 30, 2019
by
Andrej Ocenas
Committed by
GitHub
Sep 30, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor: Split LogRow component (#19471)
parent
d65a3318
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
328 additions
and
276 deletions
+328
-276
packages/grafana-ui/src/components/Logs/LogLabel.tsx
+3
-2
packages/grafana-ui/src/components/Logs/LogLabels.tsx
+5
-7
packages/grafana-ui/src/components/Logs/LogRow.tsx
+14
-264
packages/grafana-ui/src/components/Logs/LogRowMessage.tsx
+297
-0
packages/grafana-ui/src/components/Logs/LogRows.tsx
+6
-1
packages/grafana-ui/src/components/Logs/getLogRowStyles.ts
+3
-2
No files found.
packages/grafana-ui/src/components/Logs/LogLabel.tsx
View file @
72c15d7a
...
...
@@ -6,8 +6,9 @@ import { LogLabelStats } from './LogLabelStats';
import
{
GrafanaTheme
,
Themeable
}
from
'../../types/theme'
;
import
{
selectThemeVariant
}
from
'../../themes/selectThemeVariant'
;
import
{
withTheme
}
from
'../../themes/ThemeContext'
;
import
{
stylesFactory
}
from
'../../themes'
;
const
getStyles
=
(
theme
:
GrafanaTheme
)
=>
{
const
getStyles
=
stylesFactory
(
(
theme
:
GrafanaTheme
)
=>
{
return
{
logsLabel
:
css
`
label: logs-label;
...
...
@@ -43,7 +44,7 @@ const getStyles = (theme: GrafanaTheme) => {
box-shadow: 0 0 20px
${
selectThemeVariant
({
light
:
theme
.
colors
.
white
,
dark
:
theme
.
colors
.
black
},
theme
.
type
)}
;
`
,
};
};
}
)
;
interface
Props
extends
Themeable
{
value
:
string
;
...
...
packages/grafana-ui/src/components/Logs/LogLabels.tsx
View file @
72c15d7a
import
React
,
{
FunctionComponent
,
useContext
}
from
'react'
;
import
React
,
{
FunctionComponent
}
from
'react'
;
import
{
css
,
cx
}
from
'emotion'
;
import
{
Labels
,
LogRowModel
}
from
'@grafana/data'
;
import
{
LogLabel
}
from
'./LogLabel'
;
import
{
GrafanaTheme
}
from
'../../types/theme'
;
import
{
ThemeContext
}
from
'../../themes/ThemeContext'
;
import
{
stylesFactory
}
from
'../../themes'
;
const
getStyles
=
(
theme
:
GrafanaTheme
)
=>
({
const
getStyles
=
stylesFactory
((
)
=>
({
logsLabels
:
css
`
display: flex;
flex-wrap: wrap;
`
,
});
})
)
;
interface
Props
{
labels
:
Labels
;
...
...
@@ -21,8 +20,7 @@ interface Props {
}
export
const
LogLabels
:
FunctionComponent
<
Props
>
=
({
getRows
,
labels
,
onClickLabel
,
plain
})
=>
{
const
theme
=
useContext
(
ThemeContext
);
const
styles
=
getStyles
(
theme
);
const
styles
=
getStyles
();
return
(
<
span
className=
{
cx
([
styles
.
logsLabels
])
}
>
...
...
packages/grafana-ui/src/components/Logs/LogRow.tsx
View file @
72c15d7a
import
React
,
{
PureComponent
,
FunctionComponent
,
useContext
}
from
'react'
;
import
_
from
'lodash'
;
// @ts-ignore
import
Highlighter
from
'react-highlight-words'
;
import
{
LogRowModel
,
LogLabelStatsModel
,
LogsParser
,
TimeZone
,
calculateFieldStats
,
getParser
,
findHighlightChunksInText
,
}
from
'@grafana/data'
;
import
tinycolor
from
'tinycolor2'
;
import
{
css
,
cx
}
from
'emotion'
;
import
{
DataQueryResponse
,
GrafanaTheme
,
selectThemeVariant
,
ThemeContext
}
from
'../../index'
;
import
React
,
{
PureComponent
}
from
'react'
;
import
{
LogRowModel
,
TimeZone
}
from
'@grafana/data'
;
import
{
cx
}
from
'emotion'
;
import
{
DataQueryResponse
}
from
'../../index'
;
import
{
LogRowContextRows
,
LogRowContextQueryErrors
,
HasMoreContextRows
,
LogRowContextProvider
,
}
from
'./LogRowContextProvider'
;
import
{
LogRowContext
}
from
'./LogRowContext'
;
import
{
LogLabels
}
from
'./LogLabels'
;
import
{
LogMessageAnsi
}
from
'./LogMessageAnsi'
;
import
{
LogLabelStats
}
from
'./LogLabelStats'
;
import
{
Themeable
}
from
'../../types/theme'
;
import
{
withTheme
}
from
'../../themes/index'
;
import
{
getLogRowStyles
}
from
'./getLogRowStyles'
;
import
{
LogRowMessage
}
from
'./LogRowMessage'
;
interface
Props
extends
Themeable
{
highlighterExpressions
?:
string
[];
...
...
@@ -42,62 +28,10 @@ interface Props extends Themeable {
}
interface
State
{
fieldCount
:
number
;
fieldLabel
:
string
;
fieldStats
:
LogLabelStatsModel
[];
fieldValue
:
string
;
parsed
:
boolean
;
parser
?:
LogsParser
;
parsedFieldHighlights
:
string
[];
showFieldStats
:
boolean
;
showContext
:
boolean
;
}
/**
* Renders a highlighted field.
* When hovering, a stats icon is shown.
*/
const
FieldHighlight
=
(
onClick
:
any
):
FunctionComponent
<
any
>
=>
(
props
:
any
)
=>
{
const
theme
=
useContext
(
ThemeContext
);
const
style
=
getLogRowStyles
(
theme
);
return
(
<
span
className=
{
props
.
className
}
style=
{
props
.
style
}
>
{
props
.
children
}
<
span
className=
{
cx
([
style
,
'logs-row__field-highlight--icon'
,
'fa fa-signal'
])
}
onClick=
{
()
=>
onClick
(
props
.
children
)
}
/>
</
span
>
);
};
const
logRowStyles
=
css
`
position: relative;
/* z-index: 0; */
/* outline: none; */
`
;
const
getLogRowWithContextStyles
=
(
theme
:
GrafanaTheme
,
state
:
State
)
=>
{
const
outlineColor
=
selectThemeVariant
(
{
light
:
theme
.
colors
.
white
,
dark
:
theme
.
colors
.
black
,
},
theme
.
type
);
return
{
row
:
css
`
z-index: 1;
outline: 9999px solid
${
tinycolor
(
outlineColor
as
tinycolor
.
ColorInput
)
.
setAlpha
(
0.7
)
.
toRgbString
()}
;
`
,
};
};
/**
* Renders a log line.
*
* When user hovers over it for a certain time, it lazily parses the log line.
...
...
@@ -105,95 +39,10 @@ const getLogRowWithContextStyles = (theme: GrafanaTheme, state: State) => {
* When the user requests stats for a field, they will be calculated and rendered below the row.
*/
class
UnThemedLogRow
extends
PureComponent
<
Props
,
State
>
{
mouseMessageTimer
:
number
|
null
=
null
;
state
:
any
=
{
fieldCount
:
0
,
fieldLabel
:
null
,
fieldStats
:
null
,
fieldValue
:
null
,
parsed
:
false
,
parser
:
undefined
,
parsedFieldHighlights
:
[],
showFieldStats
:
false
,
state
:
State
=
{
showContext
:
false
,
};
componentWillUnmount
()
{
this
.
clearMouseMessageTimer
();
}
onClickClose
=
()
=>
{
this
.
setState
({
showFieldStats
:
false
});
};
onClickHighlight
=
(
fieldText
:
string
)
=>
{
const
{
getRows
}
=
this
.
props
;
const
{
parser
}
=
this
.
state
;
const
allRows
=
getRows
();
// Build value-agnostic row matcher based on the field label
const
fieldLabel
=
parser
.
getLabelFromField
(
fieldText
);
const
fieldValue
=
parser
.
getValueFromField
(
fieldText
);
const
matcher
=
parser
.
buildMatcher
(
fieldLabel
);
const
fieldStats
=
calculateFieldStats
(
allRows
,
matcher
);
const
fieldCount
=
fieldStats
.
reduce
((
sum
,
stat
)
=>
sum
+
stat
.
count
,
0
);
this
.
setState
({
fieldCount
,
fieldLabel
,
fieldStats
,
fieldValue
,
showFieldStats
:
true
});
};
onMouseOverMessage
=
()
=>
{
if
(
this
.
state
.
showContext
||
this
.
isTextSelected
())
{
// When showing context we don't want to the LogRow rerender as it will mess up state of context block
// making the "after" context to be scrolled to the top, what is desired only on open
// The log row message needs to be refactored to separate component that encapsulates parsing and parsed message state
return
;
}
// Don't parse right away, user might move along
this
.
mouseMessageTimer
=
window
.
setTimeout
(
this
.
parseMessage
,
500
);
};
onMouseOutMessage
=
()
=>
{
if
(
this
.
state
.
showContext
)
{
// See comment in onMouseOverMessage method
return
;
}
this
.
clearMouseMessageTimer
();
this
.
setState
({
parsed
:
false
});
};
clearMouseMessageTimer
=
()
=>
{
if
(
this
.
mouseMessageTimer
)
{
clearTimeout
(
this
.
mouseMessageTimer
);
}
};
parseMessage
=
()
=>
{
if
(
!
this
.
state
.
parsed
)
{
const
{
row
}
=
this
.
props
;
const
parser
=
getParser
(
row
.
entry
);
if
(
parser
)
{
// Use parser to highlight detected fields
const
parsedFieldHighlights
=
parser
.
getFields
(
this
.
props
.
row
.
entry
);
this
.
setState
({
parsedFieldHighlights
,
parsed
:
true
,
parser
});
}
}
};
isTextSelected
()
{
if
(
!
window
.
getSelection
)
{
return
false
;
}
const
selection
=
window
.
getSelection
();
if
(
!
selection
)
{
return
false
;
}
return
selection
.
anchorNode
!==
null
&&
selection
.
isCollapsed
===
false
;
}
toggleContext
=
()
=>
{
this
.
setState
(
state
=>
{
return
{
...
...
@@ -202,11 +51,6 @@ class UnThemedLogRow extends PureComponent<Props, State> {
});
};
onContextToggle
=
(
e
:
React
.
SyntheticEvent
<
HTMLElement
>
)
=>
{
e
.
stopPropagation
();
this
.
toggleContext
();
};
renderLogRow
(
context
?:
LogRowContextRows
,
errors
?:
LogRowContextQueryErrors
,
...
...
@@ -224,34 +68,11 @@ class UnThemedLogRow extends PureComponent<Props, State> {
showTime
,
theme
,
}
=
this
.
props
;
const
{
fieldCount
,
fieldLabel
,
fieldStats
,
fieldValue
,
parsed
,
parsedFieldHighlights
,
showFieldStats
,
showContext
,
}
=
this
.
state
;
const
{
showContext
}
=
this
.
state
;
const
style
=
getLogRowStyles
(
theme
,
row
.
logLevel
);
const
{
entry
,
hasAnsi
,
raw
}
=
row
;
const
previewHighlights
=
highlighterExpressions
&&
!
_
.
isEqual
(
highlighterExpressions
,
row
.
searchWords
);
const
highlights
=
previewHighlights
?
highlighterExpressions
:
row
.
searchWords
;
const
needsHighlighter
=
highlights
&&
highlights
.
length
>
0
&&
highlights
[
0
]
&&
highlights
[
0
].
length
>
0
;
const
highlightClassName
=
previewHighlights
?
cx
([
style
.
logsRowMatchHighLight
,
style
.
logsRowMatchHighLightPreview
])
:
cx
([
style
.
logsRowMatchHighLight
]);
const
showUtc
=
timeZone
===
'utc'
;
return
(
<
ThemeContext
.
Consumer
>
{
theme
=>
{
const
styles
=
this
.
state
.
showContext
?
cx
(
logRowStyles
,
getLogRowWithContextStyles
(
theme
,
this
.
state
).
row
)
:
logRowStyles
;
return
(
<
div
className=
{
cx
([
style
.
logsRow
])
}
>
{
showDuplicates
&&
(
<
div
className=
{
cx
([
style
.
logsRowDuplicates
])
}
>
...
...
@@ -278,89 +99,18 @@ class UnThemedLogRow extends PureComponent<Props, State> {
/>
</
div
>
)
}
<
div
className=
{
cx
([
style
.
logsRowMessage
])
}
onMouseEnter=
{
this
.
onMouseOverMessage
}
onMouseLeave=
{
this
.
onMouseOutMessage
}
>
<
div
className=
{
css
`
position: relative;
`
}
>
{
showContext
&&
context
&&
(
<
LogRowContext
<
LogRowMessage
highlighterExpressions=
{
highlighterExpressions
}
row=
{
row
}
context=
{
context
}
getRows=
{
getRows
}
errors=
{
errors
}
hasMoreContextRows=
{
hasMoreContextRows
}
onOutsideClick=
{
this
.
toggleContext
}
onLoadMoreContext=
{
()
=>
{
if
(
updateLimit
)
{
updateLimit
();
}
}
}
/>
)
}
<
span
className=
{
styles
}
>
{
parsed
&&
(
<
Highlighter
style=
{
{
whiteSpace
:
'pre-wrap'
}
}
autoEscape
highlightTag=
{
FieldHighlight
(
this
.
onClickHighlight
)
}
textToHighlight=
{
entry
}
searchWords=
{
parsedFieldHighlights
}
highlightClassName=
{
cx
([
style
.
logsRowFieldHighLight
])
}
/>
)
}
{
!
parsed
&&
needsHighlighter
&&
(
<
Highlighter
style=
{
{
whiteSpace
:
'pre-wrap'
}
}
textToHighlight=
{
entry
}
searchWords=
{
highlights
}
findChunks=
{
findHighlightChunksInText
}
highlightClassName=
{
highlightClassName
}
/>
)
}
{
hasAnsi
&&
!
parsed
&&
!
needsHighlighter
&&
<
LogMessageAnsi
value=
{
raw
}
/>
}
{
!
hasAnsi
&&
!
parsed
&&
!
needsHighlighter
&&
entry
}
{
showFieldStats
&&
(
<
div
className=
{
cx
([
style
.
logsRowStats
])
}
>
<
LogLabelStats
stats=
{
fieldStats
}
label=
{
fieldLabel
}
value=
{
fieldValue
}
onClickClose=
{
this
.
onClickClose
}
rowCount=
{
fieldCount
}
updateLimit=
{
updateLimit
}
context=
{
context
}
showContext=
{
showContext
}
onToggleContext=
{
this
.
toggleContext
}
/>
</
div
>
)
}
</
span
>
{
row
.
searchWords
&&
row
.
searchWords
.
length
>
0
&&
(
<
span
onClick=
{
this
.
onContextToggle
}
className=
{
css
`
visibility: hidden;
white-space: nowrap;
position: relative;
z-index: ${showContext ? 1 : 0};
cursor: pointer;
.${style.logsRow}:hover & {
visibility: visible;
margin-left: 10px;
text-decoration: underline;
}
`
}
>
{
showContext
?
'Hide'
:
'Show'
}
context
</
span
>
)
}
</
div
>
</
div
>
</
div
>
);
}
}
</
ThemeContext
.
Consumer
>
);
}
...
...
packages/grafana-ui/src/components/Logs/LogRowMessage.tsx
0 → 100644
View file @
72c15d7a
import
React
,
{
PureComponent
,
FunctionComponent
,
useContext
}
from
'react'
;
import
_
from
'lodash'
;
// @ts-ignore
import
Highlighter
from
'react-highlight-words'
;
import
{
LogRowModel
,
LogLabelStatsModel
,
LogsParser
,
calculateFieldStats
,
getParser
,
findHighlightChunksInText
,
}
from
'@grafana/data'
;
import
tinycolor
from
'tinycolor2'
;
import
{
css
,
cx
}
from
'emotion'
;
import
{
GrafanaTheme
,
selectThemeVariant
,
ThemeContext
}
from
'../../index'
;
import
{
LogRowContextQueryErrors
,
HasMoreContextRows
,
LogRowContextRows
}
from
'./LogRowContextProvider'
;
import
{
LogRowContext
}
from
'./LogRowContext'
;
import
{
LogMessageAnsi
}
from
'./LogMessageAnsi'
;
import
{
LogLabelStats
}
from
'./LogLabelStats'
;
import
{
Themeable
}
from
'../../types/theme'
;
import
{
withTheme
}
from
'../../themes/index'
;
import
{
getLogRowStyles
}
from
'./getLogRowStyles'
;
import
{
stylesFactory
}
from
'../../themes/stylesFactory'
;
interface
Props
extends
Themeable
{
highlighterExpressions
?:
string
[];
row
:
LogRowModel
;
getRows
:
()
=>
LogRowModel
[];
errors
?:
LogRowContextQueryErrors
;
hasMoreContextRows
?:
HasMoreContextRows
;
updateLimit
?:
()
=>
void
;
context
?:
LogRowContextRows
;
showContext
:
boolean
;
onToggleContext
:
()
=>
void
;
}
interface
State
{
fieldCount
:
number
;
fieldLabel
:
string
|
null
;
fieldStats
:
LogLabelStatsModel
[]
|
null
;
fieldValue
:
string
|
null
;
parsed
:
boolean
;
parser
?:
LogsParser
;
parsedFieldHighlights
:
string
[];
showFieldStats
:
boolean
;
}
/**
* Renders a highlighted field.
* When hovering, a stats icon is shown.
*/
const
FieldHighlight
=
(
onClick
:
any
):
FunctionComponent
<
any
>
=>
(
props
:
any
)
=>
{
const
theme
=
useContext
(
ThemeContext
);
const
style
=
getLogRowStyles
(
theme
);
return
(
<
span
className=
{
props
.
className
}
style=
{
props
.
style
}
>
{
props
.
children
}
<
span
className=
{
cx
([
style
,
'logs-row__field-highlight--icon'
,
'fa fa-signal'
])
}
onClick=
{
()
=>
onClick
(
props
.
children
)
}
/>
</
span
>
);
};
const
getStyles
=
stylesFactory
((
theme
:
GrafanaTheme
)
=>
{
const
outlineColor
=
selectThemeVariant
(
{
light
:
theme
.
colors
.
white
,
dark
:
theme
.
colors
.
black
,
},
theme
.
type
);
return
{
positionRelative
:
css
`
label: positionRelative;
position: relative;
`
,
rowWithContext
:
css
`
label: rowWithContext;
z-index: 1;
outline: 9999px solid
${
tinycolor
(
outlineColor
as
tinycolor
.
ColorInput
)
.
setAlpha
(
0.7
)
.
toRgbString
()}
;
`
,
};
});
class
UnThemedLogRowMessage
extends
PureComponent
<
Props
,
State
>
{
mouseMessageTimer
:
number
|
null
=
null
;
state
:
State
=
{
fieldCount
:
0
,
fieldLabel
:
null
,
fieldStats
:
null
,
fieldValue
:
null
,
parsed
:
false
,
parser
:
undefined
,
parsedFieldHighlights
:
[],
showFieldStats
:
false
,
};
componentWillUnmount
()
{
this
.
clearMouseMessageTimer
();
}
onClickClose
=
()
=>
{
this
.
setState
({
showFieldStats
:
false
});
};
onClickHighlight
=
(
fieldText
:
string
)
=>
{
const
{
getRows
}
=
this
.
props
;
const
{
parser
}
=
this
.
state
;
const
allRows
=
getRows
();
// Build value-agnostic row matcher based on the field label
const
fieldLabel
=
parser
!
.
getLabelFromField
(
fieldText
);
const
fieldValue
=
parser
!
.
getValueFromField
(
fieldText
);
const
matcher
=
parser
!
.
buildMatcher
(
fieldLabel
);
const
fieldStats
=
calculateFieldStats
(
allRows
,
matcher
);
const
fieldCount
=
fieldStats
.
reduce
((
sum
,
stat
)
=>
sum
+
stat
.
count
,
0
);
this
.
setState
({
fieldCount
,
fieldLabel
,
fieldStats
,
fieldValue
,
showFieldStats
:
true
});
};
onMouseOverMessage
=
()
=>
{
if
(
this
.
props
.
showContext
||
this
.
isTextSelected
())
{
// When showing context we don't want to the LogRow rerender as it will mess up state of context block
// making the "after" context to be scrolled to the top, what is desired only on open
// The log row message needs to be refactored to separate component that encapsulates parsing and parsed message state
return
;
}
// Don't parse right away, user might move along
this
.
mouseMessageTimer
=
window
.
setTimeout
(
this
.
parseMessage
,
500
);
};
onMouseOutMessage
=
()
=>
{
if
(
this
.
props
.
showContext
)
{
// See comment in onMouseOverMessage method
return
;
}
this
.
clearMouseMessageTimer
();
this
.
setState
({
parsed
:
false
});
};
clearMouseMessageTimer
=
()
=>
{
if
(
this
.
mouseMessageTimer
)
{
clearTimeout
(
this
.
mouseMessageTimer
);
}
};
parseMessage
=
()
=>
{
if
(
!
this
.
state
.
parsed
)
{
const
{
row
}
=
this
.
props
;
const
parser
=
getParser
(
row
.
entry
);
if
(
parser
)
{
// Use parser to highlight detected fields
const
parsedFieldHighlights
=
parser
.
getFields
(
this
.
props
.
row
.
entry
);
this
.
setState
({
parsedFieldHighlights
,
parsed
:
true
,
parser
});
}
}
};
isTextSelected
()
{
if
(
!
window
.
getSelection
)
{
return
false
;
}
const
selection
=
window
.
getSelection
();
if
(
!
selection
)
{
return
false
;
}
return
selection
.
anchorNode
!==
null
&&
selection
.
isCollapsed
===
false
;
}
onContextToggle
=
(
e
:
React
.
SyntheticEvent
<
HTMLElement
>
)
=>
{
e
.
stopPropagation
();
this
.
props
.
onToggleContext
();
};
render
()
{
const
{
highlighterExpressions
,
row
,
theme
,
errors
,
hasMoreContextRows
,
updateLimit
,
context
,
showContext
,
onToggleContext
,
}
=
this
.
props
;
const
{
fieldCount
,
fieldLabel
,
fieldStats
,
fieldValue
,
parsed
,
parsedFieldHighlights
,
showFieldStats
,
}
=
this
.
state
;
const
style
=
getLogRowStyles
(
theme
,
row
.
logLevel
);
const
{
entry
,
hasAnsi
,
raw
}
=
row
;
const
previewHighlights
=
highlighterExpressions
&&
!
_
.
isEqual
(
highlighterExpressions
,
row
.
searchWords
);
const
highlights
=
previewHighlights
?
highlighterExpressions
:
row
.
searchWords
;
const
needsHighlighter
=
highlights
&&
highlights
.
length
>
0
&&
highlights
[
0
]
&&
highlights
[
0
].
length
>
0
;
const
highlightClassName
=
previewHighlights
?
cx
([
style
.
logsRowMatchHighLight
,
style
.
logsRowMatchHighLightPreview
])
:
cx
([
style
.
logsRowMatchHighLight
]);
const
styles
=
getStyles
(
theme
);
return
(
<
div
className=
{
cx
([
style
.
logsRowMessage
])
}
onMouseEnter=
{
this
.
onMouseOverMessage
}
onMouseLeave=
{
this
.
onMouseOutMessage
}
>
<
div
className=
{
styles
.
positionRelative
}
>
{
showContext
&&
context
&&
(
<
LogRowContext
row=
{
row
}
context=
{
context
}
errors=
{
errors
}
hasMoreContextRows=
{
hasMoreContextRows
}
onOutsideClick=
{
onToggleContext
}
onLoadMoreContext=
{
()
=>
{
if
(
updateLimit
)
{
updateLimit
();
}
}
}
/>
)
}
<
span
className=
{
cx
(
styles
.
positionRelative
,
{
[
styles
.
rowWithContext
]:
showContext
})
}
>
{
parsed
&&
(
<
Highlighter
style=
{
{
whiteSpace
:
'pre-wrap'
}
}
autoEscape
highlightTag=
{
FieldHighlight
(
this
.
onClickHighlight
)
}
textToHighlight=
{
entry
}
searchWords=
{
parsedFieldHighlights
}
highlightClassName=
{
cx
([
style
.
logsRowFieldHighLight
])
}
/>
)
}
{
!
parsed
&&
needsHighlighter
&&
(
<
Highlighter
style=
{
{
whiteSpace
:
'pre-wrap'
}
}
textToHighlight=
{
entry
}
searchWords=
{
highlights
}
findChunks=
{
findHighlightChunksInText
}
highlightClassName=
{
highlightClassName
}
/>
)
}
{
hasAnsi
&&
!
parsed
&&
!
needsHighlighter
&&
<
LogMessageAnsi
value=
{
raw
}
/>
}
{
!
hasAnsi
&&
!
parsed
&&
!
needsHighlighter
&&
entry
}
{
showFieldStats
&&
(
<
div
className=
{
cx
([
style
.
logsRowStats
])
}
>
<
LogLabelStats
stats=
{
fieldStats
!
}
label=
{
fieldLabel
!
}
value=
{
fieldValue
!
}
onClickClose=
{
this
.
onClickClose
}
rowCount=
{
fieldCount
}
/>
</
div
>
)
}
</
span
>
{
row
.
searchWords
&&
row
.
searchWords
.
length
>
0
&&
(
<
span
onClick=
{
this
.
onContextToggle
}
className=
{
css
`
visibility: hidden;
white-space: nowrap;
position: relative;
z-index: ${showContext ? 1 : 0};
cursor: pointer;
.${style.logsRow}:hover & {
visibility: visible;
margin-left: 10px;
text-decoration: underline;
}
`
}
>
{
showContext
?
'Hide'
:
'Show'
}
context
</
span
>
)
}
</
div
>
</
div
>
);
}
}
export
const
LogRowMessage
=
withTheme
(
UnThemedLogRowMessage
);
LogRowMessage
.
displayName
=
'LogRowMessage'
;
packages/grafana-ui/src/components/Logs/LogRows.tsx
View file @
72c15d7a
...
...
@@ -6,6 +6,7 @@ import { LogRow } from './LogRow';
import
{
Themeable
}
from
'../../types/theme'
;
import
{
withTheme
}
from
'../../themes/index'
;
import
{
getLogRowStyles
}
from
'./getLogRowStyles'
;
import
memoizeOne
from
'memoize-one'
;
const
PREVIEW_LIMIT
=
100
;
const
RENDER_LIMIT
=
500
;
...
...
@@ -65,6 +66,10 @@ class UnThemedLogRows extends PureComponent<Props, State> {
}
}
makeGetRows
=
memoizeOne
((
processedRows
:
LogRowModel
[])
=>
{
return
()
=>
processedRows
;
});
render
()
{
const
{
dedupStrategy
,
...
...
@@ -95,7 +100,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
const
lastRows
=
processedRows
.
slice
(
PREVIEW_LIMIT
,
rowCount
);
// React profiler becomes unusable if we pass all rows to all rows and their labels, using getter instead
const
getRows
=
()
=>
processedRows
;
const
getRows
=
this
.
makeGetRows
(
processedRows
)
;
const
getRowContext
=
this
.
props
.
getRowContext
?
this
.
props
.
getRowContext
:
()
=>
Promise
.
resolve
([]);
const
{
logsRows
}
=
getLogRowStyles
(
theme
);
...
...
packages/grafana-ui/src/components/Logs/getLogRowStyles.ts
View file @
72c15d7a
...
...
@@ -3,8 +3,9 @@ import { LogLevel } from '@grafana/data';
import
{
GrafanaTheme
}
from
'../../types/theme'
;
import
{
selectThemeVariant
}
from
'../../themes/selectThemeVariant'
;
import
{
stylesFactory
}
from
'../../themes'
;
export
const
getLogRowStyles
=
(
theme
:
GrafanaTheme
,
logLevel
?:
LogLevel
)
=>
{
export
const
getLogRowStyles
=
stylesFactory
(
(
theme
:
GrafanaTheme
,
logLevel
?:
LogLevel
)
=>
{
let
logColor
=
selectThemeVariant
({
light
:
theme
.
colors
.
gray5
,
dark
:
theme
.
colors
.
gray2
},
theme
.
type
);
switch
(
logLevel
)
{
case
LogLevel
.
crit
:
...
...
@@ -130,4 +131,4 @@ export const getLogRowStyles = (theme: GrafanaTheme, logLevel?: LogLevel) => {
margin: 5px 0;
`
,
};
};
}
)
;
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