Selectable dashboards

This commit is contained in:
Magnus Åhall 2026-08-23 10:18:00 +02:00
parent d8a5c6d6c9
commit e68a66f5ce
4 changed files with 102 additions and 22 deletions

View file

@ -34,6 +34,23 @@ type Dashboard struct {
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) {
var rows pgx.Rows
rows, err = db.Query(context.Background(), `SELECT * FROM dashboard WHERE name = $1`, name)

15
main.go
View file

@ -409,13 +409,24 @@ func pageIndex(w http.ResponseWriter, r *http.Request) { // {{{
CONFIG: smonConfig.Settings,
}
dashboard, err := DashboardGet("start")
dashboards, err := Dashboards()
if err != nil {
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["Dashboard"] = dashboard
data["Dashboard"] = start
data["Dashboards"] = names
page.Data = data
page.Render(w, r)
} // }}}

View file

@ -46,6 +46,14 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
}
}
.header {
& > select, & > button {
height: 36px;
padding: 0px 16px;
}
}
.el-error {
display: none;
margin-bottom: 16px;
@ -68,6 +76,7 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
grid-auto-flow: column;
grid-auto-columns: min-content;
width: min-content;
margin-top: 16px;
smon-widget-empty {
display: none;
@ -110,13 +119,13 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
</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 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-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 data-el="error"></div>
@ -124,6 +133,8 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
</div>
<dialog data-el="edit">
<div style="display: flex; gap: 48px;">
<div>
<div style="font-weight: bold;">Cell operations</div>
<div style="margin-top: 8px; margin-bottom: 16px;">
<div>
@ -145,8 +156,22 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
<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 style="font-weight: bold;">Datapoint</div>
<button style="margin-top: 8px">Choose</button>
</div>
<div>
<div style="font-weight: bold; margin-top: 16px;">Trigger</div>
<button style="margin-top: 8px">Choose</button>
</div>
</div>
</div>
<div data-el="edit-components"></div>
<div style="display: flex; gap: 8px; margin-top: 16px;">
<button data-el="edit-update">Update</button>
@ -164,7 +189,10 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
this.addRows = 0
this.editedWidget = null
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.elGridAddEmptyColumns.addEventListener('click', () => { this.addColumns += 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.
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() {// {{{
// 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 = []
this.widgets = new Map()
this.occupiedCells = new Map()
@ -244,6 +291,9 @@ export class SmonDashboard extends CustomHTMLElement {// {{{
else
this.elError.classList.add('show')
}// }}}
chooseDashboard() {// {{{
location.href = `/?dashboard=${this.elDashboards.value}`
}// }}}
async editUpdate() {// {{{
const changes = await this.editedWidget.editUpdate()
this.widgetsEdited = true

View file

@ -16,4 +16,6 @@
<smon-dashboard style="margin-top: 32px">
<script type="application/json">{{ .Data.Dashboard }}</script>
</smon-dashboard>
<script id="dashboards" type="application/json">{{ .Data.Dashboards }}</script>
{{ end }}