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
cfac1432
Unverified
Commit
cfac1432
authored
Jul 28, 2020
by
Torkel Ödegaard
Committed by
GitHub
Jul 28, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
TemplateSrv: Refactoring out all formats to a formatRegistry (#26607)
parent
0d933b79
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
236 additions
and
179 deletions
+236
-179
public/app/features/templating/formatRegistry.ts
+212
-0
public/app/features/templating/template_srv.test.ts
+0
-5
public/app/features/templating/template_srv.ts
+7
-149
public/app/plugins/datasource/grafana-azure-monitor-datasource/partials/query.editor.html
+16
-14
public/app/plugins/datasource/grafana-azure-monitor-datasource/query_ctrl.ts
+1
-11
No files found.
public/app/features/templating/formatRegistry.ts
0 → 100644
View file @
cfac1432
import
kbn
from
'app/core/utils/kbn'
;
import
{
Registry
,
RegistryItem
,
VariableModel
,
textUtil
,
dateTime
}
from
'@grafana/data'
;
import
{
map
,
isArray
,
replace
}
from
'lodash'
;
export
interface
FormatRegistryItem
extends
RegistryItem
{
formatter
(
value
:
any
,
args
:
string
[],
variable
:
VariableModel
):
string
;
}
export
const
formatRegistry
=
new
Registry
<
FormatRegistryItem
>
(()
=>
{
const
formats
:
FormatRegistryItem
[]
=
[
{
id
:
'lucene'
,
name
:
'Lucene'
,
description
:
'Values are lucene escaped and multi-valued variables generate an OR expression'
,
formatter
:
value
=>
{
if
(
typeof
value
===
'string'
)
{
return
luceneEscape
(
value
);
}
if
(
value
instanceof
Array
&&
value
.
length
===
0
)
{
return
'__empty__'
;
}
const
quotedValues
=
map
(
value
,
(
val
:
string
)
=>
{
return
'"'
+
luceneEscape
(
val
)
+
'"'
;
});
return
'('
+
quotedValues
.
join
(
' OR '
)
+
')'
;
},
},
{
id
:
'regex'
,
name
:
'Regex'
,
description
:
'Values are regex escaped and multi-valued variables generate a (<value>|<value>) expression'
,
formatter
:
value
=>
{
if
(
typeof
value
===
'string'
)
{
return
kbn
.
regexEscape
(
value
);
}
const
escapedValues
=
map
(
value
,
kbn
.
regexEscape
);
if
(
escapedValues
.
length
===
1
)
{
return
escapedValues
[
0
];
}
return
'('
+
escapedValues
.
join
(
'|'
)
+
')'
;
},
},
{
id
:
'pipe'
,
name
:
'Pipe'
,
description
:
'Values are seperated by | character'
,
formatter
:
value
=>
{
if
(
typeof
value
===
'string'
)
{
return
value
;
}
return
value
.
join
(
'|'
);
},
},
{
id
:
'distributed'
,
name
:
'Distributed'
,
description
:
'Multiple values are formatted like variable=value'
,
formatter
:
(
value
,
args
,
variable
)
=>
{
if
(
typeof
value
===
'string'
)
{
return
value
;
}
value
=
map
(
value
,
(
val
:
any
,
index
:
number
)
=>
{
if
(
index
!==
0
)
{
return
variable
.
name
+
'='
+
val
;
}
else
{
return
val
;
}
});
return
value
.
join
(
','
);
},
},
{
id
:
'csv'
,
name
:
'Csv'
,
description
:
'Comma seperated values'
,
formatter
:
(
value
,
args
,
variable
)
=>
{
if
(
isArray
(
value
))
{
return
value
.
join
(
','
);
}
return
value
;
},
},
{
id
:
'html'
,
name
:
'HTML'
,
description
:
'HTML escaping of values'
,
formatter
:
(
value
,
args
,
variable
)
=>
{
if
(
isArray
(
value
))
{
return
textUtil
.
escapeHtml
(
value
.
join
(
', '
));
}
return
textUtil
.
escapeHtml
(
value
);
},
},
{
id
:
'json'
,
name
:
'JSON'
,
description
:
'JSON stringify valu'
,
formatter
:
(
value
,
args
,
variable
)
=>
{
return
JSON
.
stringify
(
value
);
},
},
{
id
:
'percentencode'
,
name
:
'Percent encode'
,
description
:
'Useful for url escaping values'
,
formatter
:
(
value
,
args
,
variable
)
=>
{
// like glob, but url escaped
if
(
isArray
(
value
))
{
return
encodeURIComponentStrict
(
'{'
+
value
.
join
(
','
)
+
'}'
);
}
return
encodeURIComponentStrict
(
value
);
},
},
{
id
:
'singlequote'
,
name
:
'Single quote'
,
description
:
'Single quoted values'
,
formatter
:
(
value
,
args
,
variable
)
=>
{
// escape single quotes with backslash
const
regExp
=
new
RegExp
(
`'`
,
'g'
);
if
(
isArray
(
value
))
{
return
map
(
value
,
(
v
:
string
)
=>
`'
${
replace
(
v
,
regExp
,
`\\'`
)}
'`
).
join
(
','
);
}
return
`'
${
replace
(
value
,
regExp
,
`\\'`
)}
'`
;
},
},
{
id
:
'doublequote'
,
name
:
'Double quote'
,
description
:
'Double quoted values'
,
formatter
:
(
value
,
args
,
variable
)
=>
{
// escape double quotes with backslash
const
regExp
=
new
RegExp
(
'"'
,
'g'
);
if
(
isArray
(
value
))
{
return
map
(
value
,
(
v
:
string
)
=>
`"
${
replace
(
v
,
regExp
,
'
\\
"'
)}
"`
).
join
(
','
);
}
return
`"
${
replace
(
value
,
regExp
,
'
\\
"'
)}
"`
;
},
},
{
id
:
'sqlstring'
,
name
:
'SQL string'
,
description
:
'SQL string quoting and commas for use in IN statements and other scenarios'
,
formatter
:
(
value
,
args
,
variable
)
=>
{
// escape single quotes by pairing them
const
regExp
=
new
RegExp
(
`'`
,
'g'
);
if
(
isArray
(
value
))
{
return
map
(
value
,
v
=>
`'
${
replace
(
v
,
regExp
,
"''"
)}
'`
).
join
(
','
);
}
return
`'
${
replace
(
value
,
regExp
,
"''"
)}
'`
;
},
},
{
id
:
'date'
,
name
:
'Date'
,
description
:
'Format date in different ways'
,
formatter
:
(
value
,
args
,
variable
)
=>
{
const
arg
=
args
[
0
]
??
'iso'
;
switch
(
arg
)
{
case
'ms'
:
return
value
;
case
'seconds'
:
return
`
${
Math
.
round
(
parseInt
(
value
,
10
)
!
/ 1000
)
}`
;
case
'iso'
:
return
dateTime
(
parseInt
(
value
,
10
)).
toISOString
();
default
:
return
dateTime
(
parseInt
(
value
,
10
)).
format
(
arg
);
}
},
}
,
{
id: 'glob',
name: 'Glob',
description: 'Format multi valued variables using glob syntax, example {value1,value2}',
formatter: (value, args, variable) => {
if (isArray(value) && value.length > 1) {
return '{' + value.join(',') + '}';
}
return value;
},
},
];
return formats;
});
function luceneEscape(value: string) {
return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, '\\$1');
}
/**
* encode string according to RFC 3986; in contrast to encodeURIComponent()
* also the sub-delims "!", "'", "(", ")" and "*" are encoded;
* unicode handling uses UTF-8 as in ECMA-262.
*/
function encodeURIComponentStrict(str: string) {
return encodeURIComponent(str).replace(/[!'()*]/g, c => {
return (
'%' +
c
.charCodeAt(0)
.toString(16)
.toUpperCase()
);
});
}
public/app/features/templating/template_srv.test.ts
View file @
cfac1432
...
...
@@ -595,11 +595,6 @@ describe('templateSrv', () => {
initTemplateSrv
([]);
});
it
(
'should be possible to fetch value with getBuilInIntervalValue'
,
()
=>
{
const
val
=
_templateSrv
.
getBuiltInIntervalValue
();
expect
(
val
).
toBe
(
'1s'
);
});
it
(
'should replace $__interval_ms with interval milliseconds'
,
()
=>
{
const
target
=
_templateSrv
.
replace
(
'10 * $__interval_ms'
,
{
__interval_ms
:
{
text
:
'100'
,
value
:
'100'
},
...
...
public/app/features/templating/template_srv.ts
View file @
cfac1432
import
kbn
from
'app/core/utils/kbn'
;
import
_
from
'lodash'
;
import
{
deprecationWarning
,
ScopedVars
,
textUtil
,
TimeRange
,
dateTim
e
}
from
'@grafana/data'
;
import
{
deprecationWarning
,
ScopedVars
,
TimeRang
e
}
from
'@grafana/data'
;
import
{
getFilteredVariables
,
getVariables
,
getVariableWithName
}
from
'../variables/state/selectors'
;
import
{
variableRegex
}
from
'../variables/utils'
;
import
{
isAdHoc
}
from
'../variables/guard'
;
import
{
VariableModel
}
from
'../variables/types'
;
import
{
setTemplateSrv
,
TemplateSrv
as
BaseTemplateSrv
}
from
'@grafana/runtime'
;
import
{
variableAdapters
}
from
'../variables/adapters'
;
function
luceneEscape
(
value
:
string
)
{
return
value
.
replace
(
/
([\!\*\+\-\=
<>
\s\&\|\(\)\[\]\{\}\^\~\?\:\\/
"
])
/g
,
'
\\
$1'
);
}
import
{
formatRegistry
}
from
'./formatRegistry'
;
interface
FieldAccessorCache
{
[
key
:
string
]:
(
obj
:
any
)
=>
any
;
...
...
@@ -33,13 +29,10 @@ export class TemplateSrv implements BaseTemplateSrv {
private
regex
=
variableRegex
;
private
index
:
any
=
{};
private
grafanaVariables
:
any
=
{};
private
builtIns
:
any
=
{};
private
timeRange
?:
TimeRange
|
null
=
null
;
private
fieldAccessorCache
:
FieldAccessorCache
=
{};
constructor
(
private
dependencies
:
TemplateSrvDependencies
=
runtimeDependencies
)
{
this
.
builtIns
[
'__interval'
]
=
{
text
:
'1s'
,
value
:
'1s'
};
this
.
builtIns
[
'__interval_ms'
]
=
{
text
:
'100'
,
value
:
'100'
};
this
.
_variables
=
[];
}
...
...
@@ -49,10 +42,6 @@ export class TemplateSrv implements BaseTemplateSrv {
this
.
updateIndex
();
}
getBuiltInIntervalValue
()
{
return
this
.
builtIns
.
__interval
.
value
;
}
/**
* @deprecated: this instance variable should not be used and will be removed in future releases
*
...
...
@@ -118,34 +107,6 @@ export class TemplateSrv implements BaseTemplateSrv {
return
filters
;
}
luceneFormat
(
value
:
any
)
{
if
(
typeof
value
===
'string'
)
{
return
luceneEscape
(
value
);
}
if
(
value
instanceof
Array
&&
value
.
length
===
0
)
{
return
'__empty__'
;
}
const
quotedValues
=
_
.
map
(
value
,
val
=>
{
return
'"'
+
luceneEscape
(
val
)
+
'"'
;
});
return
'('
+
quotedValues
.
join
(
' OR '
)
+
')'
;
}
// encode string according to RFC 3986; in contrast to encodeURIComponent()
// also the sub-delims "!", "'", "(", ")" and "*" are encoded;
// unicode handling uses UTF-8 as in ECMA-262.
encodeURIComponentStrict
(
str
:
string
)
{
return
encodeURIComponent
(
str
).
replace
(
/
[
!'()*
]
/g
,
c
=>
{
return
(
'%'
+
c
.
charCodeAt
(
0
)
.
toString
(
16
)
.
toUpperCase
()
);
});
}
formatValue
(
value
:
any
,
format
:
any
,
variable
:
any
)
{
// for some scopedVars there is no variable
variable
=
variable
||
{};
...
...
@@ -167,104 +128,12 @@ export class TemplateSrv implements BaseTemplateSrv {
args
=
[];
}
switch
(
format
)
{
case
'regex'
:
{
if
(
typeof
value
===
'string'
)
{
return
kbn
.
regexEscape
(
value
);
const
formatItem
=
formatRegistry
.
getIfExists
(
format
);
if
(
!
formatItem
)
{
throw
new
Error
(
`Variable format
${
format
}
not found`
);
}
const
escapedValues
=
_
.
map
(
value
,
kbn
.
regexEscape
);
if
(
escapedValues
.
length
===
1
)
{
return
escapedValues
[
0
];
}
return
'('
+
escapedValues
.
join
(
'|'
)
+
')'
;
}
case
'lucene'
:
{
return
this
.
luceneFormat
(
value
);
}
case
'pipe'
:
{
if
(
typeof
value
===
'string'
)
{
return
value
;
}
return
value
.
join
(
'|'
);
}
case
'distributed'
:
{
if
(
typeof
value
===
'string'
)
{
return
value
;
}
return
this
.
distributeVariable
(
value
,
variable
.
name
);
}
case
'csv'
:
{
if
(
_
.
isArray
(
value
))
{
return
value
.
join
(
','
);
}
return
value
;
}
case
'html'
:
{
if
(
_
.
isArray
(
value
))
{
return
textUtil
.
escapeHtml
(
value
.
join
(
', '
));
}
return
textUtil
.
escapeHtml
(
value
);
}
case
'json'
:
{
return
JSON
.
stringify
(
value
);
}
case
'percentencode'
:
{
// like glob, but url escaped
if
(
_
.
isArray
(
value
))
{
return
this
.
encodeURIComponentStrict
(
'{'
+
value
.
join
(
','
)
+
'}'
);
}
return
this
.
encodeURIComponentStrict
(
value
);
}
case
'singlequote'
:
{
// escape single quotes with backslash
const
regExp
=
new
RegExp
(
`'`
,
'g'
);
if
(
_
.
isArray
(
value
))
{
return
_
.
map
(
value
,
v
=>
`'
${
_
.
replace
(
v
,
regExp
,
`\\'`
)}
'`
).
join
(
','
);
}
return
`'
${
_
.
replace
(
value
,
regExp
,
`\\'`
)}
'`
;
}
case
'doublequote'
:
{
// escape double quotes with backslash
const
regExp
=
new
RegExp
(
'"'
,
'g'
);
if
(
_
.
isArray
(
value
))
{
return
_
.
map
(
value
,
v
=>
`"
${
_
.
replace
(
v
,
regExp
,
'
\\
"'
)}
"`
).
join
(
','
);
}
return
`"
${
_
.
replace
(
value
,
regExp
,
'
\\
"'
)}
"`
;
}
case
'sqlstring'
:
{
// escape single quotes by pairing them
const
regExp
=
new
RegExp
(
`'`
,
'g'
);
if
(
_
.
isArray
(
value
))
{
return
_
.
map
(
value
,
v
=>
`'
${
_
.
replace
(
v
,
regExp
,
"''"
)}
'`
).
join
(
','
);
}
return
`'
${
_
.
replace
(
value
,
regExp
,
"''"
)}
'`
;
}
case
'date'
:
{
return
this
.
formatDate
(
value
,
args
);
}
case
'glob'
:
{
if
(
_
.
isArray
(
value
)
&&
value
.
length
>
1
)
{
return
'{'
+
value
.
join
(
','
)
+
'}'
;
}
return
value
;
}
}
}
formatDate
(
value
:
any
,
args
:
string
[]):
string
{
const
arg
=
args
[
0
]
??
'iso'
;
switch
(
arg
)
{
case
'ms'
:
return
value
;
case
'seconds'
:
return
`
${
Math
.
round
(
parseInt
(
value
,
10
)
!
/ 1000
)
}`
;
case
'iso'
:
return
dateTime
(
parseInt
(
value
,
10
)).
toISOString
();
default
:
return
dateTime
(
parseInt
(
value
,
10
)).
format
(
arg
);
}
return
formatItem
.
formatter
(
value
,
args
,
variable
);
}
setGrafanaVariable
(
name
:
string
,
value
:
any
)
{
...
...
@@ -310,7 +179,7 @@ export class TemplateSrv implements BaseTemplateSrv {
str
=
_
.
escape
(
str
);
this
.
regex
.
lastIndex
=
0
;
return
str
.
replace
(
this
.
regex
,
(
match
,
var1
,
var2
,
fmt2
,
var3
)
=>
{
if
(
this
.
getVariableAtIndex
(
var1
||
var2
||
var3
)
||
this
.
builtIns
[
var1
||
var2
||
var3
]
)
{
if
(
this
.
getVariableAtIndex
(
var1
||
var2
||
var3
))
{
return
'<span class="template-variable">'
+
match
+
'</span>'
;
}
return
match
;
...
...
@@ -448,17 +317,6 @@ export class TemplateSrv implements BaseTemplateSrv {
});
};
distributeVariable
(
value
:
any
,
variable
:
any
)
{
value
=
_
.
map
(
value
,
(
val
:
any
,
index
:
number
)
=>
{
if
(
index
!==
0
)
{
return
variable
+
'='
+
val
;
}
else
{
return
val
;
}
});
return
value
.
join
(
','
);
}
private
getVariableAtIndex
(
name
:
string
)
{
if
(
!
name
)
{
return
;
...
...
public/app/plugins/datasource/grafana-azure-monitor-datasource/partials/query.editor.html
View file @
cfac1432
<query-editor-row
query-ctrl=
"ctrl"
can-collapse=
"false"
>
<query-editor-row
query-ctrl=
"ctrl"
can-collapse=
"false"
>
<div
class=
"gf-form-inline"
>
<div
class=
"gf-form"
>
<label
class=
"gf-form-label query-keyword width-9"
>
Service
</label>
...
...
@@ -143,7 +140,9 @@
<label
class=
"gf-form-label query-keyword width-9"
>
Dimension
</label>
</div>
<div
class=
"gf-form"
>
<a
ng-click=
"ctrl.azureMonitorAddDimensionFilter()"
class=
"gf-form-label query-part"
><icon
name=
"'plus'"
></icon></a>
<a
ng-click=
"ctrl.azureMonitorAddDimensionFilter()"
class=
"gf-form-label query-part"
><icon
name=
"'plus'"
></icon
></a>
</div>
<div
class=
"gf-form gf-form--grow"
>
<div
class=
"gf-form-label gf-form-label--grow"
></div>
...
...
@@ -175,10 +174,14 @@
/>
</div>
<div
class=
"gf-form"
>
<a
ng-click=
"ctrl.azureMonitorRemoveDimensionFilter($index)"
class=
"gf-form-label query-part"
><icon
name=
"'minus'"
></icon></a>
<a
ng-click=
"ctrl.azureMonitorRemoveDimensionFilter($index)"
class=
"gf-form-label query-part"
><icon
name=
"'minus'"
></icon
></a>
</div>
<div
class=
"gf-form"
ng-if=
"$last"
>
<a
ng-click=
"ctrl.azureMonitorAddDimensionFilter()"
class=
"gf-form-label query-part"
><icon
name=
"'plus'"
></icon></a>
<a
ng-click=
"ctrl.azureMonitorAddDimensionFilter()"
class=
"gf-form-label query-part"
><icon
name=
"'plus'"
></icon
></a>
</div>
<div
class=
"gf-form gf-form--grow"
>
<div
class=
"gf-form-label gf-form-label--grow"
></div>
...
...
@@ -360,7 +363,6 @@
<div
class=
"gf-form-label gf-form-label--grow"
></div>
</div>
</div>
</div>
<div
ng-if=
"ctrl.target.queryType === 'Application Insights'"
>
...
...
@@ -396,13 +398,14 @@
<div
class=
"gf-form"
>
<label
class=
"gf-form-label query-keyword width-9"
>
Group By
</label>
</div>
<div
ng-repeat=
"d in ctrl.target.appInsights.dimension track by $index"
<div
ng-repeat=
"d in ctrl.target.appInsights.dimension track by $index"
class=
"gf-form"
ng-click=
"ctrl.removeGroupBy($index);"
onmouseover=
"this.style['text-decoration'] = 'line-through';"
onmouseout=
"this.style['text-decoration'] = '';"
>
<label
class=
"gf-form-label"
style=
"cursor: pointer;"
>
{{d}}
<icon
name=
"'times'"
></icon></label>
onmouseout=
"this.style['text-decoration'] = '';"
>
<label
class=
"gf-form-label"
style=
"cursor: pointer;"
>
{{d}}
<icon
name=
"'times'"
></icon></label>
</div>
<div>
<gf-form-dropdown
...
...
@@ -472,8 +475,7 @@
</div>
</div>
<div
class=
"gf-form"
ng-hide=
"ctrl.target.appInsights.timeGrainType !== 'auto'"
>
<label
class=
"gf-form-label"
>
Auto Interval
</label>
<label
class=
"gf-form-label"
>
{{ctrl.getAppInsightsAutoInterval()}}
</label>
<label
class=
"gf-form-label"
>
Auto Interval (see query options)
</label>
</div>
<div
class=
"gf-form gf-form--grow"
>
<div
class=
"gf-form-label gf-form-label--grow"
></div>
...
...
public/app/plugins/datasource/grafana-azure-monitor-datasource/query_ctrl.ts
View file @
cfac1432
...
...
@@ -499,7 +499,7 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
generateAutoUnits
(
timeGrain
:
string
,
timeGrains
:
Array
<
{
value
:
string
}
>
)
{
if
(
timeGrain
===
'auto'
)
{
return
TimegrainConverter
.
findClosestTimeGrain
(
this
.
templateSrv
.
getBuiltInIntervalValue
()
,
'1m'
,
_
.
map
(
timeGrains
,
o
=>
TimegrainConverter
.
createKbnUnitFromISO8601Duration
(
o
.
value
))
||
[
'1m'
,
'5m'
,
...
...
@@ -580,16 +580,6 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
return
this
.
templateSrv
.
getVariables
().
map
(
t
=>
'$'
+
t
.
name
);
}
/* Application Insights Section */
getAppInsightsAutoInterval
()
{
const
interval
=
this
.
templateSrv
.
getBuiltInIntervalValue
();
if
(
interval
[
interval
.
length
-
1
]
===
's'
)
{
return
'1m'
;
}
return
interval
;
}
getAppInsightsMetricNames
()
{
if
(
!
this
.
datasource
.
appInsightsDatasource
.
isConfigured
())
{
return
;
...
...
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