Improve dashboard repo search (#1652)
* Add VueJS * Improve dashboard search * Fix tab switching * Fix input autofocus
This commit is contained in:
		
							parent
							
								
									51d0becb42
								
							
						
					
					
						commit
						ab79069dc7
					
				
					 6 changed files with 8654 additions and 32 deletions
				
			
		|  | @ -115,9 +115,6 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (repos RepositoryList, coun | ||||||
| 		cond = builder.NewCond() | 		cond = builder.NewCond() | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	if len(opts.Keyword) == 0 { |  | ||||||
| 		return repos, 0, nil |  | ||||||
| 	} |  | ||||||
| 	opts.Keyword = strings.ToLower(opts.Keyword) | 	opts.Keyword = strings.ToLower(opts.Keyword) | ||||||
| 
 | 
 | ||||||
| 	if opts.Page <= 0 { | 	if opts.Page <= 0 { | ||||||
|  |  | ||||||
|  | @ -1560,6 +1560,7 @@ $(document).ready(function () { | ||||||
|     initWebhook(); |     initWebhook(); | ||||||
|     initAdmin(); |     initAdmin(); | ||||||
|     initCodeView(); |     initCodeView(); | ||||||
|  |     initDashboardSearch(); | ||||||
| 
 | 
 | ||||||
|     // Repo clone url.
 |     // Repo clone url.
 | ||||||
|     if ($('#repo-clone-url').length > 0) { |     if ($('#repo-clone-url').length > 0) { | ||||||
|  | @ -1635,13 +1636,6 @@ $(function () { | ||||||
|     if ($('.user.signin').length > 0) return; |     if ($('.user.signin').length > 0) return; | ||||||
|     $('form').areYouSure(); |     $('form').areYouSure(); | ||||||
| 
 | 
 | ||||||
|     $("#search_repo").on('change paste keyup',function(){ |  | ||||||
|         var value = $(this).val(); |  | ||||||
|         $.map($('.search-list li'), function(i) { |  | ||||||
|             $(i).css("display", (value.trim().length == 0 || $(i).attr("data-title").trim().toLowerCase().indexOf(value.trim().toLowerCase()) > -1) ? "" : "none"); |  | ||||||
|         }); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     // Parse SSH Key
 |     // Parse SSH Key
 | ||||||
|     $("#ssh-key-content").on('change paste keyup',function(){ |     $("#ssh-key-content").on('change paste keyup',function(){ | ||||||
|         var arrays = $(this).val().split(" "); |         var arrays = $(this).val().split(" "); | ||||||
|  | @ -1651,3 +1645,64 @@ $(function () { | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|  | 
 | ||||||
|  | function initDashboardSearch() { | ||||||
|  |     var el = document.getElementById('dashboard-repo-search'); | ||||||
|  |     if (!el) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     new Vue({ | ||||||
|  |         delimiters: ['<%', '%>'], | ||||||
|  |         el: el, | ||||||
|  | 
 | ||||||
|  |         data: { | ||||||
|  |             tab: 'repos', | ||||||
|  |             repos: [], | ||||||
|  |             searchQuery: '', | ||||||
|  |             suburl: document.querySelector('meta[name=_suburl]').content, | ||||||
|  |             uid: document.querySelector('meta[name=_uid]').content | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         mounted: function() { | ||||||
|  |             this.searchRepos(); | ||||||
|  | 
 | ||||||
|  |             Vue.nextTick(function() { | ||||||
|  |                 document.querySelector('#search_repo').focus(); | ||||||
|  |             }); | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         methods: { | ||||||
|  |             changeTab: function(t) { | ||||||
|  |                 this.tab = t; | ||||||
|  |             }, | ||||||
|  | 
 | ||||||
|  |             searchKeyUp: function() { | ||||||
|  |                 this.searchRepos(); | ||||||
|  |             }, | ||||||
|  | 
 | ||||||
|  |             searchRepos: function() { | ||||||
|  |                 var self = this; | ||||||
|  |                 $.getJSON(this.searchURL(), function(result) { | ||||||
|  |                     self.repos = result.data; | ||||||
|  |                 }); | ||||||
|  |             }, | ||||||
|  | 
 | ||||||
|  |             searchURL: function() { | ||||||
|  |                 return this.suburl + '/api/v1/repos/search?uid=' + this.uid + '&q=' + this.searchQuery; | ||||||
|  |             }, | ||||||
|  | 
 | ||||||
|  |             repoClass: function(repo) { | ||||||
|  |                 if (repo.fork) { | ||||||
|  |                     return 'octicon octicon-repo-forked'; | ||||||
|  |                 } else if (repo.mirror) { | ||||||
|  |                     return 'octicon octicon-repo-clone'; | ||||||
|  |                 } else if (repo.private) { | ||||||
|  |                     return 'octicon octicon-repo-forked'; | ||||||
|  |                 } else { | ||||||
|  |                     return 'octicon octicon-repo'; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										8568
									
								
								public/js/libs/vue.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8568
									
								
								public/js/libs/vue.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -65,5 +65,6 @@ | ||||||
| 	<script src="{{AppSubUrl}}/js/libs/autolink.js"></script> | 	<script src="{{AppSubUrl}}/js/libs/autolink.js"></script> | ||||||
| 	<script src="{{AppSubUrl}}/js/libs/emojify-1.1.0.min.js"></script> | 	<script src="{{AppSubUrl}}/js/libs/emojify-1.1.0.min.js"></script> | ||||||
| 	<script src="{{AppSubUrl}}/js/libs/clipboard-1.5.9.min.js"></script> | 	<script src="{{AppSubUrl}}/js/libs/clipboard-1.5.9.min.js"></script> | ||||||
|  | 	<script src="{{AppSubUrl}}/js/libs/vue.js"></script> | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
|  |  | ||||||
|  | @ -11,6 +11,9 @@ | ||||||
| 	<meta name="referrer" content="no-referrer" /> | 	<meta name="referrer" content="no-referrer" /> | ||||||
| 	<meta name="_csrf" content="{{.CsrfToken}}" /> | 	<meta name="_csrf" content="{{.CsrfToken}}" /> | ||||||
| 	<meta name="_suburl" content="{{AppSubUrl}}" /> | 	<meta name="_suburl" content="{{AppSubUrl}}" /> | ||||||
|  | 	{{if .IsSigned}} | ||||||
|  | 		<meta name="_uid" content="{{.SignedUser.ID}}" /> | ||||||
|  | 	{{end}} | ||||||
| {{if .GoGetImport}} | {{if .GoGetImport}} | ||||||
| 	<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}"> | 	<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}"> | ||||||
| 	<meta name="go-source" content="{{.GoGetImport}} _ {{.GoDocDirectory}} {{.GoDocFile}}"> | 	<meta name="go-source" content="{{.GoGetImport}} _ {{.GoDocDirectory}} {{.GoDocFile}}"> | ||||||
|  |  | ||||||
|  | @ -7,17 +7,17 @@ | ||||||
| 			<div class="ten wide column"> | 			<div class="ten wide column"> | ||||||
| 				{{template "user/dashboard/feeds" .}} | 				{{template "user/dashboard/feeds" .}} | ||||||
| 			</div> | 			</div> | ||||||
| 			<div class="six wide column"> | 			<div id="dashboard-repo-search" class="six wide column"> | ||||||
| 				<div class="ui {{if not .ContextUser.IsOrganization}}three{{else}}two{{end}} item tabable menu"> | 				<div class="ui {{if not .ContextUser.IsOrganization}}three{{else}}two{{end}} item tabable menu"> | ||||||
| 					<a class="item active" data-tab="repos">{{.i18n.Tr "repository"}}</a> | 					<a :class="{item: true, active: tab === 'repos'}" @click="changeTab('repos')">{{.i18n.Tr "repository"}}</a> | ||||||
| 					{{if not .ContextUser.IsOrganization}} | 					{{if not .ContextUser.IsOrganization}} | ||||||
| 						<a class="item" data-tab="orgs">{{.i18n.Tr "organization"}}</a> | 						<a :class="{item: true, active: tab === 'orgs'}" @click="changeTab('orgs')">{{.i18n.Tr "organization"}}</a> | ||||||
| 					{{end}} | 					{{end}} | ||||||
| 					<a class="item" data-tab="mirrors">{{.i18n.Tr "mirror"}}</a> | 					<a :class="{item: true, active: tab === 'mirrors'}" @click="changeTab('mirrors')">{{.i18n.Tr "mirror"}}</a> | ||||||
| 				</div> | 				</div> | ||||||
| 				<div class="ui tab active list" data-tab="repos"> | 				<div v-if="tab === 'repos'" class="ui tab active list"> | ||||||
| 					<div class="ui fluid input"> | 					<div class="ui fluid input"> | ||||||
| 						<input id="search_repo" name="q" value="" placeholder="{{.i18n.Tr "home.search_repos"}}" autofocus=""> | 						<input @keyUp="searchKeyUp" v-model="searchQuery" id="search_repo" placeholder="{{.i18n.Tr "home.search_repos"}}"> | ||||||
| 					</div> | 					</div> | ||||||
| 					<h4 class="ui top attached header"> | 					<h4 class="ui top attached header"> | ||||||
| 						{{.i18n.Tr "home.my_repos"}} <span class="ui grey label">{{.ContextUser.NumRepos}}</span> | 						{{.i18n.Tr "home.my_repos"}} <span class="ui grey label">{{.ContextUser.NumRepos}}</span> | ||||||
|  | @ -29,18 +29,16 @@ | ||||||
| 						</div> | 						</div> | ||||||
| 					</h4> | 					</h4> | ||||||
| 					<div class="ui attached table segment"> | 					<div class="ui attached table segment"> | ||||||
| 						<ul class="repo-owner-name-list search-list"> | 						<ul class="repo-owner-name-list"> | ||||||
| 							{{range .Repos}} | 							<li v-for="repo in repos" :class="{'private': repo.private}"> | ||||||
| 								<li {{if .IsPrivate}}class="private"{{end}} data-title="{{.Name}}"> | 								<a :href="'{{AppSubUrl}}/' + repo.full_name"> | ||||||
| 									<a href="{{AppSubUrl}}/{{$.ContextUser.Name}}/{{.Name}}"> | 									<i :class="repoClass(repo)"></i> | ||||||
| 										<i class="octicon octicon-{{if .IsFork}}repo-forked{{else if .IsPrivate}}lock{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i> | 									<strong class="text truncate item-name"><% repo.full_name %></strong> | ||||||
| 										<strong class="text truncate item-name">{{.Name}}</strong> | 									<span class="ui right text light grey"> | ||||||
| 										<span class="ui right text light grey"> | 										<% repo.stars_count %> <i class="octicon octicon-star rear"></i> | ||||||
| 											{{.NumStars}} <i class="octicon octicon-star rear"></i> | 									</span> | ||||||
| 										</span> | 								</a> | ||||||
| 									</a> | 							</li> | ||||||
| 								</li> |  | ||||||
| 							{{end}} |  | ||||||
| 							{{if gt .ContextUser.NumRepos .MaxShowRepoNum}} | 							{{if gt .ContextUser.NumRepos .MaxShowRepoNum}} | ||||||
| 							<li> | 							<li> | ||||||
| 								<a href="{{.ContextUser.HomeLink}}">{{.i18n.Tr "home.show_more_repos"}}</a> | 								<a href="{{.ContextUser.HomeLink}}">{{.i18n.Tr "home.show_more_repos"}}</a> | ||||||
|  | @ -54,9 +52,9 @@ | ||||||
| 							{{.i18n.Tr "home.collaborative_repos"}} | 							{{.i18n.Tr "home.collaborative_repos"}} | ||||||
| 						</h4> | 						</h4> | ||||||
| 						<div class="ui attached table segment"> | 						<div class="ui attached table segment"> | ||||||
| 							<ul id="collaborative-repo-list" class="search-list"> | 							<ul id="collaborative-repo-list"> | ||||||
| 								{{range .CollaborativeRepos}} | 								{{range .CollaborativeRepos}} | ||||||
| 									<li {{if .IsPrivate}}class="private"{{end}} data-title="{{.Name}}"> | 									<li {{if .IsPrivate}}class="private"{{end}}> | ||||||
| 										<a href="{{AppSubUrl}}/{{.Owner.Name}}/{{.Name}}"> | 										<a href="{{AppSubUrl}}/{{.Owner.Name}}/{{.Name}}"> | ||||||
| 											<i class="octicon octicon-{{if .IsPrivate}}lock{{else if .IsFork}}repo-forked{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i> | 											<i class="octicon octicon-{{if .IsPrivate}}lock{{else if .IsFork}}repo-forked{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i> | ||||||
| 											<span class="text truncate owner-and-repo"> | 											<span class="text truncate owner-and-repo"> | ||||||
|  | @ -74,7 +72,7 @@ | ||||||
| 				</div> | 				</div> | ||||||
| 
 | 
 | ||||||
| 				{{if not .ContextUser.IsOrganization}} | 				{{if not .ContextUser.IsOrganization}} | ||||||
| 					<div class="ui tab list" data-tab="orgs"> | 					<div v-if="tab === 'orgs'" class="ui tab active list"> | ||||||
| 						<h4 class="ui top attached header"> | 						<h4 class="ui top attached header"> | ||||||
| 							{{.i18n.Tr "home.my_orgs"}} <span class="ui grey label">{{.ContextUser.GetOrganizationCount}}</span> | 							{{.i18n.Tr "home.my_orgs"}} <span class="ui grey label">{{.ContextUser.GetOrganizationCount}}</span> | ||||||
| 							<div class="ui right"> | 							<div class="ui right"> | ||||||
|  | @ -102,7 +100,7 @@ | ||||||
| 					</div> | 					</div> | ||||||
| 				{{end}} | 				{{end}} | ||||||
| 
 | 
 | ||||||
| 				<div class="ui tab list" data-tab="mirrors"> | 				<div v-if="tab === 'mirrors'" class="ui tab active list"> | ||||||
| 					<h4 class="ui top attached header"> | 					<h4 class="ui top attached header"> | ||||||
| 						{{.i18n.Tr "home.my_mirrors"}} <span class="ui grey label">{{.MirrorCount}}</span> | 						{{.i18n.Tr "home.my_mirrors"}} <span class="ui grey label">{{.MirrorCount}}</span> | ||||||
| 						<div class="ui right"> | 						<div class="ui right"> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue