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
a7daf58b
Commit
a7daf58b
authored
Nov 09, 2018
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
wip: progress on edit mode ux with tabs
parent
8a9d721c
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
293 additions
and
240 deletions
+293
-240
public/app/core/components/CustomScrollbar/CustomScrollbar.tsx
+1
-1
public/app/features/dashboard/dashgrid/EditorTabBody.tsx
+84
-0
public/app/features/dashboard/dashgrid/PanelEditor.tsx
+18
-128
public/app/features/dashboard/dashgrid/QueriesTab.tsx
+16
-1
public/app/features/dashboard/dashgrid/VisualizationTab.tsx
+56
-0
public/app/features/dashboard/dashgrid/VizTypePicker.tsx
+8
-44
public/app/features/panel/partials/metrics_tab.html
+1
-1
public/sass/components/_dashboard_grid.scss
+4
-0
public/sass/components/_gf-form.scss
+1
-1
public/sass/components/_viz_editor.scss
+104
-64
No files found.
public/app/core/components/CustomScrollbar/CustomScrollbar.tsx
View file @
a7daf58b
...
...
@@ -15,7 +15,7 @@ interface Props {
class
CustomScrollbar
extends
PureComponent
<
Props
>
{
static
defaultProps
:
Partial
<
Props
>
=
{
customClassName
:
'custom-scrollbars'
,
autoHide
:
tru
e
,
autoHide
:
fals
e
,
autoHideTimeout
:
200
,
autoHideDuration
:
200
,
hideTracksWhenNotNeeded
:
false
,
...
...
public/app/features/dashboard/dashgrid/EditorTabBody.tsx
0 → 100644
View file @
a7daf58b
import
React
,
{
PureComponent
}
from
'react'
;
import
CustomScrollbar
from
'app/core/components/CustomScrollbar/CustomScrollbar'
;
import
{
FadeIn
}
from
'app/core/components/Animations/FadeIn'
;
interface
Props
{
selectedText
?:
string
;
selectedImage
?:
string
;
children
:
JSX
.
Element
;
toolbarItems
:
EditorToolBarView
[];
}
export
interface
EditorToolBarView
{
title
:
string
;
imgSrc
:
string
;
render
:
()
=>
JSX
.
Element
;
}
interface
State
{
openView
?:
EditorToolBarView
;
}
export
class
EditorTabBody
extends
PureComponent
<
Props
,
State
>
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
openView
:
null
,
};
}
onToggleToolBarView
=
(
item
:
EditorToolBarView
)
=>
{
this
.
setState
({
openView
:
item
===
this
.
state
.
openView
?
null
:
item
,
});
}
onCloseOpenView
=
()
=>
{
this
.
setState
({
openView
:
null
});
}
renderToolBarViewToggle
(
item
:
EditorToolBarView
)
{
return
(
<
div
className=
"edit-section__selected"
onClick=
{
()
=>
this
.
onToggleToolBarView
(
item
)
}
key=
{
item
.
title
}
>
<
img
className=
"edit-section__selected-image"
src=
{
item
.
imgSrc
}
/>
<
div
className=
"edit-section__selected-name"
>
{
item
.
title
}
</
div
>
<
i
className=
"fa fa-caret-down"
/>
</
div
>
);
}
renderOpenView
(
view
:
EditorToolBarView
)
{
return
(
<
div
className=
"editor-toolbar-view"
>
<
button
className=
"editor-toolbar-view__close"
onClick=
{
this
.
onCloseOpenView
}
>
<
i
className=
"fa fa-remove"
/>
</
button
>
{
view
.
render
()
}
</
div
>
);
}
render
()
{
const
{
children
,
toolbarItems
}
=
this
.
props
;
const
{
openView
}
=
this
.
state
;
return
(
<>
<
div
className=
"edit-section"
>
<
div
className=
"edit-section__header"
>
{
toolbarItems
.
map
(
item
=>
this
.
renderToolBarViewToggle
(
item
))
}
</
div
>
</
div
>
<
div
className=
"panel-editor__scroll"
>
<
CustomScrollbar
>
<
div
className=
"panel-editor__content"
>
<
FadeIn
in=
{
openView
!==
null
}
duration=
{
300
}
>
{
openView
&&
this
.
renderOpenView
(
openView
)
}
</
FadeIn
>
{
children
}
</
div
>
</
CustomScrollbar
>
</
div
>
</>
);
}
}
public/app/features/dashboard/dashgrid/PanelEditor.tsx
View file @
a7daf58b
...
...
@@ -2,8 +2,7 @@ import React, { PureComponent } from 'react';
import
classNames
from
'classnames'
;
import
{
QueriesTab
}
from
'./QueriesTab'
;
import
{
VizTypePicker
}
from
'./VizTypePicker'
;
import
CustomScrollbar
from
'app/core/components/CustomScrollbar/CustomScrollbar'
;
import
{
VisualizationTab
}
from
'./VisualizationTab'
;
import
{
store
}
from
'app/store/configureStore'
;
import
{
updateLocation
}
from
'app/core/actions'
;
...
...
@@ -38,35 +37,6 @@ export class PanelEditor extends PureComponent<PanelEditorProps> {
];
}
renderQueriesTab
()
{
return
<
QueriesTab
panel=
{
this
.
props
.
panel
}
dashboard=
{
this
.
props
.
dashboard
}
/>;
}
renderPanelOptions
()
{
const
{
plugin
,
panel
}
=
this
.
props
;
const
{
PanelOptionsComponent
}
=
plugin
.
exports
;
if
(
PanelOptionsComponent
)
{
return
<
PanelOptionsComponent
options=
{
panel
.
getOptions
()
}
onChange=
{
this
.
onPanelOptionsChanged
}
/>;
}
else
{
return
<
p
>
Visualization has no options
</
p
>;
}
}
onPanelOptionsChanged
=
(
options
:
any
)
=>
{
this
.
props
.
panel
.
updateOptions
(
options
);
this
.
forceUpdate
();
};
renderVizTab
()
{
return
(
<
div
className=
"viz-editor"
>
<
VizTypePicker
current=
{
this
.
props
.
plugin
}
onTypeChanged=
{
this
.
props
.
onTypeChanged
}
/>
{
this
.
renderPanelOptions
()
}
</
div
>
);
}
onChangeTab
=
(
tab
:
PanelEditorTab
)
=>
{
store
.
dispatch
(
updateLocation
({
...
...
@@ -87,50 +57,8 @@ export class PanelEditor extends PureComponent<PanelEditorProps> {
};
render
()
{
return
this
.
renderAsTabs
();
// return this.renderAsBoxes();
// const { location } = store.getState();
// const activeTab = location.query.tab || 'queries';
//
// return (
// <div className="panel-editor-container__editor">
// <div className="panel-editor-resizer">
// <div className="panel-editor-resizer__handle">
// <div className="panel-editor-resizer__handle-dots" />
// </div>
// </div>
// <div className="panel-editor__aside">
// <h2 className="panel-editor__aside-header">
// <i className="fa fa-cog" />
// Edit Panel
// </h2>
//
// {this.tabs.map(tab => {
// return <TabItem tab={tab} activeTab={activeTab} onClick={this.onChangeTab} key={tab.id} />;
// })}
//
// <div className="panel-editor__aside-actions">
// <button className="btn btn-secondary" onClick={this.onClose}>
// Back to dashboard
// </button>
// <button className="btn btn-inverse" onClick={this.onClose}>
// Discard changes
// </button>
// </div>
// </div>
// <div className="panel-editor__content">
// <CustomScrollbar>
// {activeTab === 'queries' && this.renderQueriesTab()}
// {activeTab === 'visualization' && this.renderVizTab()}
// </CustomScrollbar>
// </div>
// </div>
// );
}
renderAsTabs
()
{
const
{
panel
,
dashboard
,
onTypeChanged
,
plugin
}
=
this
.
props
;
const
{
location
}
=
store
.
getState
();
const
{
panel
}
=
this
.
props
;
const
activeTab
=
location
.
query
.
tab
||
'queries'
;
return
(
...
...
@@ -141,49 +69,22 @@ export class PanelEditor extends PureComponent<PanelEditorProps> {
</
div
>
</
div
>
<
div
className=
"tabbed-view tabbed-view--new"
>
<
div
className=
"tabbed-view-header"
>
<
h3
className=
"tabbed-view-panel-title"
>
{
panel
.
title
}
</
h3
>
<
ul
className=
"gf-tabs"
>
{
this
.
tabs
.
map
(
tab
=>
{
return
<
OldTabItem
tab=
{
tab
}
activeTab=
{
activeTab
}
onClick=
{
this
.
onChangeTab
}
key=
{
tab
.
id
}
/>;
})
}
</
ul
>
<
div
className=
"panel-editor-tabs"
>
<
ul
className=
"gf-tabs"
>
{
this
.
tabs
.
map
(
tab
=>
{
return
<
TabItem
tab=
{
tab
}
activeTab=
{
activeTab
}
onClick=
{
this
.
onChangeTab
}
key=
{
tab
.
id
}
/>;
})
}
</
ul
>
<
button
className=
"tabbed-view-close-btn"
onClick=
{
this
.
onClose
}
>
<
i
className=
"fa fa-remove"
/>
</
button
>
</
div
>
<
div
className=
"tabbed-view-body"
>
<
CustomScrollbar
>
{
activeTab
===
'queries'
&&
this
.
renderQueriesTab
()
}
{
activeTab
===
'visualization'
&&
this
.
renderVizTab
()
}
</
CustomScrollbar
>
</
div
>
</
div
>
</
div
>
);
}
renderAsBoxes
()
{
const
{
location
}
=
store
.
getState
();
const
{
panel
}
=
this
.
props
;
const
activeTab
=
location
.
query
.
tab
||
'queries'
;
return
(
<
div
className=
"panel-editor-container__editor"
>
<
div
className=
"panel-editor-resizer"
>
<
div
className=
"panel-editor-resizer__handle"
>
<
div
className=
"panel-editor-resizer__handle-dots"
/>
</
div
>
<
button
className=
"panel-editor-tabs__close"
onClick=
{
this
.
onClose
}
>
<
i
className=
"fa fa-remove"
/>
</
button
>
</
div
>
<
CustomScrollbar
>
{
this
.
renderQueriesTab
()
}
{
this
.
renderVizTab
()
}
</
CustomScrollbar
>
{
activeTab
===
'queries'
&&
<
QueriesTab
panel=
{
panel
}
dashboard=
{
dashboard
}
/>
}
{
activeTab
===
'visualization'
&&
(
<
VisualizationTab
panel=
{
panel
}
dashboard=
{
dashboard
}
plugin=
{
plugin
}
onTypeChanged=
{
onTypeChanged
}
/>
)
}
</
div
>
);
}
...
...
@@ -197,26 +98,15 @@ interface TabItemParams {
function
TabItem
({
tab
,
activeTab
,
onClick
}:
TabItemParams
)
{
const
tabClasses
=
classNames
({
'panel-editor__aside-item'
:
true
,
active
:
activeTab
===
tab
.
id
,
});
return
(
<
a
className=
{
tabClasses
}
onClick=
{
()
=>
onClick
(
tab
)
}
>
<
i
className=
{
tab
.
icon
}
/>
{
tab
.
text
}
</
a
>
);
}
function
OldTabItem
({
tab
,
activeTab
,
onClick
}:
TabItemParams
)
{
const
tabClasses
=
classNames
({
'gf-tabs-link'
:
true
,
active
:
activeTab
===
tab
.
id
,
});
return
(
<
li
className=
"gf-tabs-item"
onClick=
{
()
=>
onClick
(
tab
)
}
>
<
a
className=
{
tabClasses
}
>
{
tab
.
text
}
</
a
>
<
a
className=
{
tabClasses
}
>
<
i
className=
{
tab
.
icon
}
/>
{
tab
.
text
}
</
a
>
</
li
>
);
}
public/app/features/dashboard/dashgrid/QueriesTab.tsx
View file @
a7daf58b
...
...
@@ -3,6 +3,7 @@ import React, { PureComponent } from 'react';
// Services & utils
import
{
getAngularLoader
,
AngularComponent
}
from
'app/core/services/AngularLoader'
;
import
{
EditorTabBody
}
from
'./EditorTabBody'
;
// Types
import
{
PanelModel
}
from
'../panel_model'
;
...
...
@@ -48,6 +49,20 @@ export class QueriesTab extends PureComponent<Props> {
}
render
()
{
return
<
div
ref=
{
element
=>
(
this
.
element
=
element
)
}
className=
"panel-height-helper"
/>;
const
currentDataSource
=
{
title
:
'ProductionDB'
,
imgSrc
:
'public/app/plugins/datasource/prometheus/img/prometheus_logo.svg'
,
render
:
()
=>
{
return
(
<
h2
>
Hello
</
h2
>
);
},
};
return
(
<
EditorTabBody
toolbarItems=
{
[
currentDataSource
]
}
>
<
div
ref=
{
element
=>
(
this
.
element
=
element
)
}
style=
{
{
width
:
'100%'
}
}
/>
</
EditorTabBody
>
);
}
}
public/app/features/dashboard/dashgrid/VisualizationTab.tsx
0 → 100644
View file @
a7daf58b
import
React
,
{
PureComponent
}
from
'react'
;
import
{
getAngularLoader
,
AngularComponent
}
from
'app/core/services/AngularLoader'
;
import
{
EditorTabBody
}
from
'./EditorTabBody'
;
import
{
VizTypePicker
}
from
'./VizTypePicker'
;
import
{
PanelModel
}
from
'../panel_model'
;
import
{
DashboardModel
}
from
'../dashboard_model'
;
interface
Props
{
panel
:
PanelModel
;
dashboard
:
DashboardModel
;
plugin
:
PluginModel
;
onTypeChanged
:
(
newType
:
PanelPlugin
)
=>
void
;
}
export
class
VisualizationTab
extends
PureComponent
<
Props
>
{
constructor
(
props
)
{
super
(
props
);
}
renderPanelOptions
()
{
const
{
plugin
,
panel
}
=
this
.
props
;
const
{
PanelOptionsComponent
}
=
plugin
.
exports
;
if
(
PanelOptionsComponent
)
{
return
<
PanelOptionsComponent
options=
{
panel
.
getOptions
()
}
onChange=
{
this
.
onPanelOptionsChanged
}
/>;
}
else
{
return
<
p
>
Visualization has no options
</
p
>;
}
}
onPanelOptionsChanged
=
(
options
:
any
)
=>
{
this
.
props
.
panel
.
updateOptions
(
options
);
this
.
forceUpdate
();
};
render
()
{
const
{
plugin
,
onTypeChanged
}
=
this
.
props
;
const
panelSelection
=
{
title
:
plugin
.
name
,
imgSrc
:
plugin
.
info
.
logos
.
small
,
render
:
()
=>
{
return
<
VizTypePicker
current=
{
plugin
}
onTypeChanged=
{
onTypeChanged
}
/>;
},
};
return
(
<
EditorTabBody
toolbarItems=
{
[
panelSelection
]
}
>
{
this
.
renderPanelOptions
()
}
</
EditorTabBody
>
);
}
}
public/app/features/dashboard/dashgrid/VizTypePicker.tsx
View file @
a7daf58b
...
...
@@ -2,7 +2,6 @@ import React, { PureComponent } from 'react';
import
classNames
from
'classnames'
;
import
_
from
'lodash'
;
import
{
FadeIn
}
from
'app/core/components/Animations/FadeIn'
;
import
config
from
'app/core/config'
;
import
{
PanelPlugin
}
from
'app/types/plugins'
;
...
...
@@ -13,7 +12,6 @@ interface Props {
interface
State
{
pluginList
:
PanelPlugin
[];
isOpen
:
boolean
;
}
export
class
VizTypePicker
extends
PureComponent
<
Props
,
State
>
{
...
...
@@ -22,7 +20,6 @@ export class VizTypePicker extends PureComponent<Props, State> {
this
.
state
=
{
pluginList
:
this
.
getPanelPlugins
(
''
),
isOpen
:
false
,
};
}
...
...
@@ -65,53 +62,20 @@ export class VizTypePicker extends PureComponent<Props, State> {
);
}
onToggleOpen
=
()
=>
{
this
.
setState
({
isOpen
:
!
this
.
state
.
isOpen
});
};
render
()
{
const
{
current
}
=
this
.
props
;
const
{
pluginList
,
isOpen
}
=
this
.
state
;
const
{
pluginList
}
=
this
.
state
;
return
(
<
div
className=
"viz-picker"
>
<
div
className=
"viz-picker__bar"
>
<
div
className=
"gf-form-inline"
>
<
div
className=
"gf-form"
>
<
label
className=
"gf-form-label"
>
Visualization
</
label
>
<
label
className=
"gf-form-input width-10"
onClick=
{
this
.
onToggleOpen
}
>
<
span
>
{
current
.
name
}
</
span
>
{
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-fw fa-caret-down"
/>
Help
</
label
>
</
div
>
</
div
>
<>
<
div
className=
"cta-form__bar"
>
<
div
className=
"cta-form__bar-header"
>
Select visualization
</
div
>
{
this
.
renderFilters
()
}
<
div
className=
"gf-form--grow"
/>
</
div
>
<
FadeIn
in=
{
isOpen
}
duration=
{
300
}
>
<
div
className=
"cta-form"
>
<
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
className=
"viz-picker__items"
>
{
pluginList
.
map
(
this
.
renderVizPlugin
)
}
</
div
>
</>
);
}
}
public/app/features/panel/partials/metrics_tab.html
View file @
a7daf58b
<div
class=
"gf-form-group"
>
<div
class=
"gf-form-group
hide
"
>
<div
class=
"gf-form-inline"
>
<div
class=
"gf-form"
>
<label
class=
"gf-form-label"
>
Data Source
</label>
...
...
public/sass/components/_dashboard_grid.scss
View file @
a7daf58b
...
...
@@ -19,6 +19,10 @@
transform
:
translate
(
0px
,
0px
)
!
important
;
}
.panel
{
margin
:
0
!
important
;
}
// Disable grid interaction indicators in fullscreen panels
.panel-header
:hover
{
background-color
:
inherit
;
...
...
public/sass/components/_gf-form.scss
View file @
a7daf58b
...
...
@@ -416,7 +416,7 @@ select.gf-form-input ~ .gf-form-help-icon {
position
:
absolute
;
right
:
0
;
top
:
-2px
;
font-size
:
$font-size-
lg
;
font-size
:
$font-size-
md
;
&
:hover
{
color
:
$text-color-strong
;
...
...
public/sass/components/_viz_editor.scss
View file @
a7daf58b
...
...
@@ -11,16 +11,20 @@
.panel-editor-container__editor
{
margin-top
:
$panel-margin
*
2
;
display
:
flex
;
flex-direction
:
row
;
flex-direction
:
column
;
height
:
65%
;
position
:
relative
;
}
.panel-editor__
content
{
.panel-editor__
scroll
{
flex-grow
:
1
;
min-width
:
0
;
height
:
100%
;
padding
:
0
20px
;
display
:
flex
;
padding
:
0
5px
;
}
.panel-editor__content
{
padding
:
40px
15px
;
}
.panel-in-fullscreen
{
...
...
@@ -107,66 +111,6 @@
height
:
55px
;
}
.panel-editor__aside
{
background
:
$panel-bg
;
display
:
flex
;
flex-direction
:
column
;
}
.panel-editor__aside-item
{
padding
:
8px
20px
;
color
:
$text-color
;
font-size
:
$font-size-md
;
@include
left-brand-border
;
&
.active
{
@include
left-brand-border-gradient
();
background
:
$page-bg
;
}
i
{
width
:
23px
;
}
.gicon
{
margin-bottom
:
2px
;
}
.fa
{
font-size
:
17px
;
}
}
.panel-editor__aside-actions
{
display
:
flex
;
flex-direction
:
column
;
height
:
100%
;
flex-grow
:
1
;
padding
:
60px
15px
;
button
{
margin-bottom
:
10px
;
}
}
.panel-editor__aside-header
{
color
:
$text-muted
;
font-size
:
$font-size-h3
;
padding
:
20px
30px
10px
20px
;
white-space
:
nowrap
;
i
{
font-size
:
25px
;
position
:
relative
;
top
:
1px
;
padding-right
:
5px
;
}
}
.viz-picker__bar
{
margin-bottom
:
$spacer
;
}
.panel-editor-resizer
{
position
:
absolute
;
height
:
2px
;
...
...
@@ -223,3 +167,99 @@
font-size
:
$font-size-lg
;
margin-bottom
:
20px
;
}
.edit-section
{
position
:
relative
;
}
.edit-section__header
{
display
:
flex
;
align-content
:
center
;
align-items
:
center
;
background
:
linear-gradient
(
90deg
,
#292a2d
,
black
);
padding
:
7px
30px
7px
20px
;
box-shadow
:
0
0
20px
black
;
cursor
:
pointer
;
}
.edit-section__selected
{
padding
:
$input-padding-y
$input-padding-x
;
font-size
:
$font-size-md
;
line-height
:
$input-line-height
;
color
:
$input-color
;
background-color
:
$input-bg
;
border
:
$input-border
;
border-radius
:
$input-border-radius
;
display
:
flex
;
align-items
:
center
;
.fa
{
margin-left
:
20px
;
display
:
inline-block
;
position
:
relative
;
}
}
.edit-section__title
{
font-size
:
$font-size-lg
;
padding-right
:
20px
;
width
:
150px
;
}
.edit-section__selected-image
{
margin-right
:
10px
;
display
:
inline-block
;
width
:
20px
;
height
:
20px
;
}
.panel-editor-tabs
{
z-index
:
1
;
box-shadow
:
$page-header-shadow
;
border-bottom
:
1px
solid
$page-header-border-color
;
padding
:
0
$dashboard-padding
;
@include
clearfix
();
.active.gf-tabs-link
{
background
:
#242427
;
}
}
.panel-editor-tabs__close
{
float
:
right
;
padding
:
0
;
margin
:
0
;
background-color
:
transparent
;
border
:
none
;
padding
:
$tabs-padding
;
color
:
$text-color
;
i
{
font-size
:
120%
;
}
&
:hover
{
color
:
$text-color-strong
;
}
}
.editor-toolbar-view
{
position
:
relative
;
padding
:
10px
20px
;
background-color
:
$empty-list-cta-bg
;
border-top
:
3px
solid
$orange
;
margin
:
0
100px
;
}
.editor-toolbar-view__close
{
background
:
transparent
;
padding
:
4px
8px
4px
9px
;
border
:
none
;
position
:
absolute
;
right
:
0
;
top
:
-2px
;
font-size
:
$font-size-md
;
&
:hover
{
color
:
$text-color-strong
;
}
}
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