ahoy_captain 0.81 → 0.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascript/ahoy_captain/controllers/active_links_controller.js +15 -0
- data/app/assets/javascript/ahoy_captain/controllers/filter_form_controller.js +13 -0
- data/app/assets/javascript/ahoy_captain/controllers/line_chart_controller.js +37 -0
- data/app/assets/javascript/ahoy_captain/controllers/predicate_select_controller.js +10 -0
- data/app/assets/javascript/ahoy_captain/controllers/realtime_controller.js +2 -0
- data/app/assets/javascript/ahoy_captain/controllers/search_select_controller.js +65 -0
- data/app/components/ahoy_captain/filter/modal_component.html.erb +6 -5
- data/app/components/ahoy_captain/filter/select_component.html.erb +13 -11
- data/app/components/ahoy_captain/filter/select_component.rb +21 -4
- data/app/components/ahoy_captain/table_component.html.erb +2 -35
- data/app/components/ahoy_captain/table_component.rb +13 -5
- data/app/components/ahoy_captain/tables/headers/devices_header_component.html.erb +3 -0
- data/app/components/ahoy_captain/tables/headers/devices_header_component.rb +9 -0
- data/app/components/ahoy_captain/tables/headers/goals_header_component.html.erb +6 -0
- data/app/components/ahoy_captain/tables/headers/goals_header_component.rb +9 -0
- data/app/components/ahoy_captain/tables/headers/header_component.html.erb +5 -0
- data/app/components/ahoy_captain/tables/headers/header_component.rb +12 -0
- data/app/components/ahoy_captain/tables/rows/devices_row_component.html.erb +5 -0
- data/app/components/ahoy_captain/tables/rows/devices_row_component.rb +12 -0
- data/app/components/ahoy_captain/tables/rows/goals_row_component.html.erb +11 -0
- data/app/components/ahoy_captain/tables/rows/goals_row_component.rb +12 -0
- data/app/components/ahoy_captain/tables/rows/row_component.html.erb +6 -0
- data/app/components/ahoy_captain/tables/rows/row_component.rb +41 -0
- data/app/controllers/ahoy_captain/filters/pages/entry_pages_controller.rb +2 -2
- data/app/controllers/ahoy_captain/filters/pages/exit_pages_controller.rb +1 -2
- data/app/controllers/ahoy_captain/filters/properties/names_controller.rb +11 -0
- data/app/controllers/ahoy_captain/filters/properties/values_controller.rb +15 -0
- data/app/controllers/ahoy_captain/stats/bounce_rates_controller.rb +1 -0
- data/app/controllers/ahoy_captain/stats/total_pageviews_controller.rb +1 -0
- data/app/controllers/ahoy_captain/stats/total_visits_controller.rb +1 -0
- data/app/controllers/ahoy_captain/stats/unique_visitors_controller.rb +1 -0
- data/app/controllers/ahoy_captain/stats/views_per_visits_controller.rb +3 -0
- data/app/controllers/ahoy_captain/stats/visit_durations_controller.rb +1 -0
- data/app/queries/ahoy_captain/application_query.rb +4 -3
- data/app/queries/ahoy_captain/event_query.rb +17 -15
- data/app/queries/ahoy_captain/visit_query.rb +1 -1
- data/app/views/ahoy_captain/devices/_table.html.erb +5 -0
- data/app/views/ahoy_captain/devices/index.html+details.erb +1 -1
- data/app/views/ahoy_captain/devices/index.html.erb +2 -2
- data/app/views/ahoy_captain/goals/index.html.erb +3 -35
- data/app/views/ahoy_captain/layouts/application.html.erb +1 -1
- data/app/views/ahoy_captain/roots/show.html.erb +81 -73
- data/config/routes.rb +6 -0
- data/lib/ahoy_captain/ahoy/event_methods.rb +28 -74
- data/lib/ahoy_captain/goals.rb +9 -1
- data/lib/ahoy_captain/version.rb +1 -1
- metadata +21 -18
- data/app/assets/javascript/ahoy_captain/controllers/filter_controller.js +0 -151
- data/app/assets/javascript/ahoy_captain/controllers/link_controller.js +0 -43
- data/app/assets/javascript/ahoy_captain/controllers/navigation_controller.js +0 -25
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dc0360816004f1a5f8cf41e01f4a55f30b0ff40db97084122678c1b179adf930
|
|
4
|
+
data.tar.gz: a05b89988c2220ca1077bc7eecc80ad1454f777f3eff8621d91b323c52ce6ad7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1e9806cda9cb8366c5639db6d87fe3983cdd327cff484af95782e8c68134fb9c0f3ed55f8b4b7d269ce41b125bbb5da2faf2f4cf2fc1f190faa5c77bf486e2cc
|
|
7
|
+
data.tar.gz: 3ac41065fd0f767d951785c9a46373318ace8d2c4099390d33ae17f2d39701843a4d8c478dbb8232880d8c9b2cc89bf83a0a7ec7ec6065a52281db41d33e9b70
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Controller } from '@hotwired/stimulus';
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static targets = ["link"]
|
|
5
|
+
connect() {
|
|
6
|
+
this.handleLinkClick = (event) => {
|
|
7
|
+
this.linkTargets.forEach(link => link.classList.remove('text-primary', 'font-semibold'))
|
|
8
|
+
event.target.classList.add('text-primary', 'font-semibold')
|
|
9
|
+
}
|
|
10
|
+
this.linkTargets.forEach(link => {
|
|
11
|
+
link.addEventListener('click', this.handleLinkClick)
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {Controller} from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
handleReset(event) {
|
|
5
|
+
event.preventDefault();
|
|
6
|
+
const openModal = document.querySelector('dialog.modal[open]');
|
|
7
|
+
openModal.querySelectorAll('input, select').forEach(element => {
|
|
8
|
+
element.value = ""
|
|
9
|
+
});
|
|
10
|
+
openModal.close()
|
|
11
|
+
this.element.requestSubmit()
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Controller } from '@hotwired/stimulus';
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static values = {
|
|
5
|
+
data: Object,
|
|
6
|
+
label: String
|
|
7
|
+
}
|
|
8
|
+
connect() {
|
|
9
|
+
const getCSS = (varname) => {
|
|
10
|
+
return `hsl(${getComputedStyle(document.documentElement).getPropertyValue(varname)})`
|
|
11
|
+
}
|
|
12
|
+
Chart.register(Chart.Colors)
|
|
13
|
+
|
|
14
|
+
new Chart(this.element,
|
|
15
|
+
{
|
|
16
|
+
type: 'line',
|
|
17
|
+
data: {
|
|
18
|
+
labels: Object.keys(this.dataValue),
|
|
19
|
+
datasets: [
|
|
20
|
+
{
|
|
21
|
+
label: this.labelValue,
|
|
22
|
+
data: Object.values(this.dataValue),
|
|
23
|
+
borderColor: getCSS('--p'),
|
|
24
|
+
backgroundColor: getCSS('--af'),
|
|
25
|
+
color: getCSS('--pc')
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
plugins: {
|
|
30
|
+
colors: {
|
|
31
|
+
forceOverride: true
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -7,6 +7,8 @@ export default class extends Controller {
|
|
|
7
7
|
this.reload = this.reload.bind(this);
|
|
8
8
|
this.setLabel = this.setLabel.bind(this);
|
|
9
9
|
this.labelCount = 0;
|
|
10
|
+
this.reloadInterval = setInterval(this.reload, 1000 * 30);
|
|
11
|
+
this.labelInterval = setInterval(this.setLabel, 1000);
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
reload() {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {Controller} from "@hotwired/stimulus"
|
|
2
|
+
import SlimSelect from 'slim-select'
|
|
3
|
+
|
|
4
|
+
export default class extends Controller {
|
|
5
|
+
static values = {
|
|
6
|
+
query: String,
|
|
7
|
+
url: String,
|
|
8
|
+
selected: Array
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
connect() {
|
|
12
|
+
this.loadedInitialData = false;
|
|
13
|
+
this.search = this.search.bind(this)
|
|
14
|
+
this.select = new SlimSelect({
|
|
15
|
+
select: this.element,
|
|
16
|
+
data: [],
|
|
17
|
+
settings: {
|
|
18
|
+
contentPosition: 'relative',
|
|
19
|
+
contentLocation: this.element.closest('fieldset'),
|
|
20
|
+
searchText: 'Sorry, no results found',
|
|
21
|
+
searchPlaceholder: 'Type to populate results',
|
|
22
|
+
placeholderText: `Search`,
|
|
23
|
+
searchHighlight: true
|
|
24
|
+
},
|
|
25
|
+
events: {
|
|
26
|
+
beforeOpen: async () => {
|
|
27
|
+
if (!this.loadedInitialData) {
|
|
28
|
+
const data = await this.search("");
|
|
29
|
+
this.select.setData(data);
|
|
30
|
+
this.loadedInitialData = true
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
search: this.search
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if(this.selectedValue.length) {
|
|
38
|
+
this.select.setData(this.selectedValue.map(item => ({ "text": item, "value": item })))
|
|
39
|
+
this.select.setSelected(this.selectedValue)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async search(query) {
|
|
44
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
45
|
+
const formData = new FormData(this.element.form);
|
|
46
|
+
|
|
47
|
+
let deleted = [];
|
|
48
|
+
for (const [key, value] of formData) {
|
|
49
|
+
if(!deleted.includes(key)) {
|
|
50
|
+
searchParams.delete(key)
|
|
51
|
+
deleted.push(key)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
searchParams.append(key, value)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
searchParams.delete(this.element.name);
|
|
58
|
+
searchParams.set(this.queryValue, query);
|
|
59
|
+
|
|
60
|
+
const response = await fetch(`${this.urlValue}?${searchParams.toString()}`);
|
|
61
|
+
const data = await response.json();
|
|
62
|
+
return data;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
<dialog id="<%= id %>" class="modal">
|
|
2
|
-
<
|
|
2
|
+
<div class="modal-box w-11/12 max-w-5xl">
|
|
3
3
|
<fieldset>
|
|
4
4
|
<h5><%= title %></h5>
|
|
5
5
|
<%= modal_display %>
|
|
6
6
|
<button class="btn btn-primary mt-4" type="submit">Apply</button>
|
|
7
7
|
<button class="btn btn-primary mt-4" type="reset">Reset</button>
|
|
8
8
|
</fieldset>
|
|
9
|
-
</
|
|
10
|
-
<
|
|
11
|
-
<button>
|
|
12
|
-
</
|
|
9
|
+
</div>
|
|
10
|
+
<label class="modal-backdrop">
|
|
11
|
+
<button onclick="event.preventDefault(); <%=id %>.close();">Close</button>
|
|
12
|
+
</label>
|
|
13
13
|
</dialog>
|
|
14
|
+
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
<fieldset class="flex space-x-4 items-end">
|
|
1
|
+
<fieldset class="flex space-x-4 items-end" data-controller="predicate-select">
|
|
2
2
|
<div class="flex flex-col w-[20%]">
|
|
3
3
|
<label class="label"><%= label %></label>
|
|
4
|
-
<select class='select select-bordered' data-
|
|
5
|
-
<%
|
|
6
|
-
<option value="<%=
|
|
4
|
+
<select class='select select-bordered' data-action='change->predicate-select#handleChange'>
|
|
5
|
+
<% predicate_options.each do |predicate| %>
|
|
6
|
+
<option value="<%= option_value(predicate) %>" <%= 'selected' if selected_predicate == predicate %>>
|
|
7
7
|
<%= predicate.to_s.humanize %>
|
|
8
8
|
</option>
|
|
9
9
|
<% end %>
|
|
10
10
|
</select>
|
|
11
11
|
</div>
|
|
12
|
+
|
|
12
13
|
<select
|
|
14
|
+
data-predicate-select-target="select"
|
|
15
|
+
data-controller="search-select"
|
|
13
16
|
class='w-[50%] border-base-content border-opacity-20 rounded-lg min-h-[3rem]'
|
|
14
|
-
name="<%=
|
|
15
|
-
multiple
|
|
16
|
-
data-
|
|
17
|
-
data-
|
|
18
|
-
data-
|
|
19
|
-
|
|
20
|
-
></select>
|
|
17
|
+
name="<%= column_name_with_predicate %>"
|
|
18
|
+
<% if multiple %>multiple<% end %>
|
|
19
|
+
data-search-select-query-value="q[<%= column %>_i_cont]"
|
|
20
|
+
data-search-select-url-value="<%= url %>"
|
|
21
|
+
data-search-select-selected-value="<%= values %>"
|
|
22
|
+
></select>
|
|
21
23
|
</fieldset>
|
|
@@ -1,17 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class AhoyCaptain::Filter::SelectComponent < ViewComponent::Base
|
|
4
|
-
def initialize(label:, column:, url:, predicates:)
|
|
4
|
+
def initialize(label:, column:, url:, predicates:, form:, multiple: true)
|
|
5
5
|
@label = label
|
|
6
6
|
@column = column
|
|
7
7
|
@url = url
|
|
8
8
|
@predicates = predicates
|
|
9
|
+
@form = form
|
|
10
|
+
@multiple = multiple
|
|
9
11
|
end
|
|
10
12
|
|
|
13
|
+
private
|
|
14
|
+
|
|
11
15
|
def selected_predicate
|
|
12
16
|
predicate_options.detect { |option| params.dig(:q, option) }
|
|
13
17
|
end
|
|
14
18
|
|
|
19
|
+
def option_value(predicate)
|
|
20
|
+
name = "q[#{predicate}]"
|
|
21
|
+
name += "[]" if multiple
|
|
22
|
+
name
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def column_name_with_predicate
|
|
26
|
+
if selected_predicate
|
|
27
|
+
option_value(selected_predicate)
|
|
28
|
+
else
|
|
29
|
+
option_value(predicate_options.first)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
15
33
|
def values
|
|
16
34
|
predicate_options.each do |predicate|
|
|
17
35
|
option = params.dig(:q, predicate)
|
|
@@ -23,10 +41,9 @@ class AhoyCaptain::Filter::SelectComponent < ViewComponent::Base
|
|
|
23
41
|
[]
|
|
24
42
|
end
|
|
25
43
|
|
|
26
|
-
private
|
|
27
|
-
|
|
28
44
|
def predicate_options
|
|
29
45
|
@predicate_options ||= @predicates.map { |predicate| "#{@column}_#{predicate}" }
|
|
30
46
|
end
|
|
31
|
-
|
|
47
|
+
|
|
48
|
+
attr_reader :label, :column, :url, :predicates, :form, :multiple
|
|
32
49
|
end
|
|
@@ -1,44 +1,11 @@
|
|
|
1
1
|
<div class="flex flex-col min-h-[380px] w-full pt-4">
|
|
2
|
-
|
|
3
|
-
<span class="grow"><%= category_name %></span>
|
|
4
|
-
<span ><%= unit_name %></span>
|
|
5
|
-
<% if additional_cols.include?(:percent_total) %>
|
|
6
|
-
<span class="w-8 ml-8 text-right">%</span>
|
|
7
|
-
<% end %>
|
|
8
|
-
<% if additional_cols.include?(:total) %>
|
|
9
|
-
<span class="w-8 ml-8 text-right">Total</span>
|
|
10
|
-
<% end %>
|
|
11
|
-
<% if additional_cols.include?(:conversion_rate) %>
|
|
12
|
-
<span class="w-8 ml-8 text-right">CR</span>
|
|
13
|
-
<% end %>
|
|
14
|
-
</div>
|
|
2
|
+
<%= render @header %>
|
|
15
3
|
<div class='min-h-[420px]'>
|
|
16
4
|
<div class="grow">
|
|
17
5
|
<% if items.respond_to?(:each) && items.any? %>
|
|
18
6
|
<% items.each do |item| %>
|
|
19
7
|
<div class='leading-10 flex relative'>
|
|
20
|
-
|
|
21
|
-
</progress>
|
|
22
|
-
<span class="grow text-elipsis overflow-hidden absolute left-4 bottom-3 h-8 text-base-content">
|
|
23
|
-
<%= item.display_name %>
|
|
24
|
-
</span>
|
|
25
|
-
<span class="w-8 ml-8 text-right">
|
|
26
|
-
<%= render AhoyCaptain::TooltipComponent.new(amount: item.unit_amount) %>
|
|
27
|
-
</span>
|
|
28
|
-
|
|
29
|
-
<% if additional_cols.include?(:percent_total) %>
|
|
30
|
-
<span class="w-8 ml-8 text-right"><%= percent_total(item) %></span>
|
|
31
|
-
<% end %>
|
|
32
|
-
<% if additional_cols.include?(:total) %>
|
|
33
|
-
<span class="w-8 ml-8 text-right">
|
|
34
|
-
<%= render AhoyCaptain::TooltipComponent.new(amount: item.total) %>
|
|
35
|
-
</span>
|
|
36
|
-
<% end %>
|
|
37
|
-
<% if additional_cols.include?(:conversion_rate) %>
|
|
38
|
-
<span class="w-8 ml-8 text-right">
|
|
39
|
-
<%= item.conversion_rate * 100.0 %>%
|
|
40
|
-
</span>
|
|
41
|
-
<% end %>
|
|
8
|
+
<%= render_row(item) %>
|
|
42
9
|
</div>
|
|
43
10
|
<% end %>
|
|
44
11
|
<% else %>
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class AhoyCaptain::TableComponent < ViewComponent::Base
|
|
4
|
-
|
|
4
|
+
DEFAULT_HEADER = AhoyCaptain::Tables::Headers::HeaderComponent
|
|
5
|
+
DEFAULT_ROW = AhoyCaptain::Tables::Rows::RowComponent
|
|
5
6
|
|
|
6
|
-
def initialize(items:, category_name
|
|
7
|
+
def initialize(items:, category_name: nil, unit_name: nil, header: nil, row: DEFAULT_ROW)
|
|
7
8
|
@items = items
|
|
8
9
|
@category_name = category_name
|
|
9
10
|
@unit_name = unit_name
|
|
10
11
|
@additional_cols = additional_cols
|
|
12
|
+
if header.nil?
|
|
13
|
+
@header = DEFAULT_HEADER.new(category_name: category_name, unit_name: unit_name)
|
|
14
|
+
else
|
|
15
|
+
@header = header.new
|
|
16
|
+
end
|
|
17
|
+
@row = row
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def render_row(item)
|
|
21
|
+
@row.new(table: self, item: item).render_in(view_context)
|
|
11
22
|
end
|
|
12
23
|
|
|
13
24
|
private
|
|
@@ -22,7 +33,4 @@ class AhoyCaptain::TableComponent < ViewComponent::Base
|
|
|
22
33
|
@total ||= items.first.total_count
|
|
23
34
|
end
|
|
24
35
|
|
|
25
|
-
def percent_total(item)
|
|
26
|
-
'%.1f' % ((item.unit_amount.to_i * 1.0 / total)*100.0)
|
|
27
|
-
end
|
|
28
36
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module AhoyCaptain
|
|
2
|
+
module Tables
|
|
3
|
+
module Rows
|
|
4
|
+
class RowComponent < ViewComponent::Base
|
|
5
|
+
def initialize(table:, item:)
|
|
6
|
+
@table = table
|
|
7
|
+
@item = item
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def progress_bar(value, max, label)
|
|
11
|
+
items = []
|
|
12
|
+
items << view_context.content_tag(:progress, "", class: "progress-primary bg-base-100 h-8 grow", value: value, max: max)
|
|
13
|
+
items << view_context.content_tag(:span, class: "grow text-elipsis overflow-hidden absolute left-4 bottom-3 h-8 text-base-content") do
|
|
14
|
+
label
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
items.join.html_safe
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def item(value = nil, &block)
|
|
21
|
+
view_context.content_tag(:span, class: "w-8 ml-8 text-right") do
|
|
22
|
+
if value
|
|
23
|
+
value
|
|
24
|
+
else
|
|
25
|
+
capture(&block)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def percent_total(item)
|
|
32
|
+
'%.1f' % ((item.unit_amount.to_i * 1.0 / total)*100.0)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def tooltip(value)
|
|
36
|
+
AhoyCaptain::TooltipComponent.new(amount: value).render_in(self)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module AhoyCaptain
|
|
2
2
|
module Filters
|
|
3
3
|
module Pages
|
|
4
|
-
# TODO: ACCOMODATE EXIT_PAGES
|
|
5
4
|
class EntryPagesController < BaseController
|
|
6
5
|
def index
|
|
7
|
-
query = event_query.all.
|
|
6
|
+
query = event_query.all.distinct("entry_pages.url").select("entry_pages.url as url")
|
|
7
|
+
|
|
8
8
|
render json: query.map { |row| { text: row.url } }
|
|
9
9
|
end
|
|
10
10
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
module AhoyCaptain
|
|
2
2
|
module Filters
|
|
3
3
|
module Pages
|
|
4
|
-
# TODO: ACCOMODATE ENTRY_PAGES
|
|
5
4
|
class ExitPagesController < BaseController
|
|
6
5
|
def index
|
|
7
|
-
query = event_query.
|
|
6
|
+
query = event_query.distinct("exit_pages.url").select("exit_pages.url as url")
|
|
8
7
|
|
|
9
8
|
render json: query.map { |row| { text: row.url } }
|
|
10
9
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module AhoyCaptain
|
|
2
|
+
module Filters
|
|
3
|
+
module Properties
|
|
4
|
+
class NamesController < BaseController
|
|
5
|
+
def index
|
|
6
|
+
render json: ::Ahoy::Event.select("jsonb_object_keys(properties) as keys").distinct("jsonb_object_keys(properties)").map(&:keys).map { |key| serialize(key) }
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module AhoyCaptain
|
|
2
|
+
module Filters
|
|
3
|
+
module Properties
|
|
4
|
+
class ValuesController < BaseController
|
|
5
|
+
def index
|
|
6
|
+
query = ::Ahoy::Event.with(elements: event_query.select("ahoy_events.properties->>'controller' as element"))
|
|
7
|
+
.select("distinct elements.element").from("elements")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
render json: query.map(&:element).map { |element| serialize(element) }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -53,6 +53,7 @@ module AhoyCaptain
|
|
|
53
53
|
EventQuery.call(params)
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
# this could be better
|
|
56
57
|
def ransack_params_for(type)
|
|
57
58
|
ransackable_params = {}
|
|
58
59
|
|
|
@@ -61,12 +62,13 @@ module AhoyCaptain
|
|
|
61
62
|
visit: (AhoyCaptain.visit.ransackable_attributes + AhoyCaptain.visit.ransackable_scopes).map(&:to_s),
|
|
62
63
|
event: (AhoyCaptain.event.ransackable_attributes + AhoyCaptain.event.ransackable_scopes).map(&:to_s),
|
|
63
64
|
}
|
|
65
|
+
|
|
64
66
|
pattern = /(?:_not_eq|_eq|_in|_not_in|_cont|_not_cont|_i_cont)$/
|
|
65
67
|
params[:q].each do |key, value|
|
|
66
68
|
attribute_name = key.gsub(pattern, '')
|
|
67
|
-
if type == :event && ransackable_attributes[:visit].include?(attribute_name) || ransackable_attributes[:visit].include?(key)
|
|
69
|
+
if type == :event && (ransackable_attributes[:visit].include?(attribute_name) || ransackable_attributes[:visit].include?(key))
|
|
68
70
|
ransackable_params["visit_#{key}"] = value
|
|
69
|
-
elsif type == :visit && ransackable_attributes[:event].include?(attribute_name) || ransackable_attributes[:event].include?(key)
|
|
71
|
+
elsif type == :visit && (ransackable_attributes[:event].include?(attribute_name) || ransackable_attributes[:event].include?(key))
|
|
70
72
|
ransackable_params["events_#{key}"] = value
|
|
71
73
|
else
|
|
72
74
|
ransackable_params[key] = value
|
|
@@ -102,7 +104,6 @@ module AhoyCaptain
|
|
|
102
104
|
end
|
|
103
105
|
end
|
|
104
106
|
|
|
105
|
-
|
|
106
107
|
ransackable_params
|
|
107
108
|
end
|
|
108
109
|
|