Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
qorus
grafana
Commits
adfa341d
Commit
adfa341d
authored
Mar 07, 2014
by
Torkel Ödegaard
Browse files
Merge branch 'new_func_editor'
parents
1c72e0c4
0b03ca15
Changes
9
Hide whitespace changes
Inline
Side-by-side
src/app/controllers/graphiteTarget.js
View file @
adfa341d
...
...
@@ -222,24 +222,44 @@ function (angular, _, config, gfunc, Parser) {
$scope
.
targetChanged
();
};
$scope
.
functionParamsChanged
=
function
(
func
)
{
func
.
updateText
();
$scope
.
targetChanged
();
};
$scope
.
addFunction
=
function
(
funcDef
)
{
$scope
.
functions
.
push
(
gfunc
.
createFuncInstance
(
funcDef
));
var
newFunc
=
gfunc
.
createFuncInstance
(
funcDef
);
newFunc
.
added
=
true
;
$scope
.
functions
.
push
(
newFunc
);
$scope
.
moveAliasFuncLast
();
$scope
.
smartlyHandleNewAliasByNode
(
newFunc
);
if
(
!
funcDef
.
params
&&
newFunc
.
added
)
{
$scope
.
targetChanged
();
}
};
$scope
.
moveAliasFuncLast
=
function
()
{
var
aliasFunc
=
_
.
find
(
$scope
.
functions
,
function
(
func
)
{
return
func
.
def
.
name
===
'
alias
'
;
return
func
.
def
.
name
===
'
alias
'
||
func
.
def
.
name
===
'
aliasByNode
'
||
func
.
def
.
name
===
'
aliasByMetric
'
;
});
if
(
aliasFunc
)
{
$scope
.
functions
=
_
.
without
(
$scope
.
functions
,
aliasFunc
);
$scope
.
functions
.
push
(
aliasFunc
);
}
};
$scope
.
targetChanged
();
$scope
.
smartlyHandleNewAliasByNode
=
function
(
func
)
{
if
(
func
.
def
.
name
!==
'
aliasByNode
'
)
{
return
;
}
for
(
var
i
=
0
;
i
<
$scope
.
segments
.
length
;
i
++
)
{
if
(
$scope
.
segments
[
i
].
val
.
indexOf
(
'
*
'
)
>=
0
)
{
func
.
params
[
0
]
=
i
;
func
.
added
=
false
;
$scope
.
targetChanged
();
return
;
}
}
};
$scope
.
duplicate
=
function
()
{
...
...
src/app/directives/all.js
View file @
adfa341d
...
...
@@ -13,5 +13,6 @@ define([
'
./grafanaGraph
'
,
'
./bootstrap-tagsinput
'
,
'
./bodyClass
'
,
'
./addGraphiteFunc
'
'
./addGraphiteFunc
'
,
'
./graphiteFuncEditor
'
],
function
()
{});
\ No newline at end of file
src/app/directives/graphiteFuncEditor.js
0 → 100644
View file @
adfa341d
define
([
'
angular
'
,
'
underscore
'
,
'
jquery
'
,
],
function
(
angular
,
_
,
$
)
{
'
use strict
'
;
angular
.
module
(
'
kibana.directives
'
)
.
directive
(
'
graphiteFuncEditor
'
,
function
(
$compile
)
{
var
funcSpanTemplate
=
'
<a ng-click="">{{func.def.name}}</a><span>(</span>
'
;
var
paramTemplate
=
'
<input type="text" style="display:none"
'
+
'
class="input-mini grafana-function-param-input"></input>
'
;
var
funcControlsTemplate
=
'
<div class="graphite-func-controls">
'
+
'
<span class="pointer icon-arrow-left"></span>
'
+
'
<span class="pointer icon-info-sign"></span>
'
+
'
<span class="pointer icon-remove" ></span>
'
+
'
<span class="pointer icon-arrow-right"></span>
'
+
'
</div>
'
;
return
{
restrict
:
'
A
'
,
link
:
function
postLink
(
$scope
,
elem
)
{
var
$funcLink
=
$
(
funcSpanTemplate
);
var
$funcControls
=
$
(
funcControlsTemplate
);
var
func
=
$scope
.
func
;
var
funcDef
=
func
.
def
;
function
clickFuncParam
(
paramIndex
)
{
/*jshint validthis:true */
var
$link
=
$
(
this
);
var
$input
=
$link
.
next
();
$input
.
val
(
func
.
params
[
paramIndex
]);
$input
.
css
(
'
width
'
,
(
$link
.
width
()
+
16
)
+
'
px
'
);
$link
.
hide
();
$input
.
show
();
$input
.
focus
();
$input
.
select
();
var
typeahead
=
$input
.
data
(
'
typeahead
'
);
if
(
typeahead
)
{
$input
.
val
(
''
);
typeahead
.
lookup
();
}
}
function
inputBlur
(
paramIndex
)
{
/*jshint validthis:true */
var
$input
=
$
(
this
);
var
$link
=
$input
.
prev
();
if
(
$input
.
val
()
!==
''
)
{
$link
.
text
(
$input
.
val
());
if
(
func
.
updateParam
(
$input
.
val
(),
paramIndex
))
{
$scope
.
$apply
(
function
()
{
$scope
.
targetChanged
();
});
}
}
$input
.
hide
();
$link
.
show
();
}
function
inputKeyPress
(
paramIndex
,
e
)
{
/*jshint validthis:true */
if
(
e
.
which
===
13
)
{
inputBlur
.
call
(
this
,
paramIndex
);
}
}
function
inputKeyDown
()
{
/*jshint validthis:true */
this
.
style
.
width
=
(
3
+
this
.
value
.
length
)
*
8
+
'
px
'
;
}
function
addTypeahead
(
$input
,
paramIndex
)
{
$input
.
attr
(
'
data-provide
'
,
'
typeahead
'
);
var
options
=
funcDef
.
params
[
paramIndex
].
options
;
if
(
funcDef
.
params
[
paramIndex
].
type
===
'
int
'
)
{
options
=
_
.
map
(
options
,
function
(
val
)
{
return
val
.
toString
();
}
);
}
$input
.
typeahead
({
source
:
options
,
minLength
:
0
,
items
:
20
,
updater
:
function
(
value
)
{
setTimeout
(
function
()
{
inputBlur
.
call
(
$input
[
0
],
paramIndex
);
},
0
);
return
value
;
}
});
var
typeahead
=
$input
.
data
(
'
typeahead
'
);
typeahead
.
lookup
=
function
()
{
this
.
query
=
this
.
$element
.
val
()
||
''
;
return
this
.
process
(
this
.
source
);
};
}
function
toggleFuncControls
()
{
var
targetDiv
=
elem
.
closest
(
'
.grafana-target-inner
'
);
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
()
{
$funcControls
.
appendTo
(
elem
);
$funcLink
.
appendTo
(
elem
);
_
.
each
(
funcDef
.
params
,
function
(
param
,
index
)
{
var
$paramLink
=
$
(
'
<a ng-click="" class="graphite-func-param-link">
'
+
func
.
params
[
index
]
+
'
</a>
'
);
var
$input
=
$
(
paramTemplate
);
$paramLink
.
appendTo
(
elem
);
$input
.
appendTo
(
elem
);
$input
.
blur
(
_
.
partial
(
inputBlur
,
index
));
$input
.
keyup
(
inputKeyDown
);
$input
.
keypress
(
_
.
partial
(
inputKeyPress
,
index
));
$paramLink
.
click
(
_
.
partial
(
clickFuncParam
,
index
));
if
(
index
!==
funcDef
.
params
.
length
-
1
)
{
$
(
'
<span>, </span>
'
).
appendTo
(
elem
);
}
if
(
funcDef
.
params
[
index
].
options
)
{
addTypeahead
(
$input
,
index
);
}
});
$
(
'
<span>)</span>
'
).
appendTo
(
elem
);
$compile
(
elem
.
contents
())(
$scope
);
}
function
ifJustAddedFocusFistParam
()
{
if
(
$scope
.
func
.
added
)
{
$scope
.
func
.
added
=
false
;
setTimeout
(
function
()
{
elem
.
find
(
'
.graphite-func-param-link
'
).
first
().
click
();
},
10
);
}
}
function
registerFuncControlsToggle
()
{
$funcLink
.
click
(
toggleFuncControls
);
}
function
registerFuncControlsActions
()
{
$funcControls
.
click
(
function
(
e
)
{
var
$target
=
$
(
e
.
target
);
if
(
$target
.
hasClass
(
'
icon-remove
'
))
{
toggleFuncControls
();
$scope
.
$apply
(
function
()
{
$scope
.
removeFunction
(
$scope
.
func
);
});
return
;
}
if
(
$target
.
hasClass
(
'
icon-arrow-left
'
))
{
$scope
.
$apply
(
function
()
{
_
.
move
(
$scope
.
functions
,
$scope
.
$index
,
$scope
.
$index
-
1
);
});
return
;
}
if
(
$target
.
hasClass
(
'
icon-arrow-right
'
))
{
$scope
.
$apply
(
function
()
{
_
.
move
(
$scope
.
functions
,
$scope
.
$index
,
$scope
.
$index
+
1
);
});
return
;
}
if
(
$target
.
hasClass
(
'
icon-info-sign
'
))
{
window
.
open
(
"
http://graphite.readthedocs.org/en/latest/functions.html#graphite.render.functions.
"
+
funcDef
.
name
,
'
_blank
'
);
return
;
}
});
}
addElementsAndCompile
();
ifJustAddedFocusFistParam
();
registerFuncControlsToggle
();
registerFuncControlsActions
();
}
};
});
});
\ No newline at end of file
src/app/partials/graphite/editor.html
View file @
adfa341d
...
...
@@ -7,88 +7,99 @@
ng-controller=
"GraphiteTargetCtrl"
ng-init=
"init()"
>
<div
class=
"grafana-target-inner-wrapper"
>
<div
class=
"grafana-target-inner"
>
<ul
class=
"grafana-target-controls"
>
<li
ng-show=
"parserError"
>
<a
bs-tooltip=
"parserError"
style=
"color: rgb(229, 189, 28)"
role=
"menuitem"
>
<i
class=
"icon-warning-sign"
></i>
</a>
</li>
<li>
<a
class=
"pointer"
tabindex=
"1"
ng-click=
"showTextEditor = !showTextEditor"
>
<i
class=
"icon-pencil"
></i>
</a>
</li>
<li
class=
"dropdown"
>
<a
class=
"pointer dropdown-toggle"
data-toggle=
"dropdown"
tabindex=
"1"
>
<i
class=
"icon-cog"
></i>
</a>
<ul
class=
"dropdown-menu pull-right"
role=
"menu"
>
<li
role=
"menuitem"
>
<a
tabindex=
"1"
ng-click=
"duplicate()"
>
Duplicate
</a>
</li>
</ul>
</li>
<li>
<a
class=
"pointer"
tabindex=
"1"
ng-click=
"removeTarget(target)"
>
<i
class=
"icon-remove"
></i>
</a>
</li>
</ul>
<div
class=
"grafana-target-inner"
>
<ul
class=
"grafana-target-controls"
>
<li
ng-show=
"parserError"
>
<a
bs-tooltip=
"parserError"
style=
"color: rgb(229, 189, 28)"
role=
"menuitem"
>
<i
class=
"icon-warning-sign"
></i>
</a>
</li>
<li>
<a
class=
"pointer"
tabindex=
"1"
ng-click=
"showTextEditor = !showTextEditor"
>
<i
class=
"icon-pencil"
></i>
</a>
</li>
<li
class=
"dropdown"
>
<a
class=
"pointer dropdown-toggle"
data-toggle=
"dropdown"
tabindex=
"1"
>
<i
class=
"icon-cog"
></i>
</a>
<ul
class=
"dropdown-menu pull-right"
role=
"menu"
>
<li
role=
"menuitem"
>
<a
tabindex=
"1"
ng-click=
"duplicate()"
>
Duplicate
</a>
</li>
</ul>
</li>
<li>
<a
class=
"pointer"
tabindex=
"1"
ng-click=
"removeTarget(target)"
>
<i
class=
"icon-remove"
></i>
</a>
</li>
</ul>
<ul
class=
"grafana-target-controls-left"
>
<li>
<a
class=
"grafana-target-segment"
ng-click=
"target.hide = !target.hide; get_data();"
role=
"menuitem"
>
<i
class=
"icon-eye-open"
></i>
</a>
</li>
</ul>
<ul
class=
"grafana-target-controls-left"
>
<li>
<a
class=
"grafana-target-segment"
ng-click=
"target.hide = !target.hide; get_data();"
role=
"menuitem"
>
<i
class=
"icon-eye-open"
></i>
</a>
</li>
</ul>
<input
type=
"text"
class=
"grafana-target-text-input span10"
ng-model=
"target.target"
focus-me=
"showTextEditor"
spellcheck=
'false'
ng-model-onblur
ng-change=
"targetTextChanged()"
ng-show=
"showTextEditor"
/>
<input
type=
"text"
class=
"grafana-target-text-input span10"
ng-model=
"target.target"
focus-me=
"showTextEditor"
spellcheck=
'false'
ng-model-onblur
ng-change=
"targetTextChanged()"
ng-show=
"showTextEditor"
/>
<ul
class=
"grafana-segment-list"
role=
"menu"
ng-hide=
"showTextEditor"
>
<li
class=
"dropdown"
ng-repeat=
"segment in segments"
role=
"menuitem"
>
<a
tabindex=
"1"
class=
"grafana-target-segment dropdown-toggle"
data-toggle=
"dropdown"
ng-click=
"getAltSegments($index)"
focus-me=
"segment.focus"
ng-bind-html-unsafe=
"segment.html"
>
</a>
<ul
class=
"dropdown-menu scrollable grafana-segment-dropdown-menu"
role=
"menu"
>
<li
ng-repeat=
"altSegment in altSegments"
role=
"menuitem"
>
<a
href=
"javascript:void(0)"
tabindex=
"1"
ng-click=
"setSegment($index, $parent.$index)"
ng-bind-html-unsafe=
"altSegment.html"
></a>
</li>
</ul>
</li>
<li
ng-repeat=
"func in functions"
>
<a
class=
"grafana-target-segment grafana-target-function dropdown-toggle"
bs-popover=
"'app/partials/graphite/funcEditor.html'"
data-placement=
"bottom"
>
{{func.text}}
</a>
</li>
<li
class=
"dropdown"
graphite-add-func
>
<ul
class=
"grafana-segment-list"
role=
"menu"
ng-hide=
"showTextEditor"
>
<li
class=
"dropdown"
ng-repeat=
"segment in segments"
role=
"menuitem"
>
<a
tabindex=
"1"
class=
"grafana-target-segment dropdown-toggle"
data-toggle=
"dropdown"
ng-click=
"getAltSegments($index)"
focus-me=
"segment.focus"
ng-bind-html-unsafe=
"segment.html"
>
</a>
<ul
class=
"dropdown-menu scrollable grafana-segment-dropdown-menu"
role=
"menu"
>
<li
ng-repeat=
"altSegment in altSegments"
role=
"menuitem"
>
<a
href=
"javascript:void(0)"
tabindex=
"1"
ng-click=
"setSegment($index, $parent.$index)"
ng-bind-html-unsafe=
"altSegment.html"
></a>
</li>
</ul>
</li>
<li
ng-repeat=
"func in functions"
>
<span
graphite-func-editor
class=
"grafana-target-segment grafana-target-function"
>
</span>
<!-- <a class="grafana-target-segment grafana-target-function dropdown-toggle"
bs-popover="'app/partials/graphite/funcEditor.html'"
data-placement="bottom">
{{func.def.name}}
</a> -->
<!-- <span class="grafana-target-segment grafana-target-function">
<span>{{func.def.name}}(</span><span ng-repeat="param in func.def.params">
<input type="text"
class="input-mini grafana-function-param-input"
dynamic-width
ng-model="func.params[$index]"></input>
</span><span>)</span>
</span> -->
</li>
<li
class=
"dropdown"
graphite-add-func
>
</li>
</ul>
</li>
</ul>
<div
class=
"clearfix"
></div>
</div>
<div
class=
"clearfix"
></div>
</div>
</div>
</div>
src/app/partials/graphite/funcEditor.html
deleted
100644 → 0
View file @
1c72e0c4
<div
class=
"grafana-func-editor"
>
<div
class=
"grafana-func-editor-header"
>
<a
ng-click=
"removeFunction(func)"
>
Remove
</a>
<a
ng-click=
"helpFunction(func)"
>
Help
</a>
<a
class=
"close"
ng-click=
"dismiss();"
href=
""
>
×
</a>
</div>
<div
class=
"editor-row"
ng-if=
"func.def.params.length"
>
<div
class=
"section"
>
<div
class=
"editor-option"
ng-repeat=
"param in func.def.params"
>
<label
class=
"small"
>
{{param.name}}
</label>
<div
ng-switch
on=
"param.type"
>
<div
ng-switch-when=
"int"
>
<input
type=
"number"
step=
"any"
focus-me=
"true"
class=
"input-mini"
ng-change=
"functionParamsChanged(func)"
ng-model-onblur
ng-model=
"func.params[$index]"
/>
</div>
<div
ng-switch-when=
"string"
>
<input
type=
"text"
focus-me=
"true"
class=
"input-small"
ng-change=
"functionParamsChanged(func)"
ng-model-onblur
ng-model=
"func.params[$index]"
/>
</div>
<div
ng-switch-when=
"select"
>
<select
class=
"input-mini"
ng-model=
"func.params[$index]"
ng-change=
"functionParamsChanged(func)"
focus-me=
"true"
ng-options=
"f for f in param.options"
>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
src/app/services/graphite/gfunc.js
View file @
adfa341d
...
...
@@ -89,12 +89,12 @@ function (_) {
params
:
[
{
name
:
"
node
"
,
type
:
"
selec
t
"
,
type
:
"
in
t
"
,
options
:
[
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
,
12
]
},
{
name
:
"
function
"
,
type
:
"
s
elect
"
,
type
:
"
s
tring
"
,
options
:
[
'
sum
'
,
'
avg
'
]
}
],
...
...
@@ -104,7 +104,7 @@ function (_) {
addFuncDef
({
name
:
'
aliasByNode
'
,
category
:
categories
.
Special
,
params
:
[
{
name
:
"
node
"
,
type
:
"
selec
t
"
,
options
:
[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
,
12
]
}
],
params
:
[
{
name
:
"
node
"
,
type
:
"
in
t
"
,
options
:
[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
,
12
]
}
],
defaultParams
:
[
3
]
});
...
...
@@ -211,14 +211,14 @@ function (_) {
category
:
categories
.
Filter
,
params
:
[
{
name
:
"
n
"
,
type
:
"
int
"
,
}
],
defaultParams
:
[
25
]
});
});
addFuncDef
({
name
:
'
currentBelow
'
,
category
:
categories
.
Filter
,
params
:
[
{
name
:
"
n
"
,
type
:
"
int
"
,
}
],
defaultParams
:
[
25
]
});
});
addFuncDef
({
name
:
"
exclude
"
,
...
...
@@ -279,7 +279,7 @@ function (_) {
this
.
updateText
();
}
FuncInstance
.
prototype
.
render
=
function
(
metricExp
)
{
FuncInstance
.
prototype
.
render
=
function
(
metricExp
)
{
var
str
=
this
.
def
.
name
+
'
(
'
;
var
parameters
=
_
.
map
(
this
.
params
,
function
(
value
)
{
return
_
.
isString
(
value
)
?
"
'
"
+
value
+
"
'
"
:
value
;
...
...
@@ -292,6 +292,21 @@ function (_) {
return
str
+
parameters
.
join
(
'
,
'
)
+
'
)
'
;
};
FuncInstance
.
prototype
.
updateParam
=
function
(
strValue
,
index
)
{
var
oldValue
=
this
.
params
[
index
];
if
(
this
.
def
.
params
[
index
].
type
===
'
int
'
)
{
this
.
params
[
index
]
=
parseInt
(
strValue
,
10
);
}
else
{
this
.
params
[
index
]
=
strValue
;
}
this
.
updateText
();
return
oldValue
!==
this
.
params
[
index
];
};
FuncInstance
.
prototype
.
updateText
=
function
()
{
if
(
this
.
params
.
length
===
0
)
{
this
.
text
=
this
.
def
.
name
+
'
()
'
;
...
...
src/css/bootstrap.dark.min.css
View file @
adfa341d
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/css/bootstrap.light.min.css
View file @
adfa341d
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/css/less/grafana.less
View file @
adfa341d
...
...
@@ -221,10 +221,6 @@
border-bottom: 1px solid @grafanaTargetBorder;
}
.grafana-target-inner-wrapper {
width: 100%;
}
.grafana-target-inner {
border-top: 1px solid @grafanaTargetBorder;
border-left: 1px solid @grafanaTargetBorder;
...
...
@@ -262,6 +258,10 @@
color: @grafanaTargetColor;
display: inline-block;
.has-open-function & {
padding-top: 25px;
}
.grafana-target-hidden & {
color: @grafanaTargetColorHide;
}
...
...
@@ -269,18 +269,34 @@
&:hover, &:focus {
text-decoration: none;
}
&:hover {
&
a
:hover {