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
dc6d025d
Commit
dc6d025d
authored
Sep 14, 2018
by
Daniel Lee
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
stackdriver: add filters to query editor
WIP -> Backend not implemented yet.
parent
9b4a25ed
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
292 additions
and
28 deletions
+292
-28
public/app/plugins/datasource/stackdriver/datasource.ts
+1
-0
public/app/plugins/datasource/stackdriver/query_ctrl.ts
+72
-19
public/app/plugins/datasource/stackdriver/specs/query_ctrl.test.ts
+219
-9
No files found.
public/app/plugins/datasource/stackdriver/datasource.ts
View file @
dc6d025d
...
...
@@ -19,6 +19,7 @@ export default class StackdriverDatasource {
primaryAggregation
:
t
.
aggregation
.
crossSeriesReducer
,
groupBys
:
t
.
aggregation
.
groupBys
,
view
:
t
.
view
||
'FULL'
,
filters
:
t
.
filters
,
}));
const
{
data
}
=
await
this
.
backendSrv
.
datasourceRequest
({
...
...
public/app/plugins/datasource/stackdriver/query_ctrl.ts
View file @
dc6d025d
...
...
@@ -9,11 +9,6 @@ export interface QueryMeta {
resourceLabels
:
{
[
key
:
string
]:
string
[]
};
}
export
interface
Filter
{
key
:
string
;
operator
:
string
;
value
:
string
;
}
export
class
StackdriverQueryCtrl
extends
QueryCtrl
{
static
templateUrl
=
'partials/query.editor.html'
;
target
:
{
...
...
@@ -29,9 +24,12 @@ export class StackdriverQueryCtrl extends QueryCtrl {
perSeriesAligner
:
string
;
groupBys
:
string
[];
};
filters
:
Filter
[];
filters
:
string
[];
};
defaultDropdownValue
=
'Select metric'
;
defaultDropdownValue
=
'select metric'
;
defaultFilterValue
=
'select value'
;
defaultRemoveGroupByValue
=
'-- remove group by --'
;
defaultRemoveFilterValue
=
'-- remove filter --'
;
defaults
=
{
project
:
{
...
...
@@ -96,10 +94,21 @@ export class StackdriverQueryCtrl extends QueryCtrl {
this
.
ensurePlusButton
(
this
.
groupBySegments
);
this
.
filterSegments
=
[];
this
.
target
.
filters
.
forEach
(
f
=>
{
this
.
filterSegments
.
push
(
this
.
uiSegmentSrv
.
newKey
(
f
.
key
));
this
.
filterSegments
.
push
(
this
.
uiSegmentSrv
.
newOperator
(
f
.
operator
));
this
.
filterSegments
.
push
(
this
.
uiSegmentSrv
.
newKeyValue
(
f
.
value
));
this
.
target
.
filters
.
forEach
((
f
,
index
)
=>
{
switch
(
index
%
4
)
{
case
0
:
this
.
filterSegments
.
push
(
this
.
uiSegmentSrv
.
newKey
(
f
));
break
;
case
1
:
this
.
filterSegments
.
push
(
this
.
uiSegmentSrv
.
newOperator
(
f
));
break
;
case
2
:
this
.
filterSegments
.
push
(
this
.
uiSegmentSrv
.
newKeyValue
(
f
));
break
;
case
3
:
this
.
filterSegments
.
push
(
this
.
uiSegmentSrv
.
newCondition
(
f
));
break
;
}
});
this
.
ensurePlusButton
(
this
.
filterSegments
);
}
...
...
@@ -169,9 +178,12 @@ export class StackdriverQueryCtrl extends QueryCtrl {
this
.
getLabels
();
}
getGroupBys
(
segment
,
index
,
removeText
?:
string
)
{
getGroupBys
(
segment
,
index
,
removeText
?:
string
,
removeUsed
=
true
)
{
const
metricLabels
=
Object
.
keys
(
this
.
metricLabels
)
.
filter
(
ml
=>
{
if
(
!
removeUsed
)
{
return
true
;
}
return
this
.
target
.
aggregation
.
groupBys
.
indexOf
(
'metric.label.'
+
ml
)
===
-
1
;
})
.
map
(
l
=>
{
...
...
@@ -183,6 +195,10 @@ export class StackdriverQueryCtrl extends QueryCtrl {
const
resourceLabels
=
Object
.
keys
(
this
.
resourceLabels
)
.
filter
(
ml
=>
{
if
(
!
removeUsed
)
{
return
true
;
}
return
this
.
target
.
aggregation
.
groupBys
.
indexOf
(
'resource.label.'
+
ml
)
===
-
1
;
})
.
map
(
l
=>
{
...
...
@@ -192,7 +208,7 @@ export class StackdriverQueryCtrl extends QueryCtrl {
});
});
this
.
removeSegment
.
value
=
removeText
||
'-- remove group by --'
;
this
.
removeSegment
.
value
=
removeText
||
this
.
defaultRemoveGroupByValue
;
return
Promise
.
resolve
([...
metricLabels
,
...
resourceLabels
,
this
.
removeSegment
]);
}
...
...
@@ -215,7 +231,7 @@ export class StackdriverQueryCtrl extends QueryCtrl {
this
.
refresh
();
}
getFilters
(
segment
,
index
)
{
async
getFilters
(
segment
,
index
)
{
if
(
segment
.
type
===
'condition'
)
{
return
[
this
.
uiSegmentSrv
.
newSegment
(
'AND'
)];
}
...
...
@@ -225,18 +241,19 @@ export class StackdriverQueryCtrl extends QueryCtrl {
}
if
(
segment
.
type
===
'key'
||
segment
.
type
===
'plus-button'
)
{
return
this
.
getGroupBys
(
null
,
null
,
'-- remove filter --'
);
return
this
.
getGroupBys
(
null
,
null
,
this
.
defaultRemoveFilterValue
,
false
);
}
if
(
segment
.
type
===
'value'
)
{
const
filterKey
=
this
.
filterSegments
[
index
-
2
].
value
;
const
shortKey
=
filterKey
.
substring
(
filterKey
.
indexOf
(
'.label.'
)
+
7
);
if
(
this
.
metricLabels
[
filterKey
]
)
{
return
this
.
getValuesForFilterKey
(
this
.
metricLabels
[
filter
Key
]);
if
(
filterKey
.
startsWith
(
'metric.label.'
)
&&
this
.
metricLabels
.
hasOwnProperty
(
shortKey
)
)
{
return
this
.
getValuesForFilterKey
(
this
.
metricLabels
[
short
Key
]);
}
if
(
this
.
resourceLabels
[
filterKey
]
)
{
return
this
.
getValuesForFilterKey
(
this
.
resourceLabels
[
filter
Key
]);
if
(
filterKey
.
startsWith
(
'resource.label.'
)
&&
this
.
resourceLabels
.
hasOwnProperty
(
shortKey
)
)
{
return
this
.
getValuesForFilterKey
(
this
.
resourceLabels
[
short
Key
]);
}
}
...
...
@@ -254,6 +271,42 @@ export class StackdriverQueryCtrl extends QueryCtrl {
return
filterValues
;
}
filterSegmentUpdated
(
segment
,
index
)
{
if
(
segment
.
type
===
'plus-button'
)
{
this
.
addNewFilterSegments
(
segment
,
index
);
}
else
if
(
segment
.
type
===
'key'
&&
segment
.
value
===
this
.
defaultRemoveFilterValue
)
{
this
.
removeFilterSegment
(
index
);
this
.
ensurePlusButton
(
this
.
filterSegments
);
}
else
if
(
segment
.
type
===
'value'
&&
segment
.
value
!==
this
.
defaultFilterValue
)
{
this
.
ensurePlusButton
(
this
.
filterSegments
);
}
this
.
target
.
filters
=
this
.
filterSegments
.
filter
(
s
=>
s
.
type
!==
'plus-button'
).
map
(
seg
=>
seg
.
value
);
this
.
refresh
();
}
addNewFilterSegments
(
segment
,
index
)
{
if
(
index
>
2
)
{
this
.
filterSegments
.
splice
(
index
,
0
,
this
.
uiSegmentSrv
.
newCondition
(
'AND'
));
}
segment
.
type
=
'key'
;
this
.
filterSegments
.
push
(
this
.
uiSegmentSrv
.
newOperator
(
'='
));
this
.
filterSegments
.
push
(
this
.
uiSegmentSrv
.
newFake
(
this
.
defaultFilterValue
,
'value'
,
'query-segment-value'
));
}
removeFilterSegment
(
index
)
{
this
.
filterSegments
.
splice
(
index
,
3
);
// remove trailing condition
if
(
index
>
2
&&
this
.
filterSegments
[
index
-
1
].
type
===
'condition'
)
{
this
.
filterSegments
.
splice
(
index
-
1
,
1
);
}
// remove condition if it is first segment
if
(
index
===
0
&&
this
.
filterSegments
[
0
].
type
===
'condition'
)
{
this
.
filterSegments
.
splice
(
0
,
1
);
}
}
ensurePlusButton
(
segments
)
{
const
count
=
segments
.
length
;
const
lastSegment
=
segments
[
Math
.
max
(
count
-
1
,
0
)];
...
...
public/app/plugins/datasource/stackdriver/specs/query_ctrl.test.ts
View file @
dc6d025d
...
...
@@ -4,11 +4,30 @@ describe('StackdriverQueryCtrl', () => {
let
ctrl
;
let
result
;
beforeEach
(()
=>
{
ctrl
=
createCtrlWithFakes
();
describe
(
'when initializing query editor'
,
()
=>
{
beforeEach
(()
=>
{
const
existingFilters
=
[
'key1'
,
'='
,
'val1'
,
'AND'
,
'key2'
,
'='
,
'val2'
];
ctrl
=
createCtrlWithFakes
(
existingFilters
);
});
it
(
'should initialize filter segments using the target filter values'
,
()
=>
{
expect
(
ctrl
.
filterSegments
.
length
).
toBe
(
8
);
expect
(
ctrl
.
filterSegments
[
0
].
type
).
toBe
(
'key'
);
expect
(
ctrl
.
filterSegments
[
1
].
type
).
toBe
(
'operator'
);
expect
(
ctrl
.
filterSegments
[
2
].
type
).
toBe
(
'value'
);
expect
(
ctrl
.
filterSegments
[
3
].
type
).
toBe
(
'condition'
);
expect
(
ctrl
.
filterSegments
[
4
].
type
).
toBe
(
'key'
);
expect
(
ctrl
.
filterSegments
[
5
].
type
).
toBe
(
'operator'
);
expect
(
ctrl
.
filterSegments
[
6
].
type
).
toBe
(
'value'
);
expect
(
ctrl
.
filterSegments
[
7
].
type
).
toBe
(
'plus-button'
);
});
});
describe
(
'group bys'
,
()
=>
{
beforeEach
(()
=>
{
ctrl
=
createCtrlWithFakes
();
});
describe
(
'when labels are fetched'
,
()
=>
{
beforeEach
(
async
()
=>
{
ctrl
.
metricLabels
=
{
'metric-key-1'
:
[
'metric-value-1'
]
};
...
...
@@ -76,6 +95,10 @@ describe('StackdriverQueryCtrl', () => {
});
describe
(
'filters'
,
()
=>
{
beforeEach
(()
=>
{
ctrl
=
createCtrlWithFakes
();
});
describe
(
'when values for a condition filter part are fetched'
,
()
=>
{
beforeEach
(
async
()
=>
{
const
segment
=
{
type
:
'condition'
};
...
...
@@ -139,7 +162,7 @@ describe('StackdriverQueryCtrl', () => {
'resource-key-2'
:
[
'resource-value-2'
],
};
ctrl
.
filterSegments
=
[{
type
:
'key'
,
value
:
'metric-key-1'
},
{
type
:
'operator'
,
value
:
'='
}];
ctrl
.
filterSegments
=
[{
type
:
'key'
,
value
:
'metric
.label.metric
-key-1'
},
{
type
:
'operator'
,
value
:
'='
}];
const
segment
=
{
type
:
'value'
};
result
=
await
ctrl
.
getFilters
(
segment
,
2
);
...
...
@@ -150,16 +173,186 @@ describe('StackdriverQueryCtrl', () => {
expect
(
result
[
0
].
value
).
toBe
(
'metric-value-1'
);
});
});
describe
(
'when a filter is created by clicking on plus button'
,
()
=>
{
describe
(
'and there are no other filters'
,
()
=>
{
beforeEach
(()
=>
{
const
segment
=
{
value
:
'filterkey1'
,
type
:
'plus-button'
};
ctrl
.
filterSegments
=
[
segment
];
ctrl
.
filterSegmentUpdated
(
segment
,
0
);
});
it
(
'should transform the plus button segment to a key segment'
,
()
=>
{
expect
(
ctrl
.
filterSegments
[
0
].
type
).
toBe
(
'key'
);
});
it
(
'should add an operator, value segment and plus button segment'
,
()
=>
{
expect
(
ctrl
.
filterSegments
.
length
).
toBe
(
3
);
expect
(
ctrl
.
filterSegments
[
1
].
type
).
toBe
(
'operator'
);
expect
(
ctrl
.
filterSegments
[
2
].
type
).
toBe
(
'value'
);
});
});
});
describe
(
'when has one existing filter'
,
()
=>
{
describe
(
'and user clicks on key segment'
,
()
=>
{
beforeEach
(()
=>
{
const
existingKeySegment
=
{
value
:
'filterkey1'
,
type
:
'key'
};
const
existingOperatorSegment
=
{
value
:
'='
,
type
:
'operator'
};
const
existingValueSegment
=
{
value
:
'filtervalue'
,
type
:
'value'
};
const
plusSegment
=
{
value
:
''
,
type
:
'plus-button'
};
ctrl
.
filterSegments
=
[
existingKeySegment
,
existingOperatorSegment
,
existingValueSegment
,
plusSegment
];
ctrl
.
filterSegmentUpdated
(
existingKeySegment
,
0
);
});
it
(
'should not add any new segments'
,
()
=>
{
expect
(
ctrl
.
filterSegments
.
length
).
toBe
(
4
);
expect
(
ctrl
.
filterSegments
[
0
].
type
).
toBe
(
'key'
);
expect
(
ctrl
.
filterSegments
[
1
].
type
).
toBe
(
'operator'
);
expect
(
ctrl
.
filterSegments
[
2
].
type
).
toBe
(
'value'
);
});
});
describe
(
'and user clicks on value segment and value not equal to fake value'
,
()
=>
{
beforeEach
(()
=>
{
const
existingKeySegment
=
{
value
:
'filterkey1'
,
type
:
'key'
};
const
existingOperatorSegment
=
{
value
:
'='
,
type
:
'operator'
};
const
existingValueSegment
=
{
value
:
'filtervalue'
,
type
:
'value'
};
ctrl
.
filterSegments
=
[
existingKeySegment
,
existingOperatorSegment
,
existingValueSegment
];
ctrl
.
filterSegmentUpdated
(
existingValueSegment
,
2
);
});
it
(
'should ensure that plus segment exists'
,
()
=>
{
expect
(
ctrl
.
filterSegments
.
length
).
toBe
(
4
);
expect
(
ctrl
.
filterSegments
[
0
].
type
).
toBe
(
'key'
);
expect
(
ctrl
.
filterSegments
[
1
].
type
).
toBe
(
'operator'
);
expect
(
ctrl
.
filterSegments
[
2
].
type
).
toBe
(
'value'
);
expect
(
ctrl
.
filterSegments
[
3
].
type
).
toBe
(
'plus-button'
);
});
});
describe
(
'and user clicks on value segment and value is equal to fake value'
,
()
=>
{
beforeEach
(()
=>
{
const
existingKeySegment
=
{
value
:
'filterkey1'
,
type
:
'key'
};
const
existingOperatorSegment
=
{
value
:
'='
,
type
:
'operator'
};
const
existingValueSegment
=
{
value
:
ctrl
.
defaultFilterValue
,
type
:
'value'
};
ctrl
.
filterSegments
=
[
existingKeySegment
,
existingOperatorSegment
,
existingValueSegment
];
ctrl
.
filterSegmentUpdated
(
existingValueSegment
,
2
);
});
it
(
'should not add plus segment'
,
()
=>
{
expect
(
ctrl
.
filterSegments
.
length
).
toBe
(
3
);
expect
(
ctrl
.
filterSegments
[
0
].
type
).
toBe
(
'key'
);
expect
(
ctrl
.
filterSegments
[
1
].
type
).
toBe
(
'operator'
);
expect
(
ctrl
.
filterSegments
[
2
].
type
).
toBe
(
'value'
);
});
});
describe
(
'and user removes key segment'
,
()
=>
{
beforeEach
(()
=>
{
const
existingKeySegment
=
{
value
:
ctrl
.
defaultRemoveFilterValue
,
type
:
'key'
};
const
existingOperatorSegment
=
{
value
:
'='
,
type
:
'operator'
};
const
existingValueSegment
=
{
value
:
'filtervalue'
,
type
:
'value'
};
const
plusSegment
=
{
value
:
''
,
type
:
'plus-button'
};
ctrl
.
filterSegments
=
[
existingKeySegment
,
existingOperatorSegment
,
existingValueSegment
,
plusSegment
];
ctrl
.
filterSegmentUpdated
(
existingKeySegment
,
0
);
});
it
(
'should remove filter segments'
,
()
=>
{
expect
(
ctrl
.
filterSegments
.
length
).
toBe
(
1
);
expect
(
ctrl
.
filterSegments
[
0
].
type
).
toBe
(
'plus-button'
);
});
});
describe
(
'and user removes key segment and there is a previous filter'
,
()
=>
{
beforeEach
(()
=>
{
const
existingKeySegment1
=
{
value
:
ctrl
.
defaultRemoveFilterValue
,
type
:
'key'
};
const
existingKeySegment2
=
{
value
:
ctrl
.
defaultRemoveFilterValue
,
type
:
'key'
};
const
existingOperatorSegment
=
{
value
:
'='
,
type
:
'operator'
};
const
existingValueSegment
=
{
value
:
'filtervalue'
,
type
:
'value'
};
const
conditionSegment
=
{
value
:
'AND'
,
type
:
'condition'
};
const
plusSegment
=
{
value
:
''
,
type
:
'plus-button'
};
ctrl
.
filterSegments
=
[
existingKeySegment1
,
existingOperatorSegment
,
existingValueSegment
,
conditionSegment
,
existingKeySegment2
,
Object
.
assign
({},
existingOperatorSegment
),
Object
.
assign
({},
existingValueSegment
),
plusSegment
,
];
ctrl
.
filterSegmentUpdated
(
existingKeySegment2
,
4
);
});
it
(
'should remove filter segments and the condition segment'
,
()
=>
{
expect
(
ctrl
.
filterSegments
.
length
).
toBe
(
4
);
expect
(
ctrl
.
filterSegments
[
0
].
type
).
toBe
(
'key'
);
expect
(
ctrl
.
filterSegments
[
1
].
type
).
toBe
(
'operator'
);
expect
(
ctrl
.
filterSegments
[
2
].
type
).
toBe
(
'value'
);
expect
(
ctrl
.
filterSegments
[
3
].
type
).
toBe
(
'plus-button'
);
});
});
describe
(
'and user removes key segment and there is a filter after it'
,
()
=>
{
beforeEach
(()
=>
{
const
existingKeySegment1
=
{
value
:
ctrl
.
defaultRemoveFilterValue
,
type
:
'key'
};
const
existingKeySegment2
=
{
value
:
ctrl
.
defaultRemoveFilterValue
,
type
:
'key'
};
const
existingOperatorSegment
=
{
value
:
'='
,
type
:
'operator'
};
const
existingValueSegment
=
{
value
:
'filtervalue'
,
type
:
'value'
};
const
conditionSegment
=
{
value
:
'AND'
,
type
:
'condition'
};
const
plusSegment
=
{
value
:
''
,
type
:
'plus-button'
};
ctrl
.
filterSegments
=
[
existingKeySegment1
,
existingOperatorSegment
,
existingValueSegment
,
conditionSegment
,
existingKeySegment2
,
Object
.
assign
({},
existingOperatorSegment
),
Object
.
assign
({},
existingValueSegment
),
plusSegment
,
];
ctrl
.
filterSegmentUpdated
(
existingKeySegment1
,
0
);
});
it
(
'should remove filter segments and the condition segment'
,
()
=>
{
expect
(
ctrl
.
filterSegments
.
length
).
toBe
(
4
);
expect
(
ctrl
.
filterSegments
[
0
].
type
).
toBe
(
'key'
);
expect
(
ctrl
.
filterSegments
[
1
].
type
).
toBe
(
'operator'
);
expect
(
ctrl
.
filterSegments
[
2
].
type
).
toBe
(
'value'
);
expect
(
ctrl
.
filterSegments
[
3
].
type
).
toBe
(
'plus-button'
);
});
});
describe
(
'and user clicks on plus button'
,
()
=>
{
beforeEach
(()
=>
{
const
existingKeySegment
=
{
value
:
'filterkey1'
,
type
:
'key'
};
const
existingOperatorSegment
=
{
value
:
'='
,
type
:
'operator'
};
const
existingValueSegment
=
{
value
:
'filtervalue'
,
type
:
'value'
};
const
plusSegment
=
{
value
:
'filterkey2'
,
type
:
'plus-button'
};
ctrl
.
filterSegments
=
[
existingKeySegment
,
existingOperatorSegment
,
existingValueSegment
,
plusSegment
];
ctrl
.
filterSegmentUpdated
(
plusSegment
,
3
);
});
it
(
'should condition segment and new filter segments'
,
()
=>
{
expect
(
ctrl
.
filterSegments
.
length
).
toBe
(
7
);
expect
(
ctrl
.
filterSegments
[
0
].
type
).
toBe
(
'key'
);
expect
(
ctrl
.
filterSegments
[
1
].
type
).
toBe
(
'operator'
);
expect
(
ctrl
.
filterSegments
[
2
].
type
).
toBe
(
'value'
);
expect
(
ctrl
.
filterSegments
[
3
].
type
).
toBe
(
'condition'
);
expect
(
ctrl
.
filterSegments
[
4
].
type
).
toBe
(
'key'
);
expect
(
ctrl
.
filterSegments
[
5
].
type
).
toBe
(
'operator'
);
expect
(
ctrl
.
filterSegments
[
6
].
type
).
toBe
(
'value'
);
});
});
});
});
});
function
createCtrlWithFakes
()
{
function
createCtrlWithFakes
(
existingFilters
?:
string
[]
)
{
StackdriverQueryCtrl
.
prototype
.
panelCtrl
=
{
events
:
{
on
:
()
=>
{}
},
panel
:
{
scopedVars
:
[],
targets
:
[]
},
refresh
:
()
=>
{},
};
StackdriverQueryCtrl
.
prototype
.
target
=
createTarget
();
StackdriverQueryCtrl
.
prototype
.
target
=
createTarget
(
existingFilters
);
StackdriverQueryCtrl
.
prototype
.
getMetricTypes
=
()
=>
{
return
Promise
.
resolve
();
};
...
...
@@ -168,20 +361,37 @@ function createCtrlWithFakes() {
};
const
fakeSegmentServer
=
{
newKey
:
val
=>
{
return
{
value
:
val
,
type
:
'key'
};
},
newKeyValue
:
val
=>
{
return
{
value
:
val
,
type
:
'value'
};
},
newSegment
:
obj
=>
{
return
{
value
:
obj
.
value
?
obj
.
value
:
obj
};
},
newOperators
:
ops
=>
{
return
ops
.
map
(
o
=>
{
return
{
type
:
'operator'
,
value
:
o
,
text
:
o
};
return
{
type
:
'operator'
,
value
:
o
};
});
},
newPlusButton
:
()
=>
{},
newFake
:
(
value
,
type
,
cssClass
)
=>
{
return
{
value
,
type
,
cssClass
};
},
newOperator
:
op
=>
{
return
{
value
:
op
,
type
:
'operator'
};
},
newPlusButton
:
()
=>
{
return
{
type
:
'plus-button'
};
},
newCondition
:
val
=>
{
return
{
type
:
'condition'
,
value
:
val
};
},
};
return
new
StackdriverQueryCtrl
(
null
,
null
,
fakeSegmentServer
,
null
);
}
function
createTarget
()
{
function
createTarget
(
existingFilters
?:
string
[]
)
{
return
{
project
:
{
id
:
''
,
...
...
@@ -195,6 +405,6 @@ function createTarget() {
perSeriesAligner
:
''
,
groupBys
:
[],
},
filters
:
[],
filters
:
existingFilters
||
[],
};
}
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