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
fe423644
Unverified
Commit
fe423644
authored
Oct 14, 2020
by
Ryan McKinley
Committed by
GitHub
Oct 14, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Transformations: add Concatenate fields transformer (#28237)
parent
cb72242d
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
352 additions
and
13 deletions
+352
-13
packages/grafana-data/src/transformations/transformers.ts
+2
-0
packages/grafana-data/src/transformations/transformers/concat.test.ts
+136
-0
packages/grafana-data/src/transformations/transformers/concat.ts
+105
-0
packages/grafana-data/src/transformations/transformers/ids.ts
+1
-0
packages/grafana-data/src/types/datasource.ts
+1
-1
packages/grafana-data/src/types/live.ts
+9
-9
packages/grafana-runtime/src/services/live.ts
+2
-2
packages/grafana-ui/src/components/Monaco/types.ts
+1
-1
public/app/core/components/TransformersUI/ConcatenateTransformerEditor.tsx
+93
-0
public/app/core/utils/standardTransformers.ts
+2
-0
No files found.
packages/grafana-data/src/transformations/transformers.ts
View file @
fe423644
import
{
appendTransformer
}
from
'./transformers/append'
;
import
{
reduceTransformer
}
from
'./transformers/reduce'
;
import
{
concatenateTransformer
}
from
'./transformers/concat'
;
import
{
calculateFieldTransformer
}
from
'./transformers/calculateField'
;
import
{
filterFieldsTransformer
,
filterFramesTransformer
}
from
'./transformers/filter'
;
import
{
filterFieldsByNameTransformer
}
from
'./transformers/filterByName'
;
...
...
@@ -25,6 +26,7 @@ export const standardTransformers = {
organizeFieldsTransformer
,
appendTransformer
,
reduceTransformer
,
concatenateTransformer
,
calculateFieldTransformer
,
seriesToColumnsTransformer
,
seriesToRowsTransformer
,
...
...
packages/grafana-data/src/transformations/transformers/concat.test.ts
0 → 100644
View file @
fe423644
import
{
toDataFrame
}
from
'../../dataframe/processDataFrame'
;
import
{
concatenateFields
,
ConcatenateFrameNameMode
}
from
'./concat'
;
export
const
simpleABC
=
toDataFrame
({
name
:
'ABC'
,
fields
:
[
{
name
:
'A'
,
values
:
[
1
,
2
]
},
{
name
:
'B'
,
values
:
[
1
,
2
]
},
{
name
:
'C'
,
values
:
[
1
,
2
]
},
],
});
export
const
simpleXYZ
=
toDataFrame
({
name
:
'XYZ'
,
fields
:
[
{
name
:
'X'
,
values
:
[
1
,
2
,
3
]
},
{
name
:
'Y'
,
values
:
[
1
,
2
,
3
]
},
{
name
:
'Z'
,
values
:
[
1
,
2
,
3
]
},
],
});
describe
(
'Concat Transformer'
,
()
=>
{
it
(
'dropping frame name'
,
()
=>
{
const
frame
=
concatenateFields
([
simpleABC
,
simpleXYZ
],
{
frameNameMode
:
ConcatenateFrameNameMode
.
Drop
});
expect
(
frame
.
length
).
toBe
(
3
);
expect
(
frame
.
fields
.
map
(
f
=>
({
name
:
f
.
name
,
labels
:
f
.
labels
}))).
toMatchInlineSnapshot
(
`
Array [
Object {
"labels": undefined,
"name": "A",
},
Object {
"labels": undefined,
"name": "B",
},
Object {
"labels": undefined,
"name": "C",
},
Object {
"labels": undefined,
"name": "X",
},
Object {
"labels": undefined,
"name": "Y",
},
Object {
"labels": undefined,
"name": "Z",
},
]
`
);
});
it
(
'using field name'
,
()
=>
{
const
frame
=
concatenateFields
([
simpleABC
,
simpleXYZ
],
{
frameNameMode
:
ConcatenateFrameNameMode
.
FieldName
});
expect
(
frame
.
length
).
toBe
(
3
);
expect
(
frame
.
fields
.
map
(
f
=>
({
name
:
f
.
name
,
labels
:
f
.
labels
}))).
toMatchInlineSnapshot
(
`
Array [
Object {
"labels": undefined,
"name": "ABC · A",
},
Object {
"labels": undefined,
"name": "ABC · B",
},
Object {
"labels": undefined,
"name": "ABC · C",
},
Object {
"labels": undefined,
"name": "XYZ · X",
},
Object {
"labels": undefined,
"name": "XYZ · Y",
},
Object {
"labels": undefined,
"name": "XYZ · Z",
},
]
`
);
});
it
(
'using field label'
,
()
=>
{
const
frame
=
concatenateFields
([
simpleABC
,
simpleXYZ
],
{
frameNameMode
:
ConcatenateFrameNameMode
.
Label
,
frameNameLabel
:
'sensor'
,
});
expect
(
frame
.
length
).
toBe
(
3
);
expect
(
frame
.
fields
.
map
(
f
=>
({
name
:
f
.
name
,
labels
:
f
.
labels
}))).
toMatchInlineSnapshot
(
`
Array [
Object {
"labels": Object {
"sensor": "ABC",
},
"name": "A",
},
Object {
"labels": Object {
"sensor": "ABC",
},
"name": "B",
},
Object {
"labels": Object {
"sensor": "ABC",
},
"name": "C",
},
Object {
"labels": Object {
"sensor": "XYZ",
},
"name": "X",
},
Object {
"labels": Object {
"sensor": "XYZ",
},
"name": "Y",
},
Object {
"labels": Object {
"sensor": "XYZ",
},
"name": "Z",
},
]
`
);
});
});
packages/grafana-data/src/transformations/transformers/concat.ts
0 → 100644
View file @
fe423644
import
{
map
}
from
'rxjs/operators'
;
import
{
DataTransformerID
}
from
'./ids'
;
import
{
DataTransformerInfo
}
from
'../../types/transformations'
;
import
{
DataFrame
,
Field
}
from
'../../types/dataFrame'
;
import
{
ArrayVector
}
from
'../../vector'
;
export
enum
ConcatenateFrameNameMode
{
/**
* Ignore the source frame name when moving to the destination
*/
Drop
=
'drop'
,
/**
* Copy the source frame name to the destination field. The final field will contain
* both the frame and field name
*/
FieldName
=
'field'
,
/**
* Copy the source frame name to a label on the field. The label key is controlled
* by frameNameLabel
*/
Label
=
'label'
,
}
export
interface
ConcatenateTransformerOptions
{
frameNameMode
?:
ConcatenateFrameNameMode
;
frameNameLabel
?:
string
;
}
export
const
concatenateTransformer
:
DataTransformerInfo
<
ConcatenateTransformerOptions
>
=
{
id
:
DataTransformerID
.
concatenate
,
name
:
'Concatenate fields'
,
description
:
'Combine all fields into a single frame. Values will be appended with undefined values if not the same length.'
,
defaultOptions
:
{
frameNameMode
:
ConcatenateFrameNameMode
.
FieldName
,
frameNameLabel
:
'frame'
,
},
operator
:
options
=>
source
=>
source
.
pipe
(
map
(
dataFrames
=>
{
if
(
!
Array
.
isArray
(
dataFrames
)
||
dataFrames
.
length
<
2
)
{
return
dataFrames
;
// noop with single frame
}
return
[
concatenateFields
(
dataFrames
,
options
)];
})
),
};
/**
* @internal only exported for tests
*/
export
function
concatenateFields
(
data
:
DataFrame
[],
opts
:
ConcatenateTransformerOptions
):
DataFrame
{
let
sameLength
=
true
;
let
maxLength
=
data
[
0
].
length
;
const
frameNameLabel
=
opts
.
frameNameLabel
??
'frame'
;
let
fields
:
Field
[]
=
[];
for
(
const
frame
of
data
)
{
if
(
maxLength
!==
frame
.
length
)
{
sameLength
=
false
;
maxLength
=
Math
.
max
(
maxLength
,
frame
.
length
);
}
for
(
const
f
of
frame
.
fields
)
{
const
copy
=
{
...
f
};
copy
.
state
=
undefined
;
if
(
frame
.
name
)
{
if
(
opts
.
frameNameMode
===
ConcatenateFrameNameMode
.
Drop
)
{
// nothing -- skip the name
}
else
if
(
opts
.
frameNameMode
===
ConcatenateFrameNameMode
.
Label
)
{
copy
.
labels
=
{
...
f
.
labels
};
copy
.
labels
[
frameNameLabel
]
=
frame
.
name
;
}
else
if
(
!
copy
.
name
||
copy
.
name
===
'Value'
)
{
copy
.
name
=
frame
.
name
;
}
else
{
copy
.
name
=
`
${
frame
.
name
}
·
${
f
.
name
}
`
;
}
}
fields
.
push
(
copy
);
}
}
// Make sure all fields have the same length
if
(
!
sameLength
)
{
fields
=
fields
.
map
(
f
=>
{
if
(
f
.
values
.
length
===
maxLength
)
{
return
f
;
}
const
values
=
f
.
values
.
toArray
();
values
.
length
=
maxLength
;
return
{
...
f
,
values
:
new
ArrayVector
(
values
),
};
});
}
return
{
fields
,
length
:
maxLength
,
};
}
packages/grafana-data/src/transformations/transformers/ids.ts
View file @
fe423644
...
...
@@ -10,6 +10,7 @@ export enum DataTransformerID {
seriesToColumns
=
'seriesToColumns'
,
seriesToRows
=
'seriesToRows'
,
merge
=
'merge'
,
concatenate
=
'concatenate'
,
labelsToFields
=
'labelsToFields'
,
filterFields
=
'filterFields'
,
filterFieldsByName
=
'filterFieldsByName'
,
...
...
packages/grafana-data/src/types/datasource.ts
View file @
fe423644
...
...
@@ -291,7 +291,7 @@ export abstract class DataSourceApi<
*
* Note: `plugin.json` must also define `live: true`
*
* @experimental
* @
alpha --
experimental
*/
channelSupport
?:
LiveChannelSupport
;
}
...
...
packages/grafana-data/src/types/live.ts
View file @
fe423644
...
...
@@ -15,7 +15,7 @@ export enum LiveChannelScope {
}
/**
* @experimental
* @
alpha --
experimental
*/
export
interface
LiveChannelConfig
<
TMessage
=
any
>
{
/**
...
...
@@ -69,7 +69,7 @@ export enum LiveChannelEventType {
}
/**
* @experimental
* @
alpha --
experimental
*/
export
interface
LiveChannelStatusEvent
{
type
:
LiveChannelEventType
.
Status
;
...
...
@@ -101,12 +101,12 @@ export interface LiveChannelStatusEvent {
export
interface
LiveChannelJoinEvent
{
type
:
LiveChannelEventType
.
Join
;
user
:
any
;
// @experimental -- will be filled in when we improve the UI
user
:
any
;
// @
alpha --
experimental -- will be filled in when we improve the UI
}
export
interface
LiveChannelLeaveEvent
{
type
:
LiveChannelEventType
.
Leave
;
user
:
any
;
// @experimental -- will be filled in when we improve the UI
user
:
any
;
// @
alpha --
experimental -- will be filled in when we improve the UI
}
export
interface
LiveChannelMessageEvent
<
T
>
{
...
...
@@ -137,14 +137,14 @@ export function isLiveChannelMessageEvent<T>(evt: LiveChannelEvent<T>): evt is L
}
/**
* @experimental
* @
alpha --
experimental
*/
export
interface
LiveChannelPresenceStatus
{
users
:
any
;
// @experimental -- will be filled in when we improve the UI
users
:
any
;
// @
alpha --
experimental -- will be filled in when we improve the UI
}
/**
* @experimental
* @
alpha --
experimental
*/
export
interface
LiveChannelAddress
{
scope
:
LiveChannelScope
;
...
...
@@ -160,7 +160,7 @@ export function isValidLiveChannelAddress(addr?: LiveChannelAddress): addr is Li
}
/**
* @experimental
* @
alpha --
experimental
*/
export
interface
LiveChannel
<
TMessage
=
any
,
TPublish
=
any
>
{
/** The fully qualified channel id: ${scope}/${namespace}/${path} */
...
...
@@ -201,7 +201,7 @@ export interface LiveChannel<TMessage = any, TPublish = any> {
}
/**
* @experimental
* @
alpha --
experimental
*/
export
interface
LiveChannelSupport
{
/**
...
...
packages/grafana-runtime/src/services/live.ts
View file @
fe423644
...
...
@@ -2,7 +2,7 @@ import { LiveChannel, LiveChannelAddress } from '@grafana/data';
import
{
Observable
}
from
'rxjs'
;
/**
* @experimental
* @
alpha --
experimental
*/
export
interface
GrafanaLiveSrv
{
/**
...
...
@@ -42,7 +42,7 @@ export const setGrafanaLiveSrv = (instance: GrafanaLiveSrv) => {
* Used to retrieve the {@link GrafanaLiveSrv} that allows you to subscribe to
* server side events and streams
*
* @experimental
* @
alpha --
experimental
* @public
*/
export
const
getGrafanaLiveSrv
=
():
GrafanaLiveSrv
=>
singletonInstance
;
packages/grafana-ui/src/components/Monaco/types.ts
View file @
fe423644
...
...
@@ -14,7 +14,7 @@ export interface CodeEditorProps {
/**
* Callback after the editor has mounted that gives you raw access to monaco
*
* @experimental - real type is: monaco.editor.IStandaloneCodeEditor
* @
alpha --
experimental - real type is: monaco.editor.IStandaloneCodeEditor
*/
onEditorDidMount
?:
(
editor
:
any
)
=>
void
;
...
...
public/app/core/components/TransformersUI/ConcatenateTransformerEditor.tsx
0 → 100644
View file @
fe423644
import
React
,
{
ChangeEvent
}
from
'react'
;
import
{
DataTransformerID
,
SelectableValue
,
standardTransformers
,
TransformerRegistyItem
,
TransformerUIProps
,
}
from
'@grafana/data'
;
import
{
Input
,
Select
}
from
'@grafana/ui'
;
import
{
ConcatenateTransformerOptions
,
ConcatenateFrameNameMode
,
}
from
'@grafana/data/src/transformations/transformers/concat'
;
interface
ConcatenateTransformerEditorProps
extends
TransformerUIProps
<
ConcatenateTransformerOptions
>
{}
const
nameModes
:
Array
<
SelectableValue
<
ConcatenateFrameNameMode
>>
=
[
{
value
:
ConcatenateFrameNameMode
.
FieldName
,
label
:
'Copy frame name to field name'
},
{
value
:
ConcatenateFrameNameMode
.
Label
,
label
:
'Add a label with the frame name'
},
{
value
:
ConcatenateFrameNameMode
.
Drop
,
label
:
'Ignore the frame name'
},
];
export
class
ConcatenateTransformerEditor
extends
React
.
PureComponent
<
ConcatenateTransformerEditorProps
>
{
constructor
(
props
:
ConcatenateTransformerEditorProps
)
{
super
(
props
);
}
onModeChanged
=
(
value
:
SelectableValue
<
ConcatenateFrameNameMode
>
)
=>
{
const
{
options
,
onChange
}
=
this
.
props
;
const
frameNameMode
=
value
.
value
??
ConcatenateFrameNameMode
.
FieldName
;
onChange
({
...
options
,
frameNameMode
,
});
};
onLabelChanged
=
(
evt
:
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
{
options
}
=
this
.
props
;
this
.
props
.
onChange
({
...
options
,
frameNameLabel
:
evt
.
target
.
value
,
});
};
//---------------------------------------------------------
// Render
//---------------------------------------------------------
render
()
{
const
{
options
}
=
this
.
props
;
const
frameNameMode
=
options
.
frameNameMode
??
ConcatenateFrameNameMode
.
FieldName
;
return
(
<
div
>
<
div
className=
"gf-form-inline"
>
<
div
className=
"gf-form"
>
<
div
className=
"gf-form-label width-8"
>
Name
</
div
>
<
Select
className=
"width-18"
options=
{
nameModes
}
value=
{
nameModes
.
find
(
v
=>
v
.
value
===
frameNameMode
)
}
onChange=
{
this
.
onModeChanged
}
menuPlacement=
"bottom"
/>
</
div
>
</
div
>
{
frameNameMode
===
ConcatenateFrameNameMode
.
Label
&&
(
<
div
className=
"gf-form-inline"
>
<
div
className=
"gf-form"
>
<
div
className=
"gf-form-label width-8"
>
Label
</
div
>
<
Input
className=
"width-18"
value=
{
options
.
frameNameLabel
??
''
}
placeholder=
"frame"
onChange=
{
this
.
onLabelChanged
}
/>
</
div
>
</
div
>
)
}
</
div
>
);
}
}
export
const
concatenateTransformRegistryItem
:
TransformerRegistyItem
<
ConcatenateTransformerOptions
>
=
{
id
:
DataTransformerID
.
concatenate
,
editor
:
ConcatenateTransformerEditor
,
transformation
:
standardTransformers
.
concatenateTransformer
,
name
:
'Concatenate fields'
,
description
:
'Combine all fields into a single frame. Values will be appended with undefined values if not the same length.'
,
};
public/app/core/utils/standardTransformers.ts
View file @
fe423644
...
...
@@ -9,6 +9,7 @@ import { labelsToFieldsTransformerRegistryItem } from '../components/Transformer
import
{
groupByTransformRegistryItem
}
from
'../components/TransformersUI/GroupByTransformerEditor'
;
import
{
mergeTransformerRegistryItem
}
from
'../components/TransformersUI/MergeTransformerEditor'
;
import
{
seriesToRowsTransformerRegistryItem
}
from
'../components/TransformersUI/SeriesToRowsTransformerEditor'
;
import
{
concatenateTransformRegistryItem
}
from
'../components/TransformersUI/ConcatenateTransformerEditor'
;
export
const
getStandardTransformers
=
():
Array
<
TransformerRegistyItem
<
any
>>
=>
{
return
[
...
...
@@ -18,6 +19,7 @@ export const getStandardTransformers = (): Array<TransformerRegistyItem<any>> =>
organizeFieldsTransformRegistryItem
,
seriesToFieldsTransformerRegistryItem
,
seriesToRowsTransformerRegistryItem
,
concatenateTransformRegistryItem
,
calculateFieldTransformRegistryItem
,
labelsToFieldsTransformerRegistryItem
,
groupByTransformRegistryItem
,
...
...
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