package tui import ( "fmt" "strings" "proxyctl/internal/app" "proxyctl/internal/profile" ) func (p terminalPresentation) mainView(model presentationState, width, height int) terminalPage { dashboard, operation := model.dashboard, model.operation activeProfile := model.snapshot.ActiveProfile if activeProfile == "" { activeProfile = "No Active Profile" } header := fmt.Sprintf("%s Operations Console\nActive Profile: %s Targets: %s", p.theme.title.Render("proxyctl"), activeProfile, p.stateCountSummary(model.snapshot)) if width < wideWidth { header = fmt.Sprintf("%s Operations Console\nActive Profile: %s\nTargets: %s", p.theme.title.Render("proxyctl"), activeProfile, p.stateCountSummary(model.snapshot)) } catalog := newTargetCatalog(model.snapshot, dashboard.showUnavailable, dashboard.selectedTargetID) footer := p.dashboardFooter(model, catalog) if operation.currentError != nil { footer += "\ne: expand/collapse current error x: acknowledge error" if operation.errorExpanded { footer += " PgUp/PgDn: scroll error details" } } page := terminalPage{ header: header, footer: footer, dashboard: &dashboardRenderState{ catalog: catalog, selectedTargetID: dashboard.selectedTargetID, focus: dashboard.focus, detailsOffset: dashboard.detailsOffset, operationProgress: operation.progress, applyingFrame: operation.spinnerFrame, terminalWidth: width, terminalHeight: height, }, } if dashboard.picker.open { page.dashboard = nil page.primary = dashboard.picker.view(model.snapshot, width, max(5, height-9)) page.footer = "Type to search ↑/↓ PgUp/PgDn: select Enter: activate\nEsc: cancel ?: help" if width < 70 { page.footer = "Type: search ↑/↓: select Enter: activate\nEsc: cancel ?: help" } } if dashboard.driftResolutionTargetID != "" && operation.confirmation == nil { if selected, ok := newTargetCatalog(model.snapshot, true, dashboard.driftResolutionTargetID).selected(dashboard.driftResolutionTargetID); ok { page.dashboard = nil page.primary, page.context = p.driftResolutionView(selected) page.wrapPrimary = true page.wrapContext = true page.footer = "r: Reapply Active Profile o: Restore Original\nEnter/q/Esc: cancel ?: help" } } if operation.confirmation != nil { dialog := newConfirmationDialog(*operation.confirmation) if operation.confirmationDialog != nil { dialog = *operation.confirmationDialog } page.dashboard = nil page.primary = dialog.view() page.primaryOffset = dialog.offset page.focusLine = -1 page.wrapPrimary = true page.context = "Cancellation is selected by default." page.footer = "←/→/Tab: choose PgUp/PgDn: scroll y: confirm Enter: choose\nn/q/Esc: cancel ?: help" } return page } func (p terminalPresentation) driftResolutionView(selected app.TargetSnapshot) (string, string) { var choices strings.Builder fmt.Fprintf(&choices, "%s\nChoose how to resolve %s without an automatic recovery direction.", p.theme.section.Render("Drift Resolution — "+selected.Description.Name), selected.Description.Name) for _, kind := range []app.TargetActionKind{app.ReapplyActiveProfileAction, app.RestoreOriginalAction} { action, ok := driftResolutionAction(selected, kind) label := targetActionLabel(kind) if !ok || !action.Available { reason := action.DisabledReason if reason == "" { reason = "unavailable" } fmt.Fprintf(&choices, "\n\n%s — unavailable: %s", label, reason) continue } fmt.Fprintf(&choices, "\n\n%s", label) } context := "Reapply Active Profile writes the Active Profile again. Restore Original asks the Target Adapter to use its existing ownership and restoration safeguards; insufficient evidence fails safely without overwriting external changes." return choices.String(), context } func (p terminalPresentation) dashboardFooter(model presentationState, catalog targetCatalog) string { dashboard, operation, width := model.dashboard, model.operation, model.terminal.width visibility := "u: show unavailable" if dashboard.showUnavailable { visibility = "u: hide unavailable" } if dashboard.focus == targetDetailsPane { if operation.exitDeferred { return "↑/k ↓/j PgUp/PgDn: browse Tab: focus Targets " + visibility + " ?: help\nExit pending; new work disabled until safe completion" } if width < wideWidth { if operation.active { return "↑/k ↓/j PgUp/PgDn: browse Tab: focus Targets\n?: help q/Ctrl+C: defer exit; mutations disabled" } if width < 70 { return "↑/k ↓/j PgUp/PgDn: scroll Tab: focus Targets\np: switch Profile m: manage ?: help q: quit" } return "↑/k ↓/j PgUp/PgDn: scroll Tab: focus Targets\np: switch Active Profile m: manage Proxy Profiles ?: help q: quit" } footer := "↑/k ↓/j PgUp/PgDn: scroll Tab: focus Targets " + visibility + "\np: switch Active Profile m: manage Proxy Profiles ?: help q/Ctrl+C: quit" if operation.active { footer = "↑/k ↓/j PgUp/PgDn: scroll Tab: focus Targets " + visibility + " ?: help\nq/Ctrl+C: defer safe exit; mutations disabled" } return footer } actions := "↑/k ↓/j: select Tab: focus details " + visibility if operation.exitDeferred { return actions + " ?: help\nExit pending; new work disabled until safe completion" } selected, ok := catalog.selected(dashboard.selectedTargetID) availability := targetMutationAvailability(selected, ok, operation.active || operation.exitDeferred) label := targetActionLabel(selected.PrimaryAction.Kind) if availability.available { actions = "Space: " + label + " " + actions } else { actions = "Space: " + label + " disabled (" + availability.compactReason + ") " + actions } if width < wideWidth { if availability.available { actions = "Space: " + label + " ↑/k ↓/j: select Tab: focus details" } else { actions = "Space: " + label + " disabled ↑/k ↓/j: select Tab: focus details" } if operation.active { return actions + "\n?: help q/Ctrl+C: defer exit; mutations disabled" } if width < 70 { return actions + "\np: switch Profile m: manage ?: help q: quit" } return actions + "\np: switch Active Profile m: manage Proxy Profiles ?: help q: quit" } footer := actions + "\np: switch Active Profile m: manage Proxy Profiles r: refresh ?: help q/Ctrl+C: quit" if operation.active { footer = actions + "\n?: help q: defer safe exit; new mutations disabled" } return footer } func (p terminalPresentation) profilesView(model presentationState) terminalPage { state := model.profile var list strings.Builder if len(model.snapshot.Profiles) == 0 { list.WriteString("No Proxy Profiles saved. Press n to create one.") } for i, item := range model.snapshot.Profiles { cursor, active := " ", " " if i == state.selected { cursor = "> " } if item.Name == model.snapshot.ActiveProfile { active = "*" } if list.Len() > 0 { list.WriteByte('\n') } fmt.Fprintf(&list, "%s%s %s", cursor, active, item.Name) } context := selectedProfileDetails(p, model) footer := "n: create e: edit Enter: edit d: delete PgUp/PgDn: scroll details\n↑/k ↓/j: select ?: help q/Esc: back" if model.terminal.width < 80 { footer = "↑/k ↓/j: select PgUp/PgDn: details n: create\ne/Enter: edit d: delete ?: help q/Esc: back" } if len(model.snapshot.Profiles) == 0 { footer = "n: create a Proxy Profile ?: help q/Esc: back" } if state.deletion != nil { return terminalPage{ header: p.theme.title.Render("Proxy Profile management"), primary: state.deletion.dialog.view(), primaryOffset: state.deletion.dialog.offset, wrapPrimary: true, footer: "←/→/Tab: choose PgUp/PgDn: scroll Enter: choose y: delete\nn/q/Esc: cancel ?: help", focusLine: -1, } } return terminalPage{ header: p.theme.title.Render("Proxy Profile management"), primary: list.String(), context: context, footer: footer, focusLine: state.selected, primaryOffset: state.listOffset, contextOffset: state.detailsOffset, wrapContext: true, } } func sanitizeFormText(value string) string { return sanitizeUntrustedControls(profile.RedactUserinfoText(value)) } func selectedProfileDetails(p terminalPresentation, model presentationState) string { selected, ok := profileAt(model.snapshot, model.profile.selected) if !ok { return "" } var details strings.Builder details.WriteString(p.theme.section.Render("Selected Profile")) fmt.Fprintf(&details, "\nMode: %s", selected.Mode) if selected.Mode == profile.SingleMode { fmt.Fprintf(&details, "\nProxy: %s", profile.ObscureURL(selected.SingleURL)) } else { fmt.Fprintf(&details, "\nHTTP: %s\nHTTPS: %s\nALL/SOCKS: %s", profile.ObscureURL(selected.HTTPURL), profile.ObscureURL(selected.HTTPSURL), profile.ObscureURL(selected.AllURL)) } details.WriteString("\nBypass:") if len(selected.Bypass) == 0 { details.WriteString(" (none)") } else { for _, item := range selected.Bypass { fmt.Fprintf(&details, "\n • %s", item) } } // The list gives short names the strongest scan position. Repeating the // complete value at the end of the scrollable details makes a clipped, // wide Unicode name fully reachable without displacing connection details. fmt.Fprintf(&details, "\nFull name: %s", selected.Name) return details.String() } func (p terminalPresentation) formView(model presentationState) terminalPage { form, width := model.form.state, model.terminal.width action := "Create" if form.originalName != "" { action = "Edit" } var fields, bypassPreview strings.Builder focusLine, currentLine := 0, 0 for i, item := range form.inputs { if fields.Len() > 0 { fields.WriteByte('\n') currentLine++ } cursor, focus := " ", "" if i == form.field { cursor, focus = "> ", " [focused]" focusLine = currentLine } fmt.Fprintf(&fields, "%s%s%s: %s", cursor, item.label, focus, form.renderedInput(i, width)) if probeText := form.probeText(item.field); probeText != "" { fmt.Fprintf(&fields, "\n %s", probeText) currentLine++ } if item.field == profile.NameField && form.hasProbeSourceAttachment() { fmt.Fprintf(&fields, "\n Single proxy URL probe [read-only]: %s", profile.ObscureURLForEditing(form.probe.sourceValue)) fmt.Fprintf(&fields, "\n %s", form.probe.feedback) fields.WriteString("\n Generated Advanced URL fields from this Single proxy URL probe:") currentLine += 3 } validation := form.validationText(i) if item.field == profile.NameField { if conflict := form.nameConflict(model.snapshot.Profiles); conflict != "" { validation = conflict } } validation = sanitizeFormText(validation) if validation != "" { fmt.Fprintf(&fields, "\n Error: %s", validation) currentLine++ } if item.field == profile.BypassField { analysis := form.bypassAnalysis() bypassPreview.WriteString("Normalized Bypass preview:") if len(analysis) == 0 { bypassPreview.WriteString(" (none)") } else { for _, line := range analysis { bypassPreview.WriteString("\n " + sanitizeFormText(line)) } } } } secondaryHints := "?: help q/Esc: cancel" if form.currentField() == profile.BypassField { secondaryHints = "PgUp/PgDn: scroll form preview " + secondaryHints } if form.profile.Mode == profile.SingleMode && form.currentField() == profile.SingleURLField { probeHint := "Ctrl+D: probe" if form.probe.active { probeHint = "Protocol Probe in progress" } secondaryHints = probeHint + " " + secondaryHints } footer := "Tab/Shift+Tab/↑/↓: move Ctrl+T: mode Ctrl+S: save\n" + secondaryHints return terminalPage{ header: p.theme.title.Render(fmt.Sprintf("%s Proxy Profile — %s mode", action, form.profile.Mode)), primary: fields.String(), context: bypassPreview.String(), footer: footer, focusLine: focusLine, contextAnchor: form.bypassPreviewLine, anchorContext: true, } }