main
erb 196 lines 10.6 KB
Raw
1 <% content_for :title, "CI/CD · #{@repository.full_name}" %>
2 <%= render "shared/repository_social", repository: @repository %>
3
4 <div class="border-b border-surface-600 bg-surface-800">
5 <div class="max-w-6xl mx-auto px-4 sm:px-6 pt-6 pb-0">
6 <div class="flex items-center gap-2 text-sm mb-4">
7 <svg class="w-4 h-4 text-gray-500" viewBox="0 0 16 16" fill="currentColor">
8 <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"/>
9 </svg>
10 <%= link_to "@#{@owner.username}", user_profile_path(@owner.username),
11 class: "text-brand-500 hover:underline font-medium" %>
12 <span class="text-gray-500">/</span>
13 <%= link_to @repository.name, repository_path(@owner.username, @repository.name),
14 class: "text-brand-500 hover:underline font-semibold" %>
15 <% if @repository.is_private %>
16 <span class="badge-gray ml-1">Private</span>
17 <% end %>
18 </div>
19
20 <% if @repository.description.present? %>
21 <p class="text-sm text-gray-400 mb-4"><%= @repository.description %></p>
22 <% end %>
23
24 <div class="flex items-center gap-0 -mb-px">
25 <%= link_to repository_path(@owner.username, @repository.name),
26 class: "tab-item flex items-center gap-1.5" do %>
27 <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor">
28 <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"/>
29 </svg>
30 Code
31 <% end %>
32 <% if @repository.initialized? %>
33 <%= link_to repository_commits_path(@owner.username, @repository.name, @repository.default_branch),
34 class: "tab-item flex items-center gap-1.5" do %>
35 <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor">
36 <path d="M11.93 8.5a4.002 4.002 0 0 1-7.86 0H.75a.75.75 0 0 1 0-1.5h3.32a4.002 4.002 0 0 1 7.86 0h3.32a.75.75 0 0 1 0 1.5Zm-1.43-.75a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"/>
37 </svg>
38 Commits
39 <% if @commit_count&.> 0 %>
40 <span class="badge-gray text-xs"><%= number_with_delimiter(@commit_count) %></span>
41 <% end %>
42 <% end %>
43 <% end %>
44 <%= link_to repository_pull_requests_path(@owner.username, @repository.name),
45 class: "tab-item flex items-center gap-1.5" do %>
46 <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor">
47 <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM12 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"/>
48 </svg>
49 Pulls
50 <% if @repository.open_pull_requests_count > 0 %>
51 <span class="badge-gray text-xs"><%= number_with_delimiter(@repository.open_pull_requests_count) %></span>
52 <% end %>
53 <% end %>
54 <div class="tab-item active flex items-center gap-1.5">
55 <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor">
56 <path d="M4.75 4.5C2.679 4.5 1 5.958 1 7.75S2.679 11 4.75 11c1.028 0 1.948-.36 2.75-1.242l.652-.716.696.672C10.023 10.849 10.956 11 11.25 11 13.321 11 15 9.542 15 7.75S13.321 4.5 11.25 4.5c-1.028 0-1.948.36-2.75 1.242l-.652.716-.696-.672C5.977 4.651 5.044 4.5 4.75 4.5Zm0 1.5c.483 0 .943.152 1.36.556l.562.541-.562.618C5.693 8.119 5.233 8.5 4.75 8.5c-1.241 0-2.25-.672-2.25-1.5S3.509 6 4.75 6Zm6.5 0c1.241 0 2.25.672 2.25 1.5S12.491 9 11.25 9c-.483 0-.943-.152-1.36-.556l-.562-.541.562-.618c.417-.404.877-.785 1.36-.785Z"/>
57 </svg>
58 CI/CD
59 <% if @commit_count&.> 0 %>
60 <span class="badge-gray text-xs"><%= number_with_delimiter(@commit_count) %></span>
61 <% end %>
62 </div>
63 </div>
64 </div>
65 </div>
66
67 <div class="max-w-6xl mx-auto px-4 sm:px-6 py-6">
68 <div class="grid gap-6 lg:grid-cols-[1.35fr_0.95fr]">
69 <div class="space-y-6">
70 <div class="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
71 <div class="card p-5">
72 <p class="text-xs uppercase tracking-[0.18em] text-gray-500">Success Rate</p>
73 <p class="mt-3 text-2xl font-semibold text-gray-100"><%= @pipeline_summary[:success_rate] %></p>
74 <p class="mt-1 text-xs text-emerald-400">+1.2% in the last 7 days</p>
75 </div>
76 <div class="card p-5">
77 <p class="text-xs uppercase tracking-[0.18em] text-gray-500">Avg Duration</p>
78 <p class="mt-3 text-2xl font-semibold text-gray-100"><%= @pipeline_summary[:avg_duration] %></p>
79 <p class="mt-1 text-xs text-gray-400">From build to deploy</p>
80 </div>
81 <div class="card p-5">
82 <p class="text-xs uppercase tracking-[0.18em] text-gray-500">Runs This Week</p>
83 <p class="mt-3 text-2xl font-semibold text-gray-100"><%= @pipeline_summary[:weekly_runs] %></p>
84 <p class="mt-1 text-xs text-gray-400">Across all branches</p>
85 </div>
86 <div class="card p-5">
87 <p class="text-xs uppercase tracking-[0.18em] text-gray-500">Last Deploy</p>
88 <p class="mt-3 text-2xl font-semibold text-gray-100"><%= @pipeline_summary[:last_deploy] %></p>
89 <p class="mt-1 text-xs text-brand-400">Production is live</p>
90 </div>
91 </div>
92
93 <div class="card overflow-hidden">
94 <div class="flex items-center justify-between gap-4 border-b border-surface-600 px-5 py-4 bg-surface-600">
95 <div>
96 <h2 class="text-sm font-semibold text-gray-100">Recent Pipeline Runs</h2>
97 <p class="mt-1 text-xs text-gray-400">Latest activity for <span class="text-gray-200"><%= @repository.full_name %></span></p>
98 </div>
99 <span class="badge-gray text-xs"><%= @branch %></span>
100 </div>
101
102 <div>
103 <% @pipeline_runs.each do |run| %>
104 <% status_classes = case run[:status]
105 when "passed" then "bg-emerald-500/12 text-emerald-300 ring-1 ring-inset ring-emerald-500/20"
106 when "running" then "bg-sky-500/12 text-sky-300 ring-1 ring-inset ring-sky-500/20"
107 else "bg-rose-500/12 text-rose-300 ring-1 ring-inset ring-rose-500/20"
108 end %>
109 <div class="flex items-center justify-between gap-4 border-b border-surface-600/80 px-5 py-4 last:border-b-0">
110 <div class="min-w-0">
111 <div class="flex items-center gap-3">
112 <p class="text-sm font-medium text-gray-100"><%= run[:name] %></p>
113 <span class="rounded-full px-2 py-0.5 text-[11px] font-medium <%= status_classes %>"><%= run[:status].capitalize %></span>
114 </div>
115 <p class="mt-1 text-xs text-gray-400">
116 <span class="font-mono text-brand-400"><%= run[:sha] %></span>
117 on <span class="text-gray-200"><%= run[:ref] %></span>
118 by <span class="text-gray-200"><%= run[:actor] %></span>
119 </p>
120 </div>
121 <div class="shrink-0 text-right text-xs text-gray-400">
122 <p><%= run[:duration] %></p>
123 <p class="mt-1 text-gray-500"><%= run[:started_at] %></p>
124 </div>
125 </div>
126 <% end %>
127 </div>
128 </div>
129 </div>
130
131 <div class="space-y-6">
132 <div class="card overflow-hidden">
133 <div class="border-b border-surface-600 px-5 py-4 bg-surface-600">
134 <h2 class="text-sm font-semibold text-gray-100">Environments</h2>
135 </div>
136 <div class="space-y-0">
137 <% @environments.each do |environment| %>
138 <% env_classes = case environment[:status]
139 when "healthy" then "bg-emerald-400"
140 when "building" then "bg-sky-400"
141 else "bg-amber-400"
142 end %>
143 <div class="border-b border-surface-600/80 px-5 py-4 last:border-b-0">
144 <div class="flex items-center justify-between gap-3">
145 <div class="flex items-center gap-3">
146 <span class="h-2.5 w-2.5 rounded-full <%= env_classes %>"></span>
147 <div>
148 <p class="text-sm font-medium text-gray-100"><%= environment[:name] %></p>
149 <p class="text-xs text-gray-400"><%= environment[:url] %></p>
150 </div>
151 </div>
152 <span class="badge-gray text-xs"><%= environment[:version] %></span>
153 </div>
154 <p class="mt-3 text-xs text-gray-500">Updated <%= environment[:updated_at] %></p>
155 </div>
156 <% end %>
157 </div>
158 </div>
159
160 <div class="card overflow-hidden">
161 <div class="border-b border-surface-600 px-5 py-4 bg-surface-600">
162 <h2 class="text-sm font-semibold text-gray-100">Checks</h2>
163 </div>
164 <div class="space-y-0">
165 <% @checks.each do |check| %>
166 <% icon = case check[:status]
167 when "passed" then "text-emerald-400"
168 when "running" then "text-sky-400"
169 else "text-rose-400"
170 end %>
171 <div class="flex items-start gap-3 border-b border-surface-600/80 px-5 py-4 last:border-b-0">
172 <svg class="w-4 h-4 mt-0.5 shrink-0 <%= icon %>" viewBox="0 0 16 16" fill="currentColor">
173 <path d="M8 1.5a6.5 6.5 0 1 0 6.5 6.5A6.507 6.507 0 0 0 8 1.5Zm3.03 5.28-3.5 3.75a.75.75 0 0 1-1.08.02L4.72 8.81a.75.75 0 0 1 1.06-1.06l1.18 1.18 2.95-3.17a.75.75 0 1 1 1.12 1Z"/>
174 </svg>
175 <div class="min-w-0">
176 <div class="flex items-center gap-2">
177 <p class="text-sm font-medium text-gray-100"><%= check[:name] %></p>
178 <span class="text-xs text-gray-500"><%= check[:status] %></span>
179 </div>
180 <p class="mt-1 text-xs text-gray-400"><%= check[:detail] %></p>
181 </div>
182 </div>
183 <% end %>
184 </div>
185 </div>
186
187 <div class="card p-5">
188 <h2 class="text-sm font-semibold text-gray-100">Deployment Policy</h2>
189 <p class="mt-2 text-sm text-gray-400">
190 Pushes to <span class="font-mono text-gray-200">main</span> deploy automatically after all required checks pass.
191 Release branches require one approval before staging promotion.
192 </p>
193 </div>
194 </div>
195 </div>
196 </div>