Skip to content

Refactor dashboard page to be data-driven, and expose resulting config#183

Merged
igorkasyanchuk merged 4 commits intoigorkasyanchuk:masterfrom
botandrose:data-driven-dashboard
Jan 5, 2026
Merged

Refactor dashboard page to be data-driven, and expose resulting config#183
igorkasyanchuk merged 4 commits intoigorkasyanchuk:masterfrom
botandrose:data-driven-dashboard

Conversation

@botandrose
Copy link
Copy Markdown

Hi Igor!

I found some time today to further pursue my agenda of making rails_performance more data-driven, and thus more configurable.

This PR is very similar to the work already done to make the System page data-driven, so nothing too ground-breaking here. I think the only new part is my decision to represent the P50, P95, and P99 cards as a multi-column row with a nested array:

  # config/initializers/rails_performance.rb
  config.dashboard_charts = [
    ["P50Card", "P95Card", "P99Card"],
    "ThroughputChart",
    "ResponseTimeChart"
  ] 

What do you think?

In future PRs, I'll keep pursuing this direction of refactoring page layouts into data-driven config settings, until we eventually end up with something like:

  # config/initializers/rails_performance.rb
  config.pages = {
    index: {
      title: "Dashboard",
      widgets: [
        ["P50Card", "P95Card", "P99Card"],
        "ThroughputChart",
        "ResponseTimeChart"
      ]
    },
    requests: {
      title: "Requests",
      widgets: ["RequestsTable"]
    },
    # etc
  }    

But one step at a time!

@botandrose botandrose force-pushed the data-driven-dashboard branch from db203a4 to 9522e3c Compare January 3, 2026 19:49
@botandrose botandrose force-pushed the data-driven-dashboard branch from 9522e3c to 72c6b16 Compare January 3, 2026 19:54
@botandrose
Copy link
Copy Markdown
Author

I decided to do a little more in this PR. I just pushed a commit that also extracts a _card and _chart partial, so that the index.html.erb doesn't really need to know exactly what it is rendering, only that its an array of arrays of things that respond to .to_partial_path.

@botandrose botandrose force-pushed the data-driven-dashboard branch from 69ec187 to 8dd4da4 Compare January 3, 2026 20:22
@throughput_report_data = RailsPerformance::Reports::ThroughputReport.new(db).data
@response_time_report_data = RailsPerformance::Reports::ResponseTimeReport.new(db).data
@percentile_report_data = RailsPerformance::Reports::PercentileReport.new(db).data
@widgets = RailsPerformance.dashboard_charts.map do |row|
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe code could be simpler if you consider widgets always as array of arrays, even if only one element is inside

@widgets = RailsPerformance.widgets_config_for(:dashboard).map do |row|
   Array.wrap(row).map { |class_name| DashboardCharts.const_get(class_name).new(@datasource) }
end

and in view you can always render an array of arrays

UPDATE: I see that for single widget we don't render widget inside columns/column. So maybe this is not needed.

But it would be worth to think about it and maybe try.

Also I think method like widgets_config_for will be needed for other pages in the future.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, another comment, just want to challenge - for main dashbiard page I see widgets could be useful, but what about other pages

image

maybe for System metricts also could be useful.

For requests/etc probably not?


But I like the idea of widgets, we can allow users to create own widgets with own metrics. Example:

rails_performance.config.widgets[:dashboard] << RallsPerformance::Widget.new(label: "Users", data_type: :single_value, data: -> { User.count } )
   
rails_performance.config.widgets[:dashboard] << RallsPerformance::Widget.new(label: "ReportGeneration", data_type: :sparkline, data: -> { SomeReport.group(:date_on).count } )

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

letting you to think more about it, in general PR can be merged, because it's changing some internal things, without exposing new configuration options

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like your idea of Array.wrap(row).map a lot! Maybe the CSS can be adjusted so that this can be possible with the same markup for single and multiple items in a row, to make the HTML really simple. I'm not an expert in CSS, but maybe something like display: flex? I will try this now.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the configuration API, yes! I like the idea to allow users to create their own widgets, too. I am already doing this in my projects :) And I'm sure that the exact details of the configuration API will be something you and I discuss and adjust, before we make it public and document it in the README. For now, this is mostly exploration, by making the pages configurable, one at a time, one PR at a time. When they're all configurable, then I think we can look at them all and decide what the best public API should be.

The reason that I do think it makes sense to try to make the Requests page configurable is because I want to try make the entire UI configurable, including which pages are displayed in the nav at the top, so that you could add a custom page of custom widgets, for example. Or remove whole pages if you don't want them. All in the config. But yeah that's for a future PR! Just making the dashboard page configurable is the focus for this PR.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so I'm merging it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to you, of course! But personally speaking, I think this PR is ready to be merged. As you say, its all internal changes... we're not committing to a configuration API just yet. This helps us explore what that might look like. I already have some follow-up PRs ready to go that build on top of this one and explore the space further.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merged, I'll keep it in main branch, and won't release new version

@botandrose
Copy link
Copy Markdown
Author

@igorkasyanchuk Okay I've just pushed another commit that switches the dashboard page from column-based to row-based HTML and CSS. Now rendering that page is effectively just @widgets.each { "<div class='row'>#{render it}</div>" }. Much simpler!

@igorkasyanchuk igorkasyanchuk merged commit 3503a33 into igorkasyanchuk:master Jan 5, 2026
2 checks passed
@botandrose botandrose deleted the data-driven-dashboard branch January 6, 2026 21:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants