Diff between 0a3c1255202c7657b8a39ce0232648d6289dca6d and 713f5cb7bef1c05ea143b8dff9e249d0f7e7c81a

Changed Files

File Additions Deletions Status
app.py +8 -2 modified
git/blame.py +4 -1 modified
templates/blame.html +61 -11 modified

Full Patch

diff --git a/app.py b/app.py
index 2564732..46f6d63 100644
--- a/app.py
+++ b/app.py
@@ -122,8 +122,14 @@ def repo_blob_path(repo_name, path):
 def repo_blame_path(repo_name, path):
     ref = request.args.get('ref', 'HEAD')
     refs = get_refs(f"{repo_path}/{repo_name}")
-    blame, style = get_blame(f"{repo_path}/{repo_name}", ref, path)
-    return render_template("blame.html", repo_name=repo_name, ref=ref, path=path, blame=blame, refs=refs, style=style)
+    
+    # if ajax (for loading)
+    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
+        blame, style = get_blame(f"{repo_path}/{repo_name}", ref, path)
+        return {'blame': blame, 'style': style}
+    
+    # initial
+    return render_template("blame.html", repo_name=repo_name, ref=ref, path=path, refs=refs)
 
 @app.route("/<repo_name>/diff")
 def repo_diff(repo_name):
diff --git a/git/blame.py b/git/blame.py
index 6d391de..e49463f 100644
--- a/git/blame.py
+++ b/git/blame.py
@@ -50,7 +50,10 @@ def get_blame(repo_path, ref="HEAD", file_path=""):
         # TODO: more info if needed
         info = {
             'commit_id': str(hunk.final_commit_id),
-            'author': commit.author,
+            'author': {
+                'name': commit.author.name,
+                'time': commit.author.time,
+            },
         }
         # fill premade info for lines in this hunk
         for i in range(start, min(end, len(blame_lines))): # prevent index overflow, with min
diff --git a/templates/blame.html b/templates/blame.html
index ba4b8e7..240f195 100644
--- a/templates/blame.html
+++ b/templates/blame.html
@@ -1,17 +1,67 @@
 {% extends "base.html" %}
 
 {% block content %}
-<style>{{ style }}</style>
+<style id="blame-style"></style>
 <style>.blame-code pre { line-height: 0.7; }</style>
 <h1>Blame: {{ path }}</h1>
-{% if blame %}
-<div class="blame-code"><pre>
-<!-- first 4 chars are for line number -->
-<!-- next part is for commit id (8 chars), then author (15 chars, cutoff if over), date/time -->
-<!-- this is just to keep the alignment -->
-{% for line in blame %}{{ "%4s" % line.line_num }} {% if line.blame %}<a href="{{ url_for('commit_detail', repo_name=repo_name, commit_id=line.blame.commit_id) }}">{{ line.blame.commit_id[:8] }}</a> {{ "%-15s" % line.blame.author.name[:15] }} {{ line.blame.author.time | datetime }}{% endif %} | {{ line.highlighted | safe }}
-{% endfor %}</pre></div>
-{% else %}
-<p>No blame info</p>
-{% endif %}
+<div id="loading">Loading blame information, this may take a while for large files...</div>
+<div id="pomeranian" style="display: none; margin-top: 20px;">
+    <iframe width="560" height="315" src="https://www.youtube.com/embed/Q-KciIbk_oA?si=c_DqdaVbYMlfhxW7&amp;controls=0&amp;autoplay=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
+</div>
+<div id="blame-content" style="display: none;">
+</div>
+<script>
+document.addEventListener('DOMContentLoaded', function() {
+    const repo_name = window.location.pathname.split('/')[1];
+    const pomeranianTimeout = setTimeout(() => {
+        document.getElementById('pomeranian').style.display = 'block';
+    }, 5000);
+    
+    fetch(window.location.href, {
+        headers: {
+            // let server know that this is ajax
+            'X-Requested-With': 'XMLHttpRequest'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        clearTimeout(pomeranianTimeout);
+        document.getElementById('blame-style').innerHTML = data.style;
+        
+        // add blame content, previosly templating
+        let content = '<div class="blame-code"><pre>';
+        if (data.blame && data.blame.length > 0) {
+            data.blame.forEach(line => {
+                content += `${String(line.line_num).padStart(4)} `;
+                if (line.blame) {
+                    content += `<a href="/${repo_name}/commits/${line.blame.commit_id}">${line.blame.commit_id.substring(0, 8)}</a> ${line.blame.author.name.substring(0, 15).padEnd(15)} ${new Date(line.blame.author.time * 1000).toISOString().slice(0, 19).replace('T', ' ')}`;
+                }
+                content += ` | ${line.highlighted}\n`;
+            });
+        } else {
+            content += 'No blame info';
+        }
+        content += '</pre></div>';
+        
+        document.getElementById('blame-content').innerHTML = content;
+        document.getElementById('loading').style.display = 'none';
+        // clear iframe
+        const iframe = document.querySelector('#pomeranian iframe');
+        if (iframe) {
+            iframe.src = 'about:blank';
+        }
+        document.getElementById('pomeranian').style.display = 'none';
+        document.getElementById('blame-content').style.display = 'block';
+    })
+    .catch(error => {
+        clearTimeout(pomeranianTimeout);
+        document.getElementById('loading').innerHTML = 'Error loading blame';
+        const iframe = document.querySelector('#pomeranian iframe');
+        if (iframe) {
+            iframe.src = 'about:blank';
+        }
+        document.getElementById('pomeranian').style.display = 'none';
+    });
+});
+</script>
 {% endblock %}
\ No newline at end of file