Files
Gitea/routers/web/repo/watch.go
T
Alexandre Bontems 7dbfed37eb feat: add watch options (#37571)
Adds per-event watch options, so a user can choose which repository
notifications they receive.

The watch button is now a menu with four modes: participating and
mentions (the unwatched state, as on GitHub), all activity, ignore, and
custom, which opens a dialog to pick issues, pull requests and releases.
The same dialog is reachable from the gear icon on the watched
repository list. Options apply to UI notifications and to mail.

The watcher, star and fork counts moved inside their buttons, so all
three share one shape, and the links to those lists moved to the
repository sidebar.

Assignees and requested reviewers now also receive UI notifications
without having commented first.

Buttons and dropdown:

<img width="688" height="398" alt="image"
src="https://github.com/user-attachments/assets/889b567d-086f-4a06-ac67-3a4205fc63b2"
/>

Modal:

<img width="841" height="327" alt="Screenshot 2026-08-07 at 21 10 59"
src="https://github.com/user-attachments/assets/3bedbff5-9011-4f1b-91a9-e8f5c212fb5d"
/>

New entries in sidebar:

<img width="170" height="207" alt="Screenshot 2026-08-07 at 21 13 28"
src="https://github.com/user-attachments/assets/5f5150cd-f42d-4543-bd0b-7334cf4aab0e"
/>

Fixes: https://github.com/go-gitea/gitea/issues/17238
Ref: https://github.com/go-gitea/gitea/issues/35492

---------

Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
2026-08-08 07:35:13 +00:00

73 lines
2.2 KiB
Go

// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repo
import (
"net/http"
repo_model "gitea.dev/models/repo"
"gitea.dev/modules/templates"
"gitea.dev/services/context"
)
const tplWatch templates.TplName = "repo/header/watch"
func ActionWatch(ctx *context.Context) {
action := ctx.PathParam("action")
var err error
if action == "ignore" {
err = repo_model.IgnoreRepo(ctx, ctx.Doer, ctx.Repo.Repository)
} else {
err = repo_model.WatchRepo(ctx, ctx.Doer, ctx.Repo.Repository, action == "watch")
}
if err != nil {
handleActionError(ctx, err)
return
}
if action == "watch" { // watching again always restores every event, so "all activity" can undo a custom selection
opts := repo_model.WatchOptions{PullRequests: true, Issues: true, Releases: true}
if err := repo_model.SetWatchOptions(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID, opts); err != nil {
ctx.ServerError("SetWatchOptions", err)
return
}
}
watch, err := repo_model.GetWatch(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
if err != nil {
ctx.ServerError("GetWatch", err)
return
}
ctx.Data["Watch"] = watch
ctx.Data["IsWatchingRepo"] = repo_model.IsWatchMode(watch.Mode)
ctx.Data["Repository"], err = repo_model.GetRepositoryByName(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.Name)
if err != nil {
ctx.ServerError("GetRepositoryByName", err)
return
}
ctx.HTML(http.StatusOK, tplWatch)
}
// ActionWatchOptions watches the repository with a custom selection of events
func ActionWatchOptions(ctx *context.Context) {
opts := repo_model.WatchOptions{
PullRequests: ctx.FormBool(string(repo_model.WatchPullRequests)),
Issues: ctx.FormBool(string(repo_model.WatchIssues)),
Releases: ctx.FormBool(string(repo_model.WatchReleases)),
}
if !opts.PullRequests && !opts.Issues && !opts.Releases {
ctx.JSONError(ctx.Tr("repo.watch.options.required"))
return
}
if err := repo_model.WatchRepo(ctx, ctx.Doer, ctx.Repo.Repository, true); err != nil {
handleActionError(ctx, err)
return
}
if err := repo_model.SetWatchOptions(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID, opts); err != nil {
ctx.ServerError("SetWatchOptions", err)
return
}
ctx.JSONRedirect("")
}