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
1069d7f5
Commit
1069d7f5
authored
Feb 18, 2019
by
Dominik Prokop
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Display graphite function name editor in a tooltip
parent
a6cae5b2
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
217 additions
and
97 deletions
+217
-97
packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx
+2
-2
packages/grafana-ui/src/components/Tooltip/Popper.tsx
+8
-3
packages/grafana-ui/src/components/Tooltip/PopperController.tsx
+2
-2
packages/grafana-ui/src/components/Tooltip/Tooltip.tsx
+2
-2
packages/grafana-ui/src/components/index.ts
+2
-0
public/app/core/angular_wrappers.ts
+2
-0
public/app/plugins/datasource/graphite/FunctionEditor.tsx
+104
-0
public/app/plugins/datasource/graphite/FunctionEditorControls.tsx
+65
-0
public/app/plugins/datasource/graphite/func_editor.ts
+20
-87
public/app/plugins/datasource/graphite/graphite_query.ts
+5
-0
public/app/plugins/datasource/graphite/query_ctrl.ts
+5
-0
public/sass/components/_query_editor.scss
+0
-1
No files found.
packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx
View file @
1069d7f5
import
React
,
{
Component
,
createRef
}
from
'react'
;
import
React
,
{
Component
,
createRef
}
from
'react'
;
import
PopperController
from
'../Tooltip/PopperController'
;
import
{
PopperController
}
from
'../Tooltip/PopperController'
;
import
Popper
from
'../Tooltip/Popper'
;
import
{
Popper
}
from
'../Tooltip/Popper'
;
import
{
ColorPickerPopover
}
from
'./ColorPickerPopover'
;
import
{
ColorPickerPopover
}
from
'./ColorPickerPopover'
;
import
{
Themeable
}
from
'../../types'
;
import
{
Themeable
}
from
'../../types'
;
import
{
getColorFromHexRgbOrName
}
from
'../../utils/namedColorsPalette'
;
import
{
getColorFromHexRgbOrName
}
from
'../../utils/namedColorsPalette'
;
...
...
packages/grafana-ui/src/components/Tooltip/Popper.tsx
View file @
1069d7f5
...
@@ -58,7 +58,7 @@ class Popper extends PureComponent<Props> {
...
@@ -58,7 +58,7 @@ class Popper extends PureComponent<Props> {
// TODO: move modifiers config to popper controller
// TODO: move modifiers config to popper controller
modifiers=
{
{
preventOverflow
:
{
enabled
:
true
,
boundariesElement
:
'window'
}
}
}
modifiers=
{
{
preventOverflow
:
{
enabled
:
true
,
boundariesElement
:
'window'
}
}
}
>
>
{
({
ref
,
style
,
placement
,
arrowProps
})
=>
{
{
({
ref
,
style
,
placement
,
arrowProps
,
scheduleUpdate
})
=>
{
return
(
return
(
<
div
<
div
onMouseEnter=
{
onMouseEnter
}
onMouseEnter=
{
onMouseEnter
}
...
@@ -73,7 +73,12 @@ class Popper extends PureComponent<Props> {
...
@@ -73,7 +73,12 @@ class Popper extends PureComponent<Props> {
className=
{
`${wrapperClassName}`
}
className=
{
`${wrapperClassName}`
}
>
>
<
div
className=
{
className
}
>
<
div
className=
{
className
}
>
{
typeof
content
===
'string'
?
content
:
React
.
cloneElement
(
content
)
}
{
typeof
content
===
'string'
&&
content
}
{
React
.
isValidElement
(
content
)
&&
React
.
cloneElement
(
content
)
}
{
typeof
content
===
'function'
&&
content
({
updatePopperPosition
:
scheduleUpdate
,
})
}
{
renderArrow
&&
{
renderArrow
&&
renderArrow
({
renderArrow
({
arrowProps
,
arrowProps
,
...
@@ -93,4 +98,4 @@ class Popper extends PureComponent<Props> {
...
@@ -93,4 +98,4 @@ class Popper extends PureComponent<Props> {
}
}
}
}
export
default
Popper
;
export
{
Popper
}
;
packages/grafana-ui/src/components/Tooltip/PopperController.tsx
View file @
1069d7f5
...
@@ -7,7 +7,7 @@ export interface PopperContentProps {
...
@@ -7,7 +7,7 @@ export interface PopperContentProps {
updatePopperPosition
?:
()
=>
void
;
updatePopperPosition
?:
()
=>
void
;
}
}
export
type
PopperContent
<
T
extends
PopperContentProps
>
=
string
|
React
.
ReactElement
<
T
>
;
export
type
PopperContent
<
T
extends
PopperContentProps
>
=
string
|
React
.
ReactElement
<
T
>
|
((
props
:
T
)
=>
JSX
.
Element
)
;
export
interface
UsingPopperProps
{
export
interface
UsingPopperProps
{
show
?:
boolean
;
show
?:
boolean
;
...
@@ -101,4 +101,4 @@ class PopperController extends React.Component<Props, State> {
...
@@ -101,4 +101,4 @@ class PopperController extends React.Component<Props, State> {
}
}
}
}
export
default
PopperController
;
export
{
PopperController
}
;
packages/grafana-ui/src/components/Tooltip/Tooltip.tsx
View file @
1069d7f5
import
React
,
{
createRef
}
from
'react'
;
import
React
,
{
createRef
}
from
'react'
;
import
*
as
PopperJS
from
'popper.js'
;
import
*
as
PopperJS
from
'popper.js'
;
import
Popper
from
'./Popper'
;
import
{
Popper
}
from
'./Popper'
;
import
PopperController
,
{
UsingPopperProps
}
from
'./PopperController'
;
import
{
PopperController
,
UsingPopperProps
}
from
'./PopperController'
;
interface
TooltipProps
extends
UsingPopperProps
{
interface
TooltipProps
extends
UsingPopperProps
{
theme
?:
'info'
|
'error'
;
theme
?:
'info'
|
'error'
;
...
...
packages/grafana-ui/src/components/index.ts
View file @
1069d7f5
export
{
DeleteButton
}
from
'./DeleteButton/DeleteButton'
;
export
{
DeleteButton
}
from
'./DeleteButton/DeleteButton'
;
export
{
Tooltip
}
from
'./Tooltip/Tooltip'
;
export
{
Tooltip
}
from
'./Tooltip/Tooltip'
;
export
{
PopperController
}
from
'./Tooltip/PopperController'
;
export
{
Popper
}
from
'./Tooltip/Popper'
;
export
{
Portal
}
from
'./Portal/Portal'
;
export
{
Portal
}
from
'./Portal/Portal'
;
export
{
CustomScrollbar
}
from
'./CustomScrollbar/CustomScrollbar'
;
export
{
CustomScrollbar
}
from
'./CustomScrollbar/CustomScrollbar'
;
...
...
public/app/core/angular_wrappers.ts
View file @
1069d7f5
...
@@ -10,10 +10,12 @@ import { SideMenu } from './components/sidemenu/SideMenu';
...
@@ -10,10 +10,12 @@ import { SideMenu } from './components/sidemenu/SideMenu';
import
{
MetricSelect
}
from
'./components/Select/MetricSelect'
;
import
{
MetricSelect
}
from
'./components/Select/MetricSelect'
;
import
AppNotificationList
from
'./components/AppNotifications/AppNotificationList'
;
import
AppNotificationList
from
'./components/AppNotifications/AppNotificationList'
;
import
{
ColorPicker
,
SeriesColorPickerPopoverWithTheme
}
from
'@grafana/ui'
;
import
{
ColorPicker
,
SeriesColorPickerPopoverWithTheme
}
from
'@grafana/ui'
;
import
{
FunctionEditor
}
from
'app/plugins/datasource/graphite/FunctionEditor'
;
export
function
registerAngularDirectives
()
{
export
function
registerAngularDirectives
()
{
react2AngularDirective
(
'passwordStrength'
,
PasswordStrength
,
[
'password'
]);
react2AngularDirective
(
'passwordStrength'
,
PasswordStrength
,
[
'password'
]);
react2AngularDirective
(
'sidemenu'
,
SideMenu
,
[]);
react2AngularDirective
(
'sidemenu'
,
SideMenu
,
[]);
react2AngularDirective
(
'functionEditor'
,
FunctionEditor
,
[
'func'
,
'onRemove'
,
'onMoveLeft'
,
'onMoveRight'
]);
react2AngularDirective
(
'appNotificationsList'
,
AppNotificationList
,
[]);
react2AngularDirective
(
'appNotificationsList'
,
AppNotificationList
,
[]);
react2AngularDirective
(
'pageHeader'
,
PageHeader
,
[
'model'
,
'noTabs'
]);
react2AngularDirective
(
'pageHeader'
,
PageHeader
,
[
'model'
,
'noTabs'
]);
react2AngularDirective
(
'emptyListCta'
,
EmptyListCTA
,
[
'model'
]);
react2AngularDirective
(
'emptyListCta'
,
EmptyListCTA
,
[
'model'
]);
...
...
public/app/plugins/datasource/graphite/FunctionEditor.tsx
0 → 100644
View file @
1069d7f5
import
React
from
'react'
;
import
{
PopperController
,
Popper
}
from
'@grafana/ui'
;
import
rst2html
from
'rst2html'
;
import
{
FunctionDescriptor
,
FunctionEditorControlsProps
,
FunctionEditorControls
}
from
'./FunctionEditorControls'
;
interface
FunctionEditorProps
extends
FunctionEditorControlsProps
{
func
:
FunctionDescriptor
;
}
interface
FunctionEditorState
{
showingDescription
:
boolean
;
}
class
FunctionEditor
extends
React
.
PureComponent
<
FunctionEditorProps
,
FunctionEditorState
>
{
private
triggerRef
=
React
.
createRef
<
HTMLSpanElement
>
();
constructor
(
props
:
FunctionEditorProps
)
{
super
(
props
);
this
.
state
=
{
showingDescription
:
false
,
};
}
renderContent
=
({
updatePopperPosition
})
=>
{
const
{
onMoveLeft
,
onMoveRight
,
func
:
{
def
:
{
name
,
description
}
}
}
=
this
.
props
;
const
{
showingDescription
}
=
this
.
state
;
if
(
showingDescription
)
{
return
(
<
div
style=
{
{
overflow
:
'auto'
,
maxHeight
:
'30rem'
,
textAlign
:
'left'
,
fontWeight
:
'normal'
}
}
>
<
h4
style=
{
{
color
:
'white'
}
}
>
{
name
}
</
h4
>
<
div
dangerouslySetInnerHTML=
{
{
__html
:
rst2html
(
description
),
}
}
/>
</
div
>
);
}
return
(
<
FunctionEditorControls
{
...
this
.
props
}
onMoveLeft=
{
()
=>
{
onMoveLeft
(
this
.
props
.
func
);
updatePopperPosition
();
}
}
onMoveRight=
{
()
=>
{
onMoveRight
(
this
.
props
.
func
);
updatePopperPosition
();
}
}
onDescriptionShow=
{
()
=>
{
this
.
setState
({
showingDescription
:
true
},
()
=>
{
updatePopperPosition
();
});
}
}
/>
);
};
render
()
{
return
(
<
PopperController
content=
{
this
.
renderContent
}
placement=
"top"
hideAfter=
{
300
}
>
{
(
showPopper
,
hidePopper
,
popperProps
)
=>
{
return
(
<>
{
this
.
triggerRef
&&
(
<
Popper
{
...
popperProps
}
referenceElement=
{
this
.
triggerRef
.
current
}
wrapperClassName=
"popper"
className=
"popper__background"
onMouseLeave=
{
()
=>
{
this
.
setState
({
showingDescription
:
false
});
hidePopper
();
}
}
onMouseEnter=
{
showPopper
}
renderArrow=
{
({
arrowProps
,
placement
})
=>
(
<
div
className=
"popper__arrow"
data
-
placement=
{
placement
}
{
...
arrowProps
}
/>
)
}
/>
)
}
<
span
ref=
{
this
.
triggerRef
}
onClick=
{
popperProps
.
show
?
hidePopper
:
showPopper
}
onMouseLeave=
{
()
=>
{
hidePopper
();
this
.
setState
({
showingDescription
:
false
});
}
}
style=
{
{
cursor
:
'pointer'
}
}
>
{
this
.
props
.
func
.
def
.
name
}
</
span
>
</>
);
}
}
</
PopperController
>
);
}
}
export
{
FunctionEditor
};
public/app/plugins/datasource/graphite/FunctionEditorControls.tsx
0 → 100644
View file @
1069d7f5
import
React
from
'react'
;
export
interface
FunctionDescriptor
{
text
:
string
;
params
:
string
[];
def
:
{
category
:
string
;
defaultParams
:
string
[];
description
?:
string
;
fake
:
boolean
;
name
:
string
;
params
:
string
[];
};
}
export
interface
FunctionEditorControlsProps
{
onMoveLeft
:
(
func
:
FunctionDescriptor
)
=>
void
;
onMoveRight
:
(
func
:
FunctionDescriptor
)
=>
void
;
onRemove
:
(
func
:
FunctionDescriptor
)
=>
void
;
}
const
FunctionHelpButton
=
(
props
:
{
description
:
string
;
name
:
string
;
onDescriptionShow
:
()
=>
void
})
=>
{
if
(
props
.
description
)
{
return
<
span
className=
"pointer fa fa-question-circle"
onClick=
{
props
.
onDescriptionShow
}
/>;
}
return
(
<
span
className=
"pointer fa fa-question-circle"
onClick=
{
()
=>
{
window
.
open
(
'http://graphite.readthedocs.org/en/latest/functions.html#graphite.render.functions.'
+
props
.
name
,
'_blank'
);
}
}
/>
);
};
export
const
FunctionEditorControls
=
(
props
:
FunctionEditorControlsProps
&
{
func
:
FunctionDescriptor
;
onDescriptionShow
:
()
=>
void
;
}
)
=>
{
const
{
func
,
onMoveLeft
,
onMoveRight
,
onRemove
,
onDescriptionShow
}
=
props
;
return
(
<
div
style=
{
{
display
:
'flex'
,
width
:
'60px'
,
justifyContent
:
'space-between'
,
}
}
>
<
span
className=
"pointer fa fa-arrow-left"
onClick=
{
()
=>
onMoveLeft
(
func
)
}
/>
<
FunctionHelpButton
name=
{
func
.
def
.
name
}
description=
{
func
.
def
.
description
}
onDescriptionShow=
{
onDescriptionShow
}
/>
<
span
className=
"pointer fa fa-remove"
onClick=
{
()
=>
onRemove
(
func
)
}
/>
<
span
className=
"pointer fa fa-arrow-right"
onClick=
{
()
=>
onMoveRight
(
func
)
}
/>
</
div
>
);
};
public/app/plugins/datasource/graphite/func_editor.ts
View file @
1069d7f5
import
_
from
'lodash'
;
import
_
from
'lodash'
;
import
$
from
'jquery'
;
import
$
from
'jquery'
;
import
rst2html
from
'rst2html'
;
import
coreModule
from
'app/core/core_module'
;
import
coreModule
from
'app/core/core_module'
;
/** @ngInject */
/** @ngInject */
export
function
graphiteFuncEditor
(
$compile
,
templateSrv
,
popoverSrv
)
{
export
function
graphiteFuncEditor
(
$compile
,
templateSrv
,
popoverSrv
)
{
const
funcSpanTemplate
=
'<a ng-click="">{{func.def.name}}</a><span>(</span>'
;
const
funcSpanTemplate
=
`
<function-editor
func="func"
onRemove="ctrl.handleRemoveFunction"
onMoveLeft="ctrl.handleMoveLeft"
onMoveRight="ctrl.handleMoveRight"
/><span>(</span>
`
;
const
paramTemplate
=
const
paramTemplate
=
'<input type="text" style="display:none"'
+
' class="input-small tight-form-func-param"></input>'
;
'<input type="text" style="display:none"'
+
' class="input-small tight-form-func-param"></input>'
;
const
funcControlsTemplate
=
`
<div class="tight-form-func-controls">
<span class="pointer fa fa-arrow-left"></span>
<span class="pointer fa fa-question-circle"></span>
<span class="pointer fa fa-remove" ></span>
<span class="pointer fa fa-arrow-right"></span>
</div>`
;
return
{
return
{
restrict
:
'A'
,
restrict
:
'A'
,
link
:
function
postLink
(
$scope
,
elem
)
{
link
:
function
postLink
(
$scope
,
elem
)
{
const
$funcLink
=
$
(
funcSpanTemplate
);
const
$funcLink
=
$
(
funcSpanTemplate
);
const
$funcControls
=
$
(
funcControlsTemplate
);
const
ctrl
=
$scope
.
ctrl
;
const
ctrl
=
$scope
.
ctrl
;
const
func
=
$scope
.
func
;
const
func
=
$scope
.
func
;
let
scheduledRelink
=
false
;
let
scheduledRelink
=
false
;
let
paramCountAtLink
=
0
;
let
paramCountAtLink
=
0
;
let
cancelBlur
=
null
;
let
cancelBlur
=
null
;
ctrl
.
handleRemoveFunction
=
func
=>
{
ctrl
.
removeFunction
(
func
);
};
ctrl
.
handleMoveLeft
=
func
=>
{
ctrl
.
moveFunction
(
func
,
-
1
);
};
ctrl
.
handleMoveRight
=
func
=>
{
ctrl
.
moveFunction
(
func
,
1
);
};
function
clickFuncParam
(
this
:
any
,
paramIndex
)
{
function
clickFuncParam
(
this
:
any
,
paramIndex
)
{
/*jshint validthis:true */
/*jshint validthis:true */
...
@@ -158,24 +167,7 @@ export function graphiteFuncEditor($compile, templateSrv, popoverSrv) {
...
@@ -158,24 +167,7 @@ export function graphiteFuncEditor($compile, templateSrv, popoverSrv) {
};
};
}
}
function
toggleFuncControls
()
{
const
targetDiv
=
elem
.
closest
(
'.tight-form'
);
if
(
elem
.
hasClass
(
'show-function-controls'
))
{
elem
.
removeClass
(
'show-function-controls'
);
targetDiv
.
removeClass
(
'has-open-function'
);
$funcControls
.
hide
();
return
;
}
elem
.
addClass
(
'show-function-controls'
);
targetDiv
.
addClass
(
'has-open-function'
);
$funcControls
.
show
();
}
function
addElementsAndCompile
()
{
function
addElementsAndCompile
()
{
$funcControls
.
appendTo
(
elem
);
$funcLink
.
appendTo
(
elem
);
$funcLink
.
appendTo
(
elem
);
const
defParams
=
_
.
clone
(
func
.
def
.
params
);
const
defParams
=
_
.
clone
(
func
.
def
.
params
);
...
@@ -245,69 +237,10 @@ export function graphiteFuncEditor($compile, templateSrv, popoverSrv) {
...
@@ -245,69 +237,10 @@ export function graphiteFuncEditor($compile, templateSrv, popoverSrv) {
}
}
}
}
function
registerFuncControlsToggle
()
{
$funcLink
.
click
(
toggleFuncControls
);
}
function
registerFuncControlsActions
()
{
$funcControls
.
click
(
e
=>
{
const
$target
=
$
(
e
.
target
);
if
(
$target
.
hasClass
(
'fa-remove'
))
{
toggleFuncControls
();
$scope
.
$apply
(()
=>
{
ctrl
.
removeFunction
(
$scope
.
func
);
});
return
;
}
if
(
$target
.
hasClass
(
'fa-arrow-left'
))
{
$scope
.
$apply
(()
=>
{
_
.
move
(
ctrl
.
queryModel
.
functions
,
$scope
.
$index
,
$scope
.
$index
-
1
);
ctrl
.
targetChanged
();
});
return
;
}
if
(
$target
.
hasClass
(
'fa-arrow-right'
))
{
$scope
.
$apply
(()
=>
{
_
.
move
(
ctrl
.
queryModel
.
functions
,
$scope
.
$index
,
$scope
.
$index
+
1
);
ctrl
.
targetChanged
();
});
return
;
}
if
(
$target
.
hasClass
(
'fa-question-circle'
))
{
const
funcDef
=
ctrl
.
datasource
.
getFuncDef
(
func
.
def
.
name
);
if
(
funcDef
&&
funcDef
.
description
)
{
popoverSrv
.
show
({
element
:
e
.
target
,
position
:
'bottom left'
,
classNames
:
'drop-popover drop-function-def'
,
template
:
`
<div style="overflow:auto;max-height:30rem;">
<h4>
${
funcDef
.
name
}
</h4>
${
rst2html
(
funcDef
.
description
)}
</div>`
,
openOn
:
'click'
,
});
}
else
{
window
.
open
(
'http://graphite.readthedocs.org/en/latest/functions.html#graphite.render.functions.'
+
func
.
def
.
name
,
'_blank'
);
}
return
;
}
});
}
function
relink
()
{
function
relink
()
{
elem
.
children
().
remove
();
elem
.
children
().
remove
();
addElementsAndCompile
();
addElementsAndCompile
();
ifJustAddedFocusFirstParam
();
ifJustAddedFocusFirstParam
();
registerFuncControlsToggle
();
registerFuncControlsActions
();
}
}
relink
();
relink
();
...
...
public/app/plugins/datasource/graphite/graphite_query.ts
View file @
1069d7f5
...
@@ -154,6 +154,11 @@ export default class GraphiteQuery {
...
@@ -154,6 +154,11 @@ export default class GraphiteQuery {
this
.
functions
=
_
.
without
(
this
.
functions
,
func
);
this
.
functions
=
_
.
without
(
this
.
functions
,
func
);
}
}
moveFunction
(
func
,
offset
)
{
const
index
=
this
.
functions
.
indexOf
(
func
);
_
.
move
(
this
.
functions
,
index
,
index
+
offset
);
}
updateModelTarget
(
targets
)
{
updateModelTarget
(
targets
)
{
// render query
// render query
if
(
!
this
.
target
.
textEditor
)
{
if
(
!
this
.
target
.
textEditor
)
{
...
...
public/app/plugins/datasource/graphite/query_ctrl.ts
View file @
1069d7f5
...
@@ -272,6 +272,11 @@ export class GraphiteQueryCtrl extends QueryCtrl {
...
@@ -272,6 +272,11 @@ export class GraphiteQueryCtrl extends QueryCtrl {
this
.
targetChanged
();
this
.
targetChanged
();
}
}
moveFunction
(
func
,
offset
)
{
this
.
queryModel
.
moveFunction
(
func
,
offset
);
this
.
targetChanged
();
}
addSeriesByTagFunc
(
tag
)
{
addSeriesByTagFunc
(
tag
)
{
const
newFunc
=
this
.
datasource
.
createFuncInstance
(
'seriesByTag'
,
{
const
newFunc
=
this
.
datasource
.
createFuncInstance
(
'seriesByTag'
,
{
withDefaultParams
:
false
,
withDefaultParams
:
false
,
...
...
public/sass/components/_query_editor.scss
View file @
1069d7f5
...
@@ -50,7 +50,6 @@ input[type='text'].tight-form-func-param {
...
@@ -50,7 +50,6 @@ input[type='text'].tight-form-func-param {
}
}
.tight-form-func-controls
{
.tight-form-func-controls
{
display
:
none
;
text-align
:
center
;
text-align
:
center
;
.fa-arrow-left
{
.fa-arrow-left
{
...
...
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