Real data profile
Seto Elkahfi committed
Jun 17, 2026 at 07:49 UTC
b6f4d7c16ee44986f90587cfdf6ca6dc786fb3b6
3 files changed
+97
-8
app/controllers/users_controller.rb
+41
-8
@@ -1,6 +1,10 @@
1
class UsersController < ApplicationController
2
before_action :require_sign_in!, only: [ :settings, :update_settings ]
3
4
+ # Username whose profile shows the curated showcase feed instead of a
5
+ # real activity feed.
6
+ DEMO_FEED_USERNAME = "sigit"
7
+
8
def show
9
@profile_user = User.find_by!(username: params[:username])
10
@repositories = if signed_in? && current_user == @profile_user
@@ -9,14 +13,19 @@ class UsersController < ApplicationController
13
@profile_user.repositories.where(is_private: false).order(updated_at: :desc)
14
end
15
12
- feed_repo = @repositories.find { |r| r.name == "sigit" } || @repositories.first
13
- if feed_repo&.initialized?
14
- @feed_repo = feed_repo
15
- @feed_commits = GitRepositoryService.commits(
16
- feed_repo.disk_path,
17
- feed_repo.default_branch,
18
- limit: 3
19
- )
16
+ if @profile_user.username == DEMO_FEED_USERNAME
17
+ # Curated showcase feed for the demo profile.
18
+ feed_repo = @repositories.find { |r| r.name == "sigit" } || @repositories.first
19
+ if feed_repo&.initialized?
20
+ @feed_repo = feed_repo
21
+ @feed_commits = GitRepositoryService.commits(
22
+ feed_repo.disk_path,
23
+ feed_repo.default_branch,
24
+ limit: 3
25
+ )
26
+ end
27
+ else
28
+ @activity_items = build_activity_feed(@repositories)
29
end
30
rescue ActiveRecord::RecordNotFound
31
render file: Rails.public_path.join("404.html"), status: :not_found, layout: false
@@ -40,4 +49,28 @@ class UsersController < ApplicationController
49
def user_settings_params
50
params.require(:user).permit(:display_name, :avatar_url)
51
end
52
+
53
+ # Real activity feed for a profile, newest first: repository creations and
54
+ # recent pushes (latest commits per repo) merged and sorted by time.
55
+ def build_activity_feed(repositories, limit: 10)
56
+ items = []
57
+
58
+ repositories.each do |repo|
59
+ items << { kind: :created_repo, at: repo.created_at, repo: repo }
60
+
61
+ next unless repo.initialized?
62
+
63
+ commits = GitRepositoryService.commits(repo.disk_path, repo.default_branch, limit: 3)
64
+ next if commits.blank?
65
+
66
+ items << {
67
+ kind: :pushed,
68
+ at: commits.first[:authored_date] || repo.updated_at,
69
+ repo: repo,
70
+ commits: commits
71
+ }
72
+ end
73
+
74
+ items.sort_by { |item| item[:at] || Time.at(0) }.reverse.first(limit)
75
+ end
76
end
app/views/users/_activity_item.html.erb
new
+43
@@ -0,0 +1,43 @@
1
+<%# Renders one real activity-feed entry. Locals: item, profile_user %>
2
+<li class="mb-8 ml-6">
3
+ <% case item[:kind] %>
4
+ <% when :pushed %>
5
+ <span class="absolute -left-3 flex h-6 w-6 items-center justify-center rounded-full border border-surface-500 bg-surface-700">
6
+ <svg class="w-3.5 h-3.5 text-brand-500" viewBox="0 0 16 16" fill="currentColor">
7
+ <path d="M1.643 3.143 .427 1.927A.25.25 0 0 0 0 2.104V5.75c0 .138.112.25.25.25h3.646a.25.25 0 0 0 .177-.427L2.715 4.215a6.5 6.5 0 1 1-1.18 4.458.75.75 0 1 0-1.493.154 8.001 8.001 0 1 0 1.6-5.684ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"/>
8
+ </svg>
9
+ </span>
10
+ <div class="card px-4 py-3">
11
+ <p class="text-xs text-gray-500 mb-2"><%= time_ago_in_words(item[:at]) %> ago</p>
12
+ <p class="text-sm mb-3">
13
+ <span class="text-gray-400">Pushed </span>
14
+ <span class="font-semibold text-gray-200"><%= pluralize(item[:commits].size, "commit") %></span>
15
+ <span class="text-gray-400"> to </span>
16
+ <%= link_to "@#{profile_user.username}/#{item[:repo].name}", repository_path(profile_user.username, item[:repo].name), class: "text-brand-500 hover:underline font-medium" %>
17
+ <span class="text-gray-400"> on </span>
18
+ <code class="bg-surface-600 px-1.5 py-0.5 rounded text-xs text-gray-200"><%= item[:repo].default_branch || "main" %></code>
19
+ </p>
20
+ <ul class="space-y-1.5 border-t border-surface-600 pt-3">
21
+ <% item[:commits].each do |commit| %>
22
+ <li class="flex items-start gap-2 text-xs text-gray-400">
23
+ <%= link_to commit[:short_sha], repository_commit_path(profile_user.username, item[:repo].name, commit[:sha]), class: "text-brand-400 shrink-0 font-mono hover:underline" %>
24
+ <span><%= commit[:subject] %></span>
25
+ </li>
26
+ <% end %>
27
+ </ul>
28
+ </div>
29
+ <% when :created_repo %>
30
+ <span class="absolute -left-3 flex h-6 w-6 items-center justify-center rounded-full border border-surface-500 bg-surface-700">
31
+ <svg class="w-3.5 h-3.5 text-gray-400" viewBox="0 0 16 16" fill="currentColor">
32
+ <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8Z"/>
33
+ </svg>
34
+ </span>
35
+ <div class="card px-4 py-3">
36
+ <p class="text-xs text-gray-500 mb-2"><%= time_ago_in_words(item[:at]) %> ago</p>
37
+ <p class="text-sm">
38
+ <span class="text-gray-400">Created repository </span>
39
+ <%= link_to "@#{profile_user.username}/#{item[:repo].name}", repository_path(profile_user.username, item[:repo].name), class: "text-brand-500 hover:underline font-medium" %>
40
+ </p>
41
+ </div>
42
+ <% end %>
43
+</li>
app/views/users/show.html.erb
+13
@@ -128,6 +128,10 @@
128
129
<%# ── Feed panel ── %>
130
<div data-tabs-target="panel" data-tabs-key="feed">
131
+ <% if @profile_user.username == "sigit" %>
132
+ <%# Curated showcase feed for the demo profile. Every other profile
133
+ renders a real activity feed (@activity_items) built from its
134
+ repositories and commits. %>
135
<ol class="relative border-l border-surface-600 ml-3 space-y-0">
136
137
<%# Item: push commits %>
@@ -232,6 +236,15 @@
236
</li>
237
238
</ol>
239
+ <% elsif @activity_items.present? %>
240
+ <ol class="relative border-l border-surface-600 ml-3 space-y-0">
241
+ <%= render partial: "users/activity_item", collection: @activity_items, as: :item, locals: { profile_user: @profile_user } %>
242
+ </ol>
243
+ <% else %>
244
+ <div class="card px-4 py-8 text-center text-sm text-gray-500">
245
+ No activity yet.
246
+ </div>
247
+ <% end %>
248
</div>
249
250
<%# ── Repositories panel ── %>