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
fd409f11
Unverified
Commit
fd409f11
authored
Apr 18, 2018
by
Marcus Efraimsson
Committed by
GitHub
Apr 18, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #10986 from grafana/10427_addpanel_filter
add tabs and search filter to new panel control
parents
0ad63366
606257a1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
268 additions
and
22 deletions
+268
-22
public/app/core/components/ScrollBar/ScrollBar.tsx
+4
-0
public/app/features/dashboard/dashgrid/AddPanelPanel.tsx
+134
-9
public/app/features/dashboard/specs/AddPanelPanel.jest.tsx
+102
-0
public/app/features/panel/panel_ctrl.ts
+4
-4
public/sass/components/_panel_add_panel.scss
+19
-2
public/sass/components/_tabs.scss
+5
-7
No files found.
public/app/core/components/ScrollBar/ScrollBar.tsx
View file @
fd409f11
...
...
@@ -54,6 +54,10 @@ export default class ScrollBar extends React.Component<Props, any> {
return
false
;
}
update
()
{
this
.
scrollbar
.
update
();
}
handleRef
=
ref
=>
{
this
.
container
=
ref
;
};
...
...
public/app/features/dashboard/dashgrid/AddPanelPanel.tsx
View file @
fd409f11
import
React
from
'react'
;
import
_
from
'lodash'
;
import
classNames
from
'classnames'
;
import
config
from
'app/core/config'
;
import
{
PanelModel
}
from
'../panel_model'
;
import
{
PanelContainer
}
from
'./PanelContainer'
;
import
ScrollBar
from
'app/core/components/ScrollBar/ScrollBar'
;
import
store
from
'app/core/store'
;
import
{
LS_PANEL_COPY_KEY
}
from
'app/core/constants'
;
import
Highlighter
from
'react-highlight-words'
;
export
interface
AddPanelPanelProps
{
panel
:
PanelModel
;
...
...
@@ -16,21 +17,42 @@ export interface AddPanelPanelProps {
export
interface
AddPanelPanelState
{
filter
:
string
;
panelPlugins
:
any
[];
copiedPanelPlugins
:
any
[];
tab
:
string
;
}
export
class
AddPanelPanel
extends
React
.
Component
<
AddPanelPanelProps
,
AddPanelPanelState
>
{
private
scrollbar
:
ScrollBar
;
constructor
(
props
)
{
super
(
props
);
this
.
handleCloseAddPanel
=
this
.
handleCloseAddPanel
.
bind
(
this
);
this
.
renderPanelItem
=
this
.
renderPanelItem
.
bind
(
this
);
this
.
panelSizeChanged
=
this
.
panelSizeChanged
.
bind
(
this
);
this
.
state
=
{
panelPlugins
:
this
.
getPanelPlugins
(),
panelPlugins
:
this
.
getPanelPlugins
(
''
),
copiedPanelPlugins
:
this
.
getCopiedPanelPlugins
(
''
),
filter
:
''
,
tab
:
'Add'
,
};
}
getPanelPlugins
()
{
componentDidMount
()
{
this
.
props
.
panel
.
events
.
on
(
'panel-size-changed'
,
this
.
panelSizeChanged
);
}
componentWillUnmount
()
{
this
.
props
.
panel
.
events
.
off
(
'panel-size-changed'
,
this
.
panelSizeChanged
);
}
panelSizeChanged
()
{
setTimeout
(()
=>
{
this
.
scrollbar
.
update
();
});
}
getPanelPlugins
(
filter
)
{
let
panels
=
_
.
chain
(
config
.
panels
)
.
filter
({
hideFromList
:
false
})
.
map
(
item
=>
item
)
...
...
@@ -39,6 +61,19 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
// add special row type
panels
.
push
({
id
:
'row'
,
name
:
'Row'
,
sort
:
8
,
info
:
{
logos
:
{
small
:
'public/img/icn-row.svg'
}
}
});
panels
=
this
.
filterPanels
(
panels
,
filter
);
// add sort by sort property
return
_
.
sortBy
(
panels
,
'sort'
);
}
getCopiedPanelPlugins
(
filter
)
{
let
panels
=
_
.
chain
(
config
.
panels
)
.
filter
({
hideFromList
:
false
})
.
map
(
item
=>
item
)
.
value
();
let
copiedPanels
=
[];
let
copiedPanelJson
=
store
.
get
(
LS_PANEL_COPY_KEY
);
if
(
copiedPanelJson
)
{
let
copiedPanel
=
JSON
.
parse
(
copiedPanelJson
);
...
...
@@ -48,12 +83,13 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
pluginCopy
.
name
=
copiedPanel
.
title
;
pluginCopy
.
sort
=
-
1
;
pluginCopy
.
defaults
=
copiedPanel
;
p
anels
.
push
(
pluginCopy
);
copiedP
anels
.
push
(
pluginCopy
);
}
}
// add sort by sort property
return
_
.
sortBy
(
panels
,
'sort'
);
copiedPanels
=
this
.
filterPanels
(
copiedPanels
,
filter
);
return
_
.
sortBy
(
copiedPanels
,
'sort'
);
}
onAddPanel
=
panelPluginInfo
=>
{
...
...
@@ -92,28 +128,117 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
dashboard
.
removePanel
(
dashboard
.
panels
[
0
]);
}
renderText
(
text
:
string
)
{
let
searchWords
=
this
.
state
.
filter
.
split
(
''
);
return
<
Highlighter
highlightClassName=
"highlight-search-match"
textToHighlight=
{
text
}
searchWords=
{
searchWords
}
/>;
}
renderPanelItem
(
panel
,
index
)
{
return
(
<
div
key=
{
index
}
className=
"add-panel__item"
onClick=
{
()
=>
this
.
onAddPanel
(
panel
)
}
title=
{
panel
.
name
}
>
<
img
className=
"add-panel__item-img"
src=
{
panel
.
info
.
logos
.
small
}
/>
<
div
className=
"add-panel__item-name"
>
{
panel
.
name
}
</
div
>
<
div
className=
"add-panel__item-name"
>
{
this
.
renderText
(
panel
.
name
)
}
</
div
>
</
div
>
);
}
noCopiedPanelPlugins
()
{
return
<
div
className=
"add-panel__no-panels"
>
No copied panels yet.
</
div
>;
}
filterChange
(
evt
)
{
this
.
setState
({
filter
:
evt
.
target
.
value
,
panelPlugins
:
this
.
getPanelPlugins
(
evt
.
target
.
value
),
copiedPanelPlugins
:
this
.
getCopiedPanelPlugins
(
evt
.
target
.
value
),
});
}
filterPanels
(
panels
,
filter
)
{
let
regex
=
new
RegExp
(
filter
,
'i'
);
return
panels
.
filter
(
panel
=>
{
return
regex
.
test
(
panel
.
name
);
});
}
openCopy
()
{
this
.
setState
({
tab
:
'Copy'
,
filter
:
''
,
panelPlugins
:
this
.
getPanelPlugins
(
''
),
copiedPanelPlugins
:
this
.
getCopiedPanelPlugins
(
''
),
});
}
openAdd
()
{
this
.
setState
({
tab
:
'Add'
,
filter
:
''
,
panelPlugins
:
this
.
getPanelPlugins
(
''
),
copiedPanelPlugins
:
this
.
getCopiedPanelPlugins
(
''
),
});
}
render
()
{
let
addClass
=
classNames
({
'active active--panel'
:
this
.
state
.
tab
===
'Add'
,
''
:
this
.
state
.
tab
===
'Copy'
,
});
let
copyClass
=
classNames
({
''
:
this
.
state
.
tab
===
'Add'
,
'active active--panel'
:
this
.
state
.
tab
===
'Copy'
,
});
let
panelTab
;
if
(
this
.
state
.
tab
===
'Add'
)
{
panelTab
=
this
.
state
.
panelPlugins
.
map
(
this
.
renderPanelItem
);
}
else
if
(
this
.
state
.
tab
===
'Copy'
)
{
if
(
this
.
state
.
copiedPanelPlugins
.
length
>
0
)
{
panelTab
=
this
.
state
.
copiedPanelPlugins
.
map
(
this
.
renderPanelItem
);
}
else
{
panelTab
=
this
.
noCopiedPanelPlugins
();
}
}
return
(
<
div
className=
"panel-container add-panel-container"
>
<
div
className=
"add-panel"
>
<
div
className=
"add-panel__header"
>
<
i
className=
"gicon gicon-add-panel"
/>
<
span
className=
"add-panel__title"
>
New Panel
</
span
>
<
span
className=
"add-panel__sub-title"
>
Select a visualization
</
span
>
<
ul
className=
"gf-tabs"
>
<
li
className=
"gf-tabs-item"
>
<
div
className=
{
'gf-tabs-link pointer '
+
addClass
}
onClick=
{
this
.
openAdd
.
bind
(
this
)
}
>
Add
</
div
>
</
li
>
<
li
className=
"gf-tabs-item"
>
<
div
className=
{
'gf-tabs-link pointer '
+
copyClass
}
onClick=
{
this
.
openCopy
.
bind
(
this
)
}
>
Paste
</
div
>
</
li
>
</
ul
>
<
button
className=
"add-panel__close"
onClick=
{
this
.
handleCloseAddPanel
}
>
<
i
className=
"fa fa-close"
/>
</
button
>
</
div
>
<
ScrollBar
className=
"add-panel__items"
>
{
this
.
state
.
panelPlugins
.
map
(
this
.
renderPanelItem
)
}
</
ScrollBar
>
<
ScrollBar
ref=
{
element
=>
(
this
.
scrollbar
=
element
)
}
className=
"add-panel__items"
>
<
div
className=
"add-panel__searchbar"
>
<
label
className=
"gf-form gf-form--grow gf-form--has-input-icon"
>
<
input
type=
"text"
className=
"gf-form-input max-width-20"
placeholder=
"Panel Search Filter"
value=
{
this
.
state
.
filter
}
onChange=
{
this
.
filterChange
.
bind
(
this
)
}
/>
<
i
className=
"gf-form-input-icon fa fa-search"
/>
</
label
>
</
div
>
{
panelTab
}
</
ScrollBar
>
</
div
>
</
div
>
);
...
...
public/app/features/dashboard/specs/AddPanelPanel.jest.tsx
0 → 100644
View file @
fd409f11
import
React
from
'react'
;
import
{
AddPanelPanel
}
from
'./../dashgrid/AddPanelPanel'
;
import
{
PanelModel
}
from
'../panel_model'
;
import
{
shallow
}
from
'enzyme'
;
import
config
from
'../../../core/config'
;
jest
.
mock
(
'app/core/store'
,
()
=>
({
get
:
key
=>
{
return
null
;
},
delete
:
key
=>
{
return
null
;
},
}));
describe
(
'AddPanelPanel'
,
()
=>
{
let
wrapper
,
dashboardMock
,
getPanelContainer
,
panel
;
beforeEach
(()
=>
{
config
.
panels
=
[
{
id
:
'singlestat'
,
hideFromList
:
false
,
name
:
'Singlestat'
,
sort
:
2
,
info
:
{
logos
:
{
small
:
''
,
},
},
},
{
id
:
'hidden'
,
hideFromList
:
true
,
name
:
'Hidden'
,
sort
:
100
,
info
:
{
logos
:
{
small
:
''
,
},
},
},
{
id
:
'graph'
,
hideFromList
:
false
,
name
:
'Graph'
,
sort
:
1
,
info
:
{
logos
:
{
small
:
''
,
},
},
},
{
id
:
'alexander_zabbix'
,
hideFromList
:
false
,
name
:
'Zabbix'
,
sort
:
100
,
info
:
{
logos
:
{
small
:
''
,
},
},
},
{
id
:
'piechart'
,
hideFromList
:
false
,
name
:
'Piechart'
,
sort
:
100
,
info
:
{
logos
:
{
small
:
''
,
},
},
},
];
dashboardMock
=
{
toggleRow
:
jest
.
fn
()
};
getPanelContainer
=
jest
.
fn
().
mockReturnValue
({
getDashboard
:
jest
.
fn
().
mockReturnValue
(
dashboardMock
),
getPanelLoader
:
jest
.
fn
(),
});
panel
=
new
PanelModel
({
collapsed
:
false
});
wrapper
=
shallow
(<
AddPanelPanel
panel=
{
panel
}
getPanelContainer=
{
getPanelContainer
}
/>);
});
it
(
'should fetch all panels sorted with core plugins first'
,
()
=>
{
//console.log(wrapper.debug());
//console.log(wrapper.find('.add-panel__item').get(0).props.title);
expect
(
wrapper
.
find
(
'.add-panel__item'
).
get
(
1
).
props
.
title
).
toBe
(
'Singlestat'
);
expect
(
wrapper
.
find
(
'.add-panel__item'
).
get
(
4
).
props
.
title
).
toBe
(
'Piechart'
);
});
it
(
'should filter'
,
()
=>
{
wrapper
.
find
(
'input'
).
simulate
(
'change'
,
{
target
:
{
value
:
'p'
}
});
expect
(
wrapper
.
find
(
'.add-panel__item'
).
get
(
1
).
props
.
title
).
toBe
(
'Piechart'
);
expect
(
wrapper
.
find
(
'.add-panel__item'
).
get
(
0
).
props
.
title
).
toBe
(
'Graph'
);
});
});
public/app/features/panel/panel_ctrl.ts
View file @
fd409f11
...
...
@@ -194,8 +194,8 @@ export class PanelCtrl {
});
menu
.
push
({
text
:
'
Add to Panel List
'
,
click
:
'ctrl.
addToPanelList
()'
,
text
:
'
Copy
'
,
click
:
'ctrl.
copyPanel
()'
,
role
:
'Editor'
,
});
}
...
...
@@ -260,9 +260,9 @@ export class PanelCtrl {
});
}
addToPanelList
()
{
copyPanel
()
{
store
.
set
(
LS_PANEL_COPY_KEY
,
JSON
.
stringify
(
this
.
panel
.
getSaveModel
()));
appEvents
.
emit
(
'alert-success'
,
[
'Panel
temporarily added to panel list
'
]);
appEvents
.
emit
(
'alert-success'
,
[
'Panel
copied. Open Add Panel to paste
'
]);
}
replacePanel
(
newPanel
,
oldPanel
)
{
...
...
public/sass/components/_panel_add_panel.scss
View file @
fd409f11
...
...
@@ -11,9 +11,12 @@
}
.add-panel__header
{
padding
:
5px
15px
;
padding
:
0
15px
;
display
:
flex
;
align-items
:
center
;
background
:
$page-header-bg
;
box-shadow
:
$page-header-shadow
;
border-bottom
:
1px
solid
$page-header-border-color
;
.gicon
{
font-size
:
30px
;
...
...
@@ -31,7 +34,7 @@
.add-panel__title
{
font-size
:
$font-size-md
;
margin-right
:
$spacer
/
2
;
margin-right
:
$spacer
*
2
;
}
.add-panel__sub-title
{
...
...
@@ -47,6 +50,7 @@
flex-direction
:
row
;
flex-wrap
:
wrap
;
overflow
:
auto
;
height
:
100%
;
align-content
:
flex-start
;
justify-content
:
space-around
;
position
:
relative
;
...
...
@@ -84,3 +88,16 @@
.add-panel__item-icon
{
padding
:
2px
;
}
.add-panel__searchbar
{
width
:
100%
;
margin-bottom
:
10px
;
margin-top
:
7px
;
}
.add-panel__no-panels
{
color
:
$text-color-weak
;
font-style
:
italic
;
width
:
100%
;
padding
:
3px
8px
;
}
public/sass/components/_tabs.scss
View file @
fd409f11
...
...
@@ -44,18 +44,16 @@
&
:
:
before
{
display
:
block
;
content
:
" "
;
content
:
' '
;
position
:
absolute
;
left
:
0
;
right
:
0
;
height
:
2px
;
top
:
0
;
background-image
:
linear-gradient
(
to
right
,
#ffd500
0%
,
#ff4400
99%
,
#ff4400
100%
);
background-image
:
linear-gradient
(
to
right
,
#ffd500
0%
,
#ff4400
99%
,
#ff4400
100%
);
}
}
&
.active--panel
{
background
:
$panel-bg
!
important
;
}
}
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