* Adding more context to `/admin/abtests` Prior to this commit, the `/admin/abtests` was fully rendered by the field_test gem (see https://github.com/ankane/field_test/blob/master/app/views/field_test/experiments/index.html.erb and https://github.com/ankane/field_test/blob/master/app/views/field_test/experiments/show.html.erb). With this commit, we're pre-pending our own partial (e.g. `app/views/field_test/experiments/_experiments.html.erb`) in the view paths; which means instead of rendering https://github.com/ankane/field_test/blob/master/app/views/field_test/experiments/_experiments.html.erb we render our newly created `app/views/field_test/experiments/_experiments.html.erb`) Why the ugly antics in the view? As I'm not fully certain if this will "meet" the full needs of those monitoring the experiments. I'm also constructing this to most closely match the spreadsheet that has been assembled for tracking this information. Why introduce another caching layer for the variant assembly? The original caching layer (e.g. `Articles::Feeds::VariantAssembler.pre_assembled_variants`) is in place to provide the quickest access to the assembled variants. But due to the nature of the implemented view, we are needing a programmatic representation of all variants. And the added Rails cache is there to minimize disk reads. Closes forem/forem#17820 * Update app/models/articles/feeds/variant_assembler.rb Co-authored-by: Ridhwana <Ridhwana.Khan16@gmail.com> * Update app/models/articles/feeds/variant_assembler.rb Co-authored-by: Ridhwana <Ridhwana.Khan16@gmail.com> Co-authored-by: Ridhwana <Ridhwana.Khan16@gmail.com>
118 lines
4.4 KiB
Text
118 lines
4.4 KiB
Text
<style>
|
|
details details { padding: 1em 0 0 1.5em; }
|
|
</style>
|
|
<% experiments.reverse_each do |experiment| %>
|
|
<h2><%= experiment.name %><% unless experiment.active? %> <small class="closed">Completed</small><% end %></h2>
|
|
<details<%= " open" if experiment.active? %>>
|
|
<summary>Experiment Details</summary>
|
|
|
|
<% if experiment.description %>
|
|
<p class="description"><%= experiment.description %></p>
|
|
<% end %>
|
|
|
|
<details<%= " open" if experiment.active? %>>
|
|
<summary>Goals for <%= experiment.name %></summary>
|
|
<% experiment.goals.each do |goal| %>
|
|
<% results = experiment.results(goal: goal) %>
|
|
|
|
<% if experiment.multiple_goals? %>
|
|
<h3><%= goal.titleize %></h3>
|
|
<% end %>
|
|
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Variant</th>
|
|
<th style="width: 20%;">Participants</th>
|
|
<th style="width: 20%;">Conversions</th>
|
|
<th style="width: 20%;">Conversion Rate</th>
|
|
<th style="width: 20%;">Prob Winning</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% results.each do |variant, result| %>
|
|
<tr>
|
|
<td>
|
|
<%= variant %>
|
|
<% if variant == experiment.winner %>
|
|
<span class="check">✓</span>
|
|
<% end %>
|
|
</td>
|
|
<td><%= result[:participated] %></td>
|
|
<td><%= result[:converted] %></td>
|
|
<td>
|
|
<% if result[:conversion_rate] %>
|
|
<%= (100.0 * result[:conversion_rate]).round(FieldTest.precision) %>%
|
|
<% else %>
|
|
-
|
|
<% end %>
|
|
</td>
|
|
<td>
|
|
<% if result[:prob_winning] %>
|
|
<% if result[:prob_winning] < 0.01 %>
|
|
< 1%
|
|
<% else %>
|
|
<%= (100.0 * result[:prob_winning]).round(FieldTest.precision) %>%
|
|
<% end %>
|
|
<% end %>
|
|
</td>
|
|
</tr>
|
|
<% end %>
|
|
</tbody>
|
|
</table>
|
|
<% end %>
|
|
</details>
|
|
|
|
<% if experiment.id.start_with?("feed_strategy") %>
|
|
<% experiment.variants.each do |variant| %>
|
|
<details>
|
|
<summary>Config for <%= variant %> <% if variant == experiment.winner %><span class="check">✓</span><% end %></summary>
|
|
<% config = Articles::Feeds::VariantAssembler.user_config_hash_for(variant: variant) %>
|
|
<dl>
|
|
<dt>Description</dt>
|
|
<dd><%= config["description"] || "n/a" %></dd>
|
|
<dt>Weight</dt>
|
|
<dd><%= experiment.weights[experiment.variants.index(variant)] %></dd>
|
|
<dt>Order Lever</dt>
|
|
<dd><%= config["order_by"] %></dd>
|
|
<% config["levers"].each do |lever_key, lever| %>
|
|
<% next unless lever.key?("query_parameters") %>
|
|
<dt>Parameters for <strong><%= lever_key %></strong> relevancy lever</dt>
|
|
<% lever["query_parameters"].each do |key, value| %>
|
|
<dd><strong><%= key %>:</strong> <%= value %></dd>
|
|
<% end %>
|
|
<% end %>
|
|
</dl>
|
|
|
|
<table>
|
|
<% lever_range = config["levers"].map { |_, lever| lever["cases"].map(&:first) }.flatten.uniq.sort %>
|
|
<caption>Relevency Lever(s): Fallback and Range Factors</caption>
|
|
<thead>
|
|
<tr>
|
|
<th>Lever</th>
|
|
<th>Fallback</th>
|
|
<% lever_range.each do |i| %>
|
|
<th><%= i %></th>
|
|
<% end %>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% config["levers"].each do |lever_key, lever| %>
|
|
<% cases = lever["cases"].each_with_object({}) { |(key, value), mem| mem[key] = value } %>
|
|
<tr>
|
|
<th><%= lever_key %></th>
|
|
<td><%= lever["fallback"] %></th>
|
|
<% lever_range.each do |i| %>
|
|
<td><%= cases.fetch(i, " ".html_safe) %></td>
|
|
<% end %>
|
|
</tr>
|
|
<% end %>
|
|
</tbody>
|
|
</table>
|
|
</details>
|
|
<% end %>
|
|
<% end %>
|
|
|
|
<p><%= link_to "Data Details", experiment_path(experiment.id) %> <small>(individual user conversions)</small></p>
|
|
</details>
|
|
<% end %>
|