Skip to content

Fix ::User Profile Page - Project/Packages Tabs Have Inconsistent Layout #25108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
095c30c
Fix ::User Profile Page - Project/Packages Tabs Have Inconsistent Lay…
puni9869 Jun 6, 2023
e863960
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 6, 2023
e0813ef
fix packages dropdown
silverwind Jun 6, 2023
e66e26d
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 7, 2023
91906db
Code tab fix for profile avatar
puni9869 Jun 7, 2023
ee7b36d
Fixing linting issues in template
puni9869 Jun 7, 2023
f51c22d
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 7, 2023
75f9726
Fixing header ctx key
puni9869 Jun 7, 2023
8fc29fe
Merge branch 'go-gitea:main' into punit/ISSUE-24871-fixing-user-profi…
puni9869 Jun 8, 2023
cc79eba
fix all value in package search dropdown
silverwind Jun 8, 2023
b887c71
Making visible project tab when we are on code tab
puni9869 Jun 8, 2023
449462b
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 8, 2023
cac6f0d
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 9, 2023
3b21c82
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 9, 2023
c64bbb1
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 9, 2023
127ae11
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 9, 2023
11d473d
Merge branch 'go-gitea:main' into punit/ISSUE-24871-fixing-user-profi…
puni9869 Jun 10, 2023
c62a81c
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 12, 2023
3a0a73f
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 12, 2023
6c990c4
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
lunny Jun 14, 2023
59c21a4
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
silverwind Jun 14, 2023
a906f9b
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 15, 2023
f3762b4
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 15, 2023
75961e1
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 16, 2023
7c8eda1
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 18, 2023
3ec39d8
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jun 18, 2023
c65e84c
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jul 1, 2023
f437075
Merge branch 'main' into punit/ISSUE-24871-fixing-user-profile-page-1
puni9869 Jul 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions routers/web/org/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func MustEnableProjects(ctx *context.Context) {

// Projects renders the home page of projects
func Projects(ctx *context.Context) {
shared_user.RenderProfileBigAvatar(ctx)
ctx.Data["Title"] = ctx.Tr("repo.project_board")

sortType := ctx.FormTrim("sort")
Expand Down
90 changes: 90 additions & 0 deletions routers/web/shared/user/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,102 @@
package user

import (
"fmt"

"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
)

// RenderProfileBigAvatar set the context for big avatar view on repo
func RenderProfileBigAvatar(ctx *context.Context) {
// check view permissions
if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) {
ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name))
return
}

// advertise feed via meta tag
ctx.Data["FeedURL"] = ctx.ContextUser.HomeLink()

// Show OpenID URIs
openIDs, err := user_model.GetUserOpenIDs(ctx.ContextUser.ID)
if err != nil {
ctx.ServerError("GetUserOpenIDs", err)
return
}

var isFollowing bool
if ctx.Doer != nil {
isFollowing = user_model.IsFollowing(ctx.Doer.ID, ctx.ContextUser.ID)
}

ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["OpenIDs"] = openIDs
ctx.Data["IsFollowing"] = isFollowing

if len(ctx.ContextUser.Description) != 0 {
content, err := markdown.RenderString(&markup.RenderContext{
URLPrefix: ctx.Repo.RepoLink,
Metas: map[string]string{"mode": "document"},
GitRepo: ctx.Repo.GitRepo,
Ctx: ctx,
}, ctx.ContextUser.Description)
if err != nil {
ctx.ServerError("RenderString", err)
return
}
ctx.Data["RenderedDescription"] = content
}
showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
orgs, err := organization.FindOrgs(organization.FindOrgOptions{
UserID: ctx.ContextUser.ID,
IncludePrivate: showPrivate,
})
if err != nil {
ctx.ServerError("FindOrgs", err)
return
}
ctx.Data["Orgs"] = orgs
ctx.Data["HasOrgsVisible"] = organization.HasOrgsVisible(orgs, ctx.Doer)

badges, _, err := user_model.GetUserBadges(ctx, ctx.ContextUser)
if err != nil {
ctx.ServerError("GetUserBadges", err)
return
}
ctx.Data["Badges"] = badges

pagingNum := setting.UI.User.RepoPagingNum
page := ctx.FormInt("page")
_, numFollowers, err := user_model.GetUserFollowers(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{
PageSize: pagingNum,
Page: page,
})
if err != nil {
ctx.ServerError("GetUserFollowers", err)
return
}
ctx.Data["NumFollowers"] = numFollowers
_, numFollowing, err := user_model.GetUserFollowing(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{
PageSize: pagingNum,
Page: page,
})
if err != nil {
ctx.ServerError("GetUserFollowing", err)
return
}
ctx.Data["NumFollowing"] = numFollowing
ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate
ctx.Data["EnableFeed"] = setting.Other.EnableFeed
}

func RenderUserHeader(ctx *context.Context) {
ctx.Data["IsProjectEnabled"] = true
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
Expand Down
5 changes: 2 additions & 3 deletions routers/web/user/code.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/modules/context"
code_indexer "code.gitea.io/gitea/modules/indexer/code"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/web/shared/user"
)

const (
Expand All @@ -19,17 +20,16 @@ const (

// CodeSearch render user/organization code search page
func CodeSearch(ctx *context.Context) {
user.RenderProfileBigAvatar(ctx)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name and usage seems not ideal.

  • The name: it doesn't "render", it only prepares some data
  • If the response has been written in it, the caller shouldn't continue (by checking Written)

Copy link
Member Author

@puni9869 puni9869 Jun 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, and I am even in favour of changing the naming pattern, but when I see https://github.com/go-gitea/gitea/pull/25108/files/6c990c4da74a329f700ffffaa5ddfa1d6195fd7b#diff-f4279417070a8e33829c338abeb42877500377f490abb1495ae6357d50b6a765R92 in the same function doing something like that and implementation looks like this

func RenderUserHeader(ctx *context.Context) {
,
I don't want to break the pattern, if you are suggesting an explicit change in function, that I can.

In short maintainability is the real concern here.

Could you suggest something which is easier for maintainers. I have less knowledge on naming conventions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the old code is buggy, so I won't say it is a must now.

if !setting.Indexer.RepoIndexerEnabled {
ctx.Redirect(ctx.ContextUser.HomeLink())
return
}

ctx.Data["IsProjectEnabled"] = true
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["Title"] = ctx.Tr("explore.code")
ctx.Data["ContextUser"] = ctx.ContextUser

language := ctx.FormTrim("l")
keyword := ctx.FormTrim("q")

Expand Down Expand Up @@ -109,6 +109,5 @@ func CodeSearch(ctx *context.Context) {
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "l", "Language")
ctx.Data["Page"] = pager

ctx.HTML(http.StatusOK, tplUserCode)
}
1 change: 1 addition & 0 deletions routers/web/user/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (

// ListPackages displays a list of all packages of the context user
func ListPackages(ctx *context.Context) {
shared_user.RenderProfileBigAvatar(ctx)
page := ctx.FormInt("page")
if page <= 1 {
page = 1
Expand Down
25 changes: 21 additions & 4 deletions templates/org/projects/list.tmpl
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
{{template "base/head" .}}
<div role="main" aria-label="{{.Title}}" class="page-content repository packages">
{{template "user/overview/header" .}}
{{template "projects/list" .}}
</div>
{{if .ContextUser.IsOrganization}}
<div role="main" aria-label="{{.Title}}" class="page-content repository packages">
{{template "shared/user/profile_big_avatar" .}}
{{template "user/overview/header" .}}
{{template "projects/list" .}}
</div>
{{else}}
<div role="main" aria-label="{{.Title}}" class="page-content user profile">
<div class="ui container">
<div class="ui stackable grid">
<div class="ui four wide column">
{{template "shared/user/profile_big_avatar" .}}
</div>
<div class="ui twelve wide column">
{{template "user/overview/header" .}}
{{template "projects/list" .}}
</div>
</div>
</div>
</div>
{{end}}
{{template "base/footer" .}}
18 changes: 16 additions & 2 deletions templates/package/shared/list.tmpl
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
<div class="ui container">
<div class="ui {{if .ContextUser.IsOrganization}} container{{end}}">
{{template "base/alert" .}}
<form class="ui form ignore-dirty">
<form class="ui form ignore-dirty search-input">
<div class="ui fluid action input">
<input name="q" value="{{.Query}}" placeholder="{{.locale.Tr "explore.search"}}..." autofocus>
<div class="ui dropdown selection">
<input name="type" type="hidden" value="{{if $.PackageType}}{{$.PackageType}}{{else}}all{{end}}">
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="default text">{{.locale.Tr "packages.filter.type"}}</div>
<div class="menu">
<div class="item" data-value="all">{{.locale.Tr "packages.filter.type.all"}}</div>
{{range $type := .AvailableTypes}}
<div class="item" data-value="{{$type.Name}}">
{{$type.Name}}
</div>
{{end}}
</div>
</div>
{{template "shared/searchinput" dict "locale" .locale "Value" .Query "AutoFocus" true}}
<select class="ui dropdown" name="type">
<option value="">{{.locale.Tr "packages.filter.type"}}</option>
Expand Down
4 changes: 2 additions & 2 deletions templates/package/shared/versionlist.tmpl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="ui container">
<div class="ui{{if .ContextUser.IsOrganization}} container{{end}}">
<p><a href="{{.PackageDescriptor.PackageWebLink}}">{{.PackageDescriptor.Package.Name}}</a> / <strong>{{.locale.Tr "packages.versions"}}</strong></p>
<form class="ui form ignore-dirty">
<form class="ui form ignore-dirty ">
<div class="ui fluid action input">
{{template "shared/searchinput" dict "locale" .locale "Value" .Query "AutoFocus" true}}
<select class="ui dropdown" name="sort">
Expand Down
2 changes: 1 addition & 1 deletion templates/projects/list.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div role="main" aria-label="{{.Title}}" class="page-content repository projects">
<div class="ui container">
<div class="ui{{if .ContextUser.IsOrganization}} container{{end}}">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's too hacky. Why "IsOrganization" means "container"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible, remove the container.

Copy link
Member Author

@puni9869 puni9869 Jun 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately container cannot be removed, it is hacky beause we are sharing this between repository and orgransation page. I tried removing it but it will mass the whole project tab design in org view.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, it might be an acceptable compromise then. Didn't check the details.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My opinion is that these if-else tricks are too fragile, so I can't vote my approval, while I won't block if others like it and approve.

{{if .CanWriteProjects}}
<div class="navbar">
<div class="ui right">
Expand Down
135 changes: 135 additions & 0 deletions templates/shared/user/profile_big_avatar.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
{{if .ContextUser.IsOrganization}}
{{with .ContextUser}}
<div class="ui container">
<div class="ui vertically grid head">
<div class="column">
<div class="ui header">
{{avatar $.Context . 100}}
<span class="text thin grey"><a href="{{.HomeLink}}">{{.DisplayName}}</a></span>
<span class="org-visibility">
{{if .Visibility.IsLimited}}<div class="ui medium basic horizontal label">{{$.locale.Tr "org.settings.visibility.limited_shortname"}}</div>{{end}}
{{if .Visibility.IsPrivate}}<div class="ui medium basic horizontal label">{{$.locale.Tr "org.settings.visibility.private_shortname"}}</div>{{end}}
</span>
</div>
</div>
</div>
</div>
{{end}}
{{else}}
<div class="ui card">
<div id="profile-avatar" class="content gt-df">
{{if eq .SignedUserID .ContextUser.ID}}
<a class="image" href="{{AppSubUrl}}/user/settings" data-tooltip-content="{{.locale.Tr "user.change_avatar"}}">
{{/* the size doesn't take affect (and no need to take affect), image size(width) should be controlled by the parent container since this is not a flex layout*/}}
{{avatar $.Context .ContextUser 256}}
</a>
{{else}}
<span class="image">
{{avatar $.Context .ContextUser 256}}
</span>
{{end}}
</div>
<div class="content gt-word-break profile-avatar-name">
{{if .ContextUser.FullName}}<span class="header text center">{{.ContextUser.FullName}}</span>{{end}}
<span class="username text center">{{.ContextUser.Name}}</span>
{{if .EnableFeed}}
<a href="{{.ContextUser.HomeLink}}.rss"><i class="ui text grey gt-ml-3" data-tooltip-content="{{.locale.Tr "rss_feed"}}">{{svg "octicon-rss" 18}}</i></a>
{{end}}
<div class="gt-mt-3">
<a class="muted" href="{{.ContextUser.HomeLink}}?tab=followers">{{svg "octicon-person" 18 "gt-mr-2"}}{{.NumFollowers}} {{.locale.Tr "user.followers"}}</a> · <a class="muted" href="{{.ContextUser.HomeLink}}?tab=following">{{.NumFollowing}} {{.locale.Tr "user.following"}}</a>
</div>
</div>
<div class="extra content gt-word-break">
<ul>
{{if .ContextUser.Location}}
<li>{{svg "octicon-location"}} {{.ContextUser.Location}}</li>
{{end}}
{{if (eq .SignedUserID .ContextUser.ID)}}
<li>
{{svg "octicon-mail"}}
<a href="mailto:{{.ContextUser.Email}}" rel="nofollow">{{.ContextUser.Email}}</a>
<a href="{{AppSubUrl}}/user/settings#keep-email-private">
{{if .ShowUserEmail}}
<i class="ui right" data-tooltip-content="{{.locale.Tr "user.email_visibility.limited"}}">
{{svg "octicon-unlock"}}
</i>
{{else}}
<i class="ui right" data-tooltip-content="{{.locale.Tr "user.email_visibility.private"}}">
{{svg "octicon-lock"}}
</i>
{{end}}
</a>
</li>
{{else}}
{{if .ShowUserEmail}}
<li>
{{svg "octicon-mail"}}
<a href="mailto:{{.ContextUser.Email}}" rel="nofollow">{{.ContextUser.Email}}</a>
</li>
{{end}}
{{end}}
{{if .ContextUser.Website}}
<li>
{{svg "octicon-link"}}
<a target="_blank" rel="noopener noreferrer me" href="{{.ContextUser.Website}}">{{.ContextUser.Website}}</a>
</li>
{{end}}
{{if $.RenderedDescription}}
<li>
<div class="render-content markup">{{$.RenderedDescription|Str2html}}</div>
</li>
{{end}}
{{range .OpenIDs}}
{{if .Show}}
<li>
{{svg "fontawesome-openid"}}
<a target="_blank" rel="noopener noreferrer" href="{{.URI}}">{{.URI}}</a>
</li>
{{end}}
{{end}}
<li>{{svg "octicon-clock"}} {{.locale.Tr "user.joined_on" (DateTime "short" .ContextUser.CreatedUnix) | Safe}}</li>
{{if and .Orgs .HasOrgsVisible}}
<li>
<ul class="user-orgs">
{{range .Orgs}}
{{if (or .Visibility.IsPublic (and ($.SignedUser) (or .Visibility.IsLimited (and (.HasMemberWithUserID $.SignedUserID) .Visibility.IsPrivate) ($.IsAdmin))))}}
<li>
<a href="{{.HomeLink}}" data-tooltip-content="{{.Name}}">
{{avatar $.Context .}}
</a>
</li>
{{end}}
{{end}}
</ul>
</li>
{{end}}
{{if .Badges}}
<li>
<ul class="user-badges">
{{range .Badges}}
<li>
<img width="64" height="64" src="{{.ImageURL}}" alt="{{.Description}}" data-tooltip-content="{{.Description}}">
</li>
{{end}}
</ul>
</li>
{{end}}
{{if and .IsSigned (ne .SignedUserID .ContextUser.ID)}}
<li class="follow">
{{if $.IsFollowing}}
<form method="post" action="{{.Link}}?action=unfollow&redirect_to={{$.Link}}">
{{$.CsrfTokenHtml}}
<button type="submit" class="ui basic red button">{{svg "octicon-person"}} {{.locale.Tr "user.unfollow"}}</button>
</form>
{{else}}
<form method="post" action="{{.Link}}?action=follow&redirect_to={{$.Link}}">
{{$.CsrfTokenHtml}}
<button type="submit" class="ui basic green button">{{svg "octicon-person"}} {{.locale.Tr "user.follow"}}</button>
</form>
{{end}}
</li>
{{end}}
</ul>
</div>
</div>
{{end}}
Loading