Selectable dashboards
This commit is contained in:
parent
d8a5c6d6c9
commit
e68a66f5ce
4 changed files with 102 additions and 22 deletions
17
dashboard.go
17
dashboard.go
|
|
@ -34,6 +34,23 @@ type Dashboard struct {
|
||||||
Widgets []Widget
|
Widgets []Widget
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Dashboards() (dashboards []Dashboard, err error) {
|
||||||
|
var rows pgx.Rows
|
||||||
|
rows, err = db.Query(context.Background(), `SELECT * FROM dashboard ORDER BY name ASC`)
|
||||||
|
if err != nil {
|
||||||
|
err = werr.Wrap(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboards, err = pgx.CollectRows(rows, pgx.RowToStructByNameLax[Dashboard])
|
||||||
|
if err != nil {
|
||||||
|
err = werr.Wrap(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func DashboardGet(name string) (dashboard Dashboard, err error) {
|
func DashboardGet(name string) (dashboard Dashboard, err error) {
|
||||||
var rows pgx.Rows
|
var rows pgx.Rows
|
||||||
rows, err = db.Query(context.Background(), `SELECT * FROM dashboard WHERE name = $1`, name)
|
rows, err = db.Query(context.Background(), `SELECT * FROM dashboard WHERE name = $1`, name)
|
||||||
|
|
|
||||||
15
main.go
15
main.go
|
|
@ -409,13 +409,24 @@ func pageIndex(w http.ResponseWriter, r *http.Request) { // {{{
|
||||||
CONFIG: smonConfig.Settings,
|
CONFIG: smonConfig.Settings,
|
||||||
}
|
}
|
||||||
|
|
||||||
dashboard, err := DashboardGet("start")
|
dashboards, err := Dashboards()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("dashboard", "error", err)
|
logger.Error("dashboard", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbname := r.URL.Query().Get("dashboard")
|
||||||
|
var start Dashboard
|
||||||
|
var names []string
|
||||||
|
for _, dash := range dashboards {
|
||||||
|
if (dbname == "" && dash.Name == "start") || (dbname != "" && dash.Name == dbname) {
|
||||||
|
start = dash
|
||||||
|
}
|
||||||
|
names = append(names, dash.Name)
|
||||||
|
}
|
||||||
|
|
||||||
data := make(map[string]any)
|
data := make(map[string]any)
|
||||||
data["Dashboard"] = dashboard
|
data["Dashboard"] = start
|
||||||
|
data["Dashboards"] = names
|
||||||
page.Data = data
|
page.Data = data
|
||||||
page.Render(w, r)
|
page.Render(w, r)
|
||||||
} // }}}
|
} // }}}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,14 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
& > select, & > button {
|
||||||
|
height: 36px;
|
||||||
|
padding: 0px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
.el-error {
|
.el-error {
|
||||||
display: none;
|
display: none;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
|
@ -68,6 +76,7 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
grid-auto-columns: min-content;
|
grid-auto-columns: min-content;
|
||||||
width: min-content;
|
width: min-content;
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
smon-widget-empty {
|
smon-widget-empty {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
@ -110,13 +119,13 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div style="display: flex; gap: 8px;">
|
<div style="display: flex; gap: 8px;" class="header">
|
||||||
|
<select data-el="dashboards"></select>
|
||||||
<button data-el="edit-dashboard">Edit dashboard</button>
|
<button data-el="edit-dashboard">Edit dashboard</button>
|
||||||
|
<button class="only-on-edit" data-el="update-dashboard">Update dashboard</button>
|
||||||
|
|
||||||
<svg class="only-on-edit" data-el="grid-add-empty-columns" style="width: 36px; height: 36px; cursor: pointer;"><use href="/images/${_VERSION}/grid_management.svg#add-empty-columns" /></svg>
|
<svg class="only-on-edit" data-el="grid-add-empty-columns" style="width: 36px; height: 36px; cursor: pointer;"><use href="/images/${_VERSION}/grid_management.svg#add-empty-columns" /></svg>
|
||||||
<svg class="only-on-edit" data-el="grid-add-empty-rows" style="width: 36px; height: 36px; cursor: pointer;"><use href="/images/${_VERSION}/grid_management.svg#add-empty-rows" /></svg>
|
<svg class="only-on-edit" data-el="grid-add-empty-rows" style="width: 36px; height: 36px; cursor: pointer;"><use href="/images/${_VERSION}/grid_management.svg#add-empty-rows" /></svg>
|
||||||
|
|
||||||
<button class="only-on-edit" data-el="update-dashboard">Update dashboard</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-el="error"></div>
|
<div data-el="error"></div>
|
||||||
|
|
@ -124,29 +133,45 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<dialog data-el="edit">
|
<dialog data-el="edit">
|
||||||
<div style="font-weight: bold;">Cell operations</div>
|
<div style="display: flex; gap: 48px;">
|
||||||
<div style="margin-top: 8px; margin-bottom: 16px;">
|
|
||||||
<div>
|
<div>
|
||||||
<svg data-el="grid-add-left" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#add-left" /></svg>
|
<div style="font-weight: bold;">Cell operations</div>
|
||||||
<svg data-el="grid-add-right" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#add-right" /></svg>
|
<div style="margin-top: 8px; margin-bottom: 16px;">
|
||||||
<svg data-el="grid-add-above" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#add-above" /></svg>
|
<div>
|
||||||
<svg data-el="grid-add-below" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#add-below" /></svg>
|
<svg data-el="grid-add-left" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#add-left" /></svg>
|
||||||
|
<svg data-el="grid-add-right" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#add-right" /></svg>
|
||||||
|
<svg data-el="grid-add-above" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#add-above" /></svg>
|
||||||
|
<svg data-el="grid-add-below" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#add-below" /></svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<svg data-el="grid-add-column-left" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#add-column-left" /></svg>
|
||||||
|
<svg data-el="grid-add-column-above" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#add-column-above" /></svg>
|
||||||
|
<svg data-el="grid-remove-column" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#remove-column" /></svg>
|
||||||
|
<svg data-el="grid-remove-row" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#remove-row" /></svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<svg data-el="grid-remove" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#remove" /></svg>
|
||||||
|
<svg data-el="grid-remove-move-left" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#remove-move-left" /></svg>
|
||||||
|
<svg data-el="grid-remove-move-up" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#remove-move-up" /></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<svg data-el="grid-add-column-left" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#add-column-left" /></svg>
|
<div>
|
||||||
<svg data-el="grid-add-column-above" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#add-column-above" /></svg>
|
<div style="font-weight: bold;">Datapoint</div>
|
||||||
<svg data-el="grid-remove-column" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#remove-column" /></svg>
|
<button style="margin-top: 8px">Choose</button>
|
||||||
<svg data-el="grid-remove-row" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#remove-row" /></svg>
|
</div>
|
||||||
|
<div>
|
||||||
|
<div style="font-weight: bold; margin-top: 16px;">Trigger</div>
|
||||||
|
<button style="margin-top: 8px">Choose</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<svg data-el="grid-remove" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#remove" /></svg>
|
|
||||||
<svg data-el="grid-remove-move-left" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#remove-move-left" /></svg>
|
|
||||||
<svg data-el="grid-remove-move-up" style="width: 36px; height: 36px;"><use href="/images/${_VERSION}/grid_management.svg#remove-move-up" /></svg>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div data-el="edit-components"></div>
|
<div data-el="edit-components"></div>
|
||||||
<div style="display: flex; gap: 8px; margin-top: 16px;">
|
<div style="display: flex; gap: 8px; margin-top: 16px;">
|
||||||
<button data-el="edit-update">Update</button>
|
<button data-el="edit-update">Update</button>
|
||||||
|
|
@ -164,7 +189,10 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
|
||||||
this.addRows = 0
|
this.addRows = 0
|
||||||
this.editedWidget = null
|
this.editedWidget = null
|
||||||
this.widgetsEdited = false
|
this.widgetsEdited = false
|
||||||
|
this.dashboards = this.getDashboardNames()
|
||||||
|
this.selectedDashboard = this.getSelectedDashboardName()
|
||||||
|
|
||||||
|
this.elDashboards.addEventListener('change', ()=>this.chooseDashboard())
|
||||||
this.elEditDashboard.addEventListener('click', () => this.classList.toggle('edit'))
|
this.elEditDashboard.addEventListener('click', () => this.classList.toggle('edit'))
|
||||||
this.elGridAddEmptyColumns.addEventListener('click', () => { this.addColumns += 5; this.render() })
|
this.elGridAddEmptyColumns.addEventListener('click', () => { this.addColumns += 5; this.render() })
|
||||||
this.elGridAddEmptyRows.addEventListener('click', () => { this.addRows += 5; this.render() })
|
this.elGridAddEmptyRows.addEventListener('click', () => { this.addRows += 5; this.render() })
|
||||||
|
|
@ -189,8 +217,27 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
|
||||||
this.fetchData() // Retrieve one as fast as possible since setInterval doesn't run before an interval.
|
this.fetchData() // Retrieve one as fast as possible since setInterval doesn't run before an interval.
|
||||||
setInterval(() => this.fetchData(), 10000)
|
setInterval(() => this.fetchData(), 10000)
|
||||||
}// }}}
|
}// }}}
|
||||||
|
getSelectedDashboardName() {// {{{
|
||||||
|
// Selected dashboard comes from a query parameter.
|
||||||
|
const params = new URLSearchParams(window.location.search)
|
||||||
|
return params.get('dashboard') || 'start'
|
||||||
|
}// }}}
|
||||||
|
getDashboardNames() {// {{{
|
||||||
|
return JSON.parse(document.getElementById('dashboards').textContent)
|
||||||
|
}// }}}
|
||||||
|
|
||||||
render() {// {{{
|
render() {// {{{
|
||||||
|
// Dashboard list for selection.
|
||||||
|
for (const name of this.dashboards) {
|
||||||
|
const db = document.createElement('option')
|
||||||
|
db.innerText = name
|
||||||
|
if (this.selectedDashboard === name)
|
||||||
|
db.selected = true
|
||||||
|
this.elDashboards.append(db)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Render the actual dashboard
|
||||||
const widgets = []
|
const widgets = []
|
||||||
this.widgets = new Map()
|
this.widgets = new Map()
|
||||||
this.occupiedCells = new Map()
|
this.occupiedCells = new Map()
|
||||||
|
|
@ -244,6 +291,9 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
|
||||||
else
|
else
|
||||||
this.elError.classList.add('show')
|
this.elError.classList.add('show')
|
||||||
}// }}}
|
}// }}}
|
||||||
|
chooseDashboard() {// {{{
|
||||||
|
location.href = `/?dashboard=${this.elDashboards.value}`
|
||||||
|
}// }}}
|
||||||
async editUpdate() {// {{{
|
async editUpdate() {// {{{
|
||||||
const changes = await this.editedWidget.editUpdate()
|
const changes = await this.editedWidget.editUpdate()
|
||||||
this.widgetsEdited = true
|
this.widgetsEdited = true
|
||||||
|
|
|
||||||
|
|
@ -16,4 +16,6 @@
|
||||||
<smon-dashboard style="margin-top: 32px">
|
<smon-dashboard style="margin-top: 32px">
|
||||||
<script type="application/json">{{ .Data.Dashboard }}</script>
|
<script type="application/json">{{ .Data.Dashboard }}</script>
|
||||||
</smon-dashboard>
|
</smon-dashboard>
|
||||||
|
|
||||||
|
<script id="dashboards" type="application/json">{{ .Data.Dashboards }}</script>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue