/images offers the models that make pictures, and the chat no longer offers them. Like the chat, the browser holds a session and never a key; the page's request is rebuilt from its own fields and sent down the path every /v1/images/generations request takes. Size, how many, seed, steps and a negative prompt; each picture shown with its seed, a download link and a way to make it again. Nothing is kept but the usage. The menu offers the page while some model makes pictures. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
86 lines
2.6 KiB
Go
86 lines
2.6 KiB
Go
package web
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/store"
|
|
)
|
|
|
|
// Nav is the menu at the top of every signed-in page.
|
|
//
|
|
// One menu, drawn by one template, because each page used to write its own:
|
|
// the same links in a different order, some missing, and the page you were on
|
|
// sometimes listed and sometimes not. Moving between pages then read as moving
|
|
// between different programs.
|
|
type Nav struct {
|
|
// Current is the page being shown, so its link is marked rather than
|
|
// offered: "cluster", "people", "quotas", "usage", "mirror", "chat", "images",
|
|
// "keys".
|
|
Current string
|
|
// Admin shows the administration links, and Role which of them: a
|
|
// billing role sees usage and quotas only.
|
|
Admin bool
|
|
Role string
|
|
// Mirror and Quotas are whether those pages were mounted at all; usage is
|
|
// mounted with quotas.
|
|
Mirror, Quotas bool
|
|
// Guard is whether the guardrails page was mounted.
|
|
Guard bool
|
|
// Settings offers the cluster's settings: mounted, and to an
|
|
// administrator only.
|
|
Settings bool
|
|
// CSRF signs the sign-out form.
|
|
CSRF string
|
|
// Org offers the organization page: to an administrator, and to anyone
|
|
// who manages an organization.
|
|
Org bool
|
|
// Images offers the pictures page, while some model makes them.
|
|
Images bool
|
|
}
|
|
|
|
type navKey struct{}
|
|
|
|
// navFor builds the menu for a signed-in person.
|
|
func (p *AccountPages) navFor(r *http.Request, user store.User, current string) Nav {
|
|
n := Nav{
|
|
Current: current,
|
|
Admin: user.Staff(),
|
|
Role: user.StaffRole(),
|
|
Mirror: p.hasMirror,
|
|
Quotas: p.hasQuotas,
|
|
Guard: p.hasGuard,
|
|
Settings: p.hasSettings && user.IsAdmin,
|
|
CSRF: csrfFor(r),
|
|
Images: p.images != nil && p.images(),
|
|
}
|
|
// Only when there is an organization to show: a link that leads to "there
|
|
// are none" on every page is noise.
|
|
if p.orgs != nil {
|
|
var orgs []store.Org
|
|
var err error
|
|
if user.IsAdmin {
|
|
orgs, err = p.orgs.AllOrgs(r.Context())
|
|
} else {
|
|
orgs, err = p.orgs.ManagedOrgs(r.Context(), user.ID)
|
|
}
|
|
n.Org = err == nil && len(orgs) > 0
|
|
}
|
|
return n
|
|
}
|
|
|
|
// withNav carries the menu to a page rendered by a handler that has no
|
|
// session of its own — the dashboard and the node logs are built without the
|
|
// account pages and wrapped by them.
|
|
func (p *AccountPages) withNav(r *http.Request, user store.User) *http.Request {
|
|
return r.WithContext(context.WithValue(r.Context(), navKey{}, p.navFor(r, user, "")))
|
|
}
|
|
|
|
// navFrom reads the menu withNav stored, marked for the page being drawn.
|
|
// Zero when there is none, which draws no admin links.
|
|
func navFrom(r *http.Request, current string) Nav {
|
|
n, _ := r.Context().Value(navKey{}).(Nav)
|
|
n.Current = current
|
|
return n
|
|
}
|