Introduce a commercial license option alongside AGPL-3.0-only, require a CLA for contributors, and document the terms in COMMERCIAL.md and NOTICE. Add a script to stamp SPDX headers on Go files and apply it across the tree.
71 lines
2.5 KiB
Go
71 lines
2.5 KiB
Go
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial
|
|
// SPDX-FileCopyrightText: 2025-2026 Christian Galo
|
|
|
|
package server
|
|
|
|
// Shell is the data every top-level page hands the shared application
|
|
// shell (docs/design-system.md, "Application shell"): the top bar with its
|
|
// account menu (partials/shell_topbar.html) and, on the member surface, the
|
|
// rail (partials/shell_rail_member.html). One value per page, so the shell
|
|
// is written once and both surfaces render it the same way
|
|
// (chrome-conventions: "One shell for both surfaces"; "Session controls
|
|
// live in the account menu on both surfaces").
|
|
type Shell struct {
|
|
// Surface is ShellMember or ShellOperator. The operator surface adds
|
|
// the muted "Operator" label after the brand; the member surface
|
|
// renders the member rail.
|
|
Surface string
|
|
// Name, Username, and Email are the session's identity claims. Name is
|
|
// empty when the identity provider supplied none.
|
|
Name string
|
|
Username string
|
|
Email string
|
|
// KeycloakAccountURL is the identity provider's account console, the
|
|
// "Identity and Access" destination.
|
|
KeycloakAccountURL string
|
|
// IsOperator gates the member rail's "Operator panel" surface switch.
|
|
IsOperator bool
|
|
// Active names the member rail entry to mark active: "dashboard",
|
|
// "products", or "billing". The operator rail keeps its own
|
|
// ActiveCapability logic in operator.html and ignores this.
|
|
Active string
|
|
}
|
|
|
|
// The two surfaces the shell renders.
|
|
const (
|
|
ShellMember = "member"
|
|
ShellOperator = "operator"
|
|
)
|
|
|
|
// Label is the account menu's trigger text: the person's display name, the
|
|
// username when the identity provider supplied no name, and a neutral word
|
|
// when it supplied neither, so the trigger is never blank.
|
|
func (s Shell) Label() string {
|
|
if s.Name != "" {
|
|
return s.Name
|
|
}
|
|
if s.Username != "" {
|
|
return s.Username
|
|
}
|
|
return "Account"
|
|
}
|
|
|
|
// IsOperatorSurface reports whether the shell renders the operator surface.
|
|
func (s Shell) IsOperatorSurface() bool { return s.Surface == ShellOperator }
|
|
|
|
// Shell derives the operator surface's shell from the page data, which
|
|
// already carries the person's identity and the account console URL.
|
|
// Every operator page (this package's and an integration's via
|
|
// BuildOperatorPageData) gets the same shell without touching its
|
|
// constructor.
|
|
func (d OperatorPageData) Shell() Shell {
|
|
return Shell{
|
|
Surface: ShellOperator,
|
|
Name: d.Name,
|
|
Username: d.Username,
|
|
Email: d.Email,
|
|
KeycloakAccountURL: d.KeycloakAccountURL,
|
|
IsOperator: true,
|
|
}
|
|
}
|