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
e9c8881d
Commit
e9c8881d
authored
Jun 15, 2017
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'metric-segment-remake'
parents
581b9777
840099be
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
341 additions
and
52 deletions
+341
-52
public/app/core/components/form_dropdown/form_dropdown.ts
+248
-0
public/app/core/core.ts
+2
-0
public/app/core/directives/dash_edit_link.js
+1
-1
public/app/features/panel/metrics_tab.ts
+20
-31
public/app/features/panel/partials/metrics_tab.html
+10
-5
public/app/plugins/datasource/elasticsearch/bucket_agg.js
+14
-7
public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html
+44
-6
public/app/plugins/datasource/elasticsearch/query_ctrl.ts
+2
-2
No files found.
public/app/core/components/form_dropdown/form_dropdown.ts
0 → 100644
View file @
e9c8881d
///<reference path="../../../headers/common.d.ts" />
import
config
from
'app/core/config'
;
import
_
from
'lodash'
;
import
$
from
'jquery'
;
import
coreModule
from
'../../core_module'
;
function
typeaheadMatcher
(
item
)
{
var
str
=
this
.
query
;
if
(
str
[
0
]
===
'/'
)
{
str
=
str
.
substring
(
1
);
}
if
(
str
[
str
.
length
-
1
]
===
'/'
)
{
str
=
str
.
substring
(
0
,
str
.
length
-
1
);
}
return
item
.
toLowerCase
().
match
(
str
.
toLowerCase
());
}
export
class
FormDropdownCtrl
{
inputElement
:
any
;
linkElement
:
any
;
model
:
any
;
display
:
any
;
text
:
any
;
options
:
any
;
cssClass
:
any
;
cssClasses
:
any
;
allowCustom
:
any
;
labelMode
:
boolean
;
linkMode
:
boolean
;
cancelBlur
:
any
;
onChange
:
any
;
getOptions
:
any
;
optionCache
:
any
;
lookupText
:
boolean
;
constructor
(
private
$scope
,
$element
,
private
$sce
,
private
templateSrv
,
private
$q
)
{
this
.
inputElement
=
$element
.
find
(
'input'
).
first
();
this
.
linkElement
=
$element
.
find
(
'a'
).
first
();
this
.
linkMode
=
true
;
this
.
cancelBlur
=
null
;
// listen to model changes
$scope
.
$watch
(
"ctrl.model"
,
this
.
modelChanged
.
bind
(
this
));
if
(
this
.
labelMode
)
{
this
.
cssClasses
=
'gf-form-label '
+
this
.
cssClass
;
}
else
{
this
.
cssClasses
=
'gf-form-input gf-form-input--dropdown '
+
this
.
cssClass
;
}
this
.
inputElement
.
attr
(
'data-provide'
,
'typeahead'
);
this
.
inputElement
.
typeahead
({
source
:
this
.
typeaheadSource
.
bind
(
this
),
minLength
:
0
,
items
:
10000
,
updater
:
this
.
typeaheadUpdater
.
bind
(
this
),
matcher
:
typeaheadMatcher
,
});
// modify typeahead lookup
// this = typeahead
var
typeahead
=
this
.
inputElement
.
data
(
'typeahead'
);
typeahead
.
lookup
=
function
()
{
this
.
query
=
this
.
$element
.
val
()
||
''
;
var
items
=
this
.
source
(
this
.
query
,
$
.
proxy
(
this
.
process
,
this
));
return
items
?
this
.
process
(
items
)
:
items
;
};
this
.
linkElement
.
keydown
(
evt
=>
{
// trigger typeahead on down arrow or enter key
if
(
evt
.
keyCode
===
40
||
evt
.
keyCode
===
13
)
{
this
.
linkElement
.
click
();
}
});
this
.
inputElement
.
keydown
(
evt
=>
{
if
(
evt
.
keyCode
===
13
)
{
this
.
inputElement
.
blur
();
}
});
this
.
inputElement
.
blur
(
this
.
inputBlur
.
bind
(
this
));
}
getOptionsInternal
(
query
)
{
var
result
=
this
.
getOptions
({
$query
:
query
});
if
(
this
.
isPromiseLike
(
result
))
{
return
result
;
}
return
this
.
$q
.
when
(
result
);
}
isPromiseLike
(
obj
)
{
return
obj
&&
(
typeof
obj
.
then
===
'function'
);
}
modelChanged
()
{
if
(
_
.
isObject
(
this
.
model
))
{
this
.
updateDisplay
(
this
.
model
.
text
);
}
else
{
// if we have text use it
if
(
this
.
lookupText
)
{
this
.
getOptionsInternal
(
""
).
then
(
options
=>
{
var
item
=
_
.
find
(
options
,
{
value
:
this
.
model
});
this
.
updateDisplay
(
item
?
item
.
text
:
this
.
model
);
});
}
else
{
this
.
updateDisplay
(
this
.
model
);
}
}
}
typeaheadSource
(
query
,
callback
)
{
this
.
getOptionsInternal
(
query
).
then
(
options
=>
{
this
.
optionCache
=
options
;
// extract texts
let
optionTexts
=
_
.
map
(
options
,
'text'
);
// add custom values
if
(
this
.
allowCustom
)
{
if
(
_
.
indexOf
(
optionTexts
,
this
.
text
)
===
-
1
)
{
options
.
unshift
(
this
.
text
);
}
}
callback
(
optionTexts
);
});
}
typeaheadUpdater
(
text
)
{
if
(
text
===
this
.
text
)
{
clearTimeout
(
this
.
cancelBlur
);
this
.
inputElement
.
focus
();
return
text
;
}
this
.
inputElement
.
val
(
text
);
this
.
switchToLink
(
true
);
return
text
;
}
switchToLink
(
fromClick
)
{
if
(
this
.
linkMode
&&
!
fromClick
)
{
return
;
}
clearTimeout
(
this
.
cancelBlur
);
this
.
cancelBlur
=
null
;
this
.
linkMode
=
true
;
this
.
inputElement
.
hide
();
this
.
linkElement
.
show
();
this
.
updateValue
(
this
.
inputElement
.
val
());
}
inputBlur
()
{
// happens long before the click event on the typeahead options
// need to have long delay because the blur
this
.
cancelBlur
=
setTimeout
(
this
.
switchToLink
.
bind
(
this
),
200
);
}
updateValue
(
text
)
{
if
(
text
===
''
||
this
.
text
===
text
)
{
return
;
}
this
.
$scope
.
$apply
(()
=>
{
var
option
=
_
.
find
(
this
.
optionCache
,
{
text
:
text
});
if
(
option
)
{
if
(
_
.
isObject
(
this
.
model
))
{
this
.
model
=
option
;
}
else
{
this
.
model
=
option
.
value
;
}
this
.
text
=
option
.
text
;
}
else
if
(
this
.
allowCustom
)
{
if
(
_
.
isObject
(
this
.
model
))
{
this
.
model
.
text
=
this
.
model
.
value
=
text
;
}
else
{
this
.
model
=
text
;
}
this
.
text
=
text
;
}
// needs to call this after digest so
// property is synced with outerscope
this
.
$scope
.
$$postDigest
(()
=>
{
this
.
$scope
.
$apply
(()
=>
{
this
.
onChange
({
$option
:
option
});
});
});
});
}
updateDisplay
(
text
)
{
this
.
text
=
text
;
this
.
display
=
this
.
$sce
.
trustAsHtml
(
this
.
templateSrv
.
highlightVariablesAsHtml
(
text
));
}
open
()
{
this
.
inputElement
.
show
();
this
.
inputElement
.
css
(
'width'
,
(
Math
.
max
(
this
.
linkElement
.
width
(),
80
)
+
16
)
+
'px'
);
this
.
inputElement
.
focus
();
this
.
linkElement
.
hide
();
this
.
linkMode
=
false
;
var
typeahead
=
this
.
inputElement
.
data
(
'typeahead'
);
if
(
typeahead
)
{
this
.
inputElement
.
val
(
''
);
typeahead
.
lookup
();
}
}
}
const
template
=
`
<input type="text"
data-provide="typeahead"
class="gf-form-input"
spellcheck="false"
style="display:none">
</input>
<a ng-class="ctrl.cssClasses"
tabindex="1"
ng-click="ctrl.open()"
give-focus="ctrl.focus"
ng-bind-html="ctrl.display">
</a>
`
;
export
function
formDropdownDirective
()
{
return
{
restrict
:
'E'
,
template
:
template
,
controller
:
FormDropdownCtrl
,
bindToController
:
true
,
controllerAs
:
'ctrl'
,
scope
:
{
model
:
"="
,
getOptions
:
"&"
,
onChange
:
"&"
,
cssClass
:
"@"
,
allowCustom
:
"@"
,
labelMode
:
"@"
,
lookupText
:
"@"
,
},
};
}
coreModule
.
directive
(
'gfFormDropdown'
,
formDropdownDirective
);
public/app/core/core.ts
View file @
e9c8881d
...
...
@@ -34,6 +34,7 @@ import {switchDirective} from './components/switch';
import
{
dashboardSelector
}
from
'./components/dashboard_selector'
;
import
{
queryPartEditorDirective
}
from
'./components/query_part/query_part_editor'
;
import
{
WizardFlow
}
from
'./components/wizard/wizard'
;
import
{
formDropdownDirective
}
from
'./components/form_dropdown/form_dropdown'
;
import
'app/core/controllers/all'
;
import
'app/core/services/all'
;
import
'app/core/routes/routes'
;
...
...
@@ -68,6 +69,7 @@ export {
queryPartEditorDirective
,
WizardFlow
,
colors
,
formDropdownDirective
,
assignModelProperties
,
contextSrv
,
KeybindingSrv
,
...
...
public/app/core/directives/dash_edit_link.js
View file @
e9c8881d
...
...
@@ -35,7 +35,7 @@ function ($, angular, coreModule) {
options
.
html
=
editViewMap
[
options
.
editview
].
html
;
}
if
(
lastEditView
===
options
.
editview
)
{
if
(
lastEditView
&&
lastEditView
===
options
.
editview
)
{
hideEditorPane
(
false
);
return
;
}
...
...
public/app/features/panel/metrics_tab.ts
View file @
e9c8881d
...
...
@@ -5,8 +5,6 @@ import _ from 'lodash';
import
{
DashboardModel
}
from
'../dashboard/model'
;
export
class
MetricsTabCtrl
{
dsSegment
:
any
;
mixedDsSegment
:
any
;
dsName
:
string
;
panel
:
any
;
panelCtrl
:
any
;
...
...
@@ -14,30 +12,26 @@ export class MetricsTabCtrl {
current
:
any
;
nextRefId
:
string
;
dashboard
:
DashboardModel
;
panelDsValue
:
any
;
addQueryDropdown
:
any
;
/** @ngInject */
constructor
(
$scope
,
private
uiSegmentSrv
,
datasourceSrv
)
{
constructor
(
$scope
,
private
uiSegmentSrv
,
private
datasourceSrv
)
{
this
.
panelCtrl
=
$scope
.
ctrl
;
$scope
.
ctrl
=
this
;
this
.
panel
=
this
.
panelCtrl
.
panel
;
this
.
dashboard
=
this
.
panelCtrl
.
dashboard
;
this
.
datasources
=
datasourceSrv
.
getMetricSources
();
var
dsValue
=
this
.
panelCtrl
.
panel
.
datasource
||
null
;
this
.
panelDsValue
=
this
.
panelCtrl
.
panel
.
datasource
||
null
;
for
(
let
ds
of
this
.
datasources
)
{
if
(
ds
.
value
===
d
sValue
)
{
if
(
ds
.
value
===
this
.
panelD
sValue
)
{
this
.
current
=
ds
;
}
}
if
(
!
this
.
current
)
{
this
.
current
=
{
name
:
dsValue
+
' not found'
,
value
:
null
};
}
this
.
dsSegment
=
uiSegmentSrv
.
newSegment
({
value
:
this
.
current
.
name
,
selectMode
:
true
});
this
.
mixedDsSegment
=
uiSegmentSrv
.
newSegment
({
value
:
'Add Query'
,
selectMode
:
true
,
fake
:
true
});
this
.
addQueryDropdown
=
{
text
:
'Add Query'
,
value
:
null
,
fake
:
true
};
// update next ref id
this
.
panelCtrl
.
nextRefId
=
this
.
dashboard
.
getNextQueryLetter
(
this
.
panel
);
...
...
@@ -46,33 +40,28 @@ export class MetricsTabCtrl {
getOptions
(
includeBuiltin
)
{
return
Promise
.
resolve
(
this
.
datasources
.
filter
(
value
=>
{
return
includeBuiltin
||
!
value
.
meta
.
builtIn
;
}).
map
(
value
=>
{
return
this
.
uiSegmentSrv
.
newSegment
(
value
.
name
)
;
}).
map
(
ds
=>
{
return
{
value
:
ds
.
value
,
text
:
ds
.
name
,
datasource
:
ds
}
;
}));
}
datasourceChanged
()
{
var
ds
=
_
.
find
(
this
.
datasources
,
{
name
:
this
.
dsSegment
.
value
});
if
(
ds
)
{
this
.
current
=
ds
;
this
.
panelCtrl
.
setDatasource
(
ds
);
datasourceChanged
(
option
)
{
if
(
!
option
)
{
return
;
}
}
mixedDatasourceChanged
()
{
var
target
:
any
=
{
isNew
:
true
}
;
var
ds
=
_
.
find
(
this
.
datasources
,
{
name
:
this
.
mixedDsSegment
.
value
});
this
.
current
=
option
.
datasource
;
this
.
panelCtrl
.
setDatasource
(
option
.
datasource
)
;
}
if
(
ds
)
{
target
.
datasource
=
ds
.
name
;
this
.
panelCtrl
.
addQuery
(
target
)
;
addMixedQuery
(
option
)
{
if
(
!
option
)
{
return
;
}
// metric segments are really bad, requires hacks to update
const
segment
=
this
.
uiSegmentSrv
.
newSegment
({
value
:
'Add Query'
,
selectMode
:
true
,
fake
:
true
});
this
.
mixedDsSegment
.
value
=
segment
.
value
;
this
.
mixedDsSegment
.
html
=
segment
.
html
;
this
.
mixedDsSegment
.
text
=
segment
.
text
;
var
target
:
any
=
{
isNew
:
true
};
this
.
panelCtrl
.
addQuery
({
isNew
:
true
,
datasource
:
option
.
datasource
.
name
});
this
.
addQueryDropdown
=
{
text
:
'Add Query'
,
value
:
null
,
fake
:
true
};
}
addQuery
()
{
...
...
public/app/features/panel/partials/metrics_tab.html
View file @
e9c8881d
...
...
@@ -19,7 +19,10 @@
</button>
<div
class=
"dropdown"
ng-if=
"ctrl.current.meta.mixed"
>
<metric-segment
segment=
"ctrl.mixedDsSegment"
get-options=
"ctrl.getOptions(false)"
on-change=
"ctrl.mixedDatasourceChanged()"
></metric-segment>
<gf-form-dropdown
model=
"ctrl.addQueryDropdown"
get-options=
"ctrl.getOptions(false)"
on-change=
"ctrl.addMixedQuery($option)"
>
</gf-form-dropdown>
</div>
</div>
</div>
...
...
@@ -30,10 +33,12 @@
<div
class=
"gf-form-group"
>
<div
class=
"gf-form-inline"
>
<div
class=
"gf-form"
>
<label
class=
"gf-form-label"
>
Panel Data Source
</label>
<metric-segment
segment=
"ctrl.dsSegment"
get-options=
"ctrl.getOptions(true)"
on-change=
"ctrl.datasourceChanged()"
></metric-segment>
<label
class=
"gf-form-label"
>
Panel Data Source
</label>
<gf-form-dropdown
model=
"ctrl.panelDsValue"
lookup-text=
"true"
get-options=
"ctrl.getOptions(true)"
on-change=
"ctrl.datasourceChanged($option)"
>
</gf-form-dropdown>
</div>
</div>
</div>
...
...
public/app/plugins/datasource/elasticsearch/bucket_agg.js
View file @
e9c8881d
...
...
@@ -26,13 +26,21 @@ function (angular, _, queryDef) {
var
bucketAggs
=
$scope
.
target
.
bucketAggs
;
$scope
.
orderByOptions
=
[];
$scope
.
bucketAggTypes
=
queryDef
.
bucketAggTypes
;
$scope
.
orderOptions
=
queryDef
.
orderOptions
;
$scope
.
sizeOptions
=
queryDef
.
sizeOptions
;
$scope
.
getBucketAggTypes
=
function
()
{
return
queryDef
.
bucketAggTypes
;
};
$scope
.
getOrderOptions
=
function
()
{
return
queryDef
.
orderOptions
;
};
$scope
.
getSizeOptions
=
function
()
{
return
queryDef
.
sizeOptions
;
};
$rootScope
.
onAppEvent
(
'elastic-query-updated'
,
function
()
{
$scope
.
validateModel
();
$scope
.
updateOrderByOptions
();
},
$scope
);
$scope
.
init
=
function
()
{
...
...
@@ -166,11 +174,10 @@ function (angular, _, queryDef) {
$scope
.
toggleOptions
=
function
()
{
$scope
.
showOptions
=
!
$scope
.
showOptions
;
$scope
.
updateOrderByOptions
();
};
$scope
.
update
OrderByOptions
=
function
()
{
$scope
.
orderByOptions
=
queryDef
.
getOrderByOptions
(
$scope
.
target
);
$scope
.
get
OrderByOptions
=
function
()
{
return
queryDef
.
getOrderByOptions
(
$scope
.
target
);
};
$scope
.
getFieldsInternal
=
function
()
{
...
...
public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html
View file @
e9c8881d
...
...
@@ -5,8 +5,22 @@
<span
ng-hide=
"isFirst"
>
Then by
</span>
</label>
<metric-segment-model
property=
"agg.type"
options=
"bucketAggTypes"
on-change=
"onTypeChanged()"
custom=
"false"
css-class=
"width-10"
></metric-segment-model>
<metric-segment-model
ng-if=
"agg.field"
property=
"agg.field"
get-options=
"getFieldsInternal()"
on-change=
"onChange()"
css-class=
"width-12"
></metric-segment-model>
<gf-form-dropdown
model=
"agg.type"
lookup-text=
"true"
get-options=
"getBucketAggTypes()"
on-change=
"onTypeChanged()"
allow-custom=
"false"
label-mode=
"true"
css-class=
"width-10"
>
</gf-form-dropdown>
<gf-form-dropdown
ng-if=
"agg.field"
model=
"agg.field"
get-options=
"getFieldsInternal()"
on-change=
"onChange()"
allow-custom=
"false"
label-mode=
"true"
css-class=
"width-12"
>
</gf-form-dropdown>
</div>
<div
class=
"gf-form gf-form--grow"
>
...
...
@@ -33,7 +47,13 @@
<div
ng-if=
"agg.type === 'date_histogram'"
>
<div
class=
"gf-form offset-width-7"
>
<label
class=
"gf-form-label width-10"
>
Interval
</label>
<metric-segment-model
property=
"agg.settings.interval"
get-options=
"getIntervalOptions()"
on-change=
"onChangeInternal()"
css-class=
"width-12"
custom=
"true"
></metric-segment-model>
<gf-form-dropdown
model=
"agg.settings.interval"
get-options=
"getIntervalOptions()"
on-change=
"onChangeInternal()"
allow-custom=
"true"
label-mode=
"true"
css-class=
"width-12"
>
</gf-form-dropdown>
</div>
<div
class=
"gf-form offset-width-7"
>
...
...
@@ -66,11 +86,23 @@
<div
ng-if=
"agg.type === 'terms'"
>
<div
class=
"gf-form offset-width-7"
>
<label
class=
"gf-form-label width-10"
>
Order
</label>
<metric-segment-model
property=
"agg.settings.order"
options=
"orderOptions"
on-change=
"onChangeInternal()"
css-class=
"width-12"
></metric-segment-model>
<gf-form-dropdown
model=
"agg.settings.order"
lookup-text=
"true"
get-options=
"getOrderOptions()"
on-change=
"onChangeInternal()"
label-mode=
"true"
css-class=
"width-12"
>
</gf-form-dropdown>
</div>
<div
class=
"gf-form offset-width-7"
>
<label
class=
"gf-form-label width-10"
>
Size
</label>
<metric-segment-model
property=
"agg.settings.size"
options=
"sizeOptions"
on-change=
"onChangeInternal()"
css-class=
"width-12"
></metric-segment-model>
<gf-form-dropdown
model=
"agg.settings.size"
lookup-text=
"true"
get-options=
"getSizeOptions()"
on-change=
"onChangeInternal()"
label-mode=
"true"
css-class=
"width-12"
>
</gf-form-dropdown>
</div>
<div
class=
"gf-form offset-width-7"
>
<label
class=
"gf-form-label width-10"
>
Min Doc Count
</label>
...
...
@@ -78,7 +110,13 @@
</div>
<div
class=
"gf-form offset-width-7"
>
<label
class=
"gf-form-label width-10"
>
Order By
</label>
<metric-segment-model
property=
"agg.settings.orderBy"
options=
"orderByOptions"
on-change=
"onChangeInternal()"
css-class=
"width-12"
></metric-segment-model>
<gf-form-dropdown
model=
"agg.settings.orderBy"
lookup-text=
"true"
get-options=
"getOrderByOptions()"
on-change=
"onChangeInternal()"
label-mode=
"true"
css-class=
"width-12"
>
</gf-form-dropdown>
</div>
<div
class=
"gf-form offset-width-7"
>
<label
class=
"gf-form-label width-10"
>
...
...
public/app/plugins/datasource/elasticsearch/query_ctrl.ts
View file @
e9c8881d
...
...
@@ -31,11 +31,11 @@ export class ElasticQueryCtrl extends QueryCtrl {
queryUpdated
()
{
var
newJson
=
angular
.
toJson
(
this
.
datasource
.
queryBuilder
.
build
(
this
.
target
),
true
);
if
(
newJson
!==
this
.
rawQueryOld
)
{
this
.
rawQueryOld
=
newJson
;
if
(
this
.
rawQueryOld
&&
newJson
!==
this
.
rawQueryOld
)
{
this
.
refresh
();
}
this
.
rawQueryOld
=
newJson
;
this
.
$rootScope
.
appEvent
(
'elastic-query-updated'
);
}
...
...
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