diff --git a/options/locale_next/locale_en-US.json b/options/locale_next/locale_en-US.json index b24d96526f..6305a8a8ed 100644 --- a/options/locale_next/locale_en-US.json +++ b/options/locale_next/locale_en-US.json @@ -4,6 +4,12 @@ "home.explore_repos": "Explore repositories", "home.explore_users": "Explore users", "home.explore_orgs": "Explore organizations", + "stars.list.none": "No one starred this repo.", + "watch.list.none": "No one is watching this repo.", + "followers.incoming.list.self.none": "No one is following your profile.", + "followers.incoming.list.none": "No one is following this user.", + "followers.outgoing.list.self.none": "You are not following anyone.", + "followers.outgoing.list.none": "%s isn't following anyone.", "relativetime.now": "now", "relativetime.future": "in future", "relativetime.mins": { diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 219de722d2..de508509dc 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -1,5 +1,6 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. // Copyright 2014 The Gogs Authors. All rights reserved. +// Copyright 2017 The Gitea Authors. All rights reserved. +// Copyright 2023 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package repo @@ -1240,6 +1241,7 @@ func RenderUserCards(ctx *context.Context, total int, getter func(opts db.ListOp func Watchers(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.watchers") ctx.Data["CardsTitle"] = ctx.Tr("repo.watchers") + ctx.Data["CardsNoneMsg"] = ctx.Tr("watch.list.none") ctx.Data["PageIsWatchers"] = true RenderUserCards(ctx, ctx.Repo.Repository.NumWatches, func(opts db.ListOptions) ([]*user_model.User, error) { @@ -1251,6 +1253,7 @@ func Watchers(ctx *context.Context) { func Stars(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.stargazers") ctx.Data["CardsTitle"] = ctx.Tr("repo.stargazers") + ctx.Data["CardsNoneMsg"] = ctx.Tr("stars.list.none") ctx.Data["PageIsStargazers"] = true RenderUserCards(ctx, ctx.Repo.Repository.NumStars, func(opts db.ListOptions) ([]*user_model.User, error) { return repo_model.GetStargazers(ctx, ctx.Repo.Repository, opts) diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 5132b1da5c..8068c1c6bc 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -1,5 +1,6 @@ // Copyright 2015 The Gogs Authors. All rights reserved. // Copyright 2019 The Gitea Authors. All rights reserved. +// Copyright 2023 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT package user @@ -170,10 +171,20 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb ctx.Data["Cards"] = followers total = int(numFollowers) ctx.Data["CardsTitle"] = ctx.TrN(total, "user.followers.title.one", "user.followers.title.few") + if ctx.IsSigned && ctx.ContextUser.ID == ctx.Doer.ID { + ctx.Data["CardsNoneMsg"] = ctx.Tr("followers.incoming.list.self.none") + } else { + ctx.Data["CardsNoneMsg"] = ctx.Tr("followers.incoming.list.none") + } case "following": ctx.Data["Cards"] = following total = int(numFollowing) ctx.Data["CardsTitle"] = ctx.TrN(total, "user.following.title.one", "user.following.title.few") + if ctx.IsSigned && ctx.ContextUser.ID == ctx.Doer.ID { + ctx.Data["CardsNoneMsg"] = ctx.Tr("followers.outgoing.list.self.none") + } else { + ctx.Data["CardsNoneMsg"] = ctx.Tr("followers.outgoing.list.none", ctx.ContextUser.Name) + } case "activity": date := ctx.FormString("date") pagingNum = setting.UI.FeedPagingNum diff --git a/templates/repo/user_cards.tmpl b/templates/repo/user_cards.tmpl index fbd4ef0cee..fc5a30bd45 100644 --- a/templates/repo/user_cards.tmpl +++ b/templates/repo/user_cards.tmpl @@ -4,29 +4,33 @@ {{.CardsTitle}} {{end}} - + + {{end}} + + {{else if .CardsNoneMsg}} +
{{.CardsNoneMsg}}
+ {{end}} {{template "base/paginate" .}} diff --git a/tests/integration/repo_starwatch_test.go b/tests/integration/repo_starwatch_test.go index 3bcfa29fe3..85100eca30 100644 --- a/tests/integration/repo_starwatch_test.go +++ b/tests/integration/repo_starwatch_test.go @@ -17,7 +17,7 @@ import ( "github.com/stretchr/testify/assert" ) -func testRepoStarringOrWatching(t *testing.T, action, listURI string) { +func testRepoStarringOrWatching(t *testing.T, action, listURI string, expectEmpty bool) { t.Helper() defer tests.PrepareTestEnv(t)() @@ -50,6 +50,12 @@ func testRepoStarringOrWatching(t *testing.T, action, listURI string) { htmlDoc = NewHTMLParser(t, resp.Body) htmlDoc.AssertElement(t, ".user-cards .list .card > a[href='/user5']", true) + if expectEmpty { + // Verify which user-cards elements are present + htmlDoc.AssertElement(t, ".user-cards > .list", true) + htmlDoc.AssertElement(t, ".user-cards > div", false) + } + // Unstar/unwatch the repo as user5 req = NewRequestWithValues(t, "POST", fmt.Sprintf("/user2/repo1/action/%s", oppositeAction), map[string]string{ "_csrf": GetCSRF(t, session, "/user2/repo1"), @@ -73,15 +79,22 @@ func testRepoStarringOrWatching(t *testing.T, action, listURI string) { // Verify that "user5" is not among the stargazers/watchers htmlDoc = NewHTMLParser(t, resp.Body) - htmlDoc.AssertElement(t, ".user-cards .list .item.ui.segment > a[href='/user5']", false) + htmlDoc.AssertElement(t, ".user-cards .list .item.ui.segment > a[href='/user2']", false) + + if expectEmpty { + // Verify which user-cards elements are present + htmlDoc.AssertElement(t, ".user-cards > .list", false) + htmlDoc.AssertElement(t, ".user-cards > div", true) + } } func TestRepoStarUnstarUI(t *testing.T) { - testRepoStarringOrWatching(t, "star", "stars") + testRepoStarringOrWatching(t, "star", "stars", true) } func TestRepoWatchUnwatchUI(t *testing.T) { - testRepoStarringOrWatching(t, "watch", "watchers") + testRepoStarringOrWatching(t, "watch", "watchers", false) + // Empty list state is not checked because repo is watched by many users } func TestDisabledStars(t *testing.T) { diff --git a/tests/integration/user_profile_follows_test.go b/tests/integration/user_profile_follows_test.go index 08bd58db16..b4216865b7 100644 --- a/tests/integration/user_profile_follows_test.go +++ b/tests/integration/user_profile_follows_test.go @@ -1,5 +1,5 @@ // Copyright 2024 The Forgejo Authors. All rights reserved. -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: GPL-3.0-or-later package integration @@ -32,6 +32,7 @@ func TestUserProfileFollows(t *testing.T) { followingLink := "#profile-avatar-card a[href='/user1?tab=following']" listHeader := ".user-cards h2" listItems := ".user-cards .list" + listMsg := ".user-cards > div" // = No follows = @@ -44,7 +45,8 @@ func TestUserProfileFollows(t *testing.T) { // Verify that user1 has no followers testSelectorEquals(t, page, followersLink, "0 followers") testSelectorEquals(t, page, listHeader, "Followers") - testListCount(t, page, listItems, followCount) + page.AssertElement(t, listItems, false) + page.AssertElement(t, listMsg, true) // Request the profile of user1, the Following tab response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=following"), http.StatusOK) @@ -53,7 +55,8 @@ func TestUserProfileFollows(t *testing.T) { // Verify that user1 does not follow anyone testSelectorEquals(t, page, followingLink, "0 following") testSelectorEquals(t, page, listHeader, "Following") - testListCount(t, page, listItems, followCount) + page.AssertElement(t, listItems, false) + page.AssertElement(t, listMsg, true) // Make user1 and user2 follow each other testUserFollowUser(t, user1, "user2") @@ -71,6 +74,7 @@ func TestUserProfileFollows(t *testing.T) { testSelectorEquals(t, page, followersLink, "1 follower") testSelectorEquals(t, page, listHeader, "Follower") testListCount(t, page, listItems, followCount) + page.AssertElement(t, listMsg, false) // Request the profile of user1, the Following tab response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=following"), http.StatusOK) @@ -80,6 +84,7 @@ func TestUserProfileFollows(t *testing.T) { testSelectorEquals(t, page, followingLink, "1 following") testSelectorEquals(t, page, listHeader, "Following") testListCount(t, page, listItems, followCount) + page.AssertElement(t, listMsg, false) // Make user1 and user3 follow each other testUserFollowUser(t, user1, "user5") @@ -97,6 +102,7 @@ func TestUserProfileFollows(t *testing.T) { testSelectorEquals(t, page, followersLink, "2 followers") testSelectorEquals(t, page, listHeader, "Followers") testListCount(t, page, listItems, followCount) + page.AssertElement(t, listMsg, false) // Request the profile of user1, the Following tab response = user1.MakeRequest(t, NewRequest(t, "GET", "/user1?tab=following"), http.StatusOK) @@ -106,6 +112,7 @@ func TestUserProfileFollows(t *testing.T) { testSelectorEquals(t, page, followingLink, "2 following") testSelectorEquals(t, page, listHeader, "Following") testListCount(t, page, listItems, followCount) + page.AssertElement(t, listMsg, false) } // testUserFollowUser simply follows a user `following` by session of user `follower`