mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 21:16:26 +01:00 
			
		
		
		
	Add paging and archive/private repository filtering to dashboard list (#11321)
* Add archived options to SearchRepository Signed-off-by: Andrew Thornton <art27@cantab.net> * Add only-private search Signed-off-by: Andrew Thornton <art27@cantab.net> * Add filter options and paging to dashboard repository page Signed-off-by: Andrew Thornton <art27@cantab.net> * swagger generate Signed-off-by: Andrew Thornton <art27@cantab.net> * fix-swagger-again Signed-off-by: Andrew Thornton <art27@cantab.net> * as per @mrsdizzie also remember state Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: Lauris BH <lauris@nix.lv>
This commit is contained in:
		
							parent
							
								
									c3d9a5f846
								
							
						
					
					
						commit
						c86bc8e061
					
				@ -140,6 +140,7 @@ type SearchRepoOptions struct {
 | 
				
			|||||||
	PriorityOwnerID int64
 | 
						PriorityOwnerID int64
 | 
				
			||||||
	OrderBy         SearchOrderBy
 | 
						OrderBy         SearchOrderBy
 | 
				
			||||||
	Private         bool // Include private repositories in results
 | 
						Private         bool // Include private repositories in results
 | 
				
			||||||
 | 
						OnlyPrivate     bool // Include only private repositories in results
 | 
				
			||||||
	StarredByID     int64
 | 
						StarredByID     int64
 | 
				
			||||||
	AllPublic       bool // Include also all public repositories of users and public organisations
 | 
						AllPublic       bool // Include also all public repositories of users and public organisations
 | 
				
			||||||
	AllLimited      bool // Include also all public repositories of limited organisations
 | 
						AllLimited      bool // Include also all public repositories of limited organisations
 | 
				
			||||||
@ -159,6 +160,10 @@ type SearchRepoOptions struct {
 | 
				
			|||||||
	// True -> include just mirrors
 | 
						// True -> include just mirrors
 | 
				
			||||||
	// False -> include just non-mirrors
 | 
						// False -> include just non-mirrors
 | 
				
			||||||
	Mirror util.OptionalBool
 | 
						Mirror util.OptionalBool
 | 
				
			||||||
 | 
						// None -> include archived AND non-archived
 | 
				
			||||||
 | 
						// True -> include just archived
 | 
				
			||||||
 | 
						// False -> include just non-archived
 | 
				
			||||||
 | 
						Archived util.OptionalBool
 | 
				
			||||||
	// only search topic name
 | 
						// only search topic name
 | 
				
			||||||
	TopicOnly bool
 | 
						TopicOnly bool
 | 
				
			||||||
	// include description in keyword search
 | 
						// include description in keyword search
 | 
				
			||||||
@ -205,14 +210,26 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// Not looking at private organisations
 | 
							// Not looking at private organisations
 | 
				
			||||||
		// We should be able to see all non-private repositories that either:
 | 
							// We should be able to see all non-private repositories that
 | 
				
			||||||
		cond = cond.And(builder.Eq{"is_private": false})
 | 
							// isn't in a private or limited organisation.
 | 
				
			||||||
		accessCond := builder.Or(
 | 
							cond = cond.And(
 | 
				
			||||||
			//   A. Aren't in organisations  __OR__
 | 
								builder.Eq{"is_private": false},
 | 
				
			||||||
			builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})),
 | 
								builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(
 | 
				
			||||||
			//   B. Isn't a private or limited organisation.
 | 
									builder.And(
 | 
				
			||||||
			builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}))))
 | 
										builder.Eq{"type": UserTypeOrganization},
 | 
				
			||||||
		cond = cond.And(accessCond)
 | 
										builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}),
 | 
				
			||||||
 | 
									))))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if opts.OnlyPrivate {
 | 
				
			||||||
 | 
							cond = cond.And(
 | 
				
			||||||
 | 
								builder.Or(
 | 
				
			||||||
 | 
									builder.Eq{"is_private": true},
 | 
				
			||||||
 | 
									builder.In("owner_id", builder.Select("id").From("`user`").Where(
 | 
				
			||||||
 | 
										builder.And(
 | 
				
			||||||
 | 
											builder.Eq{"type": UserTypeOrganization},
 | 
				
			||||||
 | 
											builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}),
 | 
				
			||||||
 | 
										)))))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.Template != util.OptionalBoolNone {
 | 
						if opts.Template != util.OptionalBoolNone {
 | 
				
			||||||
@ -299,6 +316,10 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
 | 
				
			|||||||
		cond = cond.And(accessibleRepositoryCondition(opts.Actor))
 | 
							cond = cond.And(accessibleRepositoryCondition(opts.Actor))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if opts.Archived != util.OptionalBoolNone {
 | 
				
			||||||
 | 
							cond = cond.And(builder.Eq{"is_archived": opts.Archived == util.OptionalBoolTrue})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch opts.HasMilestones {
 | 
						switch opts.HasMilestones {
 | 
				
			||||||
	case util.OptionalBoolTrue:
 | 
						case util.OptionalBoolTrue:
 | 
				
			||||||
		cond = cond.And(builder.Gt{"num_milestones": 0})
 | 
							cond = cond.And(builder.Gt{"num_milestones": 0})
 | 
				
			||||||
 | 
				
			|||||||
@ -206,6 +206,17 @@ my_orgs = My Organizations
 | 
				
			|||||||
my_mirrors = My Mirrors
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					show_archived = Archived
 | 
				
			||||||
 | 
					show_both_archived_unarchived = Showing both archived and unarchived
 | 
				
			||||||
 | 
					show_only_archived = Showing only archived
 | 
				
			||||||
 | 
					show_only_unarchived = Showing only unarchived
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					show_private = Private
 | 
				
			||||||
 | 
					show_both_private_public = Showing both public and private
 | 
				
			||||||
 | 
					show_only_private = Showing only private
 | 
				
			||||||
 | 
					show_only_public = Showing only public
 | 
				
			||||||
 | 
					
 | 
				
			||||||
issues.in_your_repos = In your repositories
 | 
					issues.in_your_repos = In your repositories
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -78,10 +78,18 @@ func Search(ctx *context.APIContext) {
 | 
				
			|||||||
	//   in: query
 | 
						//   in: query
 | 
				
			||||||
	//   description: include private repositories this user has access to (defaults to true)
 | 
						//   description: include private repositories this user has access to (defaults to true)
 | 
				
			||||||
	//   type: boolean
 | 
						//   type: boolean
 | 
				
			||||||
 | 
						// - name: onlyPrivate
 | 
				
			||||||
 | 
						//   in: query
 | 
				
			||||||
 | 
						//   description: only include private repositories this user has access to (defaults to false)
 | 
				
			||||||
 | 
						//   type: boolean
 | 
				
			||||||
	// - name: template
 | 
						// - name: template
 | 
				
			||||||
	//   in: query
 | 
						//   in: query
 | 
				
			||||||
	//   description: include template repositories this user has access to (defaults to true)
 | 
						//   description: include template repositories this user has access to (defaults to true)
 | 
				
			||||||
	//   type: boolean
 | 
						//   type: boolean
 | 
				
			||||||
 | 
						// - name: archived
 | 
				
			||||||
 | 
						//   in: query
 | 
				
			||||||
 | 
						//   description: show only archived, non-archived or all repositories (defaults to all)
 | 
				
			||||||
 | 
						//   type: boolean
 | 
				
			||||||
	// - name: mode
 | 
						// - name: mode
 | 
				
			||||||
	//   in: query
 | 
						//   in: query
 | 
				
			||||||
	//   description: type of repository to search for. Supported values are
 | 
						//   description: type of repository to search for. Supported values are
 | 
				
			||||||
@ -125,6 +133,7 @@ func Search(ctx *context.APIContext) {
 | 
				
			|||||||
		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")),
 | 
				
			||||||
 | 
							OnlyPrivate:        ctx.IsSigned && ctx.QueryBool("onlyPrivate"),
 | 
				
			||||||
		Template:           util.OptionalBoolNone,
 | 
							Template:           util.OptionalBoolNone,
 | 
				
			||||||
		StarredByID:        ctx.QueryInt64("starredBy"),
 | 
							StarredByID:        ctx.QueryInt64("starredBy"),
 | 
				
			||||||
		IncludeDescription: ctx.QueryBool("includeDesc"),
 | 
							IncludeDescription: ctx.QueryBool("includeDesc"),
 | 
				
			||||||
@ -156,6 +165,10 @@ func Search(ctx *context.APIContext) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ctx.Query("archived") != "" {
 | 
				
			||||||
 | 
							opts.Archived = util.OptionalBoolOf(ctx.QueryBool("archived"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var sortMode = ctx.Query("sort")
 | 
						var sortMode = ctx.Query("sort")
 | 
				
			||||||
	if len(sortMode) > 0 {
 | 
						if len(sortMode) > 0 {
 | 
				
			||||||
		var sortOrder = ctx.Query("order")
 | 
							var sortOrder = ctx.Query("order")
 | 
				
			||||||
 | 
				
			|||||||
@ -1769,12 +1769,24 @@
 | 
				
			|||||||
            "name": "private",
 | 
					            "name": "private",
 | 
				
			||||||
            "in": "query"
 | 
					            "in": "query"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "boolean",
 | 
				
			||||||
 | 
					            "description": "only include private repositories this user has access to (defaults to false)",
 | 
				
			||||||
 | 
					            "name": "onlyPrivate",
 | 
				
			||||||
 | 
					            "in": "query"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            "type": "boolean",
 | 
					            "type": "boolean",
 | 
				
			||||||
            "description": "include template repositories this user has access to (defaults to true)",
 | 
					            "description": "include template repositories this user has access to (defaults to true)",
 | 
				
			||||||
            "name": "template",
 | 
					            "name": "template",
 | 
				
			||||||
            "in": "query"
 | 
					            "in": "query"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "boolean",
 | 
				
			||||||
 | 
					            "description": "show only archived, non-archived or all repositories (defaults to all)",
 | 
				
			||||||
 | 
					            "name": "archived",
 | 
				
			||||||
 | 
					            "in": "query"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            "type": "string",
 | 
					            "type": "string",
 | 
				
			||||||
            "description": "type of repository to search for. Supported values are \"fork\", \"source\", \"mirror\" and \"collaborative\"",
 | 
					            "description": "type of repository to search for. Supported values are \"fork\", \"source\", \"mirror\" and \"collaborative\"",
 | 
				
			||||||
 | 
				
			|||||||
@ -35,9 +35,46 @@
 | 
				
			|||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
			</h4>
 | 
								</h4>
 | 
				
			||||||
			<div class="ui attached secondary segment repos-search">
 | 
								<div class="ui attached secondary segment repos-search">
 | 
				
			||||||
				<div class="ui fluid icon input" :class="{loading: isLoading}">
 | 
									<div class="ui fluid right action left icon input" :class="{loading: isLoading}">
 | 
				
			||||||
					<input @input="searchRepos(reposFilter)" v-model="searchQuery" ref="search" placeholder="{{.i18n.Tr "home.search_repos"}}">
 | 
										<input @input="searchRepos(reposFilter)" v-model="searchQuery" ref="search" placeholder="{{.i18n.Tr "home.search_repos"}}">
 | 
				
			||||||
					<i class="search icon"></i>
 | 
										<i class="search icon"></i>
 | 
				
			||||||
 | 
										<div class="ui dropdown button" title="{{.i18n.Tr "home.filter"}}">
 | 
				
			||||||
 | 
											<i class="icon filter"></i>
 | 
				
			||||||
 | 
											<div class="menu">
 | 
				
			||||||
 | 
												<div class="item">
 | 
				
			||||||
 | 
													<a @click="toggleArchivedFilter()">
 | 
				
			||||||
 | 
														<div class="ui checkbox" id="archivedFilterCheckbox" title="{{.i18n.Tr "home.show_both_archived_unarchived"}}" v-if="archivedFilter === 'both'">
 | 
				
			||||||
 | 
															<input type="checkbox">
 | 
				
			||||||
 | 
															<label><i class="archive icon archived-icon"></i>{{.i18n.Tr "home.show_archived"}}</label>
 | 
				
			||||||
 | 
														</div>
 | 
				
			||||||
 | 
														<div class="ui checkbox" id="archivedFilterCheckbox" title="{{.i18n.Tr "home.show_only_unarchived"}}" v-if="archivedFilter === 'unarchived'">
 | 
				
			||||||
 | 
															<input type="checkbox">
 | 
				
			||||||
 | 
															<label><i class="archive icon archived-icon"></i>{{.i18n.Tr "home.show_archived"}}</label>
 | 
				
			||||||
 | 
														</div>
 | 
				
			||||||
 | 
														<div class="ui checkbox" id="archivedFilterCheckbox" title="{{.i18n.Tr "home.show_only_archived"}}" v-if="archivedFilter === 'archived'">
 | 
				
			||||||
 | 
															<input type="checkbox">
 | 
				
			||||||
 | 
															<label><i class="archive icon archived-icon"></i>{{.i18n.Tr "home.show_archived"}}</label>
 | 
				
			||||||
 | 
														</div>
 | 
				
			||||||
 | 
													</a>
 | 
				
			||||||
 | 
												</div>
 | 
				
			||||||
 | 
												<div class="item">
 | 
				
			||||||
 | 
													<a @click="togglePrivateFilter()">
 | 
				
			||||||
 | 
														<div class="ui checkbox" id="privateFilterCheckbox" title="{{.i18n.Tr "home.show_both_private_public"}}" v-if="privateFilter === 'both'">
 | 
				
			||||||
 | 
															<input type="checkbox">
 | 
				
			||||||
 | 
															<label><svg class="svg octicon-lock" width="16" height="16" aria-hidden="true"><use xlink:href="#octicon-lock" /></svg>{{.i18n.Tr "home.show_private"}}</label>
 | 
				
			||||||
 | 
														</div>
 | 
				
			||||||
 | 
														<div class="ui checkbox" id="privateFilterCheckbox" title="{{.i18n.Tr "home.show_only_public"}}" v-if="privateFilter === 'public'">
 | 
				
			||||||
 | 
															<input type="checkbox">
 | 
				
			||||||
 | 
															<label><svg class="svg octicon-lock" width="16" height="16" aria-hidden="true"><use xlink:href="#octicon-lock" /></svg>{{.i18n.Tr "home.show_private"}}</label>
 | 
				
			||||||
 | 
														</div>
 | 
				
			||||||
 | 
														<div class="ui checkbox" id="privateFilterCheckbox" title="{{.i18n.Tr "home.show_only_private"}}" v-if="privateFilter === 'private'">
 | 
				
			||||||
 | 
															<input type="checkbox">
 | 
				
			||||||
 | 
															<label><svg class="svg octicon-lock" width="16" height="16" aria-hidden="true"><use xlink:href="#octicon-lock" /></svg>{{.i18n.Tr "home.show_private"}}</label>
 | 
				
			||||||
 | 
														</div>
 | 
				
			||||||
 | 
													</a>
 | 
				
			||||||
 | 
												</div>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
										</div>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
				<div class="ui secondary tiny pointing borderless menu center aligned grid repos-filter">
 | 
									<div class="ui secondary tiny pointing borderless menu center aligned grid repos-filter">
 | 
				
			||||||
					<a class="item" :class="{active: reposFilter === 'all'}" @click="changeReposFilter('all')">
 | 
										<a class="item" :class="{active: reposFilter === 'all'}" @click="changeReposFilter('all')">
 | 
				
			||||||
@ -64,7 +101,7 @@
 | 
				
			|||||||
			</div>
 | 
								</div>
 | 
				
			||||||
			<div class="ui attached table segment">
 | 
								<div class="ui attached table segment">
 | 
				
			||||||
				<ul class="repo-owner-name-list">
 | 
									<ul class="repo-owner-name-list">
 | 
				
			||||||
					<li v-for="repo in repos" :class="{'private': repo.private}" v-show="showRepo(repo, reposFilter)">
 | 
										<li v-for="repo in repos" :class="{'private': repo.private}" v-show="showRepo(repo)">
 | 
				
			||||||
						<a :href="suburl + '/' + repo.full_name">
 | 
											<a :href="suburl + '/' + repo.full_name">
 | 
				
			||||||
							<svg :class="'svg ' + repoClass(repo)" width="16" height="16" aria-hidden="true"><use :xlink:href="'#' + repoClass(repo)" /></svg>
 | 
												<svg :class="'svg ' + repoClass(repo)" width="16" height="16" aria-hidden="true"><use :xlink:href="'#' + repoClass(repo)" /></svg>
 | 
				
			||||||
							<strong class="text truncate item-name">${repo.full_name}</strong>
 | 
												<strong class="text truncate item-name">${repo.full_name}</strong>
 | 
				
			||||||
@ -75,7 +112,27 @@
 | 
				
			|||||||
						</a>
 | 
											</a>
 | 
				
			||||||
					</li>
 | 
										</li>
 | 
				
			||||||
					<li v-if="showMoreReposLink">
 | 
										<li v-if="showMoreReposLink">
 | 
				
			||||||
						<a :href="moreReposLink">{{.i18n.Tr "home.show_more_repos"}}</a>
 | 
											<div class="center">
 | 
				
			||||||
 | 
												<div class="ui borderless pagination menu narrow">
 | 
				
			||||||
 | 
													<a class="item navigation" :class="{'disabled': page === 1}"
 | 
				
			||||||
 | 
														@click="changePage(1)" title="{{$.i18n.Tr "admin.first_page"}}">
 | 
				
			||||||
 | 
														<i class="angle double left icon"></i>
 | 
				
			||||||
 | 
													</a>
 | 
				
			||||||
 | 
													<a class="item navigation" :class="{'disabled': page === 1}"
 | 
				
			||||||
 | 
														@click="changePage(page - 1)" title="{{$.i18n.Tr "repo.issues.previous"}}">
 | 
				
			||||||
 | 
														<i class="left arrow icon"></i>
 | 
				
			||||||
 | 
													</a>
 | 
				
			||||||
 | 
													<a class="active item">${page}</a>
 | 
				
			||||||
 | 
													<a class="item navigation" :class="{'disabled': page === finalPage}"
 | 
				
			||||||
 | 
														@click="changePage(page + 1)" title="{{$.i18n.Tr "repo.issues.next"}}">
 | 
				
			||||||
 | 
														<i class="icon right arrow"></i>
 | 
				
			||||||
 | 
													</a>
 | 
				
			||||||
 | 
													<a class="item navigation" :class="{'disabled': page === finalPage}"
 | 
				
			||||||
 | 
														@click="changePage(finalPage)" title="{{$.i18n.Tr "admin.last_page"}}">
 | 
				
			||||||
 | 
														<i class="angle double right icon"></i>
 | 
				
			||||||
 | 
													</a>
 | 
				
			||||||
 | 
												</div>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
					</li>
 | 
										</li>
 | 
				
			||||||
				</ul>
 | 
									</ul>
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
 | 
				
			|||||||
@ -2662,33 +2662,70 @@ function initVueComponents() {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    data() {
 | 
					    data() {
 | 
				
			||||||
 | 
					      const params = new URLSearchParams(window.location.search);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let tab = params.get('repo-search-tab');
 | 
				
			||||||
 | 
					      if (!tab) {
 | 
				
			||||||
 | 
					        tab = 'repos';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let reposFilter = params.get('repo-search-filter');
 | 
				
			||||||
 | 
					      if (!reposFilter) {
 | 
				
			||||||
 | 
					        reposFilter = 'all';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let privateFilter = params.get('repo-search-private');
 | 
				
			||||||
 | 
					      if (!privateFilter) {
 | 
				
			||||||
 | 
					        privateFilter = 'both';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let archivedFilter = params.get('repo-search-archived');
 | 
				
			||||||
 | 
					      if (!archivedFilter) {
 | 
				
			||||||
 | 
					        archivedFilter = 'both';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let searchQuery = params.get('repo-search-query');
 | 
				
			||||||
 | 
					      if (!searchQuery) {
 | 
				
			||||||
 | 
					        searchQuery = '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let page = 1;
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        page = parseInt(params.get('repo-search-page'));
 | 
				
			||||||
 | 
					      } catch {
 | 
				
			||||||
 | 
					        // noop
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!page) {
 | 
				
			||||||
 | 
					        page = 1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        tab: 'repos',
 | 
					        tab,
 | 
				
			||||||
        repos: [],
 | 
					        repos: [],
 | 
				
			||||||
        reposTotalCount: 0,
 | 
					        reposTotalCount: 0,
 | 
				
			||||||
        reposFilter: 'all',
 | 
					        reposFilter,
 | 
				
			||||||
        searchQuery: '',
 | 
					        archivedFilter,
 | 
				
			||||||
 | 
					        privateFilter,
 | 
				
			||||||
 | 
					        page,
 | 
				
			||||||
 | 
					        finalPage: 1,
 | 
				
			||||||
 | 
					        searchQuery,
 | 
				
			||||||
        isLoading: false,
 | 
					        isLoading: false,
 | 
				
			||||||
        staticPrefix: StaticUrlPrefix,
 | 
					        staticPrefix: StaticUrlPrefix,
 | 
				
			||||||
 | 
					        counts: {},
 | 
				
			||||||
        repoTypes: {
 | 
					        repoTypes: {
 | 
				
			||||||
          all: {
 | 
					          all: {
 | 
				
			||||||
            count: 0,
 | 
					 | 
				
			||||||
            searchMode: '',
 | 
					            searchMode: '',
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          forks: {
 | 
					          forks: {
 | 
				
			||||||
            count: 0,
 | 
					 | 
				
			||||||
            searchMode: 'fork',
 | 
					            searchMode: 'fork',
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          mirrors: {
 | 
					          mirrors: {
 | 
				
			||||||
            count: 0,
 | 
					 | 
				
			||||||
            searchMode: 'mirror',
 | 
					            searchMode: 'mirror',
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          sources: {
 | 
					          sources: {
 | 
				
			||||||
            count: 0,
 | 
					 | 
				
			||||||
            searchMode: 'source',
 | 
					            searchMode: 'source',
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          collaborative: {
 | 
					          collaborative: {
 | 
				
			||||||
            count: 0,
 | 
					 | 
				
			||||||
            searchMode: 'collaborative',
 | 
					            searchMode: 'collaborative',
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -2697,21 +2734,26 @@ function initVueComponents() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    computed: {
 | 
					    computed: {
 | 
				
			||||||
      showMoreReposLink() {
 | 
					      showMoreReposLink() {
 | 
				
			||||||
        return this.repos.length > 0 && this.repos.length < this.repoTypes[this.reposFilter].count;
 | 
					        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}&q=${this.searchQuery
 | 
				
			||||||
        }&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.privateFilter === 'private' ? '&onlyPrivate=true' : ''}${this.privateFilter === 'public' ? '&private=false' : ''
 | 
				
			||||||
 | 
					        }`;
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      repoTypeCount() {
 | 
					      repoTypeCount() {
 | 
				
			||||||
        return this.repoTypes[this.reposFilter].count;
 | 
					        return this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`];
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mounted() {
 | 
					    mounted() {
 | 
				
			||||||
      this.searchRepos(this.reposFilter);
 | 
					      this.searchRepos(this.reposFilter);
 | 
				
			||||||
 | 
					      $(this.$el).find('.poping.up').popup();
 | 
				
			||||||
 | 
					      $(this.$el).find('.dropdown').dropdown();
 | 
				
			||||||
 | 
					      this.setCheckboxes();
 | 
				
			||||||
      const self = this;
 | 
					      const self = this;
 | 
				
			||||||
      Vue.nextTick(() => {
 | 
					      Vue.nextTick(() => {
 | 
				
			||||||
        self.$refs.search.focus();
 | 
					        self.$refs.search.focus();
 | 
				
			||||||
@ -2721,17 +2763,178 @@ function initVueComponents() {
 | 
				
			|||||||
    methods: {
 | 
					    methods: {
 | 
				
			||||||
      changeTab(t) {
 | 
					      changeTab(t) {
 | 
				
			||||||
        this.tab = t;
 | 
					        this.tab = t;
 | 
				
			||||||
 | 
					        this.updateHistory();
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      setCheckboxes() {
 | 
				
			||||||
 | 
					        switch (this.archivedFilter) {
 | 
				
			||||||
 | 
					          case 'unarchived':
 | 
				
			||||||
 | 
					            $('#archivedFilterCheckbox').checkbox('set unchecked');
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 'archived':
 | 
				
			||||||
 | 
					            $('#archivedFilterCheckbox').checkbox('set checked');
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 'both':
 | 
				
			||||||
 | 
					            $('#archivedFilterCheckbox').checkbox('set indeterminate');
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          default:
 | 
				
			||||||
 | 
					            this.archivedFilter = 'both';
 | 
				
			||||||
 | 
					            $('#archivedFilterCheckbox').checkbox('set indeterminate');
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        switch (this.privateFilter) {
 | 
				
			||||||
 | 
					          case 'public':
 | 
				
			||||||
 | 
					            $('#privateFilterCheckbox').checkbox('set unchecked');
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 'private':
 | 
				
			||||||
 | 
					            $('#privateFilterCheckbox').checkbox('set checked');
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 'both':
 | 
				
			||||||
 | 
					            $('#privateFilterCheckbox').checkbox('set indeterminate');
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          default:
 | 
				
			||||||
 | 
					            this.privateFilter = 'both';
 | 
				
			||||||
 | 
					            $('#privateFilterCheckbox').checkbox('set indeterminate');
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      changeReposFilter(filter) {
 | 
					      changeReposFilter(filter) {
 | 
				
			||||||
        this.reposFilter = filter;
 | 
					        this.reposFilter = filter;
 | 
				
			||||||
        this.repos = [];
 | 
					        this.repos = [];
 | 
				
			||||||
        this.repoTypes[filter].count = 0;
 | 
					        this.page = 1;
 | 
				
			||||||
        this.searchRepos(filter);
 | 
					        Vue.set(this.counts, `${filter}:${this.archivedFilter}:${this.privateFilter}`, 0);
 | 
				
			||||||
 | 
					        this.searchRepos();
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      showRepo(repo, filter) {
 | 
					      updateHistory() {
 | 
				
			||||||
        switch (filter) {
 | 
					        const params = new URLSearchParams(window.location.search);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.tab === 'repos') {
 | 
				
			||||||
 | 
					          params.delete('repo-search-tab');
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          params.set('repo-search-tab', this.tab);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.reposFilter === 'all') {
 | 
				
			||||||
 | 
					          params.delete('repo-search-filter');
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          params.set('repo-search-filter', this.reposFilter);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.privateFilter === 'both') {
 | 
				
			||||||
 | 
					          params.delete('repo-search-private');
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          params.set('repo-search-private', this.privateFilter);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.archivedFilter === 'both') {
 | 
				
			||||||
 | 
					          params.delete('repo-search-archived');
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          params.set('repo-search-archived', this.archivedFilter);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.searchQuery === '') {
 | 
				
			||||||
 | 
					          params.delete('repo-search-query');
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          params.set('repo-search-query', this.searchQuery);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.page === 1) {
 | 
				
			||||||
 | 
					          params.delete('repo-search-page');
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          params.set('repo-search-page', `${this.page}`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        window.history.replaceState({}, '', `?${params.toString()}`);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      toggleArchivedFilter() {
 | 
				
			||||||
 | 
					        switch (this.archivedFilter) {
 | 
				
			||||||
 | 
					          case 'both':
 | 
				
			||||||
 | 
					            this.archivedFilter = 'unarchived';
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 'unarchived':
 | 
				
			||||||
 | 
					            this.archivedFilter = 'archived';
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 'archived':
 | 
				
			||||||
 | 
					            this.archivedFilter = 'both';
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          default:
 | 
				
			||||||
 | 
					            this.archivedFilter = 'both';
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.page = 1;
 | 
				
			||||||
 | 
					        this.repos = [];
 | 
				
			||||||
 | 
					        this.setCheckboxes();
 | 
				
			||||||
 | 
					        Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0);
 | 
				
			||||||
 | 
					        this.searchRepos();
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      togglePrivateFilter() {
 | 
				
			||||||
 | 
					        switch (this.privateFilter) {
 | 
				
			||||||
 | 
					          case 'both':
 | 
				
			||||||
 | 
					            this.privateFilter = 'public';
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 'public':
 | 
				
			||||||
 | 
					            this.privateFilter = 'private';
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 'private':
 | 
				
			||||||
 | 
					            this.privateFilter = 'both';
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          default:
 | 
				
			||||||
 | 
					            this.privateFilter = 'both';
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.page = 1;
 | 
				
			||||||
 | 
					        this.repos = [];
 | 
				
			||||||
 | 
					        this.setCheckboxes();
 | 
				
			||||||
 | 
					        Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0);
 | 
				
			||||||
 | 
					        this.searchRepos();
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      changePage(page) {
 | 
				
			||||||
 | 
					        this.page = page;
 | 
				
			||||||
 | 
					        if (this.page > this.finalPage) {
 | 
				
			||||||
 | 
					          this.page = this.finalPage;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (this.page < 1) {
 | 
				
			||||||
 | 
					          this.page = 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.repos = [];
 | 
				
			||||||
 | 
					        Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0);
 | 
				
			||||||
 | 
					        this.searchRepos();
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      showArchivedRepo(repo) {
 | 
				
			||||||
 | 
					        switch (this.archivedFilter) {
 | 
				
			||||||
 | 
					          case 'both':
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					          case 'unarchived':
 | 
				
			||||||
 | 
					            return !repo.archived;
 | 
				
			||||||
 | 
					          case 'archived':
 | 
				
			||||||
 | 
					            return repo.archived;
 | 
				
			||||||
 | 
					          default:
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      showPrivateRepo(repo) {
 | 
				
			||||||
 | 
					        switch (this.privateFilter) {
 | 
				
			||||||
 | 
					          case 'both':
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					          case 'public':
 | 
				
			||||||
 | 
					            return !repo.private;
 | 
				
			||||||
 | 
					          case 'private':
 | 
				
			||||||
 | 
					            return repo.private;
 | 
				
			||||||
 | 
					          default:
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      showFilteredRepo(repo) {
 | 
				
			||||||
 | 
					        switch (this.reposFilter) {
 | 
				
			||||||
          case 'sources':
 | 
					          case 'sources':
 | 
				
			||||||
            return repo.owner.id === this.uid && !repo.mirror && !repo.fork;
 | 
					            return repo.owner.id === this.uid && !repo.mirror && !repo.fork;
 | 
				
			||||||
          case 'forks':
 | 
					          case 'forks':
 | 
				
			||||||
@ -2745,12 +2948,16 @@ function initVueComponents() {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      searchRepos(reposFilter) {
 | 
					      showRepo(repo) {
 | 
				
			||||||
 | 
					        return this.showArchivedRepo(repo) && this.showPrivateRepo(repo) && this.showFilteredRepo(repo);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      searchRepos() {
 | 
				
			||||||
        const self = this;
 | 
					        const self = this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.isLoading = true;
 | 
					        this.isLoading = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const searchedMode = this.repoTypes[reposFilter].searchMode;
 | 
					        const searchedMode = this.repoTypes[this.reposFilter].searchMode;
 | 
				
			||||||
        const searchedURL = this.searchURL;
 | 
					        const searchedURL = this.searchURL;
 | 
				
			||||||
        const searchedQuery = this.searchQuery;
 | 
					        const searchedQuery = this.searchQuery;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2758,10 +2965,12 @@ function initVueComponents() {
 | 
				
			|||||||
          if (searchedURL === self.searchURL) {
 | 
					          if (searchedURL === self.searchURL) {
 | 
				
			||||||
            self.repos = result.data;
 | 
					            self.repos = result.data;
 | 
				
			||||||
            const count = request.getResponseHeader('X-Total-Count');
 | 
					            const count = request.getResponseHeader('X-Total-Count');
 | 
				
			||||||
            if (searchedQuery === '' && searchedMode === '') {
 | 
					            if (searchedQuery === '' && searchedMode === '' && self.archivedFilter === 'both') {
 | 
				
			||||||
              self.reposTotalCount = count;
 | 
					              self.reposTotalCount = count;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            self.repoTypes[reposFilter].count = count;
 | 
					            Vue.set(self.counts, `${self.reposFilter}:${self.archivedFilter}:${self.privateFilter}`, count);
 | 
				
			||||||
 | 
					            self.finalPage = Math.floor(count / self.searchLimit) + 1;
 | 
				
			||||||
 | 
					            self.updateHistory();
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }).always(() => {
 | 
					        }).always(() => {
 | 
				
			||||||
          if (searchedURL === self.searchURL) {
 | 
					          if (searchedURL === self.searchURL) {
 | 
				
			||||||
 | 
				
			|||||||
@ -318,11 +318,11 @@ code,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.ui {
 | 
					.ui {
 | 
				
			||||||
    &.left {
 | 
					    &.left:not(.action) {
 | 
				
			||||||
        float: left;
 | 
					        float: left;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &.right {
 | 
					    &.right:not(.action) {
 | 
				
			||||||
        float: right;
 | 
					        float: right;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -727,6 +727,15 @@ code,
 | 
				
			|||||||
                display: none;
 | 
					                display: none;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        &.narrow .item {
 | 
				
			||||||
 | 
					            padding-left: 8px;
 | 
				
			||||||
 | 
					            padding-right: 8px;
 | 
				
			||||||
 | 
					            min-width: 1em;
 | 
				
			||||||
 | 
					            text-align: center;
 | 
				
			||||||
 | 
					            .icon {
 | 
				
			||||||
 | 
					                margin-right: 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -174,6 +174,11 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #privateFilterCheckbox .svg {
 | 
				
			||||||
 | 
					            color: #888888;
 | 
				
			||||||
 | 
					            margin-right: .25rem;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        .repo-owner-name-list {
 | 
					        .repo-owner-name-list {
 | 
				
			||||||
            .item-name {
 | 
					            .item-name {
 | 
				
			||||||
                max-width: 70%;
 | 
					                max-width: 70%;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user