Refactor dashboard management

This commit is contained in:
cuigh 2018-03-27 16:32:30 +08:00
parent f4546d0888
commit d5b5ff114a
15 changed files with 160 additions and 99 deletions

View File

@ -1348,6 +1348,13 @@ var Swirl;
this.charts.push(g);
}
});
Core.Dispatcher.bind(this.$panel).on("remove-chart", e => {
let name = $(e.target).closest("div.column").data("chart-name");
Core.Modal.confirm(`Are you sure to delete chart: <strong>${name}</strong>?`, "Delete chart", dlg => {
this.removeGraph(name);
dlg.close();
});
});
$(window).resize(e => {
$.each(this.charts, (i, g) => {
g.resize(0, 0);
@ -1409,7 +1416,7 @@ var Swirl;
this.loadData();
}
removeGraph(name) {
let index;
let index = -1;
for (let i = 0; i < this.charts.length; i++) {
let c = this.charts[i];
if (c.getName() === name) {
@ -1417,7 +1424,13 @@ var Swirl;
break;
}
}
this.loadData();
if (index >= 0) {
console.info(this.charts.length);
let $elem = this.charts[index].getElem();
this.charts.splice(index, 1);
$elem.remove();
console.info(this.charts.length);
}
}
save() {
let charts = this.charts.map(c => {
@ -1432,9 +1445,12 @@ var Swirl;
key: this.opts.key || '',
charts: charts,
};
$ajax.post(`/system/chart/save_panel`, args).json((r) => {
if (!r.success) {
Core.Modal.alert(r.message);
$ajax.post(`/system/chart/save_dashboard`, args).json((r) => {
if (r.success) {
Core.Notification.show("success", "Successfully saved.");
}
else {
Core.Notification.show("danger", r.message);
}
});
}
@ -2343,6 +2359,9 @@ var Swirl;
$("#btn-add").click(() => {
Modal.alert("Coming soon...");
});
$("#btn-save").click(() => {
Modal.alert("Coming soon...");
});
$cb_time.change(e => {
this.panel.setTime($(e.target).val());
});

File diff suppressed because one or more lines are too long

View File

@ -320,6 +320,13 @@ namespace Swirl.Core {
}
});
Dispatcher.bind(this.$panel).on("remove-chart", e => {
let name = $(e.target).closest("div.column").data("chart-name");
Modal.confirm(`Are you sure to delete chart: <strong>${name}</strong>?`, "Delete chart", dlg => {
this.removeGraph(name);
dlg.close();
});
});
$(window).resize(e => {
$.each(this.charts, (i: number, g: Graph) => {
g.resize(0, 0);
@ -356,7 +363,7 @@ namespace Swirl.Core {
}
addGraph(c: any) {
for (let i =0; i< this.charts.length; i++) {
for (let i = 0; i < this.charts.length; i++) {
let chart = this.charts[i];
if (chart.getName() === c.name) {
// chart already added.
@ -393,15 +400,22 @@ namespace Swirl.Core {
removeGraph(name: string) {
// todo:
let index:number;
for (let i =0; i< this.charts.length; i++) {
let index = -1;
for (let i = 0; i < this.charts.length; i++) {
let c = this.charts[i];
if (c.getName() === name) {
index = i;
break;
}
}
this.loadData();
if (index >= 0) {
console.info(this.charts.length);
let $elem = this.charts[index].getElem();
this.charts.splice(index, 1);
$elem.remove();
console.info(this.charts.length);
}
}
save() {
@ -418,9 +432,11 @@ namespace Swirl.Core {
key: this.opts.key || '',
charts: charts,
};
$ajax.post(`/system/chart/save_panel`, args).json<AjaxResult>((r: AjaxResult) => {
if (!r.success) {
Modal.alert(r.message);
$ajax.post(`/system/chart/save_dashboard`, args).json<AjaxResult>((r: AjaxResult) => {
if (r.success) {
Notification.show("success", "Successfully saved.");
} else {
Notification.show("danger", r.message);
}
});
}

View File

@ -21,6 +21,9 @@ namespace Swirl.Service {
$("#btn-add").click(() => {
Modal.alert("Coming soon...");
});
$("#btn-save").click(() => {
Modal.alert("Coming soon...");
});
$cb_time.change(e => {
this.panel.setTime($(e.target).val());
});

View File

@ -99,20 +99,34 @@ func (b *chartBiz) GetServiceCharts(name string) (charts []*model.Chart, err err
return
}
// nolint: gocyclo
func (b *chartBiz) Panel(panel model.ChartPanel) (charts []*model.Chart, err error) {
func (b *chartBiz) GetDashboard(name, key string) (dashboard *model.ChartDashboard, err error) {
do(func(d dao.Interface) {
if len(panel.Charts) == 0 {
dashboard, err = d.DashboardGet(name, key)
})
return
}
func (b *chartBiz) UpdateDashboard(dashboard *model.ChartDashboard, user web.User) (err error) {
do(func(d dao.Interface) {
err = d.DashboardUpdate(dashboard)
})
return
}
// nolint: gocyclo
func (b *chartBiz) GetDashboardCharts(dashboard *model.ChartDashboard) (charts []*model.Chart, err error) {
do(func(d dao.Interface) {
if len(dashboard.Charts) == 0 {
return
}
names := make([]string, len(panel.Charts))
for i, c := range panel.Charts {
names := make([]string, len(dashboard.Charts))
for i, c := range dashboard.Charts {
names[i] = c.Name
}
var cs []*model.Chart
cs, err = d.ChartBatch(names...)
cs, err = b.getCharts(names)
if err != nil {
return
}
@ -122,7 +136,7 @@ func (b *chartBiz) Panel(panel model.ChartPanel) (charts []*model.Chart, err err
for _, c := range cs {
m[c.Name] = c
}
for _, c := range panel.Charts {
for _, c := range dashboard.Charts {
if chart := m[c.Name]; chart != nil {
if c.Width > 0 {
chart.Width = c.Width

View File

@ -33,13 +33,3 @@ func (b *settingBiz) Update(setting *model.Setting, user web.User) (err error) {
})
return
}
func (b *settingBiz) UpdateDashboard(name string, dashboard *model.ChartPanel, user web.User) (err error) {
do(func(d dao.Interface) {
err = d.UpdateDashboard(name, dashboard)
if err == nil {
Event.CreateSetting(model.EventActionUpdate, user)
}
})
return
}

View File

@ -4,6 +4,7 @@ import (
"strings"
"time"
"github.com/cuigh/auxo/data"
"github.com/cuigh/auxo/errors"
"github.com/cuigh/auxo/net/web"
"github.com/cuigh/auxo/util/cast"
@ -13,29 +14,29 @@ import (
// ChartController is a controller of metric chart.
type ChartController struct {
List web.HandlerFunc `path:"/" name:"chart.list" authorize:"!" desc:"chart list page"`
Query web.HandlerFunc `path:"/query" name:"chart.query" authorize:"?" desc:"chart query"`
New web.HandlerFunc `path:"/new" name:"chart.new" authorize:"!" desc:"new chart page"`
Create web.HandlerFunc `path:"/new" method:"post" name:"chart.create" authorize:"!" desc:"create chart"`
Edit web.HandlerFunc `path:"/:name/edit" name:"chart.edit" authorize:"!" desc:"edit chart page"`
Delete web.HandlerFunc `path:"/:name/delete" method:"post" name:"chart.delete" authorize:"!" desc:"delete chart"`
Update web.HandlerFunc `path:"/:name/edit" method:"post" name:"chart.update" authorize:"!" desc:"update chart"`
Data web.HandlerFunc `path:"/data" name:"chart.data" authorize:"?" desc:"fetch chart datas"`
SavePanel web.HandlerFunc `path:"/save_panel" method:"post" name:"chart.save_panel" authorize:"!" desc:"save panel"`
List web.HandlerFunc `path:"/" name:"chart.list" authorize:"!" desc:"chart list page"`
Query web.HandlerFunc `path:"/query" name:"chart.query" authorize:"?" desc:"chart query"`
New web.HandlerFunc `path:"/new" name:"chart.new" authorize:"!" desc:"new chart page"`
Create web.HandlerFunc `path:"/new" method:"post" name:"chart.create" authorize:"!" desc:"create chart"`
Edit web.HandlerFunc `path:"/:name/edit" name:"chart.edit" authorize:"!" desc:"edit chart page"`
Delete web.HandlerFunc `path:"/:name/delete" method:"post" name:"chart.delete" authorize:"!" desc:"delete chart"`
Update web.HandlerFunc `path:"/:name/edit" method:"post" name:"chart.update" authorize:"!" desc:"update chart"`
Data web.HandlerFunc `path:"/data" name:"chart.data" authorize:"?" desc:"fetch chart datas"`
SaveDashboard web.HandlerFunc `path:"/save_dashboard" method:"post" name:"chart.save_dashboard" authorize:"!" desc:"save dashboard"`
}
// Chart creates an instance of RoleController
func Chart() (c *ChartController) {
return &ChartController{
List: chartList,
Query: chartQuery,
New: chartNew,
Create: chartCreate,
Edit: chartEdit,
Update: chartUpdate,
Delete: chartDelete,
Data: chartData,
SavePanel: chartSavePanel,
List: chartList,
Query: chartQuery,
New: chartNew,
Create: chartCreate,
Edit: chartEdit,
Update: chartUpdate,
Delete: chartDelete,
Data: chartData,
SaveDashboard: chartSaveDashboard,
}
}
@ -115,31 +116,30 @@ func chartDelete(ctx web.Context) error {
func chartData(ctx web.Context) error {
period := cast.ToDuration(ctx.Q("time"), time.Hour)
charts := strings.Split(ctx.Q("charts"), ",")
key := ctx.Q("key")
datas, err := biz.Chart.FetchDatas(key, charts, period)
if err != nil {
return err
if v := ctx.Q("charts"); v != "" {
names := strings.Split(v, ",")
key := ctx.Q("key")
datas, err := biz.Chart.FetchDatas(key, names, period)
if err != nil {
return err
}
return ctx.JSON(datas)
}
return ctx.JSON(datas)
return ctx.JSON(data.Map{})
}
func chartSavePanel(ctx web.Context) error {
data := struct {
Name string `json:"name"`
Key string `json:"key"`
model.ChartPanel
}{}
err := ctx.Bind(&data)
func chartSaveDashboard(ctx web.Context) error {
dashboard := &model.ChartDashboard{}
err := ctx.Bind(dashboard)
if err != nil {
return err
}
switch data.Name {
switch dashboard.Name {
case "home":
err = biz.Setting.UpdateDashboard(data.Name, &data.ChartPanel, ctx.User())
err = biz.Chart.UpdateDashboard(dashboard, ctx.User())
default:
err = errors.New("unknown dashboard: " + data.Name)
err = errors.New("unknown dashboard: " + dashboard.Name)
}
return ajaxResult(ctx, err)
}

View File

@ -32,10 +32,10 @@ func Home() (c *HomeController) {
func homeIndex(ctx web.Context) (err error) {
var (
count int
setting *model.Setting
charts []*model.Chart
m = newModel(ctx)
count int
dashboard *model.ChartDashboard
charts []*model.Chart
m = newModel(ctx)
)
if count, err = docker.NodeCount(); err != nil {
@ -58,10 +58,10 @@ func homeIndex(ctx web.Context) (err error) {
}
m.Set("StackCount", count)
if setting, err = biz.Setting.Get(); err != nil {
if dashboard, err = biz.Chart.GetDashboard("home", ""); err != nil {
return
}
charts, err = biz.Chart.Panel(setting.Dashboard.Home)
charts, err = biz.Chart.GetDashboardCharts(dashboard)
if err != nil {
return err
}

View File

@ -62,7 +62,6 @@ type Interface interface {
SettingGet() (setting *model.Setting, err error)
SettingUpdate(setting *model.Setting) error
UpdateDashboard(name string, dashboard *model.ChartPanel) error
ChartGet(name string) (*model.Chart, error)
ChartBatch(names ...string) ([]*model.Chart, error)
@ -70,6 +69,9 @@ type Interface interface {
ChartCreate(chart *model.Chart) error
ChartUpdate(chart *model.Chart) error
ChartDelete(name string) error
DashboardGet(name, key string) (dashboard *model.ChartDashboard, err error)
DashboardUpdate(dashboard *model.ChartDashboard) error
}
// Get return a dao instance according to DB_TYPE.

View File

@ -63,3 +63,29 @@ func (d *Dao) ChartDelete(name string) (err error) {
})
return
}
func (d *Dao) DashboardGet(name, key string) (dashboard *model.ChartDashboard, err error) {
d.do(func(db *database) {
dashboard = &model.ChartDashboard{
Name: name,
Key: key,
}
err = db.C("dashboard").FindId(dashboard.ID()).One(dashboard)
if err == mgo.ErrNotFound {
dashboard, err = nil, nil
} else if err != nil {
dashboard = nil
}
})
return
}
func (d *Dao) DashboardUpdate(dashboard *model.ChartDashboard) (err error) {
d.do(func(db *database) {
update := bson.M{
"$set": dashboard,
}
_, err = db.C("dashboard").UpsertId(dashboard.ID(), update)
})
return
}

View File

@ -28,17 +28,3 @@ func (d *Dao) SettingUpdate(setting *model.Setting) (err error) {
})
return
}
func (d *Dao) UpdateDashboard(name string, dashboard *model.ChartPanel) (err error) {
d.do(func(db *database) {
update := bson.M{
"$set": bson.M{
"dashboard": bson.M{
name: dashboard,
},
},
}
err = db.C("setting").UpdateId(settingID, update)
})
return
}

View File

@ -43,13 +43,20 @@ type ChartItem struct {
Colors []string `json:"colors"`
}
type ChartPanel struct {
Refresh bool `json:"refresh"`
Period int32 `json:"period"` // minutes
Charts []ChartItem `json:"charts"`
type ChartDashboard struct {
Name string `json:"name"`
Key string `json:"key"`
Period int32 `json:"period"` // minutes
RefreshInterval int32 `json:"refresh_interval"` // seconds, 0 means disabled.
Charts []ChartItem `json:"charts"`
}
//type ChartPanel []ChartItem
func (cd *ChartDashboard) ID() string {
if cd.Key == "" {
return cd.Name
}
return cd.Name + ":" + cd.Key
}
type ChartPoint struct {
X int64 `json:"x"`

View File

@ -47,9 +47,6 @@ type Setting struct {
Metrics struct {
Prometheus string `bson:"prometheus" json:"prometheus"`
} `bson:"metrics" json:"metrics"`
Dashboard struct {
Home ChartPanel `bson:"home" json:"home"`
} `bson:"dashboard" json:"dashboard"`
UpdatedBy string `bson:"updated_by" json:"updated_by,omitempty"`
UpdatedAt time.Time `bson:"updated_at" json:"updated_at,omitempty"`
}

View File

@ -230,6 +230,7 @@ var Perms = []PermGroup{
{Key: "chart.create", Text: "Create"},
{Key: "chart.delete", Text: "Delete"},
{Key: "chart.update", Text: "Update"},
{Key: "chart.save_dashboard", Text: "Save dashboard"},
},
},
}

View File

@ -87,16 +87,16 @@
<div class="card">
<header class="card-header">
<p class="card-header-title">{{ .Title }}</p>
<a data-action="remove-chart" class="card-header-icon is-paddingless" aria-label="remove chart">
<a data-action="remove-chart" class="card-header-icon" aria-label="remove chart">
<span class="icon">
<i class="fas fa-times has-text-danger" aria-hidden="true"></i>
</span>
</a>
<a data-action="edit-options" class="card-header-icon" aria-label="edit options">
<span class="icon">
<i class="fas fa-ellipsis-h has-text-info" aria-hidden="true"></i>
</span>
</a>
{*<a data-action="edit-options" class="card-header-icon" aria-label="edit options">*}
{*<span class="icon">*}
{*<i class="fas fa-ellipsis-h has-text-info" aria-hidden="true"></i>*}
{*</span>*}
{*</a>*}
</header>
<div class="card-content">
<div style="height: {{ .Height }}px">