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
a58a9e8e
Unverified
Commit
a58a9e8e
authored
Sep 23, 2020
by
Hugo Häggmark
Committed by
GitHub
Sep 23, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
PanelEditor: Prevents adding transformations in panels with alerts (#27706)
parent
35a145dd
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
114 additions
and
47 deletions
+114
-47
public/app/features/alerting/AlertTab.tsx
+14
-44
public/app/features/dashboard/components/PanelEditor/PanelNotSupported.test.tsx
+48
-0
public/app/features/dashboard/components/PanelEditor/PanelNotSupported.tsx
+33
-0
public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx
+19
-3
No files found.
public/app/features/alerting/AlertTab.tsx
View file @
a58a9e8e
import
React
,
{
PureComponent
}
from
'react'
;
import
React
,
{
PureComponent
}
from
'react'
;
import
{
connect
,
MapDispatchToProps
,
MapStateToProps
}
from
'react-redux'
;
import
{
connect
,
MapDispatchToProps
,
MapStateToProps
}
from
'react-redux'
;
import
{
css
}
from
'emotion'
;
import
{
Alert
,
Button
,
ConfirmModal
,
Container
,
CustomScrollbar
,
HorizontalGroup
,
IconName
,
Modal
}
from
'@grafana/ui'
;
import
{
Alert
,
Button
,
IconName
,
CustomScrollbar
,
Container
,
HorizontalGroup
,
ConfirmModal
,
Modal
}
from
'@grafana/ui'
;
import
{
selectors
}
from
'@grafana/e2e-selectors'
;
import
{
selectors
}
from
'@grafana/e2e-selectors'
;
import
{
AngularComponent
,
getAngularLoader
,
getDataSourceSrv
}
from
'@grafana/runtime'
;
import
{
AngularComponent
,
getAngularLoader
,
getDataSourceSrv
}
from
'@grafana/runtime'
;
import
{
getAlertingValidationMessage
}
from
'./getAlertingValidationMessage'
;
import
{
getAlertingValidationMessage
}
from
'./getAlertingValidationMessage'
;
...
@@ -14,8 +13,7 @@ import { DashboardModel } from '../dashboard/state/DashboardModel';
...
@@ -14,8 +13,7 @@ import { DashboardModel } from '../dashboard/state/DashboardModel';
import
{
PanelModel
}
from
'../dashboard/state/PanelModel'
;
import
{
PanelModel
}
from
'../dashboard/state/PanelModel'
;
import
{
TestRuleResult
}
from
'./TestRuleResult'
;
import
{
TestRuleResult
}
from
'./TestRuleResult'
;
import
{
AppNotificationSeverity
,
StoreState
}
from
'app/types'
;
import
{
AppNotificationSeverity
,
StoreState
}
from
'app/types'
;
import
{
updateLocation
}
from
'app/core/actions'
;
import
{
PanelNotSupported
}
from
'../dashboard/components/PanelEditor/PanelNotSupported'
;
import
{
PanelEditorTabId
}
from
'../dashboard/components/PanelEditor/types'
;
interface
OwnProps
{
interface
OwnProps
{
dashboard
:
DashboardModel
;
dashboard
:
DashboardModel
;
...
@@ -26,14 +24,12 @@ interface ConnectedProps {
...
@@ -26,14 +24,12 @@ interface ConnectedProps {
angularPanelComponent
?:
AngularComponent
|
null
;
angularPanelComponent
?:
AngularComponent
|
null
;
}
}
interface
DispatchProps
{
interface
DispatchProps
{}
updateLocation
:
typeof
updateLocation
;
}
export
type
Props
=
OwnProps
&
ConnectedProps
&
DispatchProps
;
export
type
Props
=
OwnProps
&
ConnectedProps
&
DispatchProps
;
interface
State
{
interface
State
{
validatonMessage
:
string
;
validat
i
onMessage
:
string
;
showStateHistory
:
boolean
;
showStateHistory
:
boolean
;
showDeleteConfirmation
:
boolean
;
showDeleteConfirmation
:
boolean
;
showTestRule
:
boolean
;
showTestRule
:
boolean
;
...
@@ -45,7 +41,7 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
...
@@ -45,7 +41,7 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
panelCtrl
:
any
;
panelCtrl
:
any
;
state
:
State
=
{
state
:
State
=
{
validatonMessage
:
''
,
validat
i
onMessage
:
''
,
showStateHistory
:
false
,
showStateHistory
:
false
,
showDeleteConfirmation
:
false
,
showDeleteConfirmation
:
false
,
showTestRule
:
false
,
showTestRule
:
false
,
...
@@ -94,15 +90,15 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
...
@@ -94,15 +90,15 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
this
.
component
=
loader
.
load
(
this
.
element
,
scopeProps
,
template
);
this
.
component
=
loader
.
load
(
this
.
element
,
scopeProps
,
template
);
const
validatonMessage
=
await
getAlertingValidationMessage
(
const
validat
i
onMessage
=
await
getAlertingValidationMessage
(
panel
.
transformations
,
panel
.
transformations
,
panel
.
targets
,
panel
.
targets
,
getDataSourceSrv
(),
getDataSourceSrv
(),
panel
.
datasource
panel
.
datasource
);
);
if
(
validatonMessage
)
{
if
(
validat
i
onMessage
)
{
this
.
setState
({
validatonMessage
});
this
.
setState
({
validat
i
onMessage
});
}
}
}
}
...
@@ -112,37 +108,11 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
...
@@ -112,37 +108,11 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
this
.
forceUpdate
();
this
.
forceUpdate
();
};
};
switchToQueryTab
=
()
=>
{
onToggleModal
=
(
prop
:
keyof
Omit
<
State
,
'validationMessage'
>
)
=>
{
const
{
updateLocation
}
=
this
.
props
;
updateLocation
({
query
:
{
tab
:
PanelEditorTabId
.
Query
},
partial
:
true
});
};
onToggleModal
=
(
prop
:
keyof
Omit
<
State
,
'validatonMessage'
>
)
=>
{
const
value
=
this
.
state
[
prop
];
const
value
=
this
.
state
[
prop
];
this
.
setState
({
...
this
.
state
,
[
prop
]:
!
value
});
this
.
setState
({
...
this
.
state
,
[
prop
]:
!
value
});
};
};
renderValidationMessage
=
()
=>
{
const
{
validatonMessage
}
=
this
.
state
;
return
(
<
div
className=
{
css
`
width: 508px;
margin: 128px auto;
`
}
>
<
h2
>
{
validatonMessage
}
</
h2
>
<
br
/>
<
div
className=
"gf-form-group"
>
<
Button
size=
{
'md'
}
variant=
{
'secondary'
}
icon=
"arrow-left"
onClick=
{
this
.
switchToQueryTab
}
>
Go back to Queries
</
Button
>
</
div
>
</
div
>
);
};
renderTestRule
=
()
=>
{
renderTestRule
=
()
=>
{
if
(
!
this
.
state
.
showTestRule
)
{
if
(
!
this
.
state
.
showTestRule
)
{
return
null
;
return
null
;
...
@@ -213,11 +183,11 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
...
@@ -213,11 +183,11 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
render
()
{
render
()
{
const
{
alert
,
transformations
}
=
this
.
props
.
panel
;
const
{
alert
,
transformations
}
=
this
.
props
.
panel
;
const
{
validatonMessage
}
=
this
.
state
;
const
{
validat
i
onMessage
}
=
this
.
state
;
const
hasTransformations
=
transformations
&&
transformations
.
length
>
0
;
const
hasTransformations
=
transformations
&&
transformations
.
length
>
0
;
if
(
!
alert
&&
validatonMessage
)
{
if
(
!
alert
&&
validat
i
onMessage
)
{
return
this
.
renderValidationMessage
()
;
return
<
PanelNotSupported
message=
{
validationMessage
}
/>
;
}
}
const
model
=
{
const
model
=
{
...
@@ -253,7 +223,7 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
...
@@ -253,7 +223,7 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
</
Button
>
</
Button
>
</
HorizontalGroup
>
</
HorizontalGroup
>
)
}
)
}
{
!
alert
&&
!
validatonMessage
&&
<
EmptyListCTA
{
...
model
}
/>
}
{
!
alert
&&
!
validat
i
onMessage
&&
<
EmptyListCTA
{
...
model
}
/>
}
</
div
>
</
div
>
</
Container
>
</
Container
>
</
CustomScrollbar
>
</
CustomScrollbar
>
...
@@ -272,6 +242,6 @@ const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (
...
@@ -272,6 +242,6 @@ const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (
};
};
};
};
const
mapDispatchToProps
:
MapDispatchToProps
<
DispatchProps
,
OwnProps
>
=
{
updateLocation
};
const
mapDispatchToProps
:
MapDispatchToProps
<
DispatchProps
,
OwnProps
>
=
{};
export
const
AlertTab
=
connect
(
mapStateToProps
,
mapDispatchToProps
)(
UnConnectedAlertTab
);
export
const
AlertTab
=
connect
(
mapStateToProps
,
mapDispatchToProps
)(
UnConnectedAlertTab
);
public/app/features/dashboard/components/PanelEditor/PanelNotSupported.test.tsx
0 → 100644
View file @
a58a9e8e
import
React
from
'react'
;
import
{
render
,
screen
}
from
'@testing-library/react'
;
import
userEvent
from
'@testing-library/user-event'
;
import
{
PanelNotSupported
,
Props
}
from
'./PanelNotSupported'
;
import
{
updateLocation
}
from
'../../../../core/actions'
;
import
{
PanelEditorTabId
}
from
'./types'
;
const
setupTestContext
=
(
options
:
Partial
<
Props
>
)
=>
{
const
defaults
:
Props
=
{
message
:
''
,
dispatch
:
jest
.
fn
(),
};
const
props
=
{
...
defaults
,
...
options
};
render
(<
PanelNotSupported
{
...
props
}
/>);
return
{
props
};
};
describe
(
'PanelNotSupported'
,
()
=>
{
describe
(
'when component is mounted'
,
()
=>
{
it
(
'then the supplied message should be shown'
,
()
=>
{
setupTestContext
({
message
:
'Expected message'
});
expect
(
screen
.
getByRole
(
'heading'
,
{
name
:
/expected message/i
})).
toBeInTheDocument
();
});
it
(
'then the back to queries button should exist'
,
()
=>
{
setupTestContext
({
message
:
'Expected message'
});
expect
(
screen
.
getByRole
(
'button'
,
{
name
:
/go back to queries/i
})).
toBeInTheDocument
();
});
});
describe
(
'when the back to queries button is clicked'
,
()
=>
{
it
(
'then correct action should be dispatched'
,
()
=>
{
const
{
props
:
{
dispatch
},
}
=
setupTestContext
({});
userEvent
.
click
(
screen
.
getByRole
(
'button'
,
{
name
:
/go back to queries/i
}));
expect
(
dispatch
).
toHaveBeenCalledTimes
(
1
);
expect
(
dispatch
).
toHaveBeenCalledWith
(
updateLocation
({
query
:
{
tab
:
PanelEditorTabId
.
Query
},
partial
:
true
}));
});
});
});
public/app/features/dashboard/components/PanelEditor/PanelNotSupported.tsx
0 → 100644
View file @
a58a9e8e
import
React
,
{
FC
,
useCallback
}
from
'react'
;
import
{
useDispatch
}
from
'react-redux'
;
import
{
Dispatch
}
from
'redux'
;
import
{
Button
,
VerticalGroup
}
from
'@grafana/ui'
;
import
{
Layout
}
from
'@grafana/ui/src/components/Layout/Layout'
;
import
{
PanelEditorTabId
}
from
'./types'
;
import
{
updateLocation
}
from
'../../../../core/actions'
;
export
interface
Props
{
message
:
string
;
dispatch
?:
Dispatch
;
}
export
const
PanelNotSupported
:
FC
<
Props
>
=
({
message
,
dispatch
:
propsDispatch
})
=>
{
const
dispatch
=
propsDispatch
?
propsDispatch
:
useDispatch
();
const
onBackToQueries
=
useCallback
(()
=>
{
dispatch
(
updateLocation
({
query
:
{
tab
:
PanelEditorTabId
.
Query
},
partial
:
true
}));
},
[
dispatch
]);
return
(
<
Layout
justify=
"center"
style=
{
{
marginTop
:
'100px'
}
}
>
<
VerticalGroup
spacing=
"md"
>
<
h2
>
{
message
}
</
h2
>
<
div
>
<
Button
size=
"md"
variant=
"secondary"
icon=
"arrow-left"
onClick=
{
onBackToQueries
}
>
Go back to Queries
</
Button
>
</
div
>
</
VerticalGroup
>
</
Layout
>
);
};
public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx
View file @
a58a9e8e
import
React
from
'react'
;
import
React
from
'react'
;
import
{
import
{
Alert
,
Button
,
Button
,
Container
,
Container
,
CustomScrollbar
,
CustomScrollbar
,
...
@@ -10,14 +11,14 @@ import {
...
@@ -10,14 +11,14 @@ import {
VerticalGroup
,
VerticalGroup
,
}
from
'@grafana/ui'
;
}
from
'@grafana/ui'
;
import
{
import
{
DataFrame
,
DataTransformerConfig
,
DataTransformerConfig
,
DocsId
,
GrafanaTheme
,
GrafanaTheme
,
PanelData
,
SelectableValue
,
SelectableValue
,
standardTransformersRegistry
,
standardTransformersRegistry
,
transformDataFrame
,
transformDataFrame
,
DataFrame
,
PanelData
,
DocsId
,
}
from
'@grafana/data'
;
}
from
'@grafana/data'
;
import
{
TransformationOperationRow
}
from
'./TransformationOperationRow'
;
import
{
TransformationOperationRow
}
from
'./TransformationOperationRow'
;
import
{
Card
,
CardProps
}
from
'../../../../core/components/Card/Card'
;
import
{
Card
,
CardProps
}
from
'../../../../core/components/Card/Card'
;
...
@@ -27,6 +28,8 @@ import { Unsubscribable } from 'rxjs';
...
@@ -27,6 +28,8 @@ import { Unsubscribable } from 'rxjs';
import
{
PanelModel
}
from
'../../state'
;
import
{
PanelModel
}
from
'../../state'
;
import
{
getDocsLink
}
from
'app/core/utils/docsLinks'
;
import
{
getDocsLink
}
from
'app/core/utils/docsLinks'
;
import
{
DragDropContext
,
Droppable
,
DropResult
}
from
'react-beautiful-dnd'
;
import
{
DragDropContext
,
Droppable
,
DropResult
}
from
'react-beautiful-dnd'
;
import
{
PanelNotSupported
}
from
'../PanelEditor/PanelNotSupported'
;
import
{
AppNotificationSeverity
}
from
'../../../../types'
;
interface
TransformationsEditorProps
{
interface
TransformationsEditorProps
{
panel
:
PanelModel
;
panel
:
PanelModel
;
...
@@ -285,14 +288,27 @@ export class TransformationsEditor extends React.PureComponent<TransformationsEd
...
@@ -285,14 +288,27 @@ export class TransformationsEditor extends React.PureComponent<TransformationsEd
}
}
render
()
{
render
()
{
const
{
panel
:
{
alert
},
}
=
this
.
props
;
const
{
transformations
}
=
this
.
state
;
const
{
transformations
}
=
this
.
state
;
const
hasTransforms
=
transformations
.
length
>
0
;
const
hasTransforms
=
transformations
.
length
>
0
;
if
(
!
hasTransforms
&&
alert
)
{
return
<
PanelNotSupported
message=
"Transformations can't be used on a panel with existing alerts"
/>;
}
return
(
return
(
<
CustomScrollbar
autoHeightMin=
"100%"
>
<
CustomScrollbar
autoHeightMin=
"100%"
>
<
Container
padding=
"md"
>
<
Container
padding=
"md"
>
<
div
aria
-
label=
{
selectors
.
components
.
TransformTab
.
content
}
>
<
div
aria
-
label=
{
selectors
.
components
.
TransformTab
.
content
}
>
{
hasTransforms
&&
alert
?
(
<
Alert
severity=
{
AppNotificationSeverity
.
Error
}
title=
"Transformations can't be used on a panel with alerts"
/>
)
:
null
}
{
!
hasTransforms
&&
this
.
renderNoAddedTransformsState
()
}
{
!
hasTransforms
&&
this
.
renderNoAddedTransformsState
()
}
{
hasTransforms
&&
this
.
renderTransformationEditors
()
}
{
hasTransforms
&&
this
.
renderTransformationEditors
()
}
{
hasTransforms
&&
this
.
renderTransformationSelector
()
}
{
hasTransforms
&&
this
.
renderTransformationSelector
()
}
...
...
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