Function bodies 190 total
cmd.init function · go · L32-L41 (10 LOC)cmd/yale-peer-review/cmd/root.go
func init() {
// Add the serve subcommand from internal/app
rootCmd.AddCommand(app.ServeCmd)
// Custom version template
rootCmd.SetVersionTemplate(fmt.Sprintf(
"yale-peer-review %s (commit: %s, built: %s)\n",
version, commit, date,
))
}cmd.Execute function · go · L43-L48 (6 LOC)cmd/yale-peer-review/cmd/root.go
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}app.wrapMiddleware function · go · L22-L58 (37 LOC)internal/app/pocketbase.go
func wrapMiddleware(mw func(http.Handler) http.Handler) func(*core.RequestEvent) error {
return func(re *core.RequestEvent) error {
// Track if middleware allowed the request to continue
allowed := false
// Track if response was written by middleware
responseWritten := false
// Wrap the response writer to detect if anything was written
wrappedWriter := &responseWriterDetector{
ResponseWriter: re.Response,
written: &responseWritten,
}
// Create a handler that signals continuation
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
allowed = true
// Update the request in case middleware modified it
re.Request = r
})
// Run middleware with wrapped writer
mw(handler).ServeHTTP(wrappedWriter, re.Request)
// If middleware wrote a response (redirect, error), stop the chain
if responseWritten {
return nil
}
// If middleware didn't call the next handler, stop the chain
if !allowed {
return nil
}
retapp.wrapHandler function · go · L77-L82 (6 LOC)internal/app/pocketbase.go
func wrapHandler(h http.HandlerFunc) func(*core.RequestEvent) error {
return func(re *core.RequestEvent) error {
h.ServeHTTP(re.Response, re.Request)
return nil
}
}app.StartServer function · go · L336-L361 (26 LOC)internal/app/pocketbase.go
func StartServer(dataDir string, port string) error {
// Create data directory if it doesn't exist
if dataDir != "" {
if err := os.MkdirAll(dataDir, 0755); err != nil {
return err
}
}
app := NewApp(dataDir)
log.Printf("Starting PocketBase server")
log.Printf("Data directory: %s", dataDir)
log.Printf("Server will listen on port: %s", port)
log.Printf("Admin UI available at: http://localhost:%s/_/", port)
log.Printf("Health endpoint at: http://localhost:%s/health", port)
// Set up command line args for PocketBase
app.RootCmd.SetArgs([]string{"serve", "--http", "0.0.0.0:" + port})
// Start the server
if err := app.Start(); err != nil {
return err
}
return nil
}app.init function · go · L23-L54 (32 LOC)internal/app/serve.go
func init() {
// Define flags
ServeCmd.Flags().StringP("data-dir", "d", "./data", "Directory for database and storage")
ServeCmd.Flags().StringP("port", "p", "8080", "Port to listen on")
// Bind flags to viper
viper.BindPFlag("data_dir", ServeCmd.Flags().Lookup("data-dir"))
viper.BindPFlag("port", ServeCmd.Flags().Lookup("port"))
// Set environment variable prefix
viper.SetEnvPrefix("YALE_PR")
viper.AutomaticEnv()
// Set defaults for CAS configuration
viper.SetDefault("mock_cas", false)
viper.SetDefault("mock_cas_port", "8081")
viper.SetDefault("cas_url", "http://localhost:8081/cas")
viper.SetDefault("service_url", "http://localhost:8080/auth/cas/callback")
// Optional: support config file in data directory
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath("./data")
viper.AddConfigPath(".")
// Read config file if it exists (don't error if it doesn't)
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotassets.Init function · go · L32-L99 (68 LOC)internal/assets/assets.go
func Init(staticFS fs.FS) error {
registry = make(map[string]*Asset)
byURL = make(map[string]*Asset)
m := minify.New()
m.AddFunc("text/css", css.Minify)
m.AddFunc("application/javascript", js.Minify)
// Read all files first so we can inline imports.
files := make(map[string][]byte)
err := fs.WalkDir(staticFS, ".", func(p string, d fs.DirEntry, err error) error {
if err != nil || d.IsDir() {
return err
}
data, readErr := fs.ReadFile(staticFS, p)
if readErr != nil {
return fmt.Errorf("reading %s: %w", p, readErr)
}
files[p] = data
return nil
})
if err != nil {
return fmt.Errorf("walking static files: %w", err)
}
// Inline pico.min.css into app.css.
if picoData, ok := files["css/pico.min.css"]; ok {
if appCSS, ok := files["css/app.css"]; ok {
inlined := inlinePicoImport(string(appCSS), string(picoData))
files["css/app.css"] = []byte(inlined)
}
}
for name, content := range files {
// Skip pico.min.css — it's now inlined into app.css.
iGenerated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
assets.Path function · go · L103-L109 (7 LOC)internal/assets/assets.go
func Path(name string) string {
a, ok := registry[name]
if !ok {
panic(fmt.Sprintf("assets: unknown asset %q", name))
}
return a.URLPath
}assets.Handler function · go · L113-L126 (14 LOC)internal/assets/assets.go
func Handler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
a, ok := byURL[r.URL.Path]
if !ok {
http.NotFound(w, r)
return
}
if a.ContentType != "" {
w.Header().Set("Content-Type", a.ContentType)
}
w.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
w.Write(a.Content)
}
}assets.mediaTypeFor function · go · L143-L152 (10 LOC)internal/assets/assets.go
func mediaTypeFor(name string) string {
switch path.Ext(name) {
case ".css":
return "text/css"
case ".js":
return "application/javascript"
default:
return ""
}
}auth.NewCASClient function · go · L28-L44 (17 LOC)internal/auth/cas.go
func NewCASClient(config CASConfig) (*CASValidator, error) {
casURL, err := url.Parse(config.CASURL)
if err != nil {
return nil, fmt.Errorf("invalid CAS URL: %w", err)
}
// Use an HTTP client with a timeout to prevent hung requests
client := &http.Client{
Timeout: DefaultCASTimeout,
}
validator := cas.NewServiceTicketValidator(client, casURL)
return &CASValidator{
validator: validator,
}, nil
}auth.ValidateServiceTicket function · go · L47-L66 (20 LOC)internal/auth/cas.go
func ValidateServiceTicket(validator *CASValidator, ticket string, service string) (string, error) {
// Create a service URL for validation
serviceURL, err := url.Parse(service)
if err != nil {
return "", fmt.Errorf("invalid service URL: %w", err)
}
// Validate the ticket
response, err := validator.validator.ValidateTicket(serviceURL, ticket)
if err != nil {
return "", fmt.Errorf("failed to validate service ticket: %w", err)
}
// Extract username (NetID) from response
if response.User == "" {
return "", fmt.Errorf("no user found in CAS response")
}
return response.User, nil
}auth.NewAuthHandlers function · go · L30-L37 (8 LOC)internal/auth/handlers.go
func NewAuthHandlers(app *pocketbase.PocketBase, casClient *CASValidator, serviceURL string, casURL string) *AuthHandlers {
return &AuthHandlers{
app: app,
casClient: casClient,
serviceURL: serviceURL,
casURL: casURL,
}
}auth.AuthHandlers.HandleCallback method · go · L46-L112 (67 LOC)internal/auth/handlers.go
func (h *AuthHandlers) HandleCallback(re *core.RequestEvent) error {
ticket := re.Request.URL.Query().Get("ticket")
if ticket == "" {
return re.BadRequestError("Missing ticket parameter", nil)
}
// Validate the service ticket
netid, err := ValidateServiceTicket(h.casClient, ticket, h.serviceURL)
if err != nil {
log.Printf("Failed to validate CAS ticket: %v", err)
return re.Redirect(http.StatusFound, "/auth/cas/login")
}
log.Printf("CAS authentication successful for NetID: %s", netid)
// Find or create user
user, err := h.findOrCreateUser(netid)
if err != nil {
log.Printf("Failed to find/create user: %v", err)
return re.InternalServerError("Authentication error", err)
}
// Generate auth token
token, tokenErr := user.NewAuthToken()
if tokenErr != nil {
log.Printf("Failed to generate auth token: %v", tokenErr)
return re.InternalServerError("Authentication error", tokenErr)
}
// Set auth cookie
cookie := &http.Cookie{
Name: AuthCookieName,
Valueauth.AuthHandlers.findOrCreateUser method · go · L115-L171 (57 LOC)internal/auth/handlers.go
func (h *AuthHandlers) findOrCreateUser(netid string) (*core.Record, error) {
// Normalize netid
netid = strings.ToLower(strings.TrimSpace(netid))
email := netid + "@yale.edu"
// Try to find existing user by email first (since email is unique and indexed)
record, err := h.app.FindFirstRecordByFilter("users", "email = {:email}", map[string]any{
"email": email,
})
if err == nil {
// User exists, update netid if it's not set
if record.GetString("netid") == "" {
record.Set("netid", netid)
if saveErr := h.app.Save(record); saveErr != nil {
log.Printf("Failed to update netid for existing user: %v", saveErr)
}
}
log.Printf("Found existing user: %s", netid)
return record, nil
}
// Log the error for debugging
log.Printf("User lookup by email failed (will create new user): %v", err)
// User doesn't exist, create new one
collection, err := h.app.FindCollectionByNameOrId("users")
if err != nil {
return nil, fmt.Errorf("failed to find users collection: %wAll rows above produced by Repobility · https://repobility.com
auth.generateRandomPassword function · go · L174-L180 (7 LOC)internal/auth/handlers.go
func generateRandomPassword(length int) (string, error) {
bytes := make([]byte, length)
if _, err := rand.Read(bytes); err != nil {
return "", err
}
return hex.EncodeToString(bytes), nil
}auth.RequireAuth function · go · L18-L44 (27 LOC)internal/auth/middleware.go
func RequireAuth(app *pocketbase.PocketBase) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Get token from cookie or Authorization header
token := getTokenFromRequest(r)
if token == "" {
// No token, redirect to login
http.Redirect(w, r, "/auth/cas/login", http.StatusFound)
return
}
// Validate token and get user
// FindAuthRecordByToken validates JWT tokens of type "auth" (authentication)
user, err := app.FindAuthRecordByToken(token, "auth")
if err != nil {
log.Printf("Auth token validation failed: %v", err)
// Invalid token, redirect to login
http.Redirect(w, r, "/auth/cas/login", http.StatusFound)
return
}
// Add user to context
ctx := context.WithValue(r.Context(), UserContextKey, user)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}auth.RequireTeacher function · go · L48-L71 (24 LOC)internal/auth/middleware.go
func RequireTeacher(app *pocketbase.PocketBase) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value(UserContextKey)
if user == nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
record, ok := user.(*core.Record)
if !ok {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
if !record.GetBool("is_teacher") {
http.Error(w, "Forbidden: Teacher access required", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
}auth.getTokenFromRequest function · go · L74-L88 (15 LOC)internal/auth/middleware.go
func getTokenFromRequest(r *http.Request) string {
// Try cookie first
cookie, err := r.Cookie(AuthCookieName)
if err == nil && cookie.Value != "" {
return cookie.Value
}
// Try Authorization header
authHeader := r.Header.Get("Authorization")
if authHeader != "" && len(authHeader) > 7 && authHeader[:7] == "Bearer " {
return authHeader[7:]
}
return ""
}auth.GetAuthUser function · go · L91-L103 (13 LOC)internal/auth/middleware.go
func GetAuthUser(r *http.Request) *core.Record {
user := r.Context().Value(UserContextKey)
if user == nil {
return nil
}
record, ok := user.(*core.Record)
if !ok {
return nil
}
return record
}auth.IsTeacher function · go · L106-L111 (6 LOC)internal/auth/middleware.go
func IsTeacher(user *core.Record) bool {
if user == nil {
return false
}
return user.GetBool("is_teacher")
}auth.NewMockCASServer function · go · L37-L66 (30 LOC)internal/auth/mock_cas.go
func NewMockCASServer(port string) *MockCASServer {
server := &MockCASServer{
port: port,
tickets: make(map[string]string),
}
// Create custom handler that logs all requests
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("Mock CAS: Request %s %s", r.Method, r.URL.Path)
switch r.URL.Path {
case "/cas/login":
server.handleLogin(w, r)
case "/cas/serviceValidate":
server.handleServiceValidate(w, r)
case "/cas/logout":
server.handleLogout(w, r)
default:
log.Printf("Mock CAS: 404 - %s %s", r.Method, r.URL.Path)
http.NotFound(w, r)
}
})
server.server = &http.Server{
Addr: ":" + port,
Handler: handler,
}
return server
}auth.MockCASServer.Start method · go · L69-L173 (105 LOC)internal/auth/mock_cas.go
func (m *MockCASServer) Start() error {
log.Printf("Mock CAS server starting on port %s", m.port)
log.Printf("Mock CAS endpoints:")
log.Printf(" http://localhost:%s/cas/login", m.port)
log.Printf(" http://localhost:%s/cas/serviceValidate", m.port)
log.Printf(" http://localhost:%s/cas/logout", m.port)
if err := m.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
return fmt.Errorf("mock CAS server error: %w", err)
}
return nil
}
// Stop stops the mock CAS server
func (m *MockCASServer) Stop() error {
log.Println("Mock CAS server stopping")
return m.server.Close()
}
// handleLogin handles CAS login requests
// Shows a login form if no username provided, otherwise generates ticket and redirects
func (m *MockCASServer) handleLogin(w http.ResponseWriter, r *http.Request) {
service := r.URL.Query().Get("service")
username := r.URL.Query().Get("username")
// If no username, show login form
if username == "" {
m.showLoginForm(w, service)
return
}
Repobility · code-quality intelligence platform · https://repobility.com
auth.MockCASServer.handleLogin method · go · L90-L119 (30 LOC)internal/auth/mock_cas.go
func (m *MockCASServer) handleLogin(w http.ResponseWriter, r *http.Request) {
service := r.URL.Query().Get("service")
username := r.URL.Query().Get("username")
// If no username, show login form
if username == "" {
m.showLoginForm(w, service)
return
}
// Validate service parameter
if service == "" {
http.Error(w, "Missing service parameter", http.StatusBadRequest)
return
}
// Generate a service ticket
ticket := fmt.Sprintf("ST-%s-%d", username, len(m.tickets))
// Store the ticket
m.mu.Lock()
m.tickets[ticket] = username
m.mu.Unlock()
log.Printf("Mock CAS: Generated ticket %s for user %s", ticket, username)
// Redirect back to service with ticket
redirectURL := fmt.Sprintf("%s?ticket=%s", service, ticket)
http.Redirect(w, r, redirectURL, http.StatusFound)
}auth.MockCASServer.showLoginForm method · go · L122-L159 (38 LOC)internal/auth/mock_cas.go
func (m *MockCASServer) showLoginForm(w http.ResponseWriter, service string) {
form := `<!DOCTYPE html>
<html>
<head>
<title>Mock Yale CAS - Login</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 400px; margin: 50px auto; padding: 20px; }
h1 { color: #00356b; font-size: 1.5em; }
.form-group { margin: 15px 0; }
label { display: block; margin-bottom: 5px; font-weight: bold; }
input[type="text"] { width: 100%%; padding: 10px; font-size: 16px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; }
button { background: #00356b; color: white; padding: 12px 24px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; width: 100%%; }
button:hover { background: #004080; }
.hint { color: #666; font-size: 0.9em; margin-top: 20px; }
.hint code { background: #f0f0f0; padding: 2px 6px; border-radius: 3px; }
</style>
</head>
<body>
<h1>Mock Yale CAS Login</h1>
<form method="GET">
<input type="hidden" name="service" value="%s">auth.MockCASServer.handleLogout method · go · L213-L222 (10 LOC)internal/auth/mock_cas.go
func (m *MockCASServer) handleLogout(w http.ResponseWriter, r *http.Request) {
// Clear any stored tickets for this session (simplified for mock)
log.Println("Mock CAS: Logout requested")
// In a real CAS server, would redirect to a logout page
// For mock, just return a simple message
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusOK)
w.Write([]byte("<html><body>Logged out from Mock CAS</body></html>"))
}auth.MockCASServer.writeXMLResponse method · go · L225-L238 (14 LOC)internal/auth/mock_cas.go
func (m *MockCASServer) writeXMLResponse(w http.ResponseWriter, response CASServiceResponse) {
w.Header().Set("Content-Type", "application/xml")
w.WriteHeader(http.StatusOK)
// Write XML declaration
w.Write([]byte(xml.Header))
// Marshal and write response
encoder := xml.NewEncoder(w)
encoder.Indent("", " ")
if err := encoder.Encode(response); err != nil {
log.Printf("Error encoding CAS response: %v", err)
}
}components.Page function · go · L12-L29 (18 LOC)internal/components/base.go
func Page(title string, content ...g.Node) g.Node {
return Doctype(
HTML(
Head(
Meta(Charset("utf-8")),
Meta(Name("viewport"), Content("width=device-width, initial-scale=1")),
TitleEl(g.Text(title)),
// Datastar script
Script(Src(assets.Path("js/datastar.js"))),
// Custom CSS (imports Pico CSS via @layer for proper cascade)
Link(Rel("stylesheet"), Href(assets.Path("css/app.css"))),
),
Body(
g.Group(content),
),
),
)
}components.TopNav function · go · L32-L69 (38 LOC)internal/components/base.go
func TopNav(crumbs []BreadcrumbItem, user *core.Record) g.Node {
isTeacher := user.GetBool("is_teacher")
netid := user.GetString("netid")
return Nav(Class("container"),
// Left side: breadcrumbs (first item is brand/home)
Breadcrumbs(crumbs),
// Right side: user dropdown with role-based links
Ul(
Li(
Details(Class("dropdown"),
Summary(g.Text(netid)),
Ul(
g.Attr("dir", "rtl"),
// Role-based navigation links
g.If(isTeacher,
Li(A(Href("/classes"), g.Text("My Classes"))),
),
g.If(!isTeacher,
g.Group([]g.Node{
Li(A(Href("/reviews"), g.Text("Pending Reviews"))),
Li(A(Href("/reviews/history"), g.Text("Submission History"))),
}),
),
// Divider
Li(Hr()),
// Logout
Li(
FormEl(Action("/auth/logout"), Method("post"),
Button(Type("submit"), Class("outline"), g.Text("Logout")),
),
),
),
),
),
),
)
}components.Container function · go · L73-L80 (8 LOC)internal/components/base.go
func Container(crumbs []BreadcrumbItem, user *core.Record, content ...g.Node) g.Node {
return g.Group([]g.Node{
TopNav(crumbs, user),
Main(Class("container"),
g.Group(content),
),
})
}components.AlertNode function · go · L88-L94 (7 LOC)internal/components/base.go
func AlertNode(alertType string, children ...g.Node) g.Node {
return Article(
g.Attr("role", "alert"),
Class("alert alert--"+alertType),
P(g.Group(children)),
)
}Repobility — same analyzer, your code, free for public repos · /scan/
components.ButtonLink function · go · L97-L103 (7 LOC)internal/components/base.go
func ButtonLink(text, href string) g.Node {
return A(
Href(href),
Role("button"),
g.Text(text),
)
}components.ClassList function · go · L13-L43 (31 LOC)internal/components/classes.go
func ClassList(activeClasses, archivedClasses []*core.Record) g.Node {
return Div(
PageTopmatter("My Classes", ButtonLink("Create New Class", "/classes/new")),
g.If(len(activeClasses) == 0 && len(archivedClasses) == 0,
EmptyState("You don't have any classes yet.", ButtonLink("Create your first class", "/classes/new")),
),
g.If(len(activeClasses) > 0,
ResourceListContainer(
ResourceList(
g.Map(activeClasses, func(class *core.Record) g.Node {
return ResourceListItem(ClassCard(class))
})...,
),
),
),
g.If(len(archivedClasses) > 0,
Details(
// Auto-open if no active classes
g.If(len(activeClasses) == 0, g.Attr("open", "")),
Summary(g.Textf("Archived Classes (%d)", len(archivedClasses))),
ResourceListContainer(
ResourceList(
g.Map(archivedClasses, func(class *core.Record) g.Node {
return ResourceListItem(ClassCard(class))
})...,
),
),
),
),
)
}components.ClassCard function · go · L46-L70 (25 LOC)internal/components/classes.go
func ClassCard(class *core.Record) g.Node {
archived := class.GetBool("archived")
statusLabel := "Active"
statusVariant := StatusSuccess
if archived {
statusLabel = "Archived"
statusVariant = StatusNeutral
}
// Build metadata items
metaItems := []MetaItem{
{Label: "Status", Value: StatusBadge(statusLabel, statusVariant)},
}
if name := class.GetString("name"); name != "" {
metaItems = append([]MetaItem{{Label: "Name", Value: MetaText(name)}}, metaItems...)
}
return ActionCard(ActionCardConfig{
Title: class.GetString("course_id") + " " + class.GetString("instance"),
Href: "/classes/" + class.Id,
Meta: metaItems,
ActionLabel: "View Class",
})
}components.ClassForm function · go · L73-L134 (62 LOC)internal/components/classes.go
func ClassForm(class *core.Record) g.Node {
isEdit := class != nil && class.Id != ""
title := "Create New Class"
action := "/classes/new"
courseId, instance, name := "", "", ""
if isEdit {
title = "Edit Class"
action = "/classes/" + class.Id
courseId = class.GetString("course_id")
instance = class.GetString("instance")
name = class.GetString("name")
}
return Div(
PageTopmatter(title),
FormEl(
Action(action),
Method("post"),
Div(
Label(
For("course_id"),
g.Text("Course ID (e.g., MGT656)"),
Input(
Type("text"),
Name("course_id"),
ID("course_id"),
Value(courseId),
Required(),
),
),
),
Div(
Label(
For("instance"),
g.Text("Instance (e.g., Spring 2025)"),
Input(
Type("text"),
Name("instance"),
ID("instance"),
Value(instance),
Required(),
),
),
),
Div(
Label(
For("name"),
g.Text("Name (optional)"),
Input(
Typecomponents.ArchivedBanner function · go · L137-L146 (10 LOC)internal/components/classes.go
func ArchivedBanner() g.Node {
return Div(
Class("archived-banner"),
Role("alert"),
P(
Strong(g.Text("This class is archived. ")),
g.Text("No changes can be made to projects or teams."),
),
)
}components.ClassDetail function · go · L149-L193 (45 LOC)internal/components/classes.go
func ClassDetail(class *core.Record, projects []*core.Record, progressMap map[string]db.ProjectProgress, staffMembers []*core.Record, isOwner bool) g.Node {
courseId := class.GetString("course_id")
instance := class.GetString("instance")
name := class.GetString("name")
archived := class.GetBool("archived")
// Use name as title if available, otherwise course ID
// Subtitle shows course info
title := courseId
subtitle := instance
if name != "" {
title = name
subtitle = courseId + " · " + instance
}
// Build header actions - only show create button if not archived
var headerActions []g.Node
if !archived {
headerActions = append(headerActions, ButtonLink("Create New Project", "/classes/"+class.Id+"/projects/new"))
}
return Div(
// Show archived banner if class is archived
g.If(archived, ArchivedBanner()),
PageTopmatterWithSubtitle(title, subtitle, headerActions...),
g.If(len(projects) == 0 && !archived,
EmptyState("No projects yet.", ButtonLink("Create yocomponents.StaffSection function · go · L196-L225 (30 LOC)internal/components/classes.go
func StaffSection(classId string, staffMembers []*core.Record, isOwner bool) g.Node {
// Only owners can manage staff
if !isOwner {
return g.Group(nil) // Return nothing for non-owners
}
return Article(Class("review-section"),
Header(H3(g.Text("Staff Members"))),
g.If(len(staffMembers) == 0,
P(g.Text("No staff members yet.")),
),
g.If(len(staffMembers) > 0,
Table(Class("responsive-table"),
THead(Tr(Th(g.Text("Name")), Th(g.Text("NetID")), Th(g.Text("Actions")))),
TBody(g.Group(g.Map(staffMembers, func(user *core.Record) g.Node {
return StaffMemberRow(classId, user)
}))),
),
),
// Add staff form
Footer(
FormEl(Action("/classes/"+classId+"/staff"), Method("post"),
Div(Class("grid"),
Input(Type("text"), Name("netid"), Placeholder("Enter NetID"), Required()),
Button(Type("submit"), g.Text("Add Staff")),
),
),
),
)
}components.StaffMemberRow function · go · L228-L242 (15 LOC)internal/components/classes.go
func StaffMemberRow(classId string, user *core.Record) g.Node {
name := user.GetString("name")
if name == "" {
name = user.GetString("netid")
}
return Tr(
TableCell("Name", g.Text(name)),
TableCell("NetID", g.Text(user.GetString("netid"))),
TableCellActions(
FormEl(Action("/classes/"+classId+"/staff/"+user.Id+"/remove"), Method("post"),
Button(Type("submit"), Class("secondary outline"), g.Text("Remove")),
),
),
)
}Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
components.ProjectCard function · go · L245-L271 (27 LOC)internal/components/classes.go
func ProjectCard(project *core.Record, progress db.ProjectProgress) g.Node {
isOpen := project.GetBool("is_open")
statusLabel := "Open"
statusVariant := StatusSuccess
if !isOpen {
statusLabel = "Closed"
statusVariant = StatusNeutral
}
deadline := timezone.FormatForDisplay(project.GetDateTime("deadline").Time(), "Jan 2, 3:04 PM")
// Build progress text
teamsText := g.Textf("%d of %d submitted", progress.TeamsSubmitted, progress.TotalTeams)
studentsText := g.Textf("%d of %d submitted", progress.StudentsSubmitted, progress.TotalStudents)
return ActionCard(ActionCardConfig{
Title: project.GetString("name"),
Href: "/projects/" + project.Id,
Meta: []MetaItem{
{Label: "Deadline", Value: MetaText(deadline)},
{Label: "Teams", Value: teamsText},
{Label: "Students", Value: studentsText},
{Label: "Status", Value: StatusBadge(statusLabel, statusVariant)},
},
ActionLabel: "View Project",
})
}components.DatastarResponse function · go · L19-L28 (10 LOC)internal/components/datastar.go
func DatastarResponse(w http.ResponseWriter, r *http.Request, component g.Node) error {
sse := datastar.NewSSE(w, r)
var buf bytes.Buffer
if err := component.Render(&buf); err != nil {
return err
}
return sse.MergeFragments(buf.String())
}components.ResourceCard function · go · L34-L40 (7 LOC)internal/components/primitives.go
func ResourceCard(header, body, footer g.Node) g.Node {
return Article(Class("resource-card"),
g.If(header != nil, header),
g.If(body != nil, body),
g.If(footer != nil, footer),
)
}components.ActionCard function · go · L58-L122 (65 LOC)internal/components/primitives.go
func ActionCard(cfg ActionCardConfig) g.Node {
// Determine effective URLs
titleURL := cfg.Href
if cfg.TitleHref != "" {
titleURL = cfg.TitleHref
}
buttonURL := cfg.Href
if cfg.ActionHref != "" {
buttonURL = cfg.ActionHref
}
// Warn if ActionLabel is set but no button URL
if cfg.ActionLabel != "" && buttonURL == "" {
log.Printf("ActionCard warning: ActionLabel %q set without Href or ActionHref", cfg.ActionLabel)
}
// Build CSS classes
classes := []string{"resource-card"}
if cfg.Urgency != "" {
classes = append(classes, "urgency-"+cfg.Urgency)
}
classes = append(classes, cfg.ExtraClasses...)
// Build title element
var titleNode g.Node
if titleURL != "" {
titleNode = H3(A(Href(titleURL), g.Text(cfg.Title)))
} else {
titleNode = H3(g.Text(cfg.Title))
}
// Build header
header := Header(
titleNode,
g.If(cfg.Subtitle != "", P(g.Text(cfg.Subtitle))),
g.If(cfg.Tertiary != "", Small(Class("card-tertiary"), g.Text(cfg.Tertiary))),
)
// Build body (components.ResourceCardHeader function · go · L125-L132 (8 LOC)internal/components/primitives.go
func ResourceCardHeader(title, subtitle string) g.Node {
return Header(
H3(g.Text(title)),
g.If(subtitle != "",
P(g.Text(subtitle)),
),
)
}components.ResourceCardHeaderWithID function · go · L135-L142 (8 LOC)internal/components/primitives.go
func ResourceCardHeaderWithID(id, title, subtitle string) g.Node {
return Header(
H3(ID(id), g.Text(title)),
g.If(subtitle != "",
P(g.Text(subtitle)),
),
)
}components.MetadataList function · go · L158-L169 (12 LOC)internal/components/primitives.go
func MetadataList(items []MetaItem) g.Node {
nodes := make([]g.Node, 0, len(items)*2)
for _, item := range items {
nodes = append(nodes,
Dt(g.Text(item.Label)),
Dd(item.Value),
)
}
return Dl(Class("metadata-list"),
g.Group(nodes),
)
}components.StatusBadge function · go · L191-L196 (6 LOC)internal/components/primitives.go
func StatusBadge(label string, variant StatusVariant) g.Node {
return Span(
Class("status-badge status-badge--"+string(variant)),
g.Text(label),
)
}All rows above produced by Repobility · https://repobility.com
components.ActionGroup function · go · L201-L208 (8 LOC)internal/components/primitives.go
func ActionGroup(ariaLabel string, actions ...g.Node) g.Node {
return Div(
Class("action-group"),
Role("group"),
g.Attr("aria-label", ariaLabel),
g.Group(actions),
)
}components.ActionMenu function · go · L219-L249 (31 LOC)internal/components/primitives.go
func ActionMenu(triggerLabel string, items []ActionMenuItem) g.Node {
menuItems := make([]g.Node, 0, len(items))
for _, item := range items {
var menuItem g.Node
if item.Form != nil {
menuItem = Li(item.Form)
} else {
linkClass := ""
if item.Danger {
linkClass = "contrast"
}
menuItem = Li(
A(
Href(item.Href),
g.If(linkClass != "", Class(linkClass)),
g.Text(item.Label),
),
)
}
menuItems = append(menuItems, menuItem)
}
return Details(Class("dropdown action-menu"),
Summary(
Role("button"),
Class("secondary"),
g.Text(triggerLabel),
),
Ul(g.Group(menuItems)),
)
}components.PageHeader function · go · L254-L263 (10 LOC)internal/components/primitives.go
func PageHeader(title string, actions ...g.Node) g.Node {
return Div(Class("page-header"),
H1(g.Text(title)),
g.If(len(actions) > 0,
Div(Class("page-header-actions"),
g.Group(actions),
),
),
)
}page 1 / 4next ›