Display logs in a streaming fashion JGit even on a fast workstation can only walk a few thousand commits per second with rename detection on (and in a loaded server environment it might be much slower). Loading a full page of 100 log results for a file therefore might take many seconds. Stream the output one log entry at a time so the page becomes interactive slightly faster. Each HTTP chunk is a full <li></li> tag, so browsers should be able to render incrementally. This is much simpler than an alternative solution involving AJAX to make multiple requests to the server, particularly in a multi-server cluster environment where the client is not guaranteed to talk to the same server (with the necessary RevWalk state in memory) on consecutive requests. Change-Id: I63c4bc655efd00453b6db60f333ba3dd5041e70a
diff --git a/gitiles-servlet/src/main/resources/com/google/gitiles/static/gitiles.css b/gitiles-servlet/src/main/resources/com/google/gitiles/static/gitiles.css index 25c0754..e2adfc2 100644 --- a/gitiles-servlet/src/main/resources/com/google/gitiles/static/gitiles.css +++ b/gitiles-servlet/src/main/resources/com/google/gitiles/static/gitiles.css
@@ -316,6 +316,12 @@ color: #009933; } +ol.log > li.empty:hover, ol.log > li.empty { + background: inherit; + padding: 0px; + border: 0px; +} + /* Styles for the diff detail template. */
diff --git a/gitiles-servlet/src/main/resources/com/google/gitiles/templates/LogDetail.soy b/gitiles-servlet/src/main/resources/com/google/gitiles/templates/LogDetail.soy index 71ac795..6c4de74 100644 --- a/gitiles-servlet/src/main/resources/com/google/gitiles/templates/LogDetail.soy +++ b/gitiles-servlet/src/main/resources/com/google/gitiles/templates/LogDetail.soy
@@ -23,10 +23,6 @@ * @param breadcrumbs breadcrumbs for this page. * @param? tags optional list of tags encountered when peeling this object, with * keys corresponding to gitiles.tagDetail. - * @param? logEntryVariant variant name for log entry template. - * @param entries list of log entries; see .logEntry. - * @param? nextUrl URL for the next page of results. - * @param? previousUrl URL for the previous page of results. */ {template .logDetail} {call .header data="all" /} @@ -37,40 +33,52 @@ {/foreach} {/if} -{call .logEntries data="all" /} +{call .streamingPlaceholder /} {call .footer /} {/template} + /** - * List of log entries. + * Header for list of log entries. * - * @param? logEntryVariant variant name for log entry template. - * @param? logEntryPretty base "pretty" format for the log entry template. - * @param entries list of log entries; see .logEntry. - * @param? nextUrl URL for the next page of results. + * @param? pretty base "pretty" format for the log entry template. * @param? previousUrl URL for the previous page of results. */ -{template .logEntries} +{template .logEntriesHeader} {if $previousUrl} <div class="log-nav"> <a href="{$previousUrl}">{msg desc="text for previous URL"}« Previous{/msg}</a> </div> {/if} -{if length($entries)} - <ol class="{$logEntryPretty ?: 'default'} log"> - {foreach $entry in $entries} - <li{if $previousUrl and isFirst($entry)} class="first"{/if}> - {delcall gitiles.logEntry variant="$logEntryVariant ?: 'default'" - data="$entry" /} - </li> - {/foreach} - </ol> -{else} - <p>{msg desc="informational text for when the log is empty"}No commits.{/msg}</p> -{/if} +<ol class="{$pretty ?: 'default'} log"> +{/template} + +/** + * Wrapper for a single log entry with pretty format and variant. + * + * @param firstWithPrevious whether this entry is the first in the current list, + * but also comes below a "Previous" link. + * @param variant variant name for log entry template. + * @param entry log entry; see .logEntry. + */ +{template .logEntryWrapper} +// TODO(dborowitz): Better CSS instead of this firstWithPrevious hack. +<li{if $firstWithPrevious} class="first"{/if}> + {delcall gitiles.logEntry variant="$variant ?: 'default'" data="$entry" /} +</li> +{/template} + + +/** + * Footer for the list of log entries. + * + * @param? nextUrl URL for the next page of results. + */ +{template .logEntriesFooter} +</ol> {if $nextUrl} <div class="log-nav"> <a href="{$nextUrl}">{msg desc="text for next URL"}Next »{/msg}</a> @@ -80,6 +88,14 @@ /** + * Single log entry indicating the full log is empty. + */ +{template .emptyLog} +<li class="empty">{msg desc="informational text for when the log is empty"}No commits.{/msg}</p> +{/template} + + +/** * Single pretty log entry, similar to --pretty=oneline. * * @param abbrevSha abbreviated SHA-1.
diff --git a/gitiles-servlet/src/main/resources/com/google/gitiles/templates/RepositoryIndex.soy b/gitiles-servlet/src/main/resources/com/google/gitiles/templates/RepositoryIndex.soy index 10414a5..aaba64b 100644 --- a/gitiles-servlet/src/main/resources/com/google/gitiles/templates/RepositoryIndex.soy +++ b/gitiles-servlet/src/main/resources/com/google/gitiles/templates/RepositoryIndex.soy
@@ -27,10 +27,7 @@ * @param? moreBranchesUrl URL to show more branches, if necessary. * @param tags list of tag objects with url and name keys. * @param? moreTagsUrl URL to show more branches, if necessary. - * @param? nextUrl URL for the next page of log results. - * @param? previousUrl URL for the previous page of log results. - * @param? logEntryVariant variant name for log entry template. - * @param entries list of log entries; see .logEntry. + * @param hasLog whether a log should be shown for HEAD. */ {template .repositoryIndex} {call .header} @@ -60,10 +57,10 @@ git clone {$cloneUrl} </textarea> -{if length($entries) and (length($branches) or length($tags))} +{if $hasLog and (length($branches) or length($tags))} <div class="repository-shortlog-wrapper"> <div class="repository-shortlog"> - {call .logEntries data="all" /} + {call .streamingPlaceholder /} </div> </div> @@ -71,8 +68,8 @@ {call .branches_ data="all" /} {call .tags_ data="all" /} </div> -{elseif length($entries)} - {call .logEntries data="all" /} +{elseif $hasLog} + {call .streamingPlaceholder /} {elseif length($branches) or length($tags)} {call .branches_ data="all" /} {call .tags_ data="all" /}