trailguide 0.1.31 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +73 -8
  3. data/app/assets/javascripts/trail_guide/admin/application.js +20 -1
  4. data/app/assets/stylesheets/trail_guide/admin/application.css +22 -0
  5. data/app/assets/stylesheets/trail_guide/admin/experiments.css +36 -3
  6. data/app/controllers/trail_guide/admin/application_controller.rb +59 -8
  7. data/app/controllers/trail_guide/admin/experiments_controller.rb +209 -16
  8. data/app/controllers/trail_guide/admin/groups_controller.rb +34 -0
  9. data/app/controllers/trail_guide/experiments_controller.rb +1 -1
  10. data/app/views/layouts/trail_guide/admin/_calculator.erb +24 -0
  11. data/app/views/layouts/trail_guide/admin/_footer.html.erb +27 -0
  12. data/app/views/layouts/trail_guide/admin/_header.html.erb +147 -0
  13. data/app/views/layouts/trail_guide/admin/_import_modal.html.erb +45 -0
  14. data/app/views/layouts/trail_guide/admin/application.html.erb +17 -3
  15. data/app/views/trail_guide/admin/experiments/_alert_peek.html.erb +19 -0
  16. data/app/views/trail_guide/admin/experiments/_alert_state.html.erb +49 -0
  17. data/app/views/trail_guide/admin/experiments/_btn_analyze.html.erb +11 -0
  18. data/app/views/trail_guide/admin/experiments/_btn_analyze_goal.html.erb +5 -0
  19. data/app/views/trail_guide/admin/experiments/_btn_convert.html.erb +33 -0
  20. data/app/views/trail_guide/admin/experiments/_btn_enroll.html.erb +3 -0
  21. data/app/views/trail_guide/admin/experiments/_btn_join.html.erb +11 -0
  22. data/app/views/trail_guide/admin/experiments/_btn_leave.html.erb +7 -0
  23. data/app/views/trail_guide/admin/experiments/_btn_pause.html.erb +5 -0
  24. data/app/views/trail_guide/admin/experiments/_btn_peek.html.erb +13 -0
  25. data/app/views/trail_guide/admin/experiments/_btn_reset.html.erb +5 -0
  26. data/app/views/trail_guide/admin/experiments/_btn_restart.html.erb +5 -0
  27. data/app/views/trail_guide/admin/experiments/_btn_resume.html.erb +5 -0
  28. data/app/views/trail_guide/admin/experiments/_btn_schedule.html.erb +6 -0
  29. data/app/views/trail_guide/admin/experiments/_btn_start.html.erb +5 -0
  30. data/app/views/trail_guide/admin/experiments/_btn_stop.html.erb +5 -0
  31. data/app/views/trail_guide/admin/experiments/_experiment.html.erb +68 -172
  32. data/app/views/trail_guide/admin/experiments/_header.html.erb +87 -0
  33. data/app/views/trail_guide/admin/experiments/_start_modal.html.erb +57 -0
  34. data/app/views/trail_guide/admin/experiments/_tbody.html.erb +112 -0
  35. data/app/views/trail_guide/admin/experiments/_thead.html.erb +38 -0
  36. data/app/views/trail_guide/admin/experiments/index.html.erb +8 -16
  37. data/app/views/trail_guide/admin/experiments/show.html.erb +78 -0
  38. data/app/views/trail_guide/admin/groups/index.html.erb +40 -0
  39. data/app/views/trail_guide/admin/groups/show.html.erb +9 -0
  40. data/app/views/trail_guide/admin/orphans/_alert.html.erb +44 -0
  41. data/config/initializers/trailguide.rb +72 -9
  42. data/config/routes/admin.rb +19 -12
  43. data/lib/trail_guide/admin/engine.rb +2 -0
  44. data/lib/trail_guide/admin.rb +2 -0
  45. data/lib/trail_guide/calculators/bayesian.rb +98 -0
  46. data/lib/trail_guide/calculators/calculator.rb +58 -0
  47. data/lib/trail_guide/calculators/score.rb +68 -0
  48. data/lib/trail_guide/calculators.rb +8 -0
  49. data/lib/trail_guide/catalog.rb +134 -19
  50. data/lib/trail_guide/combined_experiment.rb +8 -3
  51. data/lib/trail_guide/config.rb +6 -1
  52. data/lib/trail_guide/engine.rb +2 -0
  53. data/lib/trail_guide/errors.rb +30 -1
  54. data/lib/trail_guide/experiment.rb +0 -1
  55. data/lib/trail_guide/experiments/base.rb +189 -53
  56. data/lib/trail_guide/experiments/config.rb +82 -13
  57. data/lib/trail_guide/experiments/participant.rb +21 -1
  58. data/lib/trail_guide/helper.rb +59 -32
  59. data/lib/trail_guide/metrics/checkpoint.rb +24 -0
  60. data/lib/trail_guide/metrics/config.rb +45 -0
  61. data/lib/trail_guide/metrics/funnel.rb +24 -0
  62. data/lib/trail_guide/metrics/goal.rb +89 -0
  63. data/lib/trail_guide/metrics.rb +9 -0
  64. data/lib/trail_guide/participant.rb +54 -21
  65. data/lib/trail_guide/variant.rb +34 -12
  66. data/lib/trail_guide/version.rb +2 -2
  67. data/lib/trailguide.rb +4 -0
  68. metadata +112 -7
  69. data/app/views/layouts/trail_guide/admin/_footer.erb +0 -10
  70. data/app/views/layouts/trail_guide/admin/_header.erb +0 -42
  71. data/app/views/trail_guide/admin/experiments/_combined_experiment.html.erb +0 -189
  72. data/config/routes.rb +0 -5
@@ -0,0 +1,24 @@
1
+ <div id="calculator-modal" class="modal calculator-modal" tabindex="-1" role="dialog">
2
+ <div class="modal-dialog" role="document">
3
+ <div class="modal-content">
4
+ <form>
5
+ <div class="modal-header">
6
+ <h5 class="modal-title">Sample Size Calculator</h5>
7
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
8
+ <span aria-hidden="true">&times;</span>
9
+ </button>
10
+ </div>
11
+ <div class="modal-body text-left">
12
+ <p class="text-muted"><small>Choosing the right sample size up front is crucial to properly analyzing your experiments and avoiding Type I and Type II errors. The wrong sample size can lead to extended experiment runs, a lack of confidence in results, or other unknown errors. <a href="http://www.evanmiller.org/how-not-to-run-an-ab-test.html" target="_blank">Read more here.</a></small></p>
13
+ </div>
14
+ <div class="modal-footer">
15
+ <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
16
+ <button type="submit" class="btn btn-info">
17
+ <span class="fas fa-calculator"></span>
18
+ Calculate
19
+ </button>
20
+ </div>
21
+ </form>
22
+ </div>
23
+ </div>
24
+ </div>
@@ -0,0 +1,27 @@
1
+ <div class="footer container-fluid bg-light">
2
+ <div class="row">
3
+ <div class="col-sm-3 text-left">
4
+ <%= link_to "v#{TrailGuide::Version::VERSION}", "https://github.com/markrebec/trailguide", target: :blank, class: "text-muted" %>
5
+ </div>
6
+ <div class="col-sm-6 text-center">
7
+ <strong><%= number_with_delimiter TrailGuide.catalog.sum(&:participants) %></strong>
8
+ <span class="fas fa-users" data-toggle="tooltip" title="participants"></span> generating
9
+ <strong><%= number_with_delimiter TrailGuide.catalog.all.sum(&:converted) %></strong>
10
+ <span class="fas fa-fill-drip" data-toggle="tooltip" title="conversions"></span> against
11
+ <strong><%= number_with_delimiter TrailGuide.catalog.all.sum { |exp| exp.variants.count } %></strong>
12
+ <span class="fas fa-vials" data-toggle="tooltip" title="variants"></span> and
13
+ <strong><%= number_with_delimiter TrailGuide.catalog.all.sum { |exp| exp.goals.empty? ? 1 : exp.goals.count } %></strong>
14
+ <span class="fas fa-fill" data-toggle="tooltip" title="goals"></span> across
15
+ <strong><%= number_with_delimiter TrailGuide.catalog.all.count %></strong>
16
+ <span class="fas fa-flask" data-toggle="tooltip" title="experiments"></span>
17
+ </div>
18
+ <div class="col-sm-3 text-right">
19
+ <small class="text-muted"><%= TrailGuide.redis._client.id %><%= "/#{TrailGuide.redis.namespace}" if TrailGuide.redis.respond_to?(:namespace) %></small>
20
+ <button type="button" class="btn btn-link text-muted" style="font-size: 80%; margin: 0; padding: 0;" data-toggle="modal" data-target="#import-modal" data-tooltip="tooltip" title="Import/Export">
21
+ <span class="fas fa-file-download"></span>
22
+ </button>
23
+ </div>
24
+ </div>
25
+ </div>
26
+
27
+ <%= render partial: 'layouts/trail_guide/admin/import_modal' %>
@@ -0,0 +1,147 @@
1
+ <nav class="navbar navbar-expanded-sm navbar-light bg-light fixed-top">
2
+ <%= link_to trail_guide_admin.experiments_path, class: "navbar-brand d-none d-sm-inline-block" do %>
3
+ <%= image_tag "trail_guide/trailguide.png" %>
4
+ <%= TrailGuide::Admin.configuration.title %>
5
+ <% end %>
6
+ <div class="col-sm text-center">
7
+ <div class="btn-group">
8
+ <%= link_to trail_guide_admin.experiments_path, class: "btn btn-light text-dark", data: {toggle: :tooltip}, title: "Experiment".pluralize(TrailGuide.catalog.count) do %>
9
+ <span class="fas fa-flask"></span>
10
+ &nbsp;
11
+ <strong class="total"><%= TrailGuide.catalog.count %></strong>
12
+ <% end %>
13
+
14
+ <button type="button" class="btn btn-light text-dark dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
15
+ <span class="sr-only">Toggle Dropdown</span>
16
+ </button>
17
+
18
+ <div class="dropdown-menu">
19
+ <% if TrailGuide.catalog.unstarted.count > 0 %>
20
+ <%= link_to trail_guide_admin.scoped_experiments_path(scope: :unstarted), class: "dropdown-item text-secondary" do %>
21
+ <span class="fas fa-flask"></span>
22
+ <small>&times;</small>
23
+ <strong class="total"><%= TrailGuide.catalog.unstarted.count %></strong>
24
+ &nbsp;
25
+ <span>Unstarted</span>
26
+ <% end %>
27
+ <% end %>
28
+
29
+ <% if TrailGuide.catalog.calibrating.count > 0 %>
30
+ <%= link_to trail_guide_admin.scoped_experiments_path(scope: :calibrating), class: "dropdown-item text-secondary" do %>
31
+ <span class="fas fa-cog"></span>
32
+ <small>&times;</small>
33
+ <strong class="total"><%= TrailGuide.catalog.calibrating.count %></strong>
34
+ &nbsp;
35
+ <span>Calibrating</span>
36
+ <% end %>
37
+ <% end %>
38
+
39
+ <% if TrailGuide.catalog.running.count > 0 %>
40
+ <%= link_to trail_guide_admin.scoped_experiments_path(scope: :running), class: "dropdown-item text-success" do %>
41
+ <span class="fas fa-play"></span>
42
+ <small>&times;</small>
43
+ <strong class="total"><%= TrailGuide.catalog.running.count %></strong>
44
+ &nbsp;
45
+ <span>Running</span>
46
+ <% end %>
47
+ <% end %>
48
+
49
+ <% if TrailGuide.catalog.paused.count > 0 %>
50
+ <%= link_to trail_guide_admin.scoped_experiments_path(scope: :paused), class: "dropdown-item text-warning" do %>
51
+ <span class="fas fa-pause"></span>
52
+ <small>&times;</small>
53
+ <strong class="total"><%= TrailGuide.catalog.paused.count %></strong>
54
+ &nbsp;
55
+ <span>Paused</span>
56
+ <% end %>
57
+ <% end %>
58
+
59
+ <% if TrailGuide.catalog.scheduled.count > 0 %>
60
+ <%= link_to trail_guide_admin.scoped_experiments_path(scope: :scheduled), class: "dropdown-item text-info" do %>
61
+ <span class="fas fa-calendar"></span>
62
+ <small>&times;</small>
63
+ <strong class="total"><%= TrailGuide.catalog.scheduled.count %></strong>
64
+ &nbsp;
65
+ <span>Scheduled</span>
66
+ <% end %>
67
+ <% end %>
68
+
69
+ <% if TrailGuide.catalog.stopped.count > 0 %>
70
+ <%= link_to trail_guide_admin.scoped_experiments_path(scope: :stopped), class: "dropdown-item text-danger" do %>
71
+ <span class="fas fa-stop"></span>
72
+ <small>&times;</small>
73
+ <strong class="total"><%= TrailGuide.catalog.stopped.count %></strong>
74
+ &nbsp;
75
+ <span>Stopped</span>
76
+ <% end %>
77
+ <% end %>
78
+
79
+ <% if TrailGuide.catalog.ended.count > 0 %>
80
+ <%= link_to trail_guide_admin.scoped_experiments_path(scope: :ended), class: "dropdown-item text-primary" do %>
81
+ <span class="fas fa-flag-checkered"></span>
82
+ <small>&times;</small>
83
+ <strong class="total"><%= TrailGuide.catalog.ended.count %></strong>
84
+ &nbsp;
85
+ <span>Ended</span>
86
+ <% end %>
87
+ <% end %>
88
+ </div>
89
+ </div>
90
+
91
+ <% unless TrailGuide.catalog.groups.empty? %>
92
+ <div class="btn-group">
93
+ <%= link_to trail_guide_admin.groups_path, class: "btn btn-light text-dark", data: {toggle: :tooltip}, title: "Group".pluralize(TrailGuide.catalog.groups.count) do %>
94
+ <span class="fas fa-th-large"></span>
95
+ &nbsp;
96
+ <strong class="total">
97
+ <%= TrailGuide.catalog.groups.count %>
98
+ </strong>
99
+ <% end %>
100
+
101
+ <button type="button" class="btn btn-light text-dark dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
102
+ <span class="sr-only">Toggle Dropdown</span>
103
+ </button>
104
+
105
+ <div class="dropdown-menu">
106
+
107
+ <% TrailGuide.catalog.groups.each do |group| %>
108
+ <%= link_to trail_guide_admin.group_path(group), class: "dropdown-item text-secondary" do %>
109
+ <span class="fas fa-flask"></span>
110
+ <small>&times;</small>
111
+ <strong class="total">
112
+ <%= TrailGuide.catalog.select(group).count %>
113
+ </strong>
114
+ &nbsp;
115
+ <span><%= group.to_s.humanize.titleize %></span>
116
+ <% end %>
117
+ <% end %>
118
+ </div>
119
+ </div>
120
+ <% end %>
121
+
122
+ <button type="button" class="btn btn-light text-dark" style="display: none;" data-toggle="modal" data-target="#calculator-modal" data-tooltip="tooltip" title="sample size calculator">
123
+ <span class="fas fa-calculator"></span>
124
+ </button>
125
+ </div>
126
+ <span class="navbar-brand d-none d-md-inline-block"><small class="text-muted"><%= TrailGuide::Admin.configuration.subtitle %></small></span>
127
+ </nav>
128
+
129
+ <%= render partial: 'layouts/trail_guide/admin/calculator' %>
130
+
131
+ <div class="toasts">
132
+ <% flash.each do |key, message| %>
133
+ <div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="true" data-delay="5000">
134
+ <div class="toast-header">
135
+ <%= image_tag "trail_guide/trailguide.png", class: "rounded mr-2", style: "width: 25px; height: 25px;" %>
136
+ <strong class="mr-auto">TrailGuide</strong>
137
+ <small class="text-muted">just now</small>
138
+ <button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
139
+ <span aria-hidden="true">&times;</span>
140
+ </button>
141
+ </div>
142
+ <div class="toast-body">
143
+ <%= raw message %>
144
+ </div>
145
+ </div>
146
+ <% end %>
147
+ </div>
@@ -0,0 +1,45 @@
1
+ <div id="import-modal" class="modal import-modal" tabindex="-1" role="dialog">
2
+ <div class="modal-dialog" role="document">
3
+ <div class="modal-content">
4
+ <%= form_tag trail_guide_admin.import_experiments_path, multipart: true, method: :put do %>
5
+ <div class="modal-header">
6
+ <h5 class="modal-title">Import or Export Experiment State</h5>
7
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
8
+ <span aria-hidden="true">&times;</span>
9
+ </button>
10
+ </div>
11
+ <div class="modal-body text-left">
12
+ <p><small>You can export the current state of all experiments using the <strong class="text-info" style="white-space: nowrap;"><span class="fas fa-file-download"></span> Export JSON</strong> button below. The downloaded JSON file will include participation counts, conversion counts, winner selection, and the current state of each experiment (i.e. running, stopped).</small></p>
13
+
14
+ <p><small>If you already have an export file from another trailguide instance, you can import it using the form below. This can be useful to replicate state locally if you're trying to debug complex experiment behavior or interactions between experiments reported in another environment (like production).</small></p>
15
+
16
+ <div class="form-group row">
17
+ <label for="import-file" class="col-sm-3 col-form-label"><strong>File</strong></label>
18
+ <div class="col-sm-9">
19
+ <div class="custom-file">
20
+ <input type="file" name="file" class="custom-file-input" id="import-file">
21
+ <label class="custom-file-label" for="import-file">Choose file</label>
22
+ </div>
23
+ </div>
24
+ </div>
25
+
26
+ </div>
27
+ <div class="modal-footer">
28
+ <div class="col-sm-5">
29
+ <%= link_to trail_guide_admin.export_experiments_path(format: :json), class: "btn btn-info", data: {toggle: :tooltip}, title: "download a JSON export of the current state of all experiments" do %>
30
+ <span class="fas fa-file-download"></span>
31
+ Export JSON
32
+ <% end %>
33
+ </div>
34
+ <div class="col-sm-7 text-right">
35
+ <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
36
+ <button type="submit" class="btn btn-success">
37
+ <span class="fas fa-file-upload"></span>
38
+ Import JSON
39
+ </button>
40
+ </div>
41
+ </div>
42
+ <% end %>
43
+ </div>
44
+ </div>
45
+ </div>
@@ -7,15 +7,26 @@
7
7
  <meta charset="utf-8">
8
8
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
9
9
 
10
- <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
11
- <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
12
- <%= stylesheet_link_tag "trail_guide/admin/application", media: "all" %>
10
+ <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
11
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tempusdominus-bootstrap-4/5.0.1/css/tempusdominus-bootstrap-4.min.css" crossorigin="anonymous" />
12
+ <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous" />
13
+ <%= stylesheet_link_tag "trail_guide/admin/application", media: "all" %>
13
14
  </head>
14
15
  <body>
15
16
  <%= render 'layouts/trail_guide/admin/header' %>
16
17
 
17
18
  <main>
18
19
  <div class="container-fluid">
20
+ <% if TrailGuide.configuration.disabled %>
21
+ <div class="row justify-content-center">
22
+ <div class="col-sm-12 col-md-10 col-lg-8">
23
+ <div class="alert alert-danger">
24
+ TrailGuide is globally disabled. Your experiments are not running, and control variants will be returned for all users until it is enabled again.
25
+ </div>
26
+ </div>
27
+ </div>
28
+ <% end %>
29
+
19
30
  <%= yield %>
20
31
  </div>
21
32
  </main>
@@ -23,8 +34,11 @@
23
34
  <%= render 'layouts/trail_guide/admin/footer' %>
24
35
 
25
36
  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
37
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js" crossorigin="anonymous"></script>
26
38
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
27
39
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
40
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/bs-custom-file-input/dist/bs-custom-file-input.min.js"></script>
41
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/tempusdominus-bootstrap-4/5.0.1/js/tempusdominus-bootstrap-4.min.js"></script>
28
42
  <%= javascript_include_tag "trail_guide/admin/application" %>
29
43
  </body>
30
44
  </html>
@@ -0,0 +1,19 @@
1
+ <% if experiment_peekable?(experiment) %>
2
+ <% if experiment_peeking?(experiment) %>
3
+ <div class="alert alert-primary">
4
+ <h6>
5
+ <span class="fas fa-eye"></span>
6
+ Peeking at Results
7
+ </h6>
8
+ <p><small>You are currently peeking at this experiment's results. Use the <span class="fas fa-eye-slash"></span> button to stop peeking.</small></p>
9
+ </div>
10
+ <% else %>
11
+ <div class="alert alert-primary">
12
+ <h6>
13
+ <span class="fas fa-eye-slash"></span>
14
+ Target Sample Size
15
+ </h6>
16
+ <p><small>This experiment has been configured with <code>target_sample_size: <%= experiment.configuration.target_sample_size %></code>, which prevents variant metrics from being displayed until the experiment has ended. You may peek at the current results by clicking the <span class="fas fa-eye"></span> button.</small></p>
17
+ </div>
18
+ <% end %>
19
+ <% end %>
@@ -0,0 +1,49 @@
1
+ <div class="alert alert-<%= experiment_color(experiment) %>">
2
+ <h6 class="text-<%= experiment_color(experiment) %>">
3
+ <span class="fas <%= experiment_icon(experiment) %> text-<%= experiment_color(experiment) %>"></span>
4
+ &nbsp;
5
+ <% if experiment.winner? %>
6
+ Winner Promoted
7
+ <% elsif experiment.started? %>
8
+ <% if experiment.stopped? %>
9
+ Stopped
10
+ <% elsif experiment.paused? %>
11
+ Paused
12
+ <% else %>
13
+ Running
14
+ <% end %>
15
+ <% elsif experiment.scheduled? %>
16
+ Scheduled
17
+ <% else %>
18
+ Not Started
19
+ <% end %>
20
+ </h6>
21
+
22
+ <p><small>
23
+ <% if experiment.winner? %>
24
+ A winning variant has been selected for this experiment and will be returned to all participants.
25
+ <% if experiment.running? && experiment.configuration.track_winner_conversions %>
26
+ This experiment is configured with <code>track_winner_conversions: true</code>, so as long as your experiment is still running you will be able to continue tracking conversions against the winner. You can stop your experiment to stop tracking conversions.
27
+ <% end %>
28
+ <% elsif experiment.started? %>
29
+ <% if experiment.stopped? %>
30
+ This experiment has been stopped and he control variant will be returned to all participants until it is restarted or a winner is selected. It ran from <strong><%= experiment.started_at.strftime(TrailGuide::Admin::DISPLAY_DATE_FORMAT) %></strong> to <strong><%= experiment.stopped_at.strftime(TrailGuide::Admin::DISPLAY_DATE_FORMAT) %></strong>.
31
+ <% elsif experiment.paused? %>
32
+ This experiment was paused on <strong><%= experiment.paused_at.strftime(TrailGuide::Admin::DISPLAY_DATE_FORMAT) %></strong> paused. The control variant will be returned to all participants until it is resumed, restarted or a winner is selected.
33
+ <% else %>
34
+ This experiment was started on <strong><%= experiment.started_at.strftime(TrailGuide::Admin::DISPLAY_DATE_FORMAT) %></strong> and is currently running. Participants will be enrolled and served a variant based on the configured alrogithm.
35
+ <% end %>
36
+ <% elsif experiment.scheduled? %>
37
+ This experiment has been scheduled to start on <strong><%= experiment.started_at.strftime(TrailGuide::Admin::DISPLAY_DATE_FORMAT) %></strong>
38
+ <% if experiment.stopped_at.present? %>
39
+ and stop on <strong><%= experiment.stopped_at.strftime(TrailGuide::Admin::DISPLAY_DATE_FORMAT) %></strong>
40
+ <% end %>
41
+ <% else %>
42
+ This experiment is not running, and the control variant will be returned to all participants until it is started. You may use the controls above to start or schedule your experiment.
43
+ <% if !experiment.start_manually? %>
44
+ <br /><br />
45
+ This experiment is configured with <code>start_manually: false</code> and will start automatically the first time a participant encounters it.
46
+ <% end %>
47
+ <% end %>
48
+ </small></p>
49
+ </div>
@@ -0,0 +1,11 @@
1
+ <% if experiment.started? || experiment.calibrating? %>
2
+ <% if @analyzing %>
3
+ <%= link_to trail_guide_admin.experiment_path(experiment.experiment_name), class: "btn btn-info #{classname if defined?(classname)}", method: :put, data: {toggle: :tooltip}, title: "hide this experiment's analysis" do %>
4
+ <span class="fas fa-chart-line"></span>
5
+ <% end %>
6
+ <% else %>
7
+ <%= link_to trail_guide_admin.experiment_path(experiment.experiment_name, analyze: true, peek: true), class: "btn btn-outline-info #{classname if defined?(classname)}", method: :put, data: {toggle: :tooltip}, title: "analyze this experiment's metrics" do %>
8
+ <span class="fas fa-chart-line"></span>
9
+ <% end %>
10
+ <% end %>
11
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if @analyzing && (@analyze_goal.present? && @analyze_goal != goal.name) %>
2
+ <%= link_to trail_guide_admin.experiment_path(experiment.experiment_name, analyze: true, peek: true, goal: goal.to_s), class: "btn btn-sm btn-outline-dark border-0", method: :put, data: {toggle: :tooltip}, title: 'analyze this metric' do %>
3
+ <span class="fas fa-search"></span>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,33 @@
1
+ <% if experiment.running? || experiment.calibrating? %>
2
+ <% if participant.participating?(experiment) %>
3
+ <% if participant.converted?(experiment, goal) %>
4
+ <% if (goal.nil? && experiment.allow_multiple_conversions?) || (goal.present? && goal.allow_multiple_conversions?) %>
5
+ <%= link_to trail_guide_admin.convert_experiment_path(experiment.experiment_name, goal || "converted"), class: "btn btn-sm btn-outline-primary border-0", method: :put, data: {toggle: :tooltip}, title: 'convert this metric' do %>
6
+ <span class="fas fa-fill-drip"></span>
7
+ <% end %>
8
+ <% else %>
9
+ <span data-toggle="tooltip" title="you may not convert this metric because this experiment does not allow multiple conversions">
10
+ <%= link_to "#", class: "btn btn-sm btn-link disabled", method: :put do %>
11
+ <span class="fas fa-fill-drip"></span>
12
+ <% end %>
13
+ </span>
14
+ <% end %>
15
+ <% elsif participant.converted?(experiment) %>
16
+ <% if experiment.allow_multiple_goals? %>
17
+ <%= link_to trail_guide_admin.convert_experiment_path(experiment.experiment_name, goal || "converted"), class: "btn btn-sm btn-outline-primary border-0", method: :put, data: {toggle: :tooltip}, title: 'convert this metric' do %>
18
+ <span class="fas fa-fill-drip"></span>
19
+ <% end %>
20
+ <% else %>
21
+ <span data-toggle="tooltip" title="you may not convert this metric because this experiment does not allow multiple goals to be converted">
22
+ <%= link_to "#", class: "btn btn-sm btn-link disabled", method: :put do %>
23
+ <span class="fas fa-fill-drip"></span>
24
+ <% end %>
25
+ </span>
26
+ <% end %>
27
+ <% else %>
28
+ <%= link_to trail_guide_admin.convert_experiment_path(experiment.experiment_name, goal || "converted"), class: "btn btn-sm btn-outline-primary border-0", method: :put, data: {toggle: :tooltip}, title: 'convert this metric' do %>
29
+ <span class="fas fa-fill-drip"></span>
30
+ <% end %>
31
+ <% end %>
32
+ <% end %>
33
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <%= link_to trail_guide_admin.enroll_experiment_path(experiment.experiment_name), class: "btn btn-secondary #{classname if defined?(classname)}", method: :put, data: {toggle: :tooltip}, title: 'enroll yourself in this experiment using the configured algorithm' do %>
2
+ <span class="fas fa-dice" />
3
+ <% end %>
@@ -0,0 +1,11 @@
1
+ <% if experiment.running? || experiment.calibrating? %>
2
+ <% if participant.variant(experiment) == variant %>
3
+ <%= link_to trail_guide_admin.leave_experiment_path(experiment.experiment_name), class: "btn btn-sm btn-outline-secondary", method: :put, data: {toggle: :tooltip}, title: 'leave this cohort' do %>
4
+ <span class="fas fa-sign-out-alt fa-flip-horizontal" />
5
+ <% end %>
6
+ <% elsif !experiment.calibrating? && !experiment.winner? && experiment.configuration.store_participation? && (!experiment.is_combined? || (!participant.participating?(experiment.parent) || participant.variant(experiment.parent).name == variant.name)) %>
7
+ <%= link_to trail_guide_admin.join_experiment_path(experiment.experiment_name, variant.name), class: "btn btn-sm btn-secondary", method: :put, data: {toggle: :tooltip}, title: 'join this cohort' do %>
8
+ <span class="fas fa-sign-in-alt" />
9
+ <% end %>
10
+ <% end %>
11
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <% if experiment.running? || experiment.calibrating? %>
2
+ <% if participant.participating?(experiment) %>
3
+ <%= link_to trail_guide_admin.leave_experiment_path(experiment.experiment_name), class: "btn btn-outline-secondary", method: :put, data: {toggle: :tooltip}, title: 'leave your cohort' do %>
4
+ <span class="fas fa-sign-out-alt fa-flip-horizontal" />
5
+ <% end %>
6
+ <% end %>
7
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if experiment.running? && experiment.configuration.can_resume? %>
2
+ <%= link_to trail_guide_admin.pause_experiment_path(experiment.experiment_name), class: 'btn btn-warning', method: :put, data: {toggle: :tooltip}, title: 'pause this experiment - you will have the option to resume or reset' do %>
3
+ <span class="fas fa-pause"></span>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <% if experiment.started? && !experiment.stopped? %>
2
+ <% if experiment_peekable?(experiment) %>
3
+ <% if experiment_peeking?(experiment) %>
4
+ <%= link_to trail_guide_admin.experiment_path(experiment.experiment_name), class: "btn btn-primary #{classname if defined?(classname)}", method: :put, data: {toggle: :tooltip}, title: "hide this experiment's metrics" do %>
5
+ <span class="fas fa-eye-slash"></span>
6
+ <% end %>
7
+ <% else %>
8
+ <%= link_to peek_url(experiment), class: "btn btn-primary #{classname if defined?(classname)}", method: :put, data: {toggle: :tooltip}, title: "peek at this experiment's metrics" do %>
9
+ <span class="fas fa-eye"></span>
10
+ <% end %>
11
+ <% end %>
12
+ <% end %>
13
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if experiment.started? || experiment.scheduled? || experiment.winner? %>
2
+ <%= link_to trail_guide_admin.reset_experiment_path(experiment.experiment_name), class: 'btn btn-outline-danger',method: :put, data: {toggle: :tooltip}, title: "stop this experiment if it's running and reset all data" do %>
3
+ <span class="fas fa-ban"></span>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if experiment.stopped? %>
2
+ <%= link_to trail_guide_admin.restart_experiment_path(experiment.experiment_name), class: 'btn btn-danger',method: :put, data: {toggle: :tooltip}, title: 'restart this experiment - will reset all data and restart the experiment' do %>
3
+ <span class="fas fa-redo fa-flip-horizontal"></span>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if !experiment.stopped? && experiment.paused? && experiment.configuration.can_resume? %>
2
+ <%= link_to trail_guide_admin.resume_experiment_path(experiment.experiment_name), class: 'btn btn-success',method: :put, data: {toggle: :tooltip}, title: 'resume this experiment to start bucketing users and serving variants again' do %>
3
+ <span class="fas fa-redo"></span>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <% if !experiment.started? %>
2
+ <button type="button" class="btn btn-info" data-toggle="modal" data-target="#start-experiment-modal-<%= experiment.experiment_name %>" data-tooltip="tooltip" title="schedule this experiment to start in the future">
3
+ <span class="fas fa-clock"></span>
4
+ </button>
5
+ <%= render partial: 'start_modal', locals: { experiment: experiment } %>
6
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if !experiment.started? %>
2
+ <%= link_to trail_guide_admin.start_experiment_path(experiment.experiment_name), class: 'btn btn-success',method: :put, data: {toggle: :tooltip}, title: 'start this experiment now' do %>
3
+ <span class="fas fa-play"></span>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if experiment.running? || (experiment.paused? && !experiment.stopped?) %>
2
+ <%= link_to trail_guide_admin.stop_experiment_path(experiment.experiment_name), class: 'btn btn-danger', method: :put, data: {toggle: :tooltip}, title: 'stop this experiment - once stopped you will need to reset before restarting' do %>
3
+ <span class="fas fa-stop"></span>
4
+ <% end %>
5
+ <% end %>