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
5975c4a7
Commit
5975c4a7
authored
Nov 06, 2018
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ux: changed panel selection ux
parent
b372b432
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
154 additions
and
66 deletions
+154
-66
public/app/core/components/Animations/FadeIn.tsx
+37
-0
public/app/core/components/Animations/SlideDown.tsx
+1
-1
public/app/features/dashboard/dashgrid/DashboardPanel.tsx
+35
-34
public/app/features/dashboard/dashgrid/PanelEditor.tsx
+7
-8
public/app/features/dashboard/dashgrid/VizTypePicker.tsx
+46
-16
public/sass/components/_gf-form.scss
+21
-1
public/sass/components/_viz_editor.scss
+7
-6
No files found.
public/app/core/components/Animations/FadeIn.tsx
0 → 100644
View file @
5975c4a7
import
React
,
{
SFC
}
from
'react'
;
import
Transition
from
'react-transition-group/Transition'
;
interface
Props
{
duration
:
number
;
children
:
JSX
.
Element
;
in
:
boolean
;
}
export
const
FadeIn
:
SFC
<
Props
>
=
props
=>
{
const
defaultStyle
=
{
transition
:
`opacity
${
props
.
duration
}
ms linear`
,
opacity
:
0
,
};
const
transitionStyles
=
{
exited
:
{
opacity
:
0
,
display
:
'none'
},
entering
:
{
opacity
:
0
},
entered
:
{
opacity
:
1
},
exiting
:
{
opacity
:
0
},
};
return
(
<
Transition
in=
{
props
.
in
}
timeout=
{
props
.
duration
}
>
{
state
=>
(
<
div
style=
{
{
...
defaultStyle
,
...
transitionStyles
[
state
],
}
}
>
{
props
.
children
}
</
div
>
)
}
</
Transition
>
);
};
public/app/core/components/Animations/SlideDown.tsx
View file @
5975c4a7
...
@@ -23,7 +23,7 @@ export default ({ children, in: inProp, maxHeight = defaultMaxHeight, style = de
...
@@ -23,7 +23,7 @@ export default ({ children, in: inProp, maxHeight = defaultMaxHeight, style = de
const
transitionStyles
=
{
const
transitionStyles
=
{
exited
:
{
maxHeight
:
0
},
exited
:
{
maxHeight
:
0
},
entering
:
{
maxHeight
:
maxHeight
},
entering
:
{
maxHeight
:
maxHeight
},
entered
:
{
maxHeight
:
maxHeight
,
overflow
:
'visible'
},
entered
:
{
maxHeight
:
'unset'
,
overflow
:
'visible'
},
exiting
:
{
maxHeight
:
0
},
exiting
:
{
maxHeight
:
0
},
};
};
...
...
public/app/features/dashboard/dashgrid/DashboardPanel.tsx
View file @
5975c4a7
import
React
from
'react'
;
import
React
from
'react'
;
import
config
from
'app/core/config'
;
import
config
from
'app/core/config'
;
import
{
PanelModel
}
from
'../panel_model'
;
import
{
DashboardModel
}
from
'../dashboard_model'
;
import
{
getAngularLoader
,
AngularComponent
}
from
'app/core/services/AngularLoader'
;
import
{
getAngularLoader
,
AngularComponent
}
from
'app/core/services/AngularLoader'
;
import
{
DashboardRow
}
from
'./DashboardRow'
;
import
{
AddPanelPanel
}
from
'./AddPanelPanel'
;
import
{
importPluginModule
}
from
'app/features/plugins/plugin_loader'
;
import
{
importPluginModule
}
from
'app/features/plugins/plugin_loader'
;
import
{
PluginExports
,
PanelPlugin
}
from
'app/types/plugins'
;
import
{
AddPanelPanel
}
from
'./AddPanelPanel'
;
import
{
DashboardRow
}
from
'./DashboardRow'
;
import
{
PanelPlugin
}
from
'app/types/plugins'
;
import
{
PanelChrome
}
from
'./PanelChrome'
;
import
{
PanelChrome
}
from
'./PanelChrome'
;
import
{
PanelEditor
}
from
'./PanelEditor'
;
import
{
PanelEditor
}
from
'./PanelEditor'
;
import
{
PanelModel
}
from
'../panel_model'
;
import
{
DashboardModel
}
from
'../dashboard_model'
;
export
interface
Props
{
export
interface
Props
{
panelType
:
string
;
panelType
:
string
;
panel
:
PanelModel
;
panel
:
PanelModel
;
...
@@ -17,20 +20,19 @@ export interface Props {
...
@@ -17,20 +20,19 @@ export interface Props {
}
}
export
interface
State
{
export
interface
State
{
plugin
Exports
:
PluginExports
;
plugin
:
PanelPlugin
;
}
}
export
class
DashboardPanel
extends
React
.
Component
<
Props
,
State
>
{
export
class
DashboardPanel
extends
React
.
Component
<
Props
,
State
>
{
element
:
any
;
element
:
any
;
angularPanel
:
AngularComponent
;
angularPanel
:
AngularComponent
;
pluginInfo
:
any
;
specialPanels
=
{};
specialPanels
=
{};
constructor
(
props
)
{
constructor
(
props
)
{
super
(
props
);
super
(
props
);
this
.
state
=
{
this
.
state
=
{
plugin
Exports
:
null
,
plugin
:
null
,
};
};
this
.
specialPanels
[
'row'
]
=
this
.
renderRow
.
bind
(
this
);
this
.
specialPanels
[
'row'
]
=
this
.
renderRow
.
bind
(
this
);
...
@@ -63,20 +65,22 @@ export class DashboardPanel extends React.Component<Props, State> {
...
@@ -63,20 +65,22 @@ export class DashboardPanel extends React.Component<Props, State> {
return
;
return
;
}
}
const
{
panel
}
=
this
.
props
;
// handle plugin loading & changing of plugin type
// handle plugin loading & changing of plugin type
if
(
!
this
.
pluginInfo
||
this
.
pluginInfo
.
id
!==
this
.
props
.
panel
.
type
)
{
if
(
!
this
.
state
.
plugin
||
this
.
state
.
plugin
.
id
!==
panel
.
type
)
{
this
.
pluginInfo
=
config
.
panels
[
this
.
props
.
panel
.
type
];
const
plugin
=
config
.
panels
[
panel
.
type
];
if
(
this
.
pluginInfo
.
exports
)
{
if
(
plugin
.
exports
)
{
this
.
cleanUpAngularPanel
();
this
.
cleanUpAngularPanel
();
this
.
setState
({
plugin
Exports
:
this
.
pluginInfo
.
exports
});
this
.
setState
({
plugin
:
plugin
});
}
else
{
}
else
{
importPluginModule
(
this
.
pluginInfo
.
module
).
then
(
pluginExports
=>
{
importPluginModule
(
plugin
.
module
).
then
(
pluginExports
=>
{
this
.
cleanUpAngularPanel
();
this
.
cleanUpAngularPanel
();
// cache plugin exports (saves a promise async cycle next time)
// cache plugin exports (saves a promise async cycle next time)
this
.
pluginInfo
.
exports
=
pluginExports
;
plugin
.
exports
=
pluginExports
;
// update panel state
// update panel state
this
.
setState
({
plugin
Exports
:
pluginExports
});
this
.
setState
({
plugin
:
plugin
});
});
});
}
}
}
}
...
@@ -112,44 +116,41 @@ export class DashboardPanel extends React.Component<Props, State> {
...
@@ -112,44 +116,41 @@ export class DashboardPanel extends React.Component<Props, State> {
}
}
renderReactPanel
()
{
renderReactPanel
()
{
const
{
pluginExports
}
=
this
.
state
;
const
{
dashboard
,
panel
}
=
this
.
props
;
const
containerClass
=
this
.
props
.
panel
.
isEditing
?
'panel-editor-container'
:
'panel-height-helper'
;
const
{
plugin
}
=
this
.
state
;
const
panelWrapperClass
=
this
.
props
.
panel
.
isEditing
?
'panel-editor-container__panel'
:
'panel-height-helper'
;
const
containerClass
=
panel
.
isEditing
?
'panel-editor-container'
:
'panel-height-helper'
;
const
panelWrapperClass
=
panel
.
isEditing
?
'panel-editor-container__panel'
:
'panel-height-helper'
;
// this might look strange with these classes that change when edit, but
// this might look strange with these classes that change when edit, but
// I want to try to keep markup (parents) for panel the same in edit mode to avoide unmount / new mount of panel
// I want to try to keep markup (parents) for panel the same in edit mode to avoide unmount / new mount of panel
return
(
return
(
<
div
className=
{
containerClass
}
>
<
div
className=
{
containerClass
}
>
<
div
className=
{
panelWrapperClass
}
>
<
div
className=
{
panelWrapperClass
}
>
<
PanelChrome
<
PanelChrome
component=
{
plugin
.
exports
.
PanelComponent
}
panel=
{
panel
}
dashboard=
{
dashboard
}
/>
component=
{
pluginExports
.
PanelComponent
}
panel=
{
this
.
props
.
panel
}
dashboard=
{
this
.
props
.
dashboard
}
/>
</
div
>
</
div
>
{
this
.
props
.
panel
.
isEditing
&&
(
{
panel
.
isEditing
&&
(
<
PanelEditor
<
PanelEditor
panel=
{
panel
}
plugin=
{
plugin
}
dashboard=
{
dashboard
}
onTypeChanged=
{
this
.
onPluginTypeChanged
}
/>
panel=
{
this
.
props
.
panel
}
panelType=
{
this
.
props
.
panel
.
type
}
dashboard=
{
this
.
props
.
dashboard
}
onTypeChanged=
{
this
.
onPluginTypeChanged
}
pluginExports=
{
pluginExports
}
/>
)
}
)
}
</
div
>
</
div
>
);
);
}
}
render
()
{
render
()
{
const
{
panel
}
=
this
.
props
;
const
{
plugin
}
=
this
.
state
;
if
(
this
.
isSpecial
())
{
if
(
this
.
isSpecial
())
{
return
this
.
specialPanels
[
this
.
props
.
panel
.
type
]();
return
this
.
specialPanels
[
panel
.
type
]();
}
}
if
(
!
this
.
state
.
pluginExports
)
{
// if we have not loaded plugin exports yet, wait
if
(
!
plugin
||
!
plugin
.
exports
)
{
return
null
;
return
null
;
}
}
if
(
this
.
state
.
pluginExports
.
PanelComponent
)
{
// if exporting PanelComponent it must be a react panel
if
(
plugin
.
exports
.
PanelComponent
)
{
return
this
.
renderReactPanel
();
return
this
.
renderReactPanel
();
}
}
...
...
public/app/features/dashboard/dashgrid/PanelEditor.tsx
View file @
5975c4a7
...
@@ -10,13 +10,12 @@ import { updateLocation } from 'app/core/actions';
...
@@ -10,13 +10,12 @@ import { updateLocation } from 'app/core/actions';
import
{
PanelModel
}
from
'../panel_model'
;
import
{
PanelModel
}
from
'../panel_model'
;
import
{
DashboardModel
}
from
'../dashboard_model'
;
import
{
DashboardModel
}
from
'../dashboard_model'
;
import
{
PanelPlugin
,
PluginExports
}
from
'app/types/plugins'
;
import
{
PanelPlugin
}
from
'app/types/plugins'
;
interface
PanelEditorProps
{
interface
PanelEditorProps
{
panel
:
PanelModel
;
panel
:
PanelModel
;
dashboard
:
DashboardModel
;
dashboard
:
DashboardModel
;
panelType
:
string
;
plugin
:
PanelPlugin
;
pluginExports
:
PluginExports
;
onTypeChanged
:
(
newType
:
PanelPlugin
)
=>
void
;
onTypeChanged
:
(
newType
:
PanelPlugin
)
=>
void
;
}
}
...
@@ -44,11 +43,11 @@ export class PanelEditor extends PureComponent<PanelEditorProps> {
...
@@ -44,11 +43,11 @@ export class PanelEditor extends PureComponent<PanelEditorProps> {
}
}
renderPanelOptions
()
{
renderPanelOptions
()
{
const
{
pluginExports
,
panel
}
=
this
.
props
;
const
{
plugin
,
panel
}
=
this
.
props
;
const
{
PanelOptionsComponent
}
=
plugin
.
exports
;
if
(
pluginExports
.
PanelOptionsComponent
)
{
if
(
PanelOptionsComponent
)
{
const
OptionsComponent
=
pluginExports
.
PanelOptionsComponent
;
return
<
PanelOptionsComponent
options=
{
panel
.
getOptions
()
}
onChange=
{
this
.
onPanelOptionsChanged
}
/>;
return
<
OptionsComponent
options=
{
panel
.
getOptions
()
}
onChange=
{
this
.
onPanelOptionsChanged
}
/>;
}
else
{
}
else
{
return
<
p
>
Visualization has no options
</
p
>;
return
<
p
>
Visualization has no options
</
p
>;
}
}
...
@@ -62,7 +61,7 @@ export class PanelEditor extends PureComponent<PanelEditorProps> {
...
@@ -62,7 +61,7 @@ export class PanelEditor extends PureComponent<PanelEditorProps> {
renderVizTab
()
{
renderVizTab
()
{
return
(
return
(
<
div
className=
"viz-editor"
>
<
div
className=
"viz-editor"
>
<
VizTypePicker
current
Type=
{
this
.
props
.
panel
.
type
}
onTypeChanged=
{
this
.
props
.
onTypeChanged
}
/>
<
VizTypePicker
current
=
{
this
.
props
.
plugin
}
onTypeChanged=
{
this
.
props
.
onTypeChanged
}
/>
{
this
.
renderPanelOptions
()
}
{
this
.
renderPanelOptions
()
}
</
div
>
</
div
>
);
);
...
...
public/app/features/dashboard/dashgrid/VizTypePicker.tsx
View file @
5975c4a7
import
React
,
{
PureComponent
}
from
'react'
;
import
React
,
{
PureComponent
}
from
'react'
;
import
classNames
from
'classnames'
;
import
classNames
from
'classnames'
;
import
_
from
'lodash'
;
import
{
FadeIn
}
from
'app/core/components/Animations/FadeIn'
;
import
config
from
'app/core/config'
;
import
config
from
'app/core/config'
;
import
{
PanelPlugin
}
from
'app/types/plugins'
;
import
{
PanelPlugin
}
from
'app/types/plugins'
;
import
CustomScrollbar
from
'app/core/components/CustomScrollbar/CustomScrollbar'
;
import
_
from
'lodash'
;
interface
Props
{
interface
Props
{
current
Type
:
string
;
current
:
PanelPlugin
;
onTypeChanged
:
(
newType
:
PanelPlugin
)
=>
void
;
onTypeChanged
:
(
newType
:
PanelPlugin
)
=>
void
;
}
}
interface
State
{
interface
State
{
pluginList
:
PanelPlugin
[];
pluginList
:
PanelPlugin
[];
isOpen
:
boolean
;
}
}
export
class
VizTypePicker
extends
PureComponent
<
Props
,
State
>
{
export
class
VizTypePicker
extends
PureComponent
<
Props
,
State
>
{
...
@@ -21,6 +22,7 @@ export class VizTypePicker extends PureComponent<Props, State> {
...
@@ -21,6 +22,7 @@ export class VizTypePicker extends PureComponent<Props, State> {
this
.
state
=
{
this
.
state
=
{
pluginList
:
this
.
getPanelPlugins
(
''
),
pluginList
:
this
.
getPanelPlugins
(
''
),
isOpen
:
false
,
};
};
}
}
...
@@ -37,7 +39,7 @@ export class VizTypePicker extends PureComponent<Props, State> {
...
@@ -37,7 +39,7 @@ export class VizTypePicker extends PureComponent<Props, State> {
renderVizPlugin
=
(
plugin
,
index
)
=>
{
renderVizPlugin
=
(
plugin
,
index
)
=>
{
const
cssClass
=
classNames
({
const
cssClass
=
classNames
({
'viz-picker__item'
:
true
,
'viz-picker__item'
:
true
,
'viz-picker__item--selected'
:
plugin
.
id
===
this
.
props
.
current
Type
,
'viz-picker__item--selected'
:
plugin
.
id
===
this
.
props
.
current
.
id
,
});
});
return
(
return
(
...
@@ -55,7 +57,7 @@ export class VizTypePicker extends PureComponent<Props, State> {
...
@@ -55,7 +57,7 @@ export class VizTypePicker extends PureComponent<Props, State> {
<
input
type=
"text"
className=
"gf-form-input width-13"
placeholder=
""
/>
<
input
type=
"text"
className=
"gf-form-input width-13"
placeholder=
""
/>
<
i
className=
"gf-form-input-icon fa fa-search"
/>
<
i
className=
"gf-form-input-icon fa fa-search"
/>
</
label
>
</
label
>
<
div
>
<
div
className=
"p-l-1"
>
<
button
className=
"btn toggle-btn gf-form-btn active"
>
Basic Types
</
button
>
<
button
className=
"btn toggle-btn gf-form-btn active"
>
Basic Types
</
button
>
<
button
className=
"btn toggle-btn gf-form-btn"
>
Master Types
</
button
>
<
button
className=
"btn toggle-btn gf-form-btn"
>
Master Types
</
button
>
</
div
>
</
div
>
...
@@ -63,24 +65,52 @@ export class VizTypePicker extends PureComponent<Props, State> {
...
@@ -63,24 +65,52 @@ export class VizTypePicker extends PureComponent<Props, State> {
);
);
}
}
onToggleOpen
=
()
=>
{
this
.
setState
({
isOpen
:
!
this
.
state
.
isOpen
});
};
render
()
{
render
()
{
const
{
current
Type
}
=
this
.
props
;
const
{
current
}
=
this
.
props
;
const
{
pluginList
}
=
this
.
state
;
const
{
pluginList
,
isOpen
}
=
this
.
state
;
return
(
return
(
<
div
className=
"viz-picker"
>
<
div
className=
"viz-picker"
>
<
div
className=
"viz-picker__bar"
>
<
div
className=
"viz-picker__bar"
>
<
label
className=
"gf-form-label"
>
Visualization
</
label
>
<
div
className=
"gf-form-inline"
>
<
label
className=
"gf-form-input width-10"
>
<
div
className=
"gf-form"
>
<
span
>
{
currentType
}
</
span
>
<
label
className=
"gf-form-label"
>
Visualization
</
label
>
</
label
>
<
label
className=
"gf-form-input width-10"
onClick=
{
this
.
onToggleOpen
}
>
<
div
className=
"gf-form--grow"
/>
<
span
>
{
current
.
name
}
</
span
>
{
this
.
renderFilters
()
}
{
isOpen
&&
<
i
className=
"fa fa-caret-down pull-right"
/>
}
{
!
isOpen
&&
<
i
className=
"fa fa-caret-left pull-right"
/>
}
</
label
>
</
div
>
<
div
className=
"gf-form gf-form--grow"
>
<
label
className=
"gf-form-label gf-form-label--grow"
/>
</
div
>
<
div
className=
"gf-form"
>
<
label
className=
"gf-form-label"
>
<
i
className=
"fa fa-caret-down"
/>
Help
</
label
>
</
div
>
</
div
>
</
div
>
</
div
>
<
CustomScrollbar
>
<
FadeIn
in=
{
isOpen
}
duration=
{
300
}
>
<
div
className=
"viz-picker__items"
>
{
pluginList
.
map
(
this
.
renderVizPlugin
)
}
</
div
>
<
div
className=
"cta-form"
>
</
CustomScrollbar
>
<
button
className=
"cta-form__close"
onClick=
{
this
.
onToggleOpen
}
>
<
i
className=
"fa fa-remove"
/>
</
button
>
<
div
className=
"cta-form__bar"
>
<
div
className=
"cta-form__bar-header"
>
Select visualization
</
div
>
{
this
.
renderFilters
()
}
<
div
className=
"gf-form--grow"
/>
</
div
>
<
div
className=
"viz-picker__items"
>
{
pluginList
.
map
(
this
.
renderVizPlugin
)
}
</
div
>
</
div
>
</
FadeIn
>
</
div
>
</
div
>
);
);
}
}
...
...
public/sass/components/_gf-form.scss
View file @
5975c4a7
...
@@ -410,7 +410,27 @@ select.gf-form-input ~ .gf-form-help-icon {
...
@@ -410,7 +410,27 @@ select.gf-form-input ~ .gf-form-help-icon {
}
}
.cta-form__close
{
.cta-form__close
{
background
:
transparent
;
padding
:
4px
8px
4px
9px
;
border
:
none
;
position
:
absolute
;
position
:
absolute
;
right
:
0
;
right
:
0
;
top
:
0
;
top
:
-2px
;
font-size
:
$font-size-lg
;
&
:hover
{
color
:
$text-color-strong
;
}
}
.cta-form__bar
{
display
:
flex
;
align-items
:
center
;
align-content
:
center
;
margin-bottom
:
20px
;
}
.cta-form__bar-header
{
font-size
:
$font-size-h4
;
padding-right
:
20px
;
}
}
public/sass/components/_viz_editor.scss
View file @
5975c4a7
...
@@ -59,6 +59,7 @@
...
@@ -59,6 +59,7 @@
.viz-picker__items
{
.viz-picker__items
{
display
:
flex
;
display
:
flex
;
flex-wrap
:
wrap
;
// for scrollbar
// for scrollbar
margin-bottom
:
13px
;
margin-bottom
:
13px
;
}
}
...
@@ -68,14 +69,15 @@
...
@@ -68,14 +69,15 @@
box-shadow
:
$card-shadow
;
box-shadow
:
$card-shadow
;
border-radius
:
3px
;
border-radius
:
3px
;
height
:
7
0px
;
height
:
9
0px
;
width
:
1
3
0px
;
width
:
1
5
0px
;
flex-shrink
:
0
;
flex-shrink
:
0
;
flex-direction
:
column
;
flex-direction
:
column
;
text-align
:
center
;
text-align
:
center
;
cursor
:
pointer
;
cursor
:
pointer
;
display
:
flex
;
display
:
flex
;
margin-right
:
6px
;
margin-right
:
10px
;
margin-bottom
:
10px
;
border
:
1px
solid
transparent
;
border
:
1px
solid
transparent
;
align-items
:
center
;
align-items
:
center
;
...
@@ -98,11 +100,11 @@
...
@@ -98,11 +100,11 @@
display
:
flex
;
display
:
flex
;
flex-direction
:
column
;
flex-direction
:
column
;
align-self
:
center
;
align-self
:
center
;
height
:
2
0
px
;
height
:
2
3
px
;
}
}
.viz-picker__item-img
{
.viz-picker__item-img
{
height
:
40
px
;
height
:
55
px
;
}
}
.panel-editor__aside
{
.panel-editor__aside
{
...
@@ -162,7 +164,6 @@
...
@@ -162,7 +164,6 @@
}
}
.viz-picker__bar
{
.viz-picker__bar
{
display
:
flex
;
margin-bottom
:
$spacer
;
margin-bottom
:
$spacer
;
}
}
...
...
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