prototype: add instance default sidebar dock feature toggle and client init script

This commit is contained in:
M@
2025-12-03 15:24:13 -05:00
parent 156a6f1375
commit 03302046bf
4 changed files with 98 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
package api
import (
"encoding/json"
"net/http"
"github.com/grafana/grafana/pkg/setting"
)
// Note: This is a minimal example showing how to add feature toggles to the boot payload.
// Integrate with Grafana's actual frontend boot data code path (where the server renders JSON into the page).
func frontendSettingsHandler(w http.ResponseWriter, r *http.Request) {
// Example existing boot data:
boot := map[string]interface{}{
"settings": map[string]interface{}{},
}
// Add our feature toggle into the front-end settings payload.
settings := boot["settings"].(map[string]interface{})
settings["featureToggles"] = map[string]interface{}{
"default_sidebar_docked": setting.FeatureToggleConfig.DefaultSidebarDocked,
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(boot)
}
+21
View File
@@ -0,0 +1,21 @@
package setting
import (
"gopkg.in/ini.v1"
)
// FeatureToggles holds lightweight feature flags that can be set via grafana.ini
type FeatureToggles struct {
// DefaultSidebarDocked determines the default state of the left navigation when no per-browser
// preference exists in localStorage (grafana.navigation.docked).
DefaultSidebarDocked bool `json:"default_sidebar_docked"`
}
var FeatureToggleConfig = &FeatureToggles{DefaultSidebarDocked: true}
// loadFeatureToggles reads [feature_toggles] section from the provided INI file.
// This is a minimal helper; integrate it into your existing settings loader.
func loadFeatureToggles(cfg *ini.File) {
sec := cfg.Section("feature_toggles")
FeatureToggleConfig.DefaultSidebarDocked = sec.Key("default_sidebar_docked").MustBool(true)
}
+43
View File
@@ -0,0 +1,43 @@
// This script runs very early (before frontend bundles) so we cannot import @grafana/data here.
// Disable the lint rule that forbids direct localStorage usage for this file.
/* eslint-disable no-restricted-syntax */
(function () {
try {
let key = 'grafana.navigation.docked';
// If already set (user choice exists), do nothing.
if (localStorage.getItem(key) !== null) {
return;
}
// Try the server-provided boot data (common Grafana pattern)
let serverDefault;
if (
typeof window !== 'undefined' &&
window.grafanaBootData &&
window.grafanaBootData.settings &&
window.grafanaBootData.settings.featureToggles
) {
serverDefault = window.grafanaBootData.settings.featureToggles.default_sidebar_docked;
}
// Fallback: a page-global var you can set for quick testing in index.html
let globalDefault = typeof window !== 'undefined' ? window.__defaultSidebarDocked : undefined;
// If neither is provided, leave the existing Grafana default (true/docked).
let val =
typeof serverDefault !== 'undefined'
? serverDefault
: typeof globalDefault !== 'undefined'
? globalDefault
: undefined;
if (typeof val !== 'undefined') {
// localStorage stores strings; Grafana historically uses 'true'/'false' for this key.
localStorage.setItem(key, val ? 'true' : 'false');
}
} catch (e) {
// Keep page stable if something goes wrong
}
})();
+7
View File
@@ -267,6 +267,13 @@
<div id="reactRoot"></div>
<!-- Insert this just before the inline script that assigns window.grafanaBootData -->
<script>
// Optional quick local override for testing without changing server code:
// window.__defaultSidebarDocked = false;
</script>
<script src="/public/scripts/set-default-sidebar.js"></script>
<script nonce="[[.Nonce]]">
window.grafanaBootData = {
user: [[.User]],