130 lines
6.2 KiB
ERB
130 lines
6.2 KiB
ERB
<% content_for :body_class, "admin-body" %>
|
|
|
|
<div class="admin-page-head">
|
|
<h2 class="admin-page-title"><%= t("admin.stream_nodes.title") %></h2>
|
|
<p class="muted admin-page-sub">
|
|
<%= t("admin.stream_nodes.providers", cloud: @cloud_provider, dns: @dns_provider) %>
|
|
</p>
|
|
</div>
|
|
|
|
<% m = @autoscale_metrics %>
|
|
<section class="kpi-grid">
|
|
<div class="kpi-card <%= m[:enabled] ? 'kpi-card--accent' : '' %> <%= 'kpi-card--danger' if m[:kill_switch] %>">
|
|
<div class="kpi-label"><%= t("admin.stream_nodes.kpi.autoscaler") %></div>
|
|
<div class="kpi-value"><%= m[:kill_switch] ? t("admin.stream_nodes.kpi.kill_switch") : (m[:enabled] ? "ON" : "OFF") %></div>
|
|
<div class="kpi-sub"><%= t("admin.stream_nodes.kpi.kind", kind: m[:kind]) %></div>
|
|
</div>
|
|
<div class="kpi-card <%= m[:free_slots] <= m[:soft_free_slots] ? 'kpi-card--danger' : '' %>">
|
|
<div class="kpi-label"><%= t("admin.stream_nodes.kpi.free_slots") %></div>
|
|
<div class="kpi-value"><%= m[:free_slots] %></div>
|
|
<div class="kpi-sub"><%= t("admin.stream_nodes.kpi.soft_slots", soft: m[:soft_free_slots]) %></div>
|
|
</div>
|
|
<div class="kpi-card">
|
|
<div class="kpi-label"><%= t("admin.stream_nodes.kpi.spare") %></div>
|
|
<div class="kpi-value"><%= m[:spare_ready] %><span class="kpi-value-unit">/<%= m[:warm_spare_min] %></span></div>
|
|
<div class="kpi-sub"><%= t("admin.stream_nodes.kpi.warm_spare") %></div>
|
|
</div>
|
|
<div class="kpi-card">
|
|
<div class="kpi-label"><%= t("admin.stream_nodes.kpi.overflow") %></div>
|
|
<div class="kpi-value"><%= m[:overflow_nodes] %><span class="kpi-value-unit">/<%= m[:max_overflow_nodes] %></span></div>
|
|
<div class="kpi-sub"><%= t("admin.stream_nodes.kpi.overflow_nodes") %></div>
|
|
</div>
|
|
<div class="kpi-card <%= m[:within_budget] ? '' : 'kpi-card--danger' %>">
|
|
<div class="kpi-label"><%= t("admin.stream_nodes.kpi.budget") %></div>
|
|
<div class="kpi-value kpi-value--sm">€<%= m[:estimated_monthly_eur] %></div>
|
|
<div class="kpi-sub"><%= t("admin.stream_nodes.kpi.budget_of", budget: m[:monthly_budget_eur], ok: (m[:within_budget] ? "OK" : "OVER")) %></div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="panel" style="margin-bottom:1.5rem">
|
|
<div class="admin-panel-head">
|
|
<h2><%= t("admin.stream_nodes.actions_title") %></h2>
|
|
</div>
|
|
<div class="admin-toolbar">
|
|
<%= button_to t("admin.stream_nodes.provision_lab"), admin_stream_nodes_path, method: :post, params: { kind: "lab" }, class: "admin-btn admin-btn--secondary" %>
|
|
<% if @hetzner_configured %>
|
|
<%= button_to t("admin.stream_nodes.provision_cloud"), admin_stream_nodes_path, method: :post, params: { kind: "cloud" }, class: "admin-btn admin-btn--primary",
|
|
form: { data: { confirm: t("admin.stream_nodes.provision_cloud_confirm") } } %>
|
|
<% else %>
|
|
<span class="muted"><%= t("admin.stream_nodes.hetzner_token_missing") %></span>
|
|
<% end %>
|
|
<% if m[:kill_switch] %>
|
|
<%= button_to t("admin.stream_nodes.clear_kill_switch"), clear_kill_switch_admin_stream_nodes_path, method: :delete, class: "admin-btn admin-btn--secondary" %>
|
|
<% else %>
|
|
<%= button_to t("admin.stream_nodes.engage_kill_switch"), kill_switch_admin_stream_nodes_path, method: :post, class: "admin-btn admin-btn--danger",
|
|
form: { data: { confirm: t("admin.stream_nodes.kill_switch_confirm") } } %>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel">
|
|
<h2><%= t("admin.stream_nodes.table_title") %></h2>
|
|
<% if @nodes.any? %>
|
|
<div class="admin-table-wrap">
|
|
<table class="admin-table">
|
|
<thead>
|
|
<tr>
|
|
<th><%= t("admin.stream_nodes.col.slug") %></th>
|
|
<th><%= t("admin.stream_nodes.col.role") %></th>
|
|
<th><%= t("admin.stream_nodes.col.status") %></th>
|
|
<th><%= t("admin.stream_nodes.col.slots") %></th>
|
|
<th><%= t("admin.stream_nodes.col.hostname") %></th>
|
|
<th><%= t("admin.stream_nodes.col.provider") %></th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% @nodes.each do |node| %>
|
|
<%
|
|
badge =
|
|
case node.status
|
|
when "ready" then "badge--ready"
|
|
when "provisioning", "draining" then "badge--connecting"
|
|
when "error", "offline" then "badge--paused"
|
|
else "badge--paused"
|
|
end
|
|
%>
|
|
<tr>
|
|
<td><strong><%= node.slug %></strong></td>
|
|
<td class="muted"><%= node.role %></td>
|
|
<td><span class="badge <%= badge %>"><%= node.status %></span></td>
|
|
<td>
|
|
<strong><%= node.active_publishers %></strong>
|
|
<span class="muted">/ <%= node.max_publishers %></span>
|
|
<div class="muted" style="font-size:0.8rem"><%= t("admin.stream_nodes.free_slots", count: node.free_slots) %></div>
|
|
</td>
|
|
<td class="admin-mono"><%= node.hostname %></td>
|
|
<td class="muted">
|
|
<%= node.provider %>
|
|
<% if node.provider_instance_id.present? %>
|
|
<div class="admin-mono" style="font-size:0.75rem;margin-top:0.2rem"><%= node.provider_instance_id %></div>
|
|
<% end %>
|
|
</td>
|
|
<td class="admin-actions">
|
|
<% if node.slug != "home" %>
|
|
<% if node.status == "ready" %>
|
|
<%= button_to t("admin.stream_nodes.drain"), drain_admin_stream_node_path(node), method: :post, class: "admin-btn admin-btn--sm admin-btn--secondary" %>
|
|
<% end %>
|
|
<%= button_to t("admin.stream_nodes.destroy"), admin_stream_node_path(node), method: :delete, class: "admin-btn admin-btn--sm admin-btn--danger",
|
|
form: { data: { confirm: t("admin.stream_nodes.destroy_confirm", slug: node.slug) } } %>
|
|
<% else %>
|
|
<span class="muted">—</span>
|
|
<% end %>
|
|
</td>
|
|
</tr>
|
|
<% end %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<% else %>
|
|
<p class="empty"><%= t("admin.stream_nodes.empty") %></p>
|
|
<% end %>
|
|
</div>
|
|
|
|
<% if @lab_hosts.present? %>
|
|
<div class="panel" style="margin-top:1.5rem">
|
|
<h2><%= t("admin.stream_nodes.hosts_title") %></h2>
|
|
<pre class="admin-pre"><%= @lab_hosts %></pre>
|
|
</div>
|
|
<% end %>
|