* feat(plugin): make page tabs and sub-tabs addressable by URLs Update the plugin page so that clicking tabs and sub-tabs pushes browser history via history.pushState(), enabling bookmarkable URLs, browser back/forward navigation, and shareable links. URL mapping: - /plugin → Overview tab - /plugin/configuration → Configuration sub-tab - /plugin/detection → Job Detection sub-tab - /plugin/queue → Job Queue sub-tab - /plugin/execution → Job Execution sub-tab Job-type-specific URLs use the ?job= query parameter (e.g., /plugin/configuration?job=vacuum) so that a specific job type tab is pre-selected on page load. Changes: - Add initialJob parameter to Plugin() template and handler - Extract ?job= query param in renderPluginPage handler - Add buildPluginURL/updateURL helpers in JavaScript - Push history state on top-tab, sub-tab, and job-type clicks - Listen for popstate to restore tab state on back/forward - Replace initial history entry on page load via replaceState * make popstate handler async with proper error handling Await loadDescriptorAndConfig so data loading completes before rendering dependent views. Log errors instead of silently swallowing them.
71 lines
2.3 KiB
Go
71 lines
2.3 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bytes"
|
|
"net/http"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/admin/dash"
|
|
"github.com/seaweedfs/seaweedfs/weed/admin/view/app"
|
|
"github.com/seaweedfs/seaweedfs/weed/admin/view/layout"
|
|
)
|
|
|
|
// PluginHandlers handles plugin UI pages.
|
|
type PluginHandlers struct {
|
|
adminServer *dash.AdminServer
|
|
}
|
|
|
|
// NewPluginHandlers creates a new instance of PluginHandlers.
|
|
func NewPluginHandlers(adminServer *dash.AdminServer) *PluginHandlers {
|
|
return &PluginHandlers{
|
|
adminServer: adminServer,
|
|
}
|
|
}
|
|
|
|
// ShowPlugin displays plugin overview page.
|
|
func (h *PluginHandlers) ShowPlugin(w http.ResponseWriter, r *http.Request) {
|
|
h.renderPluginPage(w, r, "overview")
|
|
}
|
|
|
|
// ShowPluginConfiguration displays plugin configuration page.
|
|
func (h *PluginHandlers) ShowPluginConfiguration(w http.ResponseWriter, r *http.Request) {
|
|
h.renderPluginPage(w, r, "configuration")
|
|
}
|
|
|
|
// ShowPluginDetection displays plugin detection jobs page.
|
|
func (h *PluginHandlers) ShowPluginDetection(w http.ResponseWriter, r *http.Request) {
|
|
h.renderPluginPage(w, r, "detection")
|
|
}
|
|
|
|
// ShowPluginQueue displays plugin job queue page.
|
|
func (h *PluginHandlers) ShowPluginQueue(w http.ResponseWriter, r *http.Request) {
|
|
h.renderPluginPage(w, r, "queue")
|
|
}
|
|
|
|
// ShowPluginExecution displays plugin execution jobs page.
|
|
func (h *PluginHandlers) ShowPluginExecution(w http.ResponseWriter, r *http.Request) {
|
|
h.renderPluginPage(w, r, "execution")
|
|
}
|
|
|
|
// ShowPluginMonitoring displays plugin monitoring page.
|
|
func (h *PluginHandlers) ShowPluginMonitoring(w http.ResponseWriter, r *http.Request) {
|
|
// Backward-compatible alias for the old monitoring URL.
|
|
h.renderPluginPage(w, r, "detection")
|
|
}
|
|
|
|
func (h *PluginHandlers) renderPluginPage(w http.ResponseWriter, r *http.Request, page string) {
|
|
initialJob := r.URL.Query().Get("job")
|
|
component := app.Plugin(page, initialJob)
|
|
viewCtx := layout.NewViewContext(r, dash.UsernameFromContext(r.Context()), dash.CSRFTokenFromContext(r.Context()))
|
|
layoutComponent := layout.Layout(viewCtx, component)
|
|
|
|
var buf bytes.Buffer
|
|
if err := layoutComponent.Render(r.Context(), &buf); err != nil {
|
|
writeJSONError(w, http.StatusInternalServerError, "Failed to render template: "+err.Error())
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
w.WriteHeader(http.StatusOK)
|
|
_, _ = w.Write(buf.Bytes())
|
|
}
|