← back to kljensen__yale-peer-review

Function bodies 190 total

All specs Real LLM only Function bodies
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
		}

		ret
app.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.ConfigFileNot
assets.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.
		i
Generated 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,
		Value
auth.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: %w
All 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(
						Type
components.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 yo
components.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 ›