issues

package
v0.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 13, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package issues holds the Githome web front's issues handlers: the index with its search-and-filter bar, the detail page with its comment timeline and sidebar, the comment composer, the reactions, and the new-issue form. Each handler resolves and authorizes through the same domain.IssueService the REST and GraphQL surfaces use, so the page and the API never disagree, maps the result into a fe/view model with every URL precomputed through fe/route, and renders through fe/render. A repository the viewer cannot see was turned into a hard 404 by the Resolve middleware before any handler ran (the 404-not-403 rule), and every mutation has a plain HTML form path that works with no JavaScript. See implementation/08.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Deps

type Deps struct {
	Issues *domain.IssueService
	Repos  *domain.RepoService
	URLs   *presenter.URLBuilder
	Render *render.Set
	View   *view.Builder
	Markup *markup.Renderer
	Logger *slog.Logger
}

Deps are the issues handlers' dependencies: the domain issue service for every read and write, the repo service to resolve and read-gate the repository, the presenter for avatar URLs, the render set, the view builder for the shell chrome, the shared markup renderer for comment bodies, and a logger for the notices the list view emits. A nil markup renderer falls back to escaped comment source.

type Handlers

type Handlers struct {
	// contains filtered or unexported fields
}

Handlers is the issues handler set. One is built at boot and shared; it holds no per-request state.

func New

func New(d Deps) *Handlers

New wires the handler set from its dependencies.

func (*Handlers) Create

func (h *Handlers) Create(c *mizu.Ctx) error

Create opens an issue from the new-issue form and redirects to its detail page. A missing title re-renders the form with the values preserved and the message inline (the no-JS validation path), so a typo never loses the draft. The labels, assignees, and milestone the prefill carried apply through the same service input a REST create uses. The service authorizes write access; a viewer without it gets the themed 403. See implementation/08 section 10.

func (*Handlers) CreateComment

func (h *Handlers) CreateComment(c *mizu.Ctx) error

CreateComment appends a comment and redirects to its permalink. An empty body re-renders the issue with the message inline rather than posting a blank comment.

func (*Handlers) DeleteComment

func (h *Handlers) DeleteComment(c *mizu.Ctx) error

DeleteComment removes a comment and redirects to the issue.

func (*Handlers) EditComment

func (h *Handlers) EditComment(c *mizu.Ctx) error

EditComment updates a comment body and redirects to its permalink.

func (*Handlers) EditSidebar

func (h *Handlers) EditSidebar(c *mizu.Ctx) error

EditSidebar applies the label and assignee edits from the sidebar form. The service authorizes write access and resolves unknown labels or assignees the same way it does on create, so the handler only parses the comma lists and redirects back to the issue.

func (*Handlers) EditTitle

func (h *Handlers) EditTitle(c *mizu.Ctx) error

EditTitle renames the issue. An empty title re-renders the issue with the message inline.

func (*Handlers) Index

func (h *Handlers) Index(c *mizu.Ctx) error

Index renders the issues list with its search-and-filter bar. The ?q= string is the single source of filter truth: it is parsed once, projected to the domain query the API also uses, and re-composed server-side for every tab and chip so the page filters with no JavaScript. An is:pr query on this index is not a filter; it redirects to /pulls with the same query so the issues index stays issue-implicit. See implementation/08 sections 2 and 3.

func (*Handlers) Labels added in v0.1.3

func (h *Handlers) Labels(c *mizu.Ctx) error

Labels renders the repository's label list: GET /{owner}/{repo}/labels. Each row is the same color chip the issue rows wear, linking to the issues index filtered to that label, plus the label description. The list is read through the same ListLabels the REST endpoint serves, in name order. Label management stays in the REST API and the issue sidebar; this page is the browse surface. See spec 02 section 3.6.

func (*Handlers) Milestone added in v0.1.3

func (h *Handlers) Milestone(c *mizu.Ctx) error

Milestone renders one milestone's page: GET /{owner}/{repo}/milestone/{number}, github.com's singular form. The header block carries the progress and due date; below it the milestone's issues render as the same bounded rows the issues index uses, tabbed open (?closed=1 for closed). A missing milestone is the soft 404.

func (*Handlers) Milestones added in v0.1.3

func (h *Handlers) Milestones(c *mizu.Ctx) error

Milestones renders the milestone list: GET /{owner}/{repo}/milestones, with ?state=closed for the closed tab. One all-states read feeds both the rows and the honest tab counts. Milestone management stays in the REST API; this page is the browse surface. See spec 02 section 3.6.

func (*Handlers) New

func (h *Handlers) New(c *mizu.Ctx) error

New renders the new-issue form, seeded from the documented prefill query (?title=&body=&labels=&assignees=&milestone=&template=). A viewer who cannot write still sees the form shell, and the create handler authorizes the submit, so the affordance and the action stay consistent. See implementation/08 section 10.

func (*Handlers) Resolve

func (h *Handlers) Resolve(next mizu.Handler) mizu.Handler

Resolve loads the repository named by the {owner} and {repo} path parameters, read-gated for the viewer, and stores it on the context. A missing repository, or a private one the viewer cannot see, renders the same 404, so a private repo never leaks through the status code. This mirrors the code-browsing Resolve so the two surfaces gate identically. It is the one place the repo is loaded; every handler reads it back with repoFromContext.

func (*Handlers) Show

func (h *Handlers) Show(c *mizu.Ctx) error

Show renders the issue detail page: the title and state header, the comment timeline (the opening body first, then the comments oldest-first), the sidebar with the labels, assignees, and milestone, and the composer. A missing issue, or one in a repo the viewer cannot see, renders the soft 404, never a 403. See implementation/08 section 4.

func (*Handlers) ToggleCommentReaction

func (h *Handlers) ToggleCommentReaction(c *mizu.Ctx) error

ToggleCommentReaction adds or removes the viewer's reaction of the submitted content on a comment, returning to the comment's anchor on the issue page.

func (*Handlers) ToggleIssueReaction

func (h *Handlers) ToggleIssueReaction(c *mizu.Ctx) error

ToggleIssueReaction adds or removes the viewer's reaction of the submitted content on the issue body.

func (*Handlers) ToggleState

func (h *Handlers) ToggleState(c *mizu.Ctx) error

ToggleState closes or reopens the issue, optionally posting a comment in the same submit (the "Close with comment" path). The target state is derived from the issue's current state, so the one button does the right thing either way.

type Qualifier

type Qualifier struct {
	Key    string
	Value  string
	Negate bool
}

Qualifier is one key:value token, with the leading '-' negation preserved so the composer can round-trip a query it does not itself project.

type Query

type Query struct {
	Raw   string      // the literal q string, for the search input value
	State string      // "open" | "closed" | "" (unset, treated as open default)
	Type  string      // "issue" (this index) | "pr" (the handler redirects to /pulls)
	Terms []string    // bare full-text words
	Quals []Qualifier // every key:value, in source order, negation preserved
}

Query is the parsed and re-composable ?q= filter. It is the single source of truth for the issues index filter: the index handler parses it once, the templates call its composer methods to build dropdown and chip hrefs server-side, and Filter projects it to the domain query the API also uses.

func DefaultQuery

func DefaultQuery() *Query

DefaultQuery is what an index visited with no ?q= behaves as, and what the "clear filters" link restores (implementation/08 section 1.6, 2.1).

func ParseQuery

func ParseQuery(raw string) *Query

ParseQuery tokenizes the raw q string into a Query. It never errors: it cannot, because a browser can submit anything. A whitespace-only q yields the default.

func (*Query) ActiveLabels

func (q *Query) ActiveLabels() []string

ActiveLabels returns the active label set sorted for a stable chip order.

func (*Query) AddLabel

func (q *Query) AddLabel(name string) string

AddLabel appends a label: qualifier (labels are an AND set, so repeats stack). Re-adding a present label is a no-op so a chip click stays idempotent.

func (*Query) Encode

func (q *Query) Encode() string

Encode is the URL-encoded q value alone (no leading ?), for a caller that composes the query string itself.

func (*Query) Filter

func (q *Query) Filter(viewer *view.Viewer) domain.IssueQuery

Filter projects the parsed Query into the domain.IssueQuery the REST list endpoint (implementation/02 section 4.7) also builds, so the UI and API agree field for field on what a query selects. @me resolves to the viewer login here, the only viewer-relative rewrite, so the domain query carries a concrete login. Qualifiers the domain does not model are left in the Query for round-tripping but do not narrow the result (see the as-built note at the top of this file).

func (*Query) NoAssignee

func (q *Query) NoAssignee() string

NoAssignee sets no:assignee and drops any concrete assignee:.

func (*Query) NoMilestone

func (q *Query) NoMilestone() string

NoMilestone sets no:milestone and drops any concrete milestone:.

func (*Query) RemoveLabel

func (q *Query) RemoveLabel(name string) string

RemoveLabel drops a label: qualifier, the active-chip dismiss link.

func (*Query) SetAssignee

func (q *Query) SetAssignee(login string) string

SetAssignee replaces any assignee: qualifier with the given login and clears a no:assignee that would contradict it.

func (*Query) SetAuthor

func (q *Query) SetAuthor(login string) string

SetAuthor replaces any author: qualifier with the given login.

func (*Query) SetMilestone

func (q *Query) SetMilestone(title string) string

SetMilestone replaces any milestone: qualifier with the given title and clears a contradicting no:milestone.

func (*Query) SetSort

func (q *Query) SetSort(key string) string

SetSort sets the sort: qualifier, omitting it entirely when it equals the default so the canonical default URL stays bare.

func (*Query) WithState

func (q *Query) WithState(s string) string

WithState flips between is:open and is:closed, keeping every other token. The state tabs link here.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL