gitforge/templates/org/team/members.tmpl
Antonin Delpeuch c99b35cfa4 feat: setting to add team members by invitations (#12845)
Fixes #12564. Fixes #8951.

This introduces a new setting, `ADD_MEMBERS_BY_INVITATIONS`, which is turned off by default.
When turned on, adding a user to a team issues an invitation instead of adding them directly to the team.
A prerequisite for this work was to be able to link invitations to existing users (so far, they were only associated to an email address, since those invitations were meant to be issued to users who didn't have an account yet).

---

I plan to work on the following improvements, which I propose to do in separate PRs given that this one is already a bit big:
* generate an in-app notification for the invited user
* advertise the invitation to the invited user from the org page as well (#12120)
* show the list of invited users in the list of organization members (not just on the team page)

and various other improvements to invitations (#12570, #12716).

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12845
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
2026-06-15 01:46:25 +02:00

104 lines
4 KiB
Go HTML Template

{{template "base/head" .}}
<div role="main" aria-label="{{.Title}}" class="page-content organization teams">
{{template "org/header" .}}
<div class="ui container">
{{template "base/alert" .}}
<div class="ui stackable grid">
{{template "org/team/sidebar" .}}
<div class="ui ten wide column">
{{template "org/team/navbar" .}}
{{if .IsOrganizationOwner}}
<div class="ui attached segment">
<form class="ui form ignore-dirty tw-flex tw-flex-wrap tw-gap-2" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/add" method="post">
<input type="hidden" name="uid" value="{{.SignedUser.ID}}">
<div id="search-user-box" class="ui search tw-mr-2"{{if .IsEmailInviteEnabled}} data-allow-email="true" data-allow-email-description="{{ctx.Locale.Tr "org.teams.invite_team_member" $.Team.Name}}"{{end}}>
<div class="ui input">
<input class="prompt" name="uname" placeholder="{{ctx.Locale.Tr "search.user_kind"}}" autocomplete="off" required>
</div>
</div>
<button class="ui primary button">
{{if $.AddMembersByInvitations}}
{{ctx.Locale.Tr "members.invite_team_member"}}
{{else}}
{{ctx.Locale.Tr "org.teams.add_team_member"}}
{{end}}
</button>
</form>
</div>
{{end}}
<div class="ui attached segment">
<div class="flex-list">
{{range .Team.Members}}
<div class="flex-item tw-items-center">
<div class="flex-item-leading">
<a href="{{.HomeLink}}">{{ctx.AvatarUtils.Avatar . 32}}</a>
</div>
<div class="flex-item-main">
<div class="flex-item-title">
{{template "shared/user/name" .}}
</div>
</div>
<div class="flex-item-trailing">
{{if and $.IsOrganizationOwner (not (and ($.Team.IsOwnerTeam) (eq (len $.Team.Members) 1)))}}
<form>
<button class="ui red button delete-button" data-modal-id="remove-team-member"
data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/remove" data-datauid="{{.ID}}"
data-name="{{.DisplayName}}"
data-data-team-name="{{$.Team.Name}}">{{ctx.Locale.Tr "org.members.remove"}}</button>
</form>
{{end}}
</div>
</div>
{{else}}
<div class="flex-item">
<span class="text grey tw-italic">{{ctx.Locale.Tr "org.teams.members.none"}}</span>
</div>
{{end}}
</div>
{{template "base/paginate" .}}
</div>
{{if and .Invites $.IsOrganizationOwner}}
<h4 class="ui top attached header">{{ctx.Locale.Tr "org.teams.invite_team_member.list"}}</h4>
<div class="ui attached segment">
<div class="flex-list">
{{range .Invites}}
<div class="flex-item tw-items-center">
{{if .InvitedUser}}
<div class="flex-item-leading">
<a href="{{.InvitedUser.HomeLink}}">{{ctx.AvatarUtils.Avatar .InvitedUser 32}}</a>
</div>
<div class="flex-item-main">
<div class="flex-item-title">
{{template "shared/user/name" .InvitedUser}}
</div>
</div>
{{else}}
<div class="flex-item-main">
{{.Email}}
</div>
{{end}}
<div class="flex-item-trailing">
<form action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/remove_invite" method="post">
<input type="hidden" name="iid" value="{{.ID}}">
<button class="ui red button">{{ctx.Locale.Tr "org.members.remove"}}</button>
</form>
</div>
</div>
{{end}}
</div>
</div>
{{end}}
</div>
</div>
</div>
</div>
<div class="ui g-modal-confirm delete modal" id="remove-team-member">
<div class="header">
{{ctx.Locale.Tr "org.members.remove"}}
</div>
<div class="content">
<p>{{ctx.Locale.Tr "org.members.remove.detail" (`<span class="name"></span>`|TrustHTML) (`<span class="dataTeamName"></span>`|TrustHTML)}}</p>
</div>
{{template "base/modal_actions_confirm" .}}
</div>
{{template "base/footer" .}}