Permette titolo, testo e link diversi per Android e iOS negli avvisi.
Separa i canali app e mostra il nodo ingest nelle sessioni admin. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,7 +11,8 @@ module Admin
|
||||
kind: "info",
|
||||
severity: "info",
|
||||
status: "draft",
|
||||
show_on_app: true,
|
||||
show_on_android: true,
|
||||
show_on_ios: true,
|
||||
show_on_web_public: true,
|
||||
show_on_web_private: true,
|
||||
dismissible: true
|
||||
@@ -55,12 +56,18 @@ module Admin
|
||||
params.require(:app_announcement).permit(
|
||||
:kind, :severity, :status, :title, :body,
|
||||
:action_url, :action_label, :dismissible, :starts_at, :ends_at,
|
||||
:show_on_app, :show_on_web_public, :show_on_web_private
|
||||
:show_on_android, :show_on_ios, :show_on_web_public, :show_on_web_private,
|
||||
:android_title, :android_body, :android_action_url, :android_action_label,
|
||||
:ios_title, :ios_body, :ios_action_url, :ios_action_label
|
||||
).tap do |permitted|
|
||||
%i[dismissible show_on_app show_on_web_public show_on_web_private].each do |key|
|
||||
%i[dismissible show_on_android show_on_ios show_on_web_public show_on_web_private].each do |key|
|
||||
permitted[key] = ActiveModel::Type::Boolean.new.cast(permitted[key])
|
||||
end
|
||||
%i[starts_at ends_at action_url action_label].each do |key|
|
||||
%i[
|
||||
starts_at ends_at action_url action_label
|
||||
android_title android_body android_action_url android_action_label
|
||||
ios_title ios_body ios_action_url ios_action_label
|
||||
].each do |key|
|
||||
permitted[key] = nil if permitted[key].blank?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@ module Admin
|
||||
@host = HostMetrics.new.sample!
|
||||
@active_sessions = StreamSession
|
||||
.where(status: DashboardStats::ACTIVE_STATUSES)
|
||||
.includes(match: :team)
|
||||
.includes(:stream_node, match: :team)
|
||||
.order(started_at: :desc)
|
||||
@teams = Team.includes(:matches).order(:name).limit(8)
|
||||
end
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
module Admin
|
||||
class SessionsController < Admin::BaseController
|
||||
def index
|
||||
@sessions = StreamSession.includes(:match, :user).order(created_at: :desc).limit(50)
|
||||
@sessions = StreamSession.includes(:stream_node, :user, match: :team).order(created_at: :desc).limit(50)
|
||||
end
|
||||
|
||||
def show
|
||||
@session = StreamSession.find(params[:id])
|
||||
@session = StreamSession.includes(:stream_node, match: :team).find(params[:id])
|
||||
@events = @session.stream_events.recent.limit(50)
|
||||
end
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ module Api
|
||||
|
||||
def index
|
||||
platform = params[:platform].to_s.presence
|
||||
announcements = AppAnnouncement.for_app.newest
|
||||
announcements = AppAnnouncement.for_platform(platform).newest
|
||||
render json: announcements.map { |item| item.as_api_json(platform: platform) }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,6 +30,19 @@ module AdminHelper
|
||||
links
|
||||
end
|
||||
|
||||
def admin_session_ingest_badge_class(node)
|
||||
case node.role
|
||||
when "home" then "badge--ingest-home"
|
||||
when "lab" then "badge--ingest-lab"
|
||||
when "cloud" then "badge--ingest-cloud"
|
||||
else "badge--paused"
|
||||
end
|
||||
end
|
||||
|
||||
def admin_session_ingest_role_label(node)
|
||||
I18n.t("admin.sessions.ingest.role.#{node.role}", default: node.role.to_s.humanize)
|
||||
end
|
||||
|
||||
def admin_regia_expires_label(iso_time)
|
||||
return if iso_time.blank?
|
||||
|
||||
|
||||
@@ -3,10 +3,12 @@ class AppAnnouncement < ApplicationRecord
|
||||
SEVERITIES = %w[info warning critical].freeze
|
||||
STATUSES = %w[draft published archived].freeze
|
||||
CHANNELS = {
|
||||
app: :show_on_app,
|
||||
android: :show_on_android,
|
||||
ios: :show_on_ios,
|
||||
web_public: :show_on_web_public,
|
||||
web_private: :show_on_web_private
|
||||
}.freeze
|
||||
URL_FIELDS = %i[action_url android_action_url ios_action_url].freeze
|
||||
|
||||
belongs_to :created_by_admin, class_name: "AdminAccount", optional: true
|
||||
|
||||
@@ -14,10 +16,12 @@ class AppAnnouncement < ApplicationRecord
|
||||
validates :kind, inclusion: { in: KINDS }
|
||||
validates :severity, inclusion: { in: SEVERITIES }
|
||||
validates :status, inclusion: { in: STATUSES }
|
||||
validates :title, length: { maximum: 120 }
|
||||
validates :body, length: { maximum: 2000 }
|
||||
validates :action_label, length: { maximum: 40 }, allow_blank: true
|
||||
validates :action_url, format: { with: /\Ahttps?:\/\/.+/i, allow_blank: true }
|
||||
validates :title, :android_title, :ios_title, length: { maximum: 120 }, allow_blank: true
|
||||
validates :body, :android_body, :ios_body, length: { maximum: 2000 }, allow_blank: true
|
||||
validates :action_label, :android_action_label, :ios_action_label, length: { maximum: 40 }, allow_blank: true
|
||||
URL_FIELDS.each do |field|
|
||||
validates field, format: { with: /\Ahttps?:\/\/.+/i, allow_blank: true }
|
||||
end
|
||||
validate :ends_at_after_starts_at
|
||||
validate :at_least_one_channel
|
||||
|
||||
@@ -38,7 +42,15 @@ class AppAnnouncement < ApplicationRecord
|
||||
end
|
||||
|
||||
def self.for_app
|
||||
for_channel(:app)
|
||||
active_now.where("show_on_android = TRUE OR show_on_ios = TRUE")
|
||||
end
|
||||
|
||||
def self.for_platform(platform)
|
||||
case platform.to_s
|
||||
when "android" then for_channel(:android)
|
||||
when "ios" then for_channel(:ios)
|
||||
else for_app
|
||||
end
|
||||
end
|
||||
|
||||
def published?
|
||||
@@ -56,17 +68,19 @@ class AppAnnouncement < ApplicationRecord
|
||||
id: id,
|
||||
kind: kind,
|
||||
severity: severity,
|
||||
title: title,
|
||||
body: body,
|
||||
title: copy_for(platform, :title),
|
||||
body: copy_for(platform, :body),
|
||||
dismissible: dismissible,
|
||||
action_url: resolved_action_url(platform),
|
||||
action_label: action_label.presence,
|
||||
action_label: copy_for(platform, :action_label).presence,
|
||||
starts_at: starts_at&.iso8601,
|
||||
ends_at: ends_at&.iso8601
|
||||
}
|
||||
end
|
||||
|
||||
def resolved_action_url(platform)
|
||||
override = platform_override(platform, :action_url)
|
||||
return override if override.present?
|
||||
return action_url if action_url.present?
|
||||
return nil unless kind == "update"
|
||||
|
||||
@@ -78,8 +92,23 @@ class AppAnnouncement < ApplicationRecord
|
||||
|
||||
private
|
||||
|
||||
def copy_for(platform, field)
|
||||
override = platform_override(platform, field)
|
||||
override.presence || public_send(field)
|
||||
end
|
||||
|
||||
def platform_override(platform, field)
|
||||
prefix = case platform.to_s
|
||||
when "android" then :android
|
||||
when "ios" then :ios
|
||||
end
|
||||
return if prefix.blank?
|
||||
|
||||
public_send("#{prefix}_#{field}")
|
||||
end
|
||||
|
||||
def at_least_one_channel
|
||||
return if show_on_app? || show_on_web_public? || show_on_web_private?
|
||||
return if show_on_android? || show_on_ios? || show_on_web_public? || show_on_web_private?
|
||||
|
||||
errors.add(:base, :no_channel)
|
||||
end
|
||||
|
||||
@@ -19,8 +19,12 @@
|
||||
<fieldset class="admin-channels">
|
||||
<legend><%= t("admin.announcements.form.channels") %></legend>
|
||||
<label class="admin-checkbox">
|
||||
<%= f.check_box :show_on_app %>
|
||||
<span><%= t("admin.announcements.channels.app") %></span>
|
||||
<%= f.check_box :show_on_android %>
|
||||
<span><%= t("admin.announcements.channels.android") %></span>
|
||||
</label>
|
||||
<label class="admin-checkbox">
|
||||
<%= f.check_box :show_on_ios %>
|
||||
<span><%= t("admin.announcements.channels.ios") %></span>
|
||||
</label>
|
||||
<label class="admin-checkbox">
|
||||
<%= f.check_box :show_on_web_public %>
|
||||
@@ -43,6 +47,59 @@
|
||||
<%= f.text_area :body, required: true, rows: 5, maxlength: 2000 %>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= f.label :action_url, t("admin.announcements.form.action_url") %>
|
||||
<%= f.url_field :action_url, placeholder: "https://" %>
|
||||
</div>
|
||||
<p class="muted admin-form-hint"><%= t("admin.announcements.form.action_url_hint") %></p>
|
||||
|
||||
<div>
|
||||
<%= f.label :action_label, t("admin.announcements.form.action_label") %>
|
||||
<%= f.text_field :action_label, maxlength: 40 %>
|
||||
</div>
|
||||
|
||||
<fieldset class="admin-channels admin-platform-copy">
|
||||
<legend><%= t("admin.announcements.form.android_override") %></legend>
|
||||
<p class="muted admin-form-hint"><%= t("admin.announcements.form.platform_override_hint") %></p>
|
||||
<div>
|
||||
<%= f.label :android_title, t("admin.announcements.form.title") %>
|
||||
<%= f.text_field :android_title, maxlength: 120 %>
|
||||
</div>
|
||||
<div>
|
||||
<%= f.label :android_body, t("admin.announcements.form.body") %>
|
||||
<%= f.text_area :android_body, rows: 4, maxlength: 2000 %>
|
||||
</div>
|
||||
<div>
|
||||
<%= f.label :android_action_url, t("admin.announcements.form.action_url") %>
|
||||
<%= f.url_field :android_action_url, placeholder: "https://play.google.com/..." %>
|
||||
</div>
|
||||
<div>
|
||||
<%= f.label :android_action_label, t("admin.announcements.form.action_label") %>
|
||||
<%= f.text_field :android_action_label, maxlength: 40 %>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="admin-channels admin-platform-copy">
|
||||
<legend><%= t("admin.announcements.form.ios_override") %></legend>
|
||||
<p class="muted admin-form-hint"><%= t("admin.announcements.form.platform_override_hint") %></p>
|
||||
<div>
|
||||
<%= f.label :ios_title, t("admin.announcements.form.title") %>
|
||||
<%= f.text_field :ios_title, maxlength: 120 %>
|
||||
</div>
|
||||
<div>
|
||||
<%= f.label :ios_body, t("admin.announcements.form.body") %>
|
||||
<%= f.text_area :ios_body, rows: 4, maxlength: 2000 %>
|
||||
</div>
|
||||
<div>
|
||||
<%= f.label :ios_action_url, t("admin.announcements.form.action_url") %>
|
||||
<%= f.url_field :ios_action_url, placeholder: "https://apps.apple.com/..." %>
|
||||
</div>
|
||||
<div>
|
||||
<%= f.label :ios_action_label, t("admin.announcements.form.action_label") %>
|
||||
<%= f.text_field :ios_action_label, maxlength: 40 %>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="admin-form-row">
|
||||
<div>
|
||||
<%= f.label :starts_at, t("admin.announcements.form.starts_at") %>
|
||||
@@ -55,17 +112,6 @@
|
||||
</div>
|
||||
<p class="muted admin-form-hint"><%= t("admin.announcements.form.window_hint") %></p>
|
||||
|
||||
<div>
|
||||
<%= f.label :action_url, t("admin.announcements.form.action_url") %>
|
||||
<%= f.url_field :action_url, placeholder: "https://" %>
|
||||
</div>
|
||||
<p class="muted admin-form-hint"><%= t("admin.announcements.form.action_url_hint") %></p>
|
||||
|
||||
<div>
|
||||
<%= f.label :action_label, t("admin.announcements.form.action_label") %>
|
||||
<%= f.text_field :action_label, maxlength: 40 %>
|
||||
</div>
|
||||
|
||||
<label class="admin-checkbox">
|
||||
<%= f.check_box :dismissible %>
|
||||
<span><%= t("admin.announcements.form.dismissible") %></span>
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
<tr>
|
||||
<th><%= t("admin.dashboard.sessions.table.match") %></th>
|
||||
<th><%= t("admin.dashboard.sessions.table.status") %></th>
|
||||
<th><%= t("admin.dashboard.sessions.table.ingest") %></th>
|
||||
<th><%= t("admin.dashboard.sessions.table.start") %></th>
|
||||
<th><%= t("admin.dashboard.sessions.table.link") %></th>
|
||||
<th></th>
|
||||
@@ -117,6 +118,7 @@
|
||||
<tr>
|
||||
<td><%= s.match.team.name %> vs <%= s.match.opponent_name %></td>
|
||||
<td><span class="badge badge--<%= s.status == 'live' ? 'live' : (s.status == 'paused' ? 'paused' : 'connecting') %>"><%= s.status %></span></td>
|
||||
<td><%= render "admin/sessions/ingest_cell", session: s %></td>
|
||||
<td class="muted"><%= s.started_at&.strftime("%d/%m %H:%M") || t("admin.common.dash") %></td>
|
||||
<td class="admin-link-compact">
|
||||
<% admin_session_watch_links(s).each do |link| %>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<% node = session.stream_node %>
|
||||
<% if node %>
|
||||
<div class="admin-ingest">
|
||||
<code class="admin-ingest__slug"><%= node.slug %></code>
|
||||
<span class="badge <%= admin_session_ingest_badge_class(node) %>"><%= admin_session_ingest_role_label(node) %></span>
|
||||
</div>
|
||||
<% else %>
|
||||
<span class="muted"><%= t("admin.sessions.ingest.none") %></span>
|
||||
<% end %>
|
||||
@@ -4,6 +4,7 @@
|
||||
<tr>
|
||||
<th><%= t("admin.sessions.index.table.match") %></th>
|
||||
<th><%= t("admin.sessions.index.table.status") %></th>
|
||||
<th><%= t("admin.sessions.index.table.ingest") %></th>
|
||||
<th><%= t("admin.sessions.index.table.disconnects") %></th>
|
||||
<th><%= t("admin.sessions.index.table.link") %></th>
|
||||
<th></th>
|
||||
@@ -14,6 +15,7 @@
|
||||
<tr>
|
||||
<td><%= s.match.team.name %> vs <%= s.match.opponent_name %></td>
|
||||
<td><span class="badge <%= s.status == 'live' ? 'badge--live' : 'badge--paused' %>"><%= s.status %></span></td>
|
||||
<td><%= render "admin/sessions/ingest_cell", session: s %></td>
|
||||
<td><%= s.disconnection_count %></td>
|
||||
<td class="admin-link-compact">
|
||||
<% admin_session_watch_links(s).each do |link| %>
|
||||
|
||||
@@ -16,6 +16,16 @@
|
||||
<% if @session.youtube_broadcast_id %>
|
||||
<p><%= t("admin.sessions.show.youtube_studio") %>: <a href="https://studio.youtube.com/video/<%= @session.youtube_broadcast_id %>/livestreaming" target="_blank" rel="noopener"><%= t("admin.sessions.show.broadcast") %></a></p>
|
||||
<% end %>
|
||||
<p>
|
||||
<%= t("admin.sessions.show.ingest_node") %>
|
||||
<% if @session.stream_node %>
|
||||
<code><%= @session.stream_node.slug %></code>
|
||||
<span class="badge <%= admin_session_ingest_badge_class(@session.stream_node) %>"><%= admin_session_ingest_role_label(@session.stream_node) %></span>
|
||||
<span class="muted">(<%= @session.stream_node.provider %>)</span>
|
||||
<% else %>
|
||||
<span class="muted"><%= t("admin.sessions.ingest.none") %></span>
|
||||
<% end %>
|
||||
</p>
|
||||
<p><%= t("admin.sessions.show.rtmp_ingest") %> <code><%= @session.rtmp_ingest_url %></code></p>
|
||||
|
||||
<h3><%= t("admin.sessions.show.events_title") %></h3>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<title><%= t("admin.layout.title") %></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<link rel="stylesheet" href="/admin.css?v=6">
|
||||
<link rel="stylesheet" href="/admin.css?v=8">
|
||||
<% if content_for?(:replay_archive_styles) %>
|
||||
<link rel="stylesheet" href="/marketing.css?v=42">
|
||||
<% end %>
|
||||
|
||||
Reference in New Issue
Block a user