Skip to content

Commit db5d41c

Browse files
add templates for pages to add and manage teams with access to a group
1 parent 66271a0 commit db5d41c

File tree

5 files changed

+261
-5
lines changed

5 files changed

+261
-5
lines changed

models/activities/user_heatmap.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88

99
"code.gitea.io/gitea/models/db"
10+
group_model "code.gitea.io/gitea/models/group"
1011
"code.gitea.io/gitea/models/organization"
1112
user_model "code.gitea.io/gitea/models/user"
1213
"code.gitea.io/gitea/modules/setting"
@@ -21,15 +22,15 @@ type UserHeatmapData struct {
2122

2223
// GetUserHeatmapDataByUser returns an array of UserHeatmapData
2324
func GetUserHeatmapDataByUser(ctx context.Context, user, doer *user_model.User) ([]*UserHeatmapData, error) {
24-
return getUserHeatmapData(ctx, user, nil, doer)
25+
return getUserHeatmapData(ctx, user, nil, nil, doer)
2526
}
2627

2728
// GetUserHeatmapDataByUserTeam returns an array of UserHeatmapData
28-
func GetUserHeatmapDataByUserTeam(ctx context.Context, user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
29-
return getUserHeatmapData(ctx, user, team, doer)
29+
func GetUserHeatmapDataByUserTeam(ctx context.Context, user *user_model.User, team *organization.Team, group *group_model.Group, doer *user_model.User) ([]*UserHeatmapData, error) {
30+
return getUserHeatmapData(ctx, user, team, group, doer)
3031
}
3132

32-
func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
33+
func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organization.Team, group *group_model.Group, doer *user_model.User) ([]*UserHeatmapData, error) {
3334
hdata := make([]*UserHeatmapData, 0)
3435

3536
if !ActivityReadable(user, doer) {
@@ -53,6 +54,7 @@ func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organi
5354
Actor: doer,
5455
IncludePrivate: true, // don't filter by private, as we already filter by repo access
5556
IncludeDeleted: true,
57+
RequestedGroup: group,
5658
// * Heatmaps for individual users only include actions that the user themself did.
5759
// * For organizations actions by all users that were made in owned
5860
// repositories are counted.

models/shared/group/group_item.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package group
22

33
import (
4+
"code.gitea.io/gitea/models/perm"
45
"context"
56
"slices"
67

@@ -102,7 +103,7 @@ func GetTopLevelGroupItemList(ctx context.Context, orgID int64, doer *user_model
102103
ActorID: doer.ID,
103104
OwnerID: orgID,
104105
}, group_model.
105-
AccessibleGroupCondition(doer, unit.TypeInvalid))
106+
AccessibleGroupCondition(doer, unit.TypeInvalid, perm.AccessModeRead))
106107
if err != nil {
107108
return
108109
}

templates/group/team/new.tmpl

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
{{template "base/head" .}}
2+
<div role="main" aria-label="{{.Title}}" class="page-content repo-group new team">
3+
{{template "group/header" .}}
4+
<div class="ui container">
5+
<div class="ui grid">
6+
<div class="column">
7+
<form class="ui form" action="{{.OrgGroupLink}}/teams/{{.Team.LowerName | PathEscape}}/edit" data-delete-url="{{.OrgGroupLink}}/teams/{{.Team.LowerName | PathEscape}}/delete" method="post">
8+
{{.CsrfTokenHtml}}
9+
<h3 class="ui top attached header">
10+
{{ctx.Locale.Tr "org.teams.settings"}}
11+
</h3>
12+
<div class="ui attached segment">
13+
{{template "base/alert" .}}
14+
{{if not (eq .Team.LowerName "owners")}}
15+
<div class="grouped field">
16+
<label>{{ctx.Locale.Tr "org.team_access_desc"}}</label>
17+
<br>
18+
<div class="field">
19+
<div class="ui radio checkbox">
20+
<input type="radio" name="repo_access" value="specific" {{if not .Team.IncludesAllRepositories}}checked{{end}}>
21+
<label>{{ctx.Locale.Tr "org.teams.specific_repositories"}}</label>
22+
<span class="help">{{ctx.Locale.Tr "org.teams.specific_repositories_helper"}}</span>
23+
</div>
24+
</div>
25+
<div class="field">
26+
<div class="ui radio checkbox">
27+
<input type="radio" name="repo_access" value="all" {{if .Team.IncludesAllRepositories}}checked{{end}}>
28+
<label>{{ctx.Locale.Tr "org.teams.all_repositories"}}</label>
29+
<span class="help">{{ctx.Locale.Tr "org.teams.all_repositories_helper"}}</span>
30+
</div>
31+
</div>
32+
33+
<div class="field">
34+
<div class="ui checkbox">
35+
<label for="can_create_org_repo">{{ctx.Locale.Tr "org.teams.can_create_org_repo"}}</label>
36+
<input id="can_create_org_repo" name="can_create_org_repo" type="checkbox" {{if .Team.CanCreateOrgRepo}}checked{{end}}>
37+
<span class="help">{{ctx.Locale.Tr "org.teams.can_create_org_repo_helper"}}</span>
38+
</div>
39+
</div>
40+
</div>
41+
<div class="grouped field">
42+
<label>{{ctx.Locale.Tr "org.team_permission_desc"}}</label>
43+
<br>
44+
<div class="field">
45+
<div class="ui radio checkbox">
46+
<input type="radio" name="permission" value="read" {{if or .PageIsOrgTeamsNew (eq .Team.AccessMode 1) (eq .Team.AccessMode 2)}}checked{{end}}>
47+
<label>{{ctx.Locale.Tr "org.teams.general_access"}}</label>
48+
<span class="help">{{ctx.Locale.Tr "org.teams.general_access_helper"}}</span>
49+
</div>
50+
</div>
51+
<div class="field">
52+
<div class="ui radio checkbox">
53+
<input type="radio" name="permission" value="admin" {{if eq .Team.AccessMode 3}}checked{{end}}>
54+
<label>{{ctx.Locale.Tr "org.teams.admin_access"}}</label>
55+
<span class="help">{{ctx.Locale.Tr "org.teams.admin_access_helper"}}</span>
56+
</div>
57+
</div>
58+
</div>
59+
<div class="divider"></div>
60+
61+
<div class="team-units required grouped field {{if eq .Team.AccessMode 3}}tw-hidden{{end}}">
62+
<label>{{ctx.Locale.Tr "org.team_unit_desc"}}</label>
63+
<table class="ui celled table">
64+
<thead>
65+
<tr>
66+
<th>{{ctx.Locale.Tr "units.unit"}}</th>
67+
<th class="center aligned">{{ctx.Locale.Tr "org.teams.none_access"}}
68+
<span class="tw-align-middle" data-tooltip-content="{{ctx.Locale.Tr "org.teams.none_access_helper"}}">{{svg "octicon-question" 16 "tw-ml-1"}}</span></th>
69+
<th class="center aligned">{{ctx.Locale.Tr "org.teams.read_access"}}
70+
<span class="tw-align-middle" data-tooltip-content="{{ctx.Locale.Tr "org.teams.read_access_helper"}}">{{svg "octicon-question" 16 "tw-ml-1"}}</span></th>
71+
<th class="center aligned">{{ctx.Locale.Tr "org.teams.write_access"}}
72+
<span class="tw-align-middle" data-tooltip-content="{{ctx.Locale.Tr "org.teams.write_access_helper"}}">{{svg "octicon-question" 16 "tw-ml-1"}}</span></th>
73+
</tr>
74+
</thead>
75+
<tbody>
76+
{{range $t, $unit := $.Units}}
77+
{{if ge $unit.MaxPerm 2}}
78+
<tr>
79+
<td>
80+
<div {{if $unit.Type.UnitGlobalDisabled}}class="field" data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{- else -}}class="field"{{end}}>
81+
<div>
82+
<label>{{ctx.Locale.Tr $unit.NameKey}}{{if $unit.Type.UnitGlobalDisabled}} {{ctx.Locale.Tr "org.team_unit_disabled"}}{{end}}</label>
83+
<span class="help">{{ctx.Locale.Tr $unit.DescKey}}</span>
84+
</div>
85+
</div>
86+
</td>
87+
<td class="center aligned">
88+
<div class="ui radio checkbox">
89+
<input type="radio" name="unit_{{$unit.Type.Value}}" value="0"{{if or ($unit.Type.UnitGlobalDisabled) (eq ($.Team.UnitAccessMode ctx $unit.Type) 0)}} checked{{end}} title="{{ctx.Locale.Tr "org.teams.none_access"}}">
90+
</div>
91+
</td>
92+
<td class="center aligned">
93+
<div class="ui radio checkbox">
94+
<input type="radio" name="unit_{{$unit.Type.Value}}" value="1"{{if or (eq $.Team.ID 0) (eq ($.Team.UnitAccessMode ctx $unit.Type) 1)}} checked{{end}} {{if $unit.Type.UnitGlobalDisabled}}disabled{{end}} title="{{ctx.Locale.Tr "org.teams.read_access"}}">
95+
</div>
96+
</td>
97+
<td class="center aligned">
98+
<div class="ui radio checkbox">
99+
<input type="radio" name="unit_{{$unit.Type.Value}}" value="2"{{if (ge ($.Team.UnitAccessMode ctx $unit.Type) 2)}} checked{{end}} {{if $unit.Type.UnitGlobalDisabled}}disabled{{end}} title="{{ctx.Locale.Tr "org.teams.write_access"}}">
100+
</div>
101+
</td>
102+
</tr>
103+
{{end}}
104+
{{end}}
105+
</tbody>
106+
</table>
107+
{{range $t, $unit := $.Units}}
108+
{{if lt $unit.MaxPerm 2}}
109+
<div {{if $unit.Type.UnitGlobalDisabled}}class="field" data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{else}}class="field"{{end}}>
110+
<div class="ui checkbox">
111+
<input type="checkbox" name="unit_{{$unit.Type.Value}}" value="1"{{if or (eq $.Team.ID 0) (eq ($.Team.UnitAccessMode ctx $unit.Type) 1)}} checked{{end}} {{if $unit.Type.UnitGlobalDisabled}}disabled{{end}}>
112+
<label>{{ctx.Locale.Tr $unit.NameKey}}{{if $unit.Type.UnitGlobalDisabled}} {{ctx.Locale.Tr "org.team_unit_disabled"}}{{end}}</label>
113+
<span class="help">{{ctx.Locale.Tr $unit.DescKey}}</span>
114+
</div>
115+
</div>
116+
{{end}}
117+
{{end}}
118+
</div>
119+
{{end}}
120+
121+
<div class="field">
122+
<button class="ui primary button">{{ctx.Locale.Tr "org.teams.update_settings"}}</button>
123+
{{if not (eq .Team.LowerName "owners")}}
124+
<button class="ui red button delete-button" data-url="{{.OrgGroupLink}}/teams/{{.Team.Name | PathEscape}}/delete">{{ctx.Locale.Tr "org.teams.delete_team"}}</button>
125+
{{end}}
126+
</div>
127+
</div>
128+
</form>
129+
</div>
130+
</div>
131+
</div>
132+
</div>
133+
134+
<div class="ui g-modal-confirm delete modal">
135+
<div class="header">
136+
{{svg "octicon-trash"}}
137+
{{ctx.Locale.Tr "group.teams.delete_team_title"}}
138+
</div>
139+
<div class="content">
140+
<p>{{ctx.Locale.Tr "group.teams.delete_team_desc"}}</p>
141+
</div>
142+
{{template "base/modal_actions_confirm" .}}
143+
</div>
144+
{{template "base/footer" .}}

templates/group/team/teams.tmpl

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
{{template "base/head" .}}
2+
<div role="main" aria-label="{{.Title}}" class="page-content repo-group teams">
3+
{{template "group/header" .}}
4+
<div class="ui container">
5+
{{ template "base/alert" .}}
6+
7+
<div class="ui mobile reversed stackable grid">
8+
<div class="eleven wide column">
9+
<div class="ui two column stackable grid">
10+
{{if or .IsGroupAdmin .IsGroupOwner}}
11+
12+
<div class="one column row">
13+
<div class="column">
14+
<form class="ui form ignore-dirty tw-flex tw-flex-wrap tw-gap-2" action="{{$.OrgGroupLink}}/teams/add"
15+
method="post">
16+
{{.CsrfTokenHtml}}
17+
<input type="hidden" name="uid" value="{{.SignedUser.ID}}">
18+
<div id="search-team-box" data-search-url="{{$.OrgLink}}/-/search_team_candidates"
19+
class="ui search tw-mr-2 tw-flex-grow">
20+
<div class="ui input fluid">
21+
<input class="prompt" name="tname" placeholder="{{ctx.Locale.Tr "search.team_kind"}}"
22+
autocomplete="off" required>
23+
</div>
24+
</div>
25+
<button class="ui primary button">{{ctx.Locale.Tr "group.teams.add"}}</button>
26+
</form>
27+
</div>
28+
</div>
29+
{{end}}
30+
{{range .Teams}}
31+
<div class="column">
32+
<div class="ui top attached header">
33+
<a class="text black"
34+
href="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}"><strong>{{.Name}}</strong></a>
35+
<div class="ui right">
36+
<a class="ui primary tiny button"
37+
href="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}">{{ctx.Locale.Tr "view"}}</a>
38+
39+
{{if .IsMember ctx $.SignedUser.ID}}
40+
<form>
41+
<button class="ui red tiny button delete-button" data-modal-id="leave-team"
42+
data-url="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}/action/leave"
43+
data-datauid="{{$.SignedUser.ID}}"
44+
data-name="{{.Name}}">{{ctx.Locale.Tr "org.teams.leave"}}</button>
45+
</form>
46+
{{else if $.IsOrganizationOwner}}
47+
<form method="post" action="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}/action/join">
48+
{{$.CsrfTokenHtml}}
49+
<button type="submit" class="ui primary tiny button" name="uid"
50+
value="{{$.SignedUser.ID}}">{{ctx.Locale.Tr "org.teams.join"}}</button>
51+
</form>
52+
{{end}}
53+
54+
{{if and (or $.IsGroupAdmin $.IsGroupOwner) (not .IsOwnerTeam)}}
55+
<form>
56+
<button class="ui red tiny button delete-button" data-modal-id="remove-team"
57+
data-url="{{$.OrgGroupLink}}/teams/{{.LowerName | PathEscape}}/remove"
58+
data-datauid="{{$.SignedUser.ID}}"
59+
data-name="{{.Name}}">{{ctx.Locale.Tr "group.teams.remove"}}</button>
60+
</form>
61+
{{end}}
62+
</div>
63+
</div>
64+
<div class="ui attached segment members">
65+
{{range .Members}}
66+
{{template "shared/user/avatarlink" dict "user" .}}
67+
{{end}}
68+
</div>
69+
<div class="ui bottom attached header">
70+
<p class="team-meta"><a class="muted"
71+
href="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}">{{.NumMembers}} {{ctx.Locale.Tr "org.lower_members"}}</a>
72+
· <a class="muted"
73+
href="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}/repositories">{{.NumRepos}} {{ctx.Locale.Tr "org.lower_repositories"}}</a>
74+
</p>
75+
</div>
76+
</div>
77+
{{end}}
78+
</div>
79+
</div>
80+
<div class="five wide column">
81+
{{template "group/sidebar/menu" .}}
82+
</div>
83+
</div>
84+
</div>
85+
</div>
86+
<div class="ui g-modal-confirm delete modal" id="leave-team">
87+
<div class="header">
88+
{{ctx.Locale.Tr "org.teams.leave"}}
89+
</div>
90+
<div class="content">
91+
<p>{{ctx.Locale.Tr "org.teams.leave.detail" (`<span class="name"></span>`|SafeHTML)}}</p>
92+
</div>
93+
{{template "base/modal_actions_confirm" .}}
94+
</div>
95+
<div class="ui g-modal-confirm delete modal" id="remove-team">
96+
<div class="header">
97+
{{ctx.Locale.Tr "group.teams.remove"}}
98+
</div>
99+
<div class="content">
100+
<p>{{ctx.Locale.Tr "group.teams.remove.detail" (`<span class="name"></span>`|SafeHTML)}}</p>
101+
</div>
102+
{{template "base/modal_actions_confirm" .}}
103+
</div>
104+
{{template "base/footer" .}}

templates/org/team/teams.tmpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
{{template "base/head" .}}
22
<div role="main" aria-label="{{.Title}}" class="page-content organization teams">
3+
{{if .PageIsOrgTeams}}
34
{{template "org/header" .}}
5+
{{else if .PageIsGroupTeams}}
6+
{{template "group/header" .}}
7+
{{end}}
48
<div class="ui container">
59
{{template "base/alert" .}}
610
{{if .IsOrganizationOwner}}
@@ -17,6 +21,7 @@
1721
<a class="text black" href="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}"><strong>{{.Name}}</strong></a>
1822
<div class="ui right">
1923
<a class="ui primary tiny button" href="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}">{{ctx.Locale.Tr "view"}}</a>
24+
2025
{{if .IsMember ctx $.SignedUser.ID}}
2126
<form>
2227
<button class="ui red tiny button delete-button" data-modal-id="leave-team"

0 commit comments

Comments
 (0)