Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ gemspec
# Git. Remember to move these dependencies to your gemspec before releasing
# your gem to rubygems.org.

# Lock minitest to 5.x until Rails 7.1+ adds Minitest 6.0 support
# Minitest 6.0.0 was released Dec 2024 with breaking API changes
gem 'minitest', '~> 5.0'

group :development do
gem 'gem-release'
gem 'json'
Expand Down
25 changes: 24 additions & 1 deletion app/assets/javascripts/kanaui/kiddo/kiddo_initialize.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
(function (d3, $, window, document, undefined) {
function errorMessage(error) {
if (error && error.responseText) {
try {
var response = JSON.parse(error.responseText);
if (response.message) {
return response.message;
}
} catch (ex) {
return error.responseText;
}
}

return error && error.message ? error.message : String(error);
}

function renderError(message) {
var escapedMessage = $("<div/>").text(message).html();
$("#chartAnchor").prepend(
'<div class="alert alert-danger" role="alert">' + escapedMessage + "</div>"
);
}

$(document).ready(function () {
if ($("#chartAnchor").length == 0) {
return;
Expand All @@ -10,7 +32,8 @@
var renderer = new Kiddo.Renderer("#chartAnchor");

if (error) {
ajaxErrorAlert(error);
var message = errorMessage(error);
renderError(message);
return renderer.noData();
}

Expand Down
14 changes: 14 additions & 0 deletions app/assets/stylesheets/kanaui/kanaui.css
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,25 @@

/* app/views/kanaui/reports/index.html.erb */

.kanaui-flash-container {
margin: 1rem 0 1.5rem;
position: relative;
z-index: 1;
}

.kanaui-flash-container .alert {
margin-bottom: 0.75rem;
}
Comment thread
tungleduyxyz marked this conversation as resolved.

.kanaui-reports-index .configured-reports {
max-width: 80rem;
width: 100%;
}

.kanaui-reports-index .kanaui-report-notice {
margin-bottom: 1rem;
}

.kanaui-reports-index .configured-reports .configured-reports-header {
display: flex;
align-items: start;
Expand Down
10 changes: 7 additions & 3 deletions app/controllers/kanaui/dashboard_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ def index
@reports = JSON.parse(raw_reports)
@report = current_report(@reports) || {}

# If no report name is provided, redirect to the default (second) report
if @raw_name.blank? && @reports.is_a?(Array) && @reports[1].present?
default_name = @reports[1]['reportName']
# If no report name is provided, redirect to a default report.
# Prefer the historical default (second report) when present, but fall back
# to the first report so a single configured report still renders the
# dashboard controls and chart area.
default_report = @reports[1] || @reports[0] if @reports.is_a?(Array)
if @raw_name.blank? && default_report.present?
default_name = default_report['reportName']
query_params = { start_date: @start_date,
end_date: @end_date,
name: default_name,
Expand Down
18 changes: 16 additions & 2 deletions app/controllers/kanaui/engine_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,22 @@ def options_for_klient
end

rescue_from(KillBillClient::API::ResponseError) do |killbill_exception|
flash[:error] = "Error while communicating with the Kill Bill server: #{as_string(killbill_exception)}"
redirect_to dashboard_index_path
error_message = I18n.t('kanaui.errors.killbill_communication', error: as_string(killbill_exception))

if json_request?
render json: { message: error_message }, status: killbill_exception.response.code.to_i
else
flash[:error] = error_message
redirect_to dashboard_index_path
end
end

def json_request?
request.format.json? || params[:format] == 'json' || dashboard_reports_json_request?
end

def dashboard_reports_json_request?
controller_name == 'dashboard' && action_name == 'reports' && params[:format].blank?
end

def as_string(e)
Expand Down
25 changes: 17 additions & 8 deletions app/controllers/kanaui/reports_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Kanaui
class ReportsController < Kanaui::EngineController
def index
@reports = JSON.parse(Kanaui::DashboardHelper::DashboardApi.available_reports(options_for_klient)).map(&:deep_symbolize_keys)
@report_notice = report_notice_from_flash
end

def new
Expand All @@ -13,8 +14,7 @@ def new
def create
Kanaui::DashboardHelper::DashboardApi.create_report(report_from_params.to_json, options_for_klient)

flash[:notice] = 'Report successfully created'
redirect_to action: :index
redirect_to_index_with_notice(:created)
end

def edit
Expand All @@ -26,26 +26,35 @@ def edit
def update
Kanaui::DashboardHelper::DashboardApi.update_report(params.require(:id), report_from_params.to_json, options_for_klient)

flash[:notice] = 'Report successfully updated'
redirect_to action: :index
redirect_to_index_with_notice(:updated)
end

def refresh
Kanaui::DashboardHelper::DashboardApi.refresh_report(params.require(:id), options_for_klient)

flash[:notice] = 'Report refresh successfully scheduled'
redirect_to action: :index
redirect_to_index_with_notice(:refresh_scheduled)
end

def destroy
Kanaui::DashboardHelper::DashboardApi.delete_report(params.require(:id), options_for_klient)

flash[:notice] = 'Report successfully deleted'
redirect_to action: :index
redirect_to_index_with_notice(:deleted)
end

private

def report_notice_from_flash
notice_key = flash[:report_notice].presence&.to_s
return nil unless %w[created updated refresh_scheduled deleted].include?(notice_key)

I18n.t("kanaui.reports.notices.#{notice_key}", default: nil)
end

def redirect_to_index_with_notice(notice_key)
flash[:report_notice] = notice_key
redirect_to action: :index
end

def report_from_params
{
reportName: params[:report_name],
Expand Down
2 changes: 1 addition & 1 deletion app/views/kanaui/dashboard/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@
<pre><%= params[:name] -%></pre>
</li>
<% end %>
<li><%= link_to 'SQL query', kanaui_engine.reports_path(params.to_h.merge(:sql_only => true)) %></li>
<li><%= link_to t('kanaui.dashboard.advanced_controls.sql_query'), kanaui_engine.reports_path(params.to_h.merge(:sql_only => true)) %></li>
</ul>
</div>
</div>
Expand Down
26 changes: 11 additions & 15 deletions app/views/kanaui/layouts/kanaui_application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,20 @@
<div class="container">
<div class="container-fluid">
<%- # :alert used by devise -%>
<% [:error, :alert].each do |key| %>
<% if flash[key] %>
<div class="row">
<div class="col-md-10 col-md-offset-2">
<div class="alert alert-error"><%= flash[key] %></div>
</div>
</div>
<% if flash[:error] || flash[:alert] || flash[:notice] %>
<div class="kanaui-flash-container">
<% [:error, :alert].each do |key| %>
<% if flash[key] %>
<div class="alert alert-danger alert-error" role="alert"><%= flash[key] %></div>
<% end %>
<% end %>
<% end %>
<% if flash[:notice] %>
<div class="row">
<div class="col-md-10 col-md-offset-2">
<div class="alert alert-info"><%= flash[:notice] %></div>
</div>
</div>
<% if flash[:notice] %>
<div class="alert alert-info" role="status"><%= flash[:notice] %></div>
<% end %>
</div>
<% end %>
<%= yield %>
<div>
</div>
</div>
</body>
</html>
55 changes: 41 additions & 14 deletions app/views/kanaui/reports/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,64 +1,67 @@
<%= form_tag @report[:reportName].blank? ? url_for(:controller => :reports, :action => :create) : report_path(@report[:reportName]), :method => (@report[:reportName].blank? ? :post : :put), :class => 'form-horizontal' do %>
<%= form_tag @report[:reportName].blank? ? url_for(:controller => :reports, :action => :create) : report_path(@report[:reportName]), :method => (@report[:reportName].blank? ? :post : :put), :class => 'form-horizontal', :id => 'kanaui-report-form' do %>
<div class="form-group d-flex pb-3">
<%= label_tag :report_name, 'Report name', :class => 'col-sm-3 control-label' %>
<%= label_tag :report_name, t('kanaui.reports.form.report_name'), :class => 'col-sm-3 control-label' %>
<div class="col-sm-9">
<%= text_field_tag :report_name, @report[:reportName], :class => 'form-control', :disabled => !@report[:reportName].blank?, :read_only => !@report[:reportName].blank? %>
</div>
</div>
<div class="form-group d-flex pb-3">
<%= label_tag :report_pretty_name, 'Pretty name', :class => 'col-sm-3 control-label' %>
<%= label_tag :report_pretty_name, t('kanaui.reports.form.pretty_name'), :class => 'col-sm-3 control-label' %>
<div class="col-sm-9">
<%= text_field_tag :report_pretty_name, @report[:reportPrettyName], :class => 'form-control' %>
</div>
</div>
<div class="form-group d-flex pb-3">
<%= label_tag :report_type, 'Type', :class => 'col-sm-3 control-label' %>
<%= label_tag :report_type, t('kanaui.reports.form.type'), :class => 'col-sm-3 control-label' %>
<div class="col-sm-9">
<%= select_tag :report_type, options_for_select(%w(TIMELINE COUNTERS TABLE), @report[:reportType] || 'TABLE'), :class => 'form-control' %>
</div>
</div>
<div class="form-group d-flex pb-3">
<%= label_tag :source_table_name, 'Source', :class => 'col-sm-3 control-label' %>
<%= label_tag :source_table_name, t('kanaui.reports.form.source'), :class => 'col-sm-3 control-label' %>
<div class="col-sm-9">
<%= text_field_tag :source_table_name, @report[:sourceTableName], :class => 'form-control' %>
</div>
</div>
<div class="form-group d-flex pb-3">
<%= label_tag :source_name, 'Source name', :class => 'col-sm-3 control-label' %>
<%= label_tag :source_name, t('kanaui.reports.form.source_name'), :class => 'col-sm-3 control-label' %>
<div class="col-sm-9">
<%= text_field_tag :source_name, @report[:sourceName], :class => 'form-control' %>
<span>Must match a database configuration entry in the Analytics plugin</span>
<span><%= t('kanaui.reports.form.source_name_help') %></span>
</div>
</div>
<div class="form-group d-flex pb-3">
<%= label_tag :source_query, 'SQL query', :class => 'col-sm-3 control-label' %>
<%= label_tag :source_query, t('kanaui.reports.form.source_query'), :class => 'col-sm-3 control-label' %>
<div class="col-sm-9">
<%= text_area_tag :source_query, @report[:sourceQuery], rows: 10, cols: 25, :class => 'form-control' %>
<span>Don't add a trailing ;</span>
<span><%= t('kanaui.reports.form.source_query_help') %></span>
<div id="source-configuration-error" class="text-danger mt-2" style="display: none;">
<%= t('kanaui.reports.form.source_configuration_error') %>
</div>
</div>
</div>
<div class="form-group d-flex pb-3">
<%= label_tag :refresh_procedure_name, 'Refresh procedure', :class => 'col-sm-3 control-label' %>
<%= label_tag :refresh_procedure_name, t('kanaui.reports.form.refresh_procedure'), :class => 'col-sm-3 control-label' %>
<div class="col-sm-9">
<%= text_field_tag :refresh_procedure_name, @report[:refreshProcedureName], :class => 'form-control' %>
</div>
</div>
<div class="form-group d-flex pb-3">
<%= label_tag :refresh_frequency, 'Refresh frequency', :class => 'col-sm-3 control-label' %>
<%= label_tag :refresh_frequency, t('kanaui.reports.form.refresh_frequency'), :class => 'col-sm-3 control-label' %>
<div class="col-sm-9">
<%= select_tag :refresh_frequency, options_for_select(%w(HOURLY DAILY), @report[:refreshFrequency]), :class => 'form-control', :include_blank => true %>
</div>
</div>
<div class="form-group d-flex pb-3">
<%= label_tag :refresh_hour_of_day_gmt, 'Refresh hour (GMT)', :class => 'col-sm-3 control-label' %>
<%= label_tag :refresh_hour_of_day_gmt, t('kanaui.reports.form.refresh_hour_gmt'), :class => 'col-sm-3 control-label' %>
<div class="col-sm-9">
<%= number_field_tag :refresh_hour_of_day_gmt, @report[:refreshHourOfDayGmt], {:min => 1, :max => 23, :class => 'form-control'} %>
</div>
</div>

<div class="form-group d-flex justify-content-end border-top pt-3 pb-3">
<%= render "kaui/components/button/button", {
label: 'Close',
label: t('kanaui.actions.close'),
variant: "outline-secondary d-inline-flex align-items-center gap-1",
type: "button",
html_class: "kaui-button custom-hover mx-2",
Expand All @@ -67,10 +70,34 @@
}
} %>
<%= render "kaui/components/button/button", {
label: 'Save',
label: t('kanaui.actions.save'),
variant: "outline-secondary d-inline-flex align-items-center gap-1",
type: "submit",
html_class: "kaui-dropdown custom-hover"
} %>
</div>
<% end %>

<%= javascript_tag do %>
(function () {
var form = document.getElementById('kanaui-report-form');
if (!form) {
return;
}

form.addEventListener('submit', function (event) {
var sourceName = document.getElementById('source_name').value.trim();
var sourceTableName = document.getElementById('source_table_name').value.trim();
var sourceQuery = document.getElementById('source_query').value.trim();
var error = document.getElementById('source-configuration-error');

if (sourceName && !!sourceTableName === !!sourceQuery) {
event.preventDefault();
error.style.display = 'block';
document.getElementById(sourceTableName ? 'source_query' : 'source_table_name').focus();
} else {
error.style.display = 'none';
}
});
})();
<% end %>
Loading
Loading