mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Team dashboards (#14159)
This commit is contained in:
		@@ -289,6 +289,7 @@ func (a *Action) GetIssueContent() string {
 | 
				
			|||||||
// GetFeedsOptions options for retrieving feeds
 | 
					// GetFeedsOptions options for retrieving feeds
 | 
				
			||||||
type GetFeedsOptions struct {
 | 
					type GetFeedsOptions struct {
 | 
				
			||||||
	RequestedUser   *User // the user we want activity for
 | 
						RequestedUser   *User // the user we want activity for
 | 
				
			||||||
 | 
						RequestedTeam   *Team // the team we want activity for
 | 
				
			||||||
	Actor           *User // the user viewing the activity
 | 
						Actor           *User // the user viewing the activity
 | 
				
			||||||
	IncludePrivate  bool  // include private actions
 | 
						IncludePrivate  bool  // include private actions
 | 
				
			||||||
	OnlyPerformedBy bool  // only actions performed by requested user
 | 
						OnlyPerformedBy bool  // only actions performed by requested user
 | 
				
			||||||
@@ -357,6 +358,15 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if opts.RequestedTeam != nil {
 | 
				
			||||||
 | 
							env := opts.RequestedUser.AccessibleTeamReposEnv(opts.RequestedTeam)
 | 
				
			||||||
 | 
							teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("GetTeamRepositories: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							cond = cond.And(builder.In("repo_id", teamRepoIDs))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cond = cond.And(builder.Eq{"user_id": opts.RequestedUser.ID})
 | 
						cond = cond.And(builder.Eq{"user_id": opts.RequestedUser.ID})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.OnlyPerformedBy {
 | 
						if opts.OnlyPerformedBy {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -746,6 +746,7 @@ type AccessibleReposEnvironment interface {
 | 
				
			|||||||
type accessibleReposEnv struct {
 | 
					type accessibleReposEnv struct {
 | 
				
			||||||
	org     *User
 | 
						org     *User
 | 
				
			||||||
	user    *User
 | 
						user    *User
 | 
				
			||||||
 | 
						team    *Team
 | 
				
			||||||
	teamIDs []int64
 | 
						teamIDs []int64
 | 
				
			||||||
	e       Engine
 | 
						e       Engine
 | 
				
			||||||
	keyword string
 | 
						keyword string
 | 
				
			||||||
@@ -782,16 +783,31 @@ func (org *User) accessibleReposEnv(e Engine, userID int64) (AccessibleReposEnvi
 | 
				
			|||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AccessibleTeamReposEnv an AccessibleReposEnvironment for the repositories in `org`
 | 
				
			||||||
 | 
					// that are accessible to the specified team.
 | 
				
			||||||
 | 
					func (org *User) AccessibleTeamReposEnv(team *Team) AccessibleReposEnvironment {
 | 
				
			||||||
 | 
						return &accessibleReposEnv{
 | 
				
			||||||
 | 
							org:     org,
 | 
				
			||||||
 | 
							team:    team,
 | 
				
			||||||
 | 
							e:       x,
 | 
				
			||||||
 | 
							orderBy: SearchOrderByRecentUpdated,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (env *accessibleReposEnv) cond() builder.Cond {
 | 
					func (env *accessibleReposEnv) cond() builder.Cond {
 | 
				
			||||||
	var cond = builder.NewCond()
 | 
						var cond = builder.NewCond()
 | 
				
			||||||
	if env.user == nil || !env.user.IsRestricted {
 | 
						if env.team != nil {
 | 
				
			||||||
		cond = cond.Or(builder.Eq{
 | 
							cond = cond.And(builder.Eq{"team_repo.team_id": env.team.ID})
 | 
				
			||||||
			"`repository`.owner_id":   env.org.ID,
 | 
						} else {
 | 
				
			||||||
			"`repository`.is_private": false,
 | 
							if env.user == nil || !env.user.IsRestricted {
 | 
				
			||||||
		})
 | 
								cond = cond.Or(builder.Eq{
 | 
				
			||||||
	}
 | 
									"`repository`.owner_id":   env.org.ID,
 | 
				
			||||||
	if len(env.teamIDs) > 0 {
 | 
									"`repository`.is_private": false,
 | 
				
			||||||
		cond = cond.Or(builder.In("team_repo.team_id", env.teamIDs))
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(env.teamIDs) > 0 {
 | 
				
			||||||
 | 
								cond = cond.Or(builder.In("team_repo.team_id", env.teamIDs))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if env.keyword != "" {
 | 
						if env.keyword != "" {
 | 
				
			||||||
		cond = cond.And(builder.Like{"`repository`.lower_name", strings.ToLower(env.keyword)})
 | 
							cond = cond.And(builder.Like{"`repository`.lower_name", strings.ToLower(env.keyword)})
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -138,6 +138,7 @@ type SearchRepoOptions struct {
 | 
				
			|||||||
	Keyword         string
 | 
						Keyword         string
 | 
				
			||||||
	OwnerID         int64
 | 
						OwnerID         int64
 | 
				
			||||||
	PriorityOwnerID int64
 | 
						PriorityOwnerID int64
 | 
				
			||||||
 | 
						TeamID          int64
 | 
				
			||||||
	OrderBy         SearchOrderBy
 | 
						OrderBy         SearchOrderBy
 | 
				
			||||||
	Private         bool // Include private repositories in results
 | 
						Private         bool // Include private repositories in results
 | 
				
			||||||
	StarredByID     int64
 | 
						StarredByID     int64
 | 
				
			||||||
@@ -294,6 +295,10 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
 | 
				
			|||||||
		cond = cond.And(accessCond)
 | 
							cond = cond.And(accessCond)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if opts.TeamID > 0 {
 | 
				
			||||||
 | 
							cond = cond.And(builder.In("`repository`.id", builder.Select("`team_repo`.repo_id").From("team_repo").Where(builder.Eq{"`team_repo`.team_id": opts.TeamID})))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.Keyword != "" {
 | 
						if opts.Keyword != "" {
 | 
				
			||||||
		// separate keyword
 | 
							// separate keyword
 | 
				
			||||||
		var subQueryCond = builder.NewCond()
 | 
							var subQueryCond = builder.NewCond()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,15 @@ type UserHeatmapData struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// GetUserHeatmapDataByUser returns an array of UserHeatmapData
 | 
					// GetUserHeatmapDataByUser returns an array of UserHeatmapData
 | 
				
			||||||
func GetUserHeatmapDataByUser(user *User, doer *User) ([]*UserHeatmapData, error) {
 | 
					func GetUserHeatmapDataByUser(user *User, doer *User) ([]*UserHeatmapData, error) {
 | 
				
			||||||
 | 
						return getUserHeatmapData(user, nil, doer)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetUserHeatmapDataByUserTeam returns an array of UserHeatmapData
 | 
				
			||||||
 | 
					func GetUserHeatmapDataByUserTeam(user *User, team *Team, doer *User) ([]*UserHeatmapData, error) {
 | 
				
			||||||
 | 
						return getUserHeatmapData(user, team, doer)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getUserHeatmapData(user *User, team *Team, doer *User) ([]*UserHeatmapData, error) {
 | 
				
			||||||
	hdata := make([]*UserHeatmapData, 0)
 | 
						hdata := make([]*UserHeatmapData, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !activityReadable(user, doer) {
 | 
						if !activityReadable(user, doer) {
 | 
				
			||||||
@@ -39,6 +48,7 @@ func GetUserHeatmapDataByUser(user *User, doer *User) ([]*UserHeatmapData, error
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	cond, err := activityQueryCondition(GetFeedsOptions{
 | 
						cond, err := activityQueryCondition(GetFeedsOptions{
 | 
				
			||||||
		RequestedUser:  user,
 | 
							RequestedUser:  user,
 | 
				
			||||||
 | 
							RequestedTeam:  team,
 | 
				
			||||||
		Actor:          doer,
 | 
							Actor:          doer,
 | 
				
			||||||
		IncludePrivate: true, // don't filter by private, as we already filter by repo access
 | 
							IncludePrivate: true, // don't filter by private, as we already filter by repo access
 | 
				
			||||||
		IncludeDeleted: true,
 | 
							IncludeDeleted: true,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -216,6 +216,7 @@ my_mirrors = My Mirrors
 | 
				
			|||||||
view_home = View %s
 | 
					view_home = View %s
 | 
				
			||||||
search_repos = Find a repository…
 | 
					search_repos = Find a repository…
 | 
				
			||||||
filter = Other Filters
 | 
					filter = Other Filters
 | 
				
			||||||
 | 
					filter_by_team_repositories = Filter by team repositories
 | 
				
			||||||
 | 
					
 | 
				
			||||||
show_archived = Archived
 | 
					show_archived = Archived
 | 
				
			||||||
show_both_archived_unarchived = Showing both archived and unarchived
 | 
					show_both_archived_unarchived = Showing both archived and unarchived
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -70,6 +70,11 @@ func Search(ctx *context.APIContext) {
 | 
				
			|||||||
	//   description: repo owner to prioritize in the results
 | 
						//   description: repo owner to prioritize in the results
 | 
				
			||||||
	//   type: integer
 | 
						//   type: integer
 | 
				
			||||||
	//   format: int64
 | 
						//   format: int64
 | 
				
			||||||
 | 
						// - name: team_id
 | 
				
			||||||
 | 
						//   in: query
 | 
				
			||||||
 | 
						//   description: search only for repos that belong to the given team id
 | 
				
			||||||
 | 
						//   type: integer
 | 
				
			||||||
 | 
						//   format: int64
 | 
				
			||||||
	// - name: starredBy
 | 
						// - name: starredBy
 | 
				
			||||||
	//   in: query
 | 
						//   in: query
 | 
				
			||||||
	//   description: search only for repos that the user with the given id has starred
 | 
						//   description: search only for repos that the user with the given id has starred
 | 
				
			||||||
@@ -131,6 +136,7 @@ func Search(ctx *context.APIContext) {
 | 
				
			|||||||
		Keyword:            strings.Trim(ctx.Query("q"), " "),
 | 
							Keyword:            strings.Trim(ctx.Query("q"), " "),
 | 
				
			||||||
		OwnerID:            ctx.QueryInt64("uid"),
 | 
							OwnerID:            ctx.QueryInt64("uid"),
 | 
				
			||||||
		PriorityOwnerID:    ctx.QueryInt64("priority_owner_id"),
 | 
							PriorityOwnerID:    ctx.QueryInt64("priority_owner_id"),
 | 
				
			||||||
 | 
							TeamID:             ctx.QueryInt64("team_id"),
 | 
				
			||||||
		TopicOnly:          ctx.QueryBool("topic"),
 | 
							TopicOnly:          ctx.QueryBool("topic"),
 | 
				
			||||||
		Collaborate:        util.OptionalBoolNone,
 | 
							Collaborate:        util.OptionalBoolNone,
 | 
				
			||||||
		Private:            ctx.IsSigned && (ctx.Query("private") == "" || ctx.QueryBool("private")),
 | 
							Private:            ctx.IsSigned && (ctx.Query("private") == "" || ctx.QueryBool("private")),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -444,13 +444,15 @@ func RegisterMacaronRoutes(m *macaron.Macaron) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		m.Group("/:org", func() {
 | 
							m.Group("/:org", func() {
 | 
				
			||||||
			m.Get("/dashboard", user.Dashboard)
 | 
								m.Get("/dashboard", user.Dashboard)
 | 
				
			||||||
 | 
								m.Get("/dashboard/:team", user.Dashboard)
 | 
				
			||||||
			m.Get("/^:type(issues|pulls)$", user.Issues)
 | 
								m.Get("/^:type(issues|pulls)$", user.Issues)
 | 
				
			||||||
 | 
								m.Get("/^:type(issues|pulls)$/:team", user.Issues)
 | 
				
			||||||
			m.Get("/milestones", reqMilestonesDashboardPageEnabled, user.Milestones)
 | 
								m.Get("/milestones", reqMilestonesDashboardPageEnabled, user.Milestones)
 | 
				
			||||||
 | 
								m.Get("/milestones/:team", reqMilestonesDashboardPageEnabled, user.Milestones)
 | 
				
			||||||
			m.Get("/members", org.Members)
 | 
								m.Get("/members", org.Members)
 | 
				
			||||||
			m.Post("/members/action/:action", org.MembersAction)
 | 
								m.Post("/members/action/:action", org.MembersAction)
 | 
				
			||||||
 | 
					 | 
				
			||||||
			m.Get("/teams", org.Teams)
 | 
								m.Get("/teams", org.Teams)
 | 
				
			||||||
		}, context.OrgAssignment(true))
 | 
							}, context.OrgAssignment(true, false, true))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		m.Group("/:org", func() {
 | 
							m.Group("/:org", func() {
 | 
				
			||||||
			m.Get("/teams/:team", org.TeamMembers)
 | 
								m.Get("/teams/:team", org.TeamMembers)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,17 +42,8 @@ func getDashboardContextUser(ctx *context.Context) *models.User {
 | 
				
			|||||||
	ctxUser := ctx.User
 | 
						ctxUser := ctx.User
 | 
				
			||||||
	orgName := ctx.Params(":org")
 | 
						orgName := ctx.Params(":org")
 | 
				
			||||||
	if len(orgName) > 0 {
 | 
						if len(orgName) > 0 {
 | 
				
			||||||
		// Organization.
 | 
							ctxUser = ctx.Org.Organization
 | 
				
			||||||
		org, err := models.GetUserByName(orgName)
 | 
							ctx.Data["Teams"] = ctx.Org.Organization.Teams
 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			if models.IsErrUserNotExist(err) {
 | 
					 | 
				
			||||||
				ctx.NotFound("GetUserByName", err)
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				ctx.ServerError("GetUserByName", err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		ctxUser = org
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.Data["ContextUser"] = ctxUser
 | 
						ctx.Data["ContextUser"] = ctxUser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -112,12 +103,13 @@ func Dashboard(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["PageIsDashboard"] = true
 | 
						ctx.Data["PageIsDashboard"] = true
 | 
				
			||||||
	ctx.Data["PageIsNews"] = true
 | 
						ctx.Data["PageIsNews"] = true
 | 
				
			||||||
	ctx.Data["SearchLimit"] = setting.UI.User.RepoPagingNum
 | 
						ctx.Data["SearchLimit"] = setting.UI.User.RepoPagingNum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// no heatmap access for admins; GetUserHeatmapDataByUser ignores the calling user
 | 
						// no heatmap access for admins; GetUserHeatmapDataByUser ignores the calling user
 | 
				
			||||||
	// so everyone would get the same empty heatmap
 | 
						// so everyone would get the same empty heatmap
 | 
				
			||||||
	if setting.Service.EnableUserHeatmap && !ctxUser.KeepActivityPrivate {
 | 
						if setting.Service.EnableUserHeatmap && !ctxUser.KeepActivityPrivate {
 | 
				
			||||||
		data, err := models.GetUserHeatmapDataByUser(ctxUser, ctx.User)
 | 
							data, err := models.GetUserHeatmapDataByUserTeam(ctxUser, ctx.Org.Team, ctx.User)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			ctx.ServerError("GetUserHeatmapDataByUser", err)
 | 
								ctx.ServerError("GetUserHeatmapDataByUserTeam", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ctx.Data["HeatmapData"] = data
 | 
							ctx.Data["HeatmapData"] = data
 | 
				
			||||||
@@ -126,12 +118,16 @@ func Dashboard(ctx *context.Context) {
 | 
				
			|||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	var mirrors []*models.Repository
 | 
						var mirrors []*models.Repository
 | 
				
			||||||
	if ctxUser.IsOrganization() {
 | 
						if ctxUser.IsOrganization() {
 | 
				
			||||||
		env, err := ctxUser.AccessibleReposEnv(ctx.User.ID)
 | 
							var env models.AccessibleReposEnvironment
 | 
				
			||||||
		if err != nil {
 | 
							if ctx.Org.Team != nil {
 | 
				
			||||||
			ctx.ServerError("AccessibleReposEnv", err)
 | 
								env = ctxUser.AccessibleTeamReposEnv(ctx.Org.Team)
 | 
				
			||||||
			return
 | 
							} else {
 | 
				
			||||||
 | 
								env, err = ctxUser.AccessibleReposEnv(ctx.User.ID)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									ctx.ServerError("AccessibleReposEnv", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		mirrors, err = env.MirrorRepos()
 | 
							mirrors, err = env.MirrorRepos()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			ctx.ServerError("env.MirrorRepos", err)
 | 
								ctx.ServerError("env.MirrorRepos", err)
 | 
				
			||||||
@@ -155,6 +151,7 @@ func Dashboard(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	retrieveFeeds(ctx, models.GetFeedsOptions{
 | 
						retrieveFeeds(ctx, models.GetFeedsOptions{
 | 
				
			||||||
		RequestedUser:   ctxUser,
 | 
							RequestedUser:   ctxUser,
 | 
				
			||||||
 | 
							RequestedTeam:   ctx.Org.Team,
 | 
				
			||||||
		Actor:           ctx.User,
 | 
							Actor:           ctx.User,
 | 
				
			||||||
		IncludePrivate:  true,
 | 
							IncludePrivate:  true,
 | 
				
			||||||
		OnlyPerformedBy: false,
 | 
							OnlyPerformedBy: false,
 | 
				
			||||||
@@ -183,16 +180,20 @@ func Milestones(ctx *context.Context) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
						repoOpts := models.SearchRepoOptions{
 | 
				
			||||||
		repoOpts = models.SearchRepoOptions{
 | 
							Actor:         ctxUser,
 | 
				
			||||||
			Actor:         ctxUser,
 | 
							OwnerID:       ctxUser.ID,
 | 
				
			||||||
			OwnerID:       ctxUser.ID,
 | 
							Private:       true,
 | 
				
			||||||
			Private:       true,
 | 
							AllPublic:     false,                 // Include also all public repositories of users and public organisations
 | 
				
			||||||
			AllPublic:     false,                 // Include also all public repositories of users and public organisations
 | 
							AllLimited:    false,                 // Include also all public repositories of limited organisations
 | 
				
			||||||
			AllLimited:    false,                 // Include also all public repositories of limited organisations
 | 
							HasMilestones: util.OptionalBoolTrue, // Just needs display repos has milestones
 | 
				
			||||||
			HasMilestones: util.OptionalBoolTrue, // Just needs display repos has milestones
 | 
						}
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ctxUser.IsOrganization() && ctx.Org.Team != nil {
 | 
				
			||||||
 | 
							repoOpts.TeamID = ctx.Org.Team.ID
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
		userRepoCond = models.SearchRepositoryCondition(&repoOpts) // all repo condition user could visit
 | 
							userRepoCond = models.SearchRepositoryCondition(&repoOpts) // all repo condition user could visit
 | 
				
			||||||
		repoCond     = userRepoCond
 | 
							repoCond     = userRepoCond
 | 
				
			||||||
		repoIDs      []int64
 | 
							repoIDs      []int64
 | 
				
			||||||
@@ -412,10 +413,15 @@ func Issues(ctx *context.Context) {
 | 
				
			|||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	var userRepoIDs []int64
 | 
						var userRepoIDs []int64
 | 
				
			||||||
	if ctxUser.IsOrganization() {
 | 
						if ctxUser.IsOrganization() {
 | 
				
			||||||
		env, err := ctxUser.AccessibleReposEnv(ctx.User.ID)
 | 
							var env models.AccessibleReposEnvironment
 | 
				
			||||||
		if err != nil {
 | 
							if ctx.Org.Team != nil {
 | 
				
			||||||
			ctx.ServerError("AccessibleReposEnv", err)
 | 
								env = ctxUser.AccessibleTeamReposEnv(ctx.Org.Team)
 | 
				
			||||||
			return
 | 
							} else {
 | 
				
			||||||
 | 
								env, err = ctxUser.AccessibleReposEnv(ctx.User.ID)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									ctx.ServerError("AccessibleReposEnv", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		userRepoIDs, err = env.RepoIDs(1, ctxUser.NumRepos)
 | 
							userRepoIDs, err = env.RepoIDs(1, ctxUser.NumRepos)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2009,6 +2009,13 @@
 | 
				
			|||||||
            "name": "priority_owner_id",
 | 
					            "name": "priority_owner_id",
 | 
				
			||||||
            "in": "query"
 | 
					            "in": "query"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "integer",
 | 
				
			||||||
 | 
					            "format": "int64",
 | 
				
			||||||
 | 
					            "description": "search only for repos that belong to the given team id",
 | 
				
			||||||
 | 
					            "name": "team_id",
 | 
				
			||||||
 | 
					            "in": "query"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            "type": "integer",
 | 
					            "type": "integer",
 | 
				
			||||||
            "format": "int64",
 | 
					            "format": "int64",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,21 +44,51 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		{{if .ContextUser.IsOrganization}}
 | 
							{{if .ContextUser.IsOrganization}}
 | 
				
			||||||
			<div class="right stackable menu">
 | 
								<div class="right stackable menu">
 | 
				
			||||||
				<a class="{{if .PageIsNews}}active{{end}} item" style="margin-left: auto" href="{{AppSubUrl}}/org/{{.ContextUser.Name}}/dashboard">
 | 
									<div class="item">
 | 
				
			||||||
 | 
										<div class="ui floating dropdown link jump">
 | 
				
			||||||
 | 
											<span class="text">
 | 
				
			||||||
 | 
												{{svg "octicon-people" 18}}
 | 
				
			||||||
 | 
												{{if .Team}}
 | 
				
			||||||
 | 
													{{.Team.Name}}
 | 
				
			||||||
 | 
												{{else}}
 | 
				
			||||||
 | 
													{{.i18n.Tr "org.teams"}}
 | 
				
			||||||
 | 
												{{end}}
 | 
				
			||||||
 | 
												{{svg "octicon-triangle-down" 14 "dropdown icon"}}
 | 
				
			||||||
 | 
											</span>
 | 
				
			||||||
 | 
											<div class="context user overflow menu" tabindex="-1">
 | 
				
			||||||
 | 
												<div class="ui header">
 | 
				
			||||||
 | 
													{{.i18n.Tr "home.filter_by_team_repositories"}}
 | 
				
			||||||
 | 
												</div>
 | 
				
			||||||
 | 
												<div class="scrolling menu items">
 | 
				
			||||||
 | 
													<a class="{{if not $.Team}}active selected{{end}} item" title="{{.i18n.Tr "all"}}" href="{{AppSubUrl}}/org/{{$.Org.Name}}/{{if $.PageIsIssues}}issues{{else if $.PageIsPulls}}pulls{{else if $.PageIsMilestonesDashboard}}milestones{{else}}dashboard{{end}}">
 | 
				
			||||||
 | 
														{{.i18n.Tr "all"}}
 | 
				
			||||||
 | 
													</a>
 | 
				
			||||||
 | 
													{{range .Org.Teams}}
 | 
				
			||||||
 | 
														{{if not .IncludesAllRepositories}}
 | 
				
			||||||
 | 
															<a class="{{if $.Team}}{{if eq $.Team.ID .ID}}active selected{{end}}{{end}} item" title="{{.Name}}" href="{{AppSubUrl}}/org/{{$.Org.Name}}/{{if $.PageIsIssues}}issues{{else if $.PageIsPulls}}pulls{{else if $.PageIsMilestonesDashboard}}milestones{{else}}dashboard{{end}}/{{.Name}}">
 | 
				
			||||||
 | 
																{{.Name}}
 | 
				
			||||||
 | 
															</a>
 | 
				
			||||||
 | 
														{{end}}
 | 
				
			||||||
 | 
													{{end}}
 | 
				
			||||||
 | 
												</div>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
										</div>
 | 
				
			||||||
 | 
									</div>
 | 
				
			||||||
 | 
									<a class="{{if .PageIsNews}}active{{end}} item" style="margin-left: auto" href="{{AppSubUrl}}/org/{{.ContextUser.Name}}/dashboard{{if .Team}}/{{.Team.Name}}{{end}}">
 | 
				
			||||||
					{{svg "octicon-rss"}} {{.i18n.Tr "activities"}}
 | 
										{{svg "octicon-rss"}} {{.i18n.Tr "activities"}}
 | 
				
			||||||
				</a>
 | 
									</a>
 | 
				
			||||||
				{{if not .UnitIssuesGlobalDisabled}}
 | 
									{{if not .UnitIssuesGlobalDisabled}}
 | 
				
			||||||
				<a class="{{if .PageIsIssues}}active{{end}} item" href="{{AppSubUrl}}/org/{{.ContextUser.Name}}/issues">
 | 
									<a class="{{if .PageIsIssues}}active{{end}} item" href="{{AppSubUrl}}/org/{{.ContextUser.Name}}/issues{{if .Team}}/{{.Team.Name}}{{end}}">
 | 
				
			||||||
					{{svg "octicon-issue-opened"}} {{.i18n.Tr "issues"}}
 | 
										{{svg "octicon-issue-opened"}} {{.i18n.Tr "issues"}}
 | 
				
			||||||
				</a>
 | 
									</a>
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
				{{if not .UnitPullsGlobalDisabled}}
 | 
									{{if not .UnitPullsGlobalDisabled}}
 | 
				
			||||||
				<a class="{{if .PageIsPulls}}active{{end}} item" href="{{AppSubUrl}}/org/{{.ContextUser.Name}}/pulls">
 | 
									<a class="{{if .PageIsPulls}}active{{end}} item" href="{{AppSubUrl}}/org/{{.ContextUser.Name}}/pulls{{if .Team}}/{{.Team.Name}}{{end}}">
 | 
				
			||||||
					{{svg "octicon-git-pull-request"}} {{.i18n.Tr "pull_requests"}}
 | 
										{{svg "octicon-git-pull-request"}} {{.i18n.Tr "pull_requests"}}
 | 
				
			||||||
				</a>
 | 
									</a>
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
				{{if and .ShowMilestonesDashboardPage (not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled))}}
 | 
									{{if and .ShowMilestonesDashboardPage (not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled))}}
 | 
				
			||||||
				<a class="{{if .PageIsMilestonesDashboard}}active{{end}} item" href="{{AppSubUrl}}/org/{{.ContextUser.Name}}/milestones">
 | 
									<a class="{{if .PageIsMilestonesDashboard}}active{{end}} item" href="{{AppSubUrl}}/org/{{.ContextUser.Name}}/milestones{{if .Team}}/{{.Team.Name}}{{end}}">
 | 
				
			||||||
					{{svg "octicon-milestone"}} {{.i18n.Tr "milestones"}}
 | 
										{{svg "octicon-milestone"}} {{.i18n.Tr "milestones"}}
 | 
				
			||||||
				</a>
 | 
									</a>
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,9 @@
 | 
				
			|||||||
	:search-limit="searchLimit"
 | 
						:search-limit="searchLimit"
 | 
				
			||||||
	:suburl="suburl"
 | 
						:suburl="suburl"
 | 
				
			||||||
	:uid="uid"
 | 
						:uid="uid"
 | 
				
			||||||
 | 
						{{if .Team}}
 | 
				
			||||||
 | 
						:team-id="{{.Team.ID}}"
 | 
				
			||||||
 | 
						{{end}}
 | 
				
			||||||
	:more-repos-link="'{{.ContextUser.HomeLink}}'"
 | 
						:more-repos-link="'{{.ContextUser.HomeLink}}'"
 | 
				
			||||||
	{{if not .ContextUser.IsOrganization}}
 | 
						{{if not .ContextUser.IsOrganization}}
 | 
				
			||||||
	:organizations="[
 | 
						:organizations="[
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2755,6 +2755,11 @@ function initVueComponents() {
 | 
				
			|||||||
        type: Number,
 | 
					        type: Number,
 | 
				
			||||||
        required: true
 | 
					        required: true
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					      teamId: {
 | 
				
			||||||
 | 
					        type: Number,
 | 
				
			||||||
 | 
					        required: false,
 | 
				
			||||||
 | 
					        default: 0
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      organizations: {
 | 
					      organizations: {
 | 
				
			||||||
        type: Array,
 | 
					        type: Array,
 | 
				
			||||||
        default: () => [],
 | 
					        default: () => [],
 | 
				
			||||||
@@ -2853,7 +2858,7 @@ function initVueComponents() {
 | 
				
			|||||||
        return this.repos.length > 0 && this.repos.length < this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`];
 | 
					        return this.repos.length > 0 && this.repos.length < this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`];
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      searchURL() {
 | 
					      searchURL() {
 | 
				
			||||||
        return `${this.suburl}/api/v1/repos/search?sort=updated&order=desc&uid=${this.uid}&q=${this.searchQuery
 | 
					        return `${this.suburl}/api/v1/repos/search?sort=updated&order=desc&uid=${this.uid}&team_id=${this.teamId}&q=${this.searchQuery
 | 
				
			||||||
        }&page=${this.page}&limit=${this.searchLimit}&mode=${this.repoTypes[this.reposFilter].searchMode
 | 
					        }&page=${this.page}&limit=${this.searchLimit}&mode=${this.repoTypes[this.reposFilter].searchMode
 | 
				
			||||||
        }${this.reposFilter !== 'all' ? '&exclusive=1' : ''
 | 
					        }${this.reposFilter !== 'all' ? '&exclusive=1' : ''
 | 
				
			||||||
        }${this.archivedFilter === 'archived' ? '&archived=true' : ''}${this.archivedFilter === 'unarchived' ? '&archived=false' : ''
 | 
					        }${this.archivedFilter === 'archived' ? '&archived=true' : ''}${this.archivedFilter === 'unarchived' ? '&archived=false' : ''
 | 
				
			||||||
@@ -3034,7 +3039,7 @@ function initVueComponents() {
 | 
				
			|||||||
        this.isLoading = true;
 | 
					        this.isLoading = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!this.reposTotalCount) {
 | 
					        if (!this.reposTotalCount) {
 | 
				
			||||||
          const totalCountSearchURL = `${this.suburl}/api/v1/repos/search?sort=updated&order=desc&uid=${this.uid}&q=&page=1&mode=`;
 | 
					          const totalCountSearchURL = `${this.suburl}/api/v1/repos/search?sort=updated&order=desc&uid=${this.uid}&team_id=${this.teamId}&q=&page=1&mode=`;
 | 
				
			||||||
          $.getJSON(totalCountSearchURL, (_result, _textStatus, request) => {
 | 
					          $.getJSON(totalCountSearchURL, (_result, _textStatus, request) => {
 | 
				
			||||||
            self.reposTotalCount = request.getResponseHeader('X-Total-Count');
 | 
					            self.reposTotalCount = request.getResponseHeader('X-Total-Count');
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user