package web import ( "bytes" "encoding/csv" "fmt" "net/http" "net/url" "sort" "strconv" "strings" ) type controlsRow struct { ID int Name string Type string Status string Selected bool ToggleURL string EditURL string RemoveURL string } type controlsPageData struct { Title string CurrentPath string Rows []controlsRow Segment string Page int Pager tableDemoPager VisibleCount int SelectedCount int SelectedVisible int SelectedHidden int ActionMessage string SegmentedCounts map[string]int SegmentURLs map[string]string SelectVisibleURL string SelectFilteredURL string ClearVisibleURL string ClearFilteredURL string ClearSelectionURL string BulkReviewURL string BulkArchiveURL string BulkExportURL string BulkRetrySyncURL string OpenEditSelectedURL string OpenDeleteSelectedURL string HasSelection bool SimulateLoading bool SimulateLoadingURL string ClearLoadingURL string } type modalDemoPageData struct { Title string CurrentPath string Open string Stage string Message string SelectedIDs []string } type ioImportPreviewRow struct { RowNo int ItemCode string Name string Qty int Status string } type ioPageData struct { Title string CurrentPath string ImportMode string FileName string ImportMessage string PreviewRows []ioImportPreviewRow ExportFormat string ExportScope string ExportMessage string } type formsDemoPageData struct { Title string CurrentPath string Mode string Step string ServerSerial string Location string ComponentSerial string EventDate string Details string Message string FieldErrors map[string]string LocationOptions []string ServerOptions []string ComponentOptions []string StepURLs map[string]string ModeURLs map[string]string } type stylePlaygroundPageData struct { Title string CurrentPath string Style string StyleLabel string StyleURLs map[string]string StyleClass string LoadingDemo bool LoadingDemoURL string ClearLoadingURL string } type operatorToolJob struct { ID string Tool string Scope string Mode string Status string Owner string StartedAt string Selected bool ToggleURL string RetryURL string CancelURL string ExportURL string InspectURL string } type operatorToolsPageData struct { Title string CurrentPath string Scope string Queue string Rows []operatorToolJob VisibleCount int SelectedCount int SelectedVisible int SelectionOutside int ActionMessage string ScopeURLs map[string]string QueueURLs map[string]string SelectVisibleURL string ClearVisibleURL string ClearSelectionURL string RunSelectedURL string RetrySelectedURL string CancelSelectedURL string OpenReviewModalURL string ImportPreviewURL string ExportFilteredURL string ExportSelectedURL string SafetyChecklist []string RecentActivityNotes []string } type timelineEvent struct { ID string At string Action string Source string Entity string Target string Detail string Slot string Device string } type timelineCard struct { ID string Day string Title string Action string Source string Count int SummaryLeft []string SummaryRight []string Items []timelineEvent OpenURL string Open bool } type timelinePageData struct { Title string CurrentPath string ActionFilter string SourceFilter string ActionURLs map[string]string SourceURLs map[string]string Cards []timelineCard OpenCard *timelineCard CardSearch string ClearCardURL string ActiveEvent *timelineEvent } func (s *Server) handleControlsPattern(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/patterns/controls" { http.NotFound(w, r) return } segment := strings.TrimSpace(r.URL.Query().Get("segment")) if segment == "" { segment = "all" } page := parsePositiveInt(r.URL.Query().Get("page"), 1) selected := parseIDSet(r.URL.Query()["sel"]) rows := demoControlsRows() counts := map[string]int{"all": len(rows), "ready": 0, "warning": 0, "review": 0} filteredAll := make([]controlsRow, 0, len(rows)) filteredIDs := make([]string, 0, len(rows)) for _, row := range rows { counts[strings.ToLower(row.Status)]++ if segment != "all" && !strings.EqualFold(row.Status, segment) { continue } filteredAll = append(filteredAll, row) filteredIDs = append(filteredIDs, strconv.Itoa(row.ID)) } pageRows, pager := paginateControlsRows(segment, selected, filteredAll, page, 5) visibleIDs := make([]string, 0, len(pageRows)) for _, row := range pageRows { visibleIDs = append(visibleIDs, strconv.Itoa(row.ID)) } switch strings.TrimSpace(r.URL.Query().Get("selection_action")) { case "select_visible": for _, id := range visibleIDs { selected[id] = true } case "clear_visible": for _, id := range visibleIDs { delete(selected, id) } case "select_filtered": for _, id := range filteredIDs { selected[id] = true } case "clear_filtered": for _, id := range filteredIDs { delete(selected, id) } case "clear_all": selected = map[string]bool{} case "toggle": id := strings.TrimSpace(r.URL.Query().Get("id")) if id != "" { if selected[id] { delete(selected, id) } else { selected[id] = true } } } selectedCSV := joinSelectedIDs(selected) pageRows, pager = paginateControlsRows(segment, selected, filteredAll, page, 5) visibleIDs = visibleIDs[:0] for _, row := range pageRows { visibleIDs = append(visibleIDs, strconv.Itoa(row.ID)) } selectedVisible := 0 for i := range pageRows { id := strconv.Itoa(pageRows[i].ID) pageRows[i].Selected = selected[id] if pageRows[i].Selected { selectedVisible++ } pageRows[i].ToggleURL = controlsURL(segment, pager.Page, selectedCSV, "toggle", id, "", nil) pageRows[i].EditURL = modalURL("edit", "edit", selectedCSV, id) pageRows[i].RemoveURL = modalURL("delete", "confirm", selectedCSV, id) } selectedHidden := len(selected) - selectedVisible if selectedHidden < 0 { selectedHidden = 0 } action := strings.TrimSpace(r.URL.Query().Get("bulk")) loading := r.URL.Query().Get("loading") == "1" actionMsg := "" if action != "" { actionMsg = fmt.Sprintf("Bulk action preview: %s on %d selected item(s).", action, len(selected)) } data := controlsPageData{ Title: "Controls + Selection Pattern", CurrentPath: "/patterns/controls", Rows: pageRows, Segment: segment, Page: pager.Page, Pager: pager, VisibleCount: len(pageRows), SelectedCount: len(selected), SelectedVisible: selectedVisible, SelectedHidden: selectedHidden, ActionMessage: actionMsg, SegmentedCounts: counts, SegmentURLs: controlsSegmentURLs(selectedCSV), SelectVisibleURL: controlsURL(segment, pager.Page, selectedCSV, "select_visible", "", "", nil), SelectFilteredURL: controlsURL(segment, pager.Page, selectedCSV, "select_filtered", "", "", nil), ClearVisibleURL: controlsURL(segment, pager.Page, selectedCSV, "clear_visible", "", "", nil), ClearFilteredURL: controlsURL(segment, pager.Page, selectedCSV, "clear_filtered", "", "", nil), ClearSelectionURL: controlsURL(segment, pager.Page, "", "clear_all", "", "", nil), BulkReviewURL: controlsURL(segment, pager.Page, selectedCSV, "", "", "review", nil), BulkArchiveURL: controlsURL(segment, pager.Page, selectedCSV, "", "", "archive", nil), BulkExportURL: controlsURL(segment, pager.Page, selectedCSV, "", "", "export", nil), BulkRetrySyncURL: controlsURL(segment, pager.Page, selectedCSV, "", "", "retry_sync", nil), OpenEditSelectedURL: modalURL("edit", "edit", selectedCSV, ""), OpenDeleteSelectedURL: modalURL("delete", "confirm", selectedCSV, ""), HasSelection: len(selected) > 0, SimulateLoading: loading, SimulateLoadingURL: controlsURL(segment, pager.Page, selectedCSV, "", "", "review", map[string]string{"loading": "1"}), ClearLoadingURL: controlsURL(segment, pager.Page, selectedCSV, "", "", "", map[string]string{"loading": ""}), } s.renderTemplate(w, "controls_pattern.html", data) } func (s *Server) handleModalPattern(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/patterns/modals" { http.NotFound(w, r) return } open := strings.TrimSpace(r.URL.Query().Get("open")) stage := strings.TrimSpace(r.URL.Query().Get("stage")) if stage == "" { stage = "edit" } selectedIDs := selectedIDSlice(r.URL.Query()["sel"]) msg := "" switch stage { case "confirm": msg = "Confirm stage: summarize changes and require explicit confirmation." case "done": msg = "Completed state: show success summary and next actions." default: msg = "Edit stage: collect inputs and validate before transition to confirm." } data := modalDemoPageData{ Title: "Modal Workflows Pattern", CurrentPath: "/patterns/modals", Open: open, Stage: stage, Message: msg, SelectedIDs: selectedIDs, } s.renderTemplate(w, "modal_pattern.html", data) } func (s *Server) handleIOPattern(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/patterns/io" { http.NotFound(w, r) return } mode := strings.TrimSpace(r.URL.Query().Get("import_mode")) if mode == "" { mode = "preview" } fileName := strings.TrimSpace(r.URL.Query().Get("file")) if fileName == "" { fileName = "items.csv" } scope := strings.TrimSpace(r.URL.Query().Get("scope")) if scope == "" { scope = "filtered" } format := strings.TrimSpace(r.URL.Query().Get("format")) if format == "" { format = "csv" } preview := []ioImportPreviewRow{ {RowNo: 1, ItemCode: "CMP-001", Name: "Controller board", Qty: 2, Status: "ok"}, {RowNo: 2, ItemCode: "CMP-002", Name: "PSU module", Qty: 1, Status: "warning"}, {RowNo: 3, ItemCode: "CMP-003", Name: "Network adapter", Qty: 4, Status: "ok"}, {RowNo: 4, ItemCode: "CMP-004", Name: "Missing mapping sample", Qty: 1, Status: "error"}, } msg := "Import workflow pattern: upload -> preview/validate -> confirm." if mode == "confirm" { msg = "Confirm import step: user reviews validation summary before submitting." } exportMsg := "Export workflow pattern: explicit format/scope selection and predictable filename." if r.URL.Query().Get("export_ready") == "1" { exportMsg = "Export is ready. Use the download action below (real CSV endpoint in demo)." } data := ioPageData{ Title: "Import / Export Pattern", CurrentPath: "/patterns/io", ImportMode: mode, FileName: fileName, ImportMessage: msg, PreviewRows: preview, ExportFormat: format, ExportScope: scope, ExportMessage: exportMsg, } s.renderTemplate(w, "io_pattern.html", data) } func (s *Server) handleFormsPattern(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/patterns/forms" { http.NotFound(w, r) return } mode := strings.TrimSpace(r.URL.Query().Get("mode")) if mode == "" { mode = "register" } step := strings.TrimSpace(r.URL.Query().Get("step")) if step == "" { step = "edit" } data := formsDemoPageData{ Title: "Forms + Validation Pattern", CurrentPath: "/patterns/forms", Mode: mode, Step: step, ServerSerial: strings.TrimSpace(r.URL.Query().Get("server_serial")), Location: strings.TrimSpace(r.URL.Query().Get("location")), ComponentSerial: strings.TrimSpace(r.URL.Query().Get("component_serial")), EventDate: strings.TrimSpace(r.URL.Query().Get("event_date")), Details: strings.TrimSpace(r.URL.Query().Get("details")), FieldErrors: map[string]string{}, LocationOptions: []string{"AOC#1", "AOC#2", "PSU#1", "PSU#2", "CTRL#1"}, ServerOptions: []string{"SRV-001", "SRV-002", "SRV-003", "SRV-010"}, ComponentOptions: []string{ "NIC-AX210-001", "NIC-AX210-002", "PSU-750W-100", "CTRL-MGMT-014", }, StepURLs: map[string]string{ "edit": formsURL(mode, "edit", url.Values{}), "review": formsURL(mode, "review", carryFormFields(r.URL.Query())), "confirm": formsURL(mode, "confirm", carryFormFields(r.URL.Query())), }, ModeURLs: map[string]string{ "register": formsURL("register", "edit", carryFormFields(r.URL.Query())), "import": formsURL("import", "edit", carryFormFields(r.URL.Query())), }, } if data.EventDate == "" { data.EventDate = "2026-02-23" } if step == "review" || step == "confirm" { validateFormsDemo(&data) if len(data.FieldErrors) > 0 && step != "edit" { data.Message = "Validation errors must be resolved before confirmation." } } if step == "edit" { data.Message = "Edit step: enter values, use suggestions, then move to review." } else if step == "review" { if len(data.FieldErrors) == 0 { data.Message = "Review step: summarize recognized values and request explicit confirmation." } } else if step == "confirm" { if len(data.FieldErrors) == 0 { data.Message = "Done state: show human-readable result and next actions." } } s.renderTemplate(w, "forms_pattern.html", data) } func (s *Server) handleStylePlaygroundPattern(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/patterns/style-playground" { http.NotFound(w, r) return } style := strings.TrimSpace(r.URL.Query().Get("style")) if style == "" { style = "aqua" } if style == "vaporwave" { style = "vaporwave-soft" } allowed := map[string]string{ "linen": "Linen / Editorial", "slate": "Slate / Utility", "signal": "Signal / Accent", "y2k-silver": "Y2K / Silver Chrome", "vaporwave-soft": "Vaporwave / Soft Day", "vaporwave-night": "Vaporwave / Night", "aqua": "macOS Aqua", "win9x": "Windows 95-2000", } label, ok := allowed[style] if !ok { style = "aqua" label = allowed[style] } styleClass := "theme-" + style if style == "vaporwave-soft" { // Keep CSS compatibility with the first vaporwave implementation. styleClass = "theme-vaporwave" } data := stylePlaygroundPageData{ Title: "Style Playground", CurrentPath: "/patterns/style-playground", Style: style, StyleLabel: label, StyleClass: styleClass, StyleURLs: map[string]string{ "linen": anchored("/patterns/style-playground?style=linen", "style-presets"), "slate": anchored("/patterns/style-playground?style=slate", "style-presets"), "signal": anchored("/patterns/style-playground?style=signal", "style-presets"), "y2k-silver": anchored("/patterns/style-playground?style=y2k-silver", "style-presets"), "vaporwave-soft": anchored("/patterns/style-playground?style=vaporwave-soft", "style-presets"), "vaporwave-night": anchored("/patterns/style-playground?style=vaporwave-night", "style-presets"), "aqua": anchored("/patterns/style-playground?style=aqua", "style-presets"), "win9x": anchored("/patterns/style-playground?style=win9x", "style-presets"), }, LoadingDemo: r.URL.Query().Get("loading") == "1", LoadingDemoURL: anchored("/patterns/style-playground?style="+style+"&loading=1", "style-components"), ClearLoadingURL: anchored("/patterns/style-playground?style="+style, "style-components"), } s.renderTemplate(w, "style_playground_pattern.html", data) } func (s *Server) handleOperatorToolsPattern(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/patterns/operator-tools" { http.NotFound(w, r) return } scope := strings.TrimSpace(r.URL.Query().Get("scope")) if scope == "" { scope = "assets" } queue := strings.TrimSpace(r.URL.Query().Get("queue")) if queue == "" { queue = "all" } selected := parseIDSet(r.URL.Query()["sel"]) all := demoOperatorToolJobs() filtered := make([]operatorToolJob, 0, len(all)) visibleIDs := make([]string, 0, len(all)) for _, row := range all { if scope != "all" && !strings.EqualFold(row.Scope, scope) { continue } if queue != "all" && !strings.EqualFold(row.Status, queue) { continue } filtered = append(filtered, row) visibleIDs = append(visibleIDs, row.ID) } switch strings.TrimSpace(r.URL.Query().Get("selection_action")) { case "select_visible": for _, id := range visibleIDs { selected[id] = true } case "clear_visible": for _, id := range visibleIDs { delete(selected, id) } case "clear_all": selected = map[string]bool{} case "toggle": id := strings.TrimSpace(r.URL.Query().Get("id")) if id != "" { if selected[id] { delete(selected, id) } else { selected[id] = true } } } selCSV := joinSelectedIDs(selected) selectedVisible := 0 for i := range filtered { filtered[i].Selected = selected[filtered[i].ID] if filtered[i].Selected { selectedVisible++ } filtered[i].ToggleURL = operatorToolsURL(scope, queue, selCSV, "toggle", filtered[i].ID, "") filtered[i].RetryURL = operatorToolsURL(scope, queue, selCSV, "", "", "retry") filtered[i].CancelURL = operatorToolsURL(scope, queue, selCSV, "", "", "cancel") filtered[i].ExportURL = anchored("/patterns/io?scope=filtered&export_ready=1", "io-export") filtered[i].InspectURL = timelineURL("", "", "c1", "", "") } selectedHidden := len(selected) - selectedVisible if selectedHidden < 0 { selectedHidden = 0 } action := strings.TrimSpace(r.URL.Query().Get("batch")) actionMessage := "" if action != "" { actionMessage = fmt.Sprintf("Operator batch preview: %s on %d selected job(s).", action, len(selected)) } if len(selected) == 0 && action != "" { actionMessage = "Operator batch preview requires explicit selection first." } data := operatorToolsPageData{ Title: "Operator Tools Pattern", CurrentPath: "/patterns/operator-tools", Scope: scope, Queue: queue, Rows: filtered, VisibleCount: len(filtered), SelectedCount: len(selected), SelectedVisible: selectedVisible, SelectionOutside: selectedHidden, ActionMessage: actionMessage, ScopeURLs: map[string]string{ "assets": operatorToolsURL("assets", queue, selCSV, "", "", ""), "components": operatorToolsURL("components", queue, selCSV, "", "", ""), "imports": operatorToolsURL("imports", queue, selCSV, "", "", ""), "maintenance": operatorToolsURL("maintenance", queue, selCSV, "", "", ""), "all": operatorToolsURL("all", queue, selCSV, "", "", ""), }, QueueURLs: map[string]string{ "all": operatorToolsURL(scope, "all", selCSV, "", "", ""), "queued": operatorToolsURL(scope, "queued", selCSV, "", "", ""), "running": operatorToolsURL(scope, "running", selCSV, "", "", ""), "failed": operatorToolsURL(scope, "failed", selCSV, "", "", ""), "done": operatorToolsURL(scope, "done", selCSV, "", "", ""), }, SelectVisibleURL: operatorToolsURL(scope, queue, selCSV, "select_visible", "", ""), ClearVisibleURL: operatorToolsURL(scope, queue, selCSV, "clear_visible", "", ""), ClearSelectionURL: operatorToolsURL(scope, queue, "", "clear_all", "", ""), RunSelectedURL: operatorToolsURL(scope, queue, selCSV, "", "", "run"), RetrySelectedURL: operatorToolsURL(scope, queue, selCSV, "", "", "retry"), CancelSelectedURL: operatorToolsURL(scope, queue, selCSV, "", "", "cancel"), OpenReviewModalURL: modalURL("edit", "confirm", selCSV, ""), ImportPreviewURL: anchored("/patterns/io?import_mode=preview&file=operator-batch.csv", "io-import"), ExportFilteredURL: anchored("/patterns/io?scope=filtered&format=csv&export_ready=1", "io-export"), ExportSelectedURL: anchored("/patterns/io?scope=selected&format=csv&export_ready=1", "io-export"), SafetyChecklist: []string{ "Require explicit selection for batch actions (never infer from hidden defaults).", "Show scope and queue filters in the action bar before executing.", "Destructive or high-impact operations must route through a confirm step.", "Batch result summaries must be exportable and human-readable.", }, RecentActivityNotes: []string{ "Failed runs should stay filterable and retryable without losing scope context.", "Import and export affordances belong near batch controls, not hidden in settings.", "Queue status labels must be stable and reused across table rows and summaries.", }, } s.renderTemplate(w, "operator_tools_pattern.html", data) } func (s *Server) handleIOExportCSV(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/patterns/io/export.csv" { http.NotFound(w, r) return } scope := r.URL.Query().Get("scope") if scope == "" { scope = "filtered" } filename := "2026-02-23 (DEMO) items.csv" w.Header().Set("Content-Type", "text/csv; charset=utf-8") w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", filename)) _, _ = w.Write([]byte{0xEF, 0xBB, 0xBF}) var buf bytes.Buffer cw := csv.NewWriter(&buf) cw.Comma = ';' _ = cw.Write([]string{"Code", "Name", "Category", "Status", "Qty"}) for _, row := range demoControlsRows() { if scope == "selected" && row.ID%2 == 0 { continue } _ = cw.Write([]string{ fmt.Sprintf("CMP-%03d", row.ID), row.Name, row.Type, row.Status, strconv.Itoa((row.ID % 5) + 1), }) } cw.Flush() _, _ = w.Write(buf.Bytes()) } func (s *Server) handleTimelinePattern(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/patterns/timeline" { http.NotFound(w, r) return } actionFilter := strings.TrimSpace(r.URL.Query().Get("action")) sourceFilter := strings.TrimSpace(r.URL.Query().Get("source")) openID := strings.TrimSpace(r.URL.Query().Get("open")) cardSearch := strings.TrimSpace(r.URL.Query().Get("q")) activeEventID := strings.TrimSpace(r.URL.Query().Get("event")) all := demoTimelineCards() cards := make([]timelineCard, 0, len(all)) for _, c := range all { if actionFilter != "" && !strings.EqualFold(c.Action, actionFilter) { continue } if sourceFilter != "" && !strings.EqualFold(c.Source, sourceFilter) { continue } c.OpenURL = timelineURL(actionFilter, sourceFilter, c.ID, "", "") c.Open = c.ID == openID if c.Open && cardSearch != "" { needle := strings.ToLower(cardSearch) items := make([]timelineEvent, 0, len(c.Items)) for _, it := range c.Items { h := strings.ToLower(strings.Join([]string{it.Action, it.Source, it.Entity, it.Target, it.Slot, it.Device, it.Detail}, " ")) if strings.Contains(h, needle) { items = append(items, it) } } c.Items = items c.Count = len(items) } cards = append(cards, c) } var openCard *timelineCard var activeEvent *timelineEvent for i := range cards { if cards[i].ID != openID { continue } openCard = &cards[i] if len(cards[i].Items) == 0 { break } idx := 0 if activeEventID != "" { for j := range cards[i].Items { if cards[i].Items[j].ID == activeEventID { idx = j break } } } activeEvent = &cards[i].Items[idx] break } data := timelinePageData{ Title: "Timeline Cards Pattern", CurrentPath: "/patterns/timeline", ActionFilter: actionFilter, SourceFilter: sourceFilter, ActionURLs: map[string]string{ "": timelineURL("", sourceFilter, "", "", ""), "installation": timelineURL("installation", sourceFilter, "", "", ""), "removal": timelineURL("removal", sourceFilter, "", "", ""), "edit": timelineURL("edit", sourceFilter, "", "", ""), }, SourceURLs: map[string]string{ "": timelineURL(actionFilter, "", "", "", ""), "manual": timelineURL(actionFilter, "manual", "", "", ""), "ingest": timelineURL(actionFilter, "ingest", "", "", ""), "system": timelineURL(actionFilter, "system", "", "", ""), }, Cards: cards, OpenCard: openCard, CardSearch: cardSearch, ClearCardURL: timelineURL(actionFilter, sourceFilter, "", "", ""), ActiveEvent: activeEvent, } s.renderTemplate(w, "timeline_pattern.html", data) } func validateFormsDemo(d *formsDemoPageData) { if d.ServerSerial == "" && d.Mode == "register" { d.FieldErrors["server_serial"] = "Server serial is required in register mode." } if d.ComponentSerial == "" { d.FieldErrors["component_serial"] = "Component serial is required." } if d.EventDate == "" { d.FieldErrors["event_date"] = "Date is required." } if d.Location == "" && d.Mode == "register" { d.FieldErrors["location"] = "Location/slot is required." } } func (s *Server) renderTemplate(w http.ResponseWriter, name string, data any) { w.Header().Set("Content-Type", "text/html; charset=utf-8") if err := s.tmpl.ExecuteTemplate(w, name, data); err != nil { http.Error(w, "template error", http.StatusInternalServerError) } } func parseIDSet(values []string) map[string]bool { out := map[string]bool{} for _, v := range values { for _, p := range strings.Split(v, ",") { p = strings.TrimSpace(p) if p == "" { continue } out[p] = true } } return out } func selectedIDSlice(values []string) []string { set := parseIDSet(values) keys := make([]string, 0, len(set)) for k := range set { keys = append(keys, k) } sort.Slice(keys, func(i, j int) bool { ai, aerr := strconv.Atoi(keys[i]) aj, berr := strconv.Atoi(keys[j]) if aerr == nil && berr == nil { return ai < aj } return keys[i] < keys[j] }) return keys } func joinSelectedIDs(set map[string]bool) string { if len(set) == 0 { return "" } keys := make([]string, 0, len(set)) for k := range set { keys = append(keys, k) } sort.Slice(keys, func(i, j int) bool { ai, aerr := strconv.Atoi(keys[i]) aj, berr := strconv.Atoi(keys[j]) if aerr == nil && berr == nil { return ai < aj } return keys[i] < keys[j] }) return strings.Join(keys, ",") } func demoControlsRows() []controlsRow { names := []string{ "Controller board", "Power module", "NIC adapter", "Drive tray", "Cooling fan", "BMC board", "CPU module", "Memory kit", "Rail set", "Backplane", "Patch panel", "Optics cage", } types := []string{"Compute", "Power", "Networking", "Storage"} statuses := []string{"ready", "warning", "review"} rows := make([]controlsRow, 0, len(names)) for i, n := range names { rows = append(rows, controlsRow{ ID: i + 1, Name: n, Type: types[i%len(types)], Status: statuses[i%len(statuses)], }) } return rows } func controlsSegmentURLs(selCSV string) map[string]string { return map[string]string{ "all": controlsURL("all", 1, selCSV, "", "", "", nil), "ready": controlsURL("ready", 1, selCSV, "", "", "", nil), "warning": controlsURL("warning", 1, selCSV, "", "", "", nil), "review": controlsURL("review", 1, selCSV, "", "", "", nil), } } func carryFormFields(q url.Values) url.Values { out := url.Values{} for _, k := range []string{"server_serial", "location", "component_serial", "event_date", "details"} { if v := strings.TrimSpace(q.Get(k)); v != "" { out.Set(k, v) } } return out } func formsURL(mode, step string, extra url.Values) string { q := url.Values{} if mode != "" { q.Set("mode", mode) } if step != "" { q.Set("step", step) } for k, vals := range extra { for _, v := range vals { q.Add(k, v) } } if qs := q.Encode(); qs != "" { return anchored("/patterns/forms?"+qs, "forms-contract") } return anchored("/patterns/forms", "forms-contract") } func paginateControlsRows(segment string, selected map[string]bool, rows []controlsRow, page, perPage int) ([]controlsRow, tableDemoPager) { totalItems := len(rows) totalPages := 1 if totalItems > 0 { totalPages = (totalItems + perPage - 1) / perPage } if page < 1 { page = 1 } if page > totalPages { page = totalPages } start := 0 end := 0 from := 0 to := 0 pageRows := []controlsRow{} if totalItems > 0 { start = (page - 1) * perPage end = start + perPage if end > totalItems { end = totalItems } from = start + 1 to = end pageRows = append(pageRows, rows[start:end]...) } selCSV := joinSelectedIDs(selected) links := buildControlsPageLinks(segment, selCSV, page, totalPages) pager := tableDemoPager{ Page: page, PerPage: perPage, TotalItems: totalItems, TotalPages: totalPages, From: from, To: to, Links: links, } if page > 1 { pager.PrevURL = controlsURL(segment, page-1, selCSV, "", "", "", nil) } if page < totalPages { pager.NextURL = controlsURL(segment, page+1, selCSV, "", "", "", nil) } return pageRows, pager } func buildControlsPageLinks(segment, selCSV string, current, totalPages int) []tableDemoPageLink { if totalPages <= 1 { return nil } if totalPages <= 4 { out := make([]tableDemoPageLink, 0, totalPages) for p := 1; p <= totalPages; p++ { out = append(out, tableDemoPageLink{ Label: strconv.Itoa(p), URL: controlsURL(segment, p, selCSV, "", "", "", nil), Current: p == current, }) } return out } pages := map[int]bool{ 1: true, 2: true, totalPages - 1: true, totalPages: true, current - 1: true, current: true, current + 1: true, } keys := make([]int, 0, len(pages)) for p := range pages { if p < 1 || p > totalPages { continue } keys = append(keys, p) } sort.Ints(keys) out := make([]tableDemoPageLink, 0, len(keys)+2) prev := 0 for _, p := range keys { if prev != 0 && p-prev > 1 { out = append(out, tableDemoPageLink{Label: "...", Ellipsis: true}) } out = append(out, tableDemoPageLink{ Label: strconv.Itoa(p), URL: controlsURL(segment, p, selCSV, "", "", "", nil), Current: p == current, }) prev = p } return out } func controlsURL(segment string, page int, selCSV, selectionAction, id, bulk string, extra map[string]string) string { q := url.Values{} if segment != "" { q.Set("segment", segment) } if page > 1 { q.Set("page", strconv.Itoa(page)) } if selCSV != "" { q.Set("sel", selCSV) } if selectionAction != "" { q.Set("selection_action", selectionAction) } if id != "" { q.Set("id", id) } if bulk != "" { q.Set("bulk", bulk) } for k, v := range extra { if v == "" { q.Del(k) continue } q.Set(k, v) } if qs := q.Encode(); qs != "" { return anchored("/patterns/controls?"+qs, "controls-selection") } return anchored("/patterns/controls", "controls-selection") } func operatorToolsURL(scope, queue, selCSV, selectionAction, id, batch string) string { q := url.Values{} if scope != "" { q.Set("scope", scope) } if queue != "" { q.Set("queue", queue) } if selCSV != "" { q.Set("sel", selCSV) } if selectionAction != "" { q.Set("selection_action", selectionAction) } if id != "" { q.Set("id", id) } if batch != "" { q.Set("batch", batch) } if qs := q.Encode(); qs != "" { return anchored("/patterns/operator-tools?"+qs, "operator-queue") } return anchored("/patterns/operator-tools", "operator-queue") } func modalURL(open, stage, selCSV, singleID string) string { q := url.Values{} if open != "" { q.Set("open", open) } if stage != "" { q.Set("stage", stage) } if singleID != "" { q.Set("sel", singleID) } else if selCSV != "" { q.Set("sel", selCSV) } if qs := q.Encode(); qs != "" { return anchored("/patterns/modals?"+qs, "modal-open-states") } return anchored("/patterns/modals", "modal-open-states") } func timelineURL(action, source, open, qtext, event string) string { q := url.Values{} if action != "" { q.Set("action", action) } if source != "" { q.Set("source", source) } if open != "" { q.Set("open", open) } if qtext != "" { q.Set("q", qtext) } if event != "" { q.Set("event", event) } fragment := "timeline-filters" if open != "" { fragment = "timeline-drilldown" } if qs := q.Encode(); qs != "" { return anchored("/patterns/timeline?"+qs, fragment) } return anchored("/patterns/timeline", fragment) } func anchored(path, fragment string) string { if fragment == "" { return path } if strings.Contains(path, "#") { return path } return path + "#" + fragment } func demoTimelineCards() []timelineCard { return []timelineCard{ { ID: "c1", Day: "2026-02-23", Title: "Installed 3 components", Action: "installation", Source: "manual", Count: 3, SummaryLeft: []string{"2x Network adapter", "1x Controller board"}, SummaryRight: []string{"AOC#1", "AOC#2", "CTRL#1"}, Items: []timelineEvent{ {ID: "e1", At: "10:12", Action: "installation", Source: "manual", Entity: "Asset A-12", Target: "Network adapter", Slot: "AOC#1", Device: "NIC", Detail: "Installed after maintenance"}, {ID: "e2", At: "10:13", Action: "installation", Source: "manual", Entity: "Asset A-12", Target: "Network adapter", Slot: "AOC#2", Device: "NIC", Detail: "Installed after maintenance"}, {ID: "e3", At: "10:16", Action: "installation", Source: "manual", Entity: "Asset A-12", Target: "Controller board", Slot: "CTRL#1", Device: "Controller", Detail: "Replacement unit attached"}, }, }, { ID: "c2", Day: "2026-02-23", Title: "Removed 2 components", Action: "removal", Source: "ingest", Count: 2, SummaryLeft: []string{"1x PSU module", "1x Cooling fan"}, SummaryRight: []string{"PSU#2", "FAN#4"}, Items: []timelineEvent{ {ID: "e4", At: "08:42", Action: "removal", Source: "ingest", Entity: "Asset B-07", Target: "PSU module", Slot: "PSU#2", Device: "Power", Detail: "Absent in latest snapshot"}, {ID: "e5", At: "08:42", Action: "removal", Source: "ingest", Entity: "Asset B-07", Target: "Cooling fan", Slot: "FAN#4", Device: "Cooling", Detail: "Absent in latest snapshot"}, }, }, { ID: "c3", Day: "2026-02-22", Title: "Bulk metadata edit", Action: "edit", Source: "system", Count: 4, SummaryLeft: []string{"Vendor normalized", "Status recomputed"}, SummaryRight: []string{"4 affected rows"}, Items: []timelineEvent{ {ID: "e6", At: "21:11", Action: "edit", Source: "system", Entity: "Asset C-03", Target: "Component metadata", Slot: "AOC#3", Device: "NIC", Detail: "Vendor name normalized"}, {ID: "e7", At: "21:11", Action: "edit", Source: "system", Entity: "Asset C-03", Target: "Component metadata", Slot: "AOC#4", Device: "NIC", Detail: "Vendor name normalized"}, {ID: "e8", At: "21:12", Action: "edit", Source: "system", Entity: "Asset C-03", Target: "Status", Slot: "PSU#1", Device: "Power", Detail: "Status recalculated from observations"}, {ID: "e9", At: "21:12", Action: "edit", Source: "system", Entity: "Asset C-03", Target: "Status", Slot: "PSU#2", Device: "Power", Detail: "Status recalculated from observations"}, }, }, } } func demoOperatorToolJobs() []operatorToolJob { return []operatorToolJob{ {ID: "job-101", Tool: "Recompute status", Scope: "assets", Mode: "dry-run", Status: "queued", Owner: "operator", StartedAt: "2026-02-23 10:20"}, {ID: "job-102", Tool: "Bulk assign labels", Scope: "components", Mode: "apply", Status: "running", Owner: "operator", StartedAt: "2026-02-23 10:16"}, {ID: "job-103", Tool: "Import snapshot preview", Scope: "imports", Mode: "preview", Status: "done", Owner: "operator", StartedAt: "2026-02-23 10:04"}, {ID: "job-104", Tool: "Repair mappings", Scope: "components", Mode: "apply", Status: "failed", Owner: "operator", StartedAt: "2026-02-23 09:58"}, {ID: "job-105", Tool: "Refresh timelines", Scope: "maintenance", Mode: "apply", Status: "queued", Owner: "scheduler", StartedAt: "2026-02-23 09:40"}, {ID: "job-106", Tool: "Export filtered report", Scope: "assets", Mode: "export", Status: "done", Owner: "operator", StartedAt: "2026-02-23 09:22"}, {ID: "job-107", Tool: "Validate import mapping", Scope: "imports", Mode: "preview", Status: "running", Owner: "operator", StartedAt: "2026-02-23 09:10"}, {ID: "job-108", Tool: "Cleanup stale drafts", Scope: "maintenance", Mode: "apply", Status: "failed", Owner: "system", StartedAt: "2026-02-23 08:55"}, } } func withQuery(base string, updates map[string]string) string { u, err := url.Parse(base) if err != nil { return base } q := u.Query() for k, v := range updates { if v == "" { q.Del(k) continue } q.Set(k, v) } u.RawQuery = q.Encode() return u.String() } func dict(args ...string) map[string]string { out := map[string]string{} for i := 0; i+1 < len(args); i += 2 { out[args[i]] = args[i+1] } return out }