rails_pulse 0.2.2 → 0.2.4
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/README.md +1 -1
- data/app/assets/stylesheets/rails_pulse/components/tags.css +2 -2
- data/app/controllers/concerns/chart_table_concern.rb +4 -3
- data/app/controllers/rails_pulse/application_controller.rb +11 -3
- data/app/controllers/rails_pulse/dashboard_controller.rb +12 -8
- data/app/controllers/rails_pulse/queries_controller.rb +13 -8
- data/app/controllers/rails_pulse/requests_controller.rb +10 -5
- data/app/controllers/rails_pulse/routes_controller.rb +14 -7
- data/app/helpers/rails_pulse/application_helper.rb +47 -2
- data/app/helpers/rails_pulse/chart_helper.rb +32 -2
- data/app/javascript/rails_pulse/application.js +3 -54
- data/app/javascript/rails_pulse/controllers/chart_controller.js +229 -0
- data/app/javascript/rails_pulse/controllers/index_controller.js +9 -14
- data/app/javascript/rails_pulse/controllers/pagination_controller.js +27 -33
- data/app/jobs/rails_pulse/backfill_summaries_job.rb +0 -2
- data/app/jobs/rails_pulse/cleanup_job.rb +0 -2
- data/app/jobs/rails_pulse/summary_job.rb +0 -2
- data/app/models/concerns/rails_pulse/taggable.rb +63 -0
- data/app/models/rails_pulse/dashboard/charts/average_response_time.rb +12 -5
- data/app/models/rails_pulse/dashboard/charts/p95_response_time.rb +12 -5
- data/app/models/rails_pulse/dashboard/tables/slow_queries.rb +7 -0
- data/app/models/rails_pulse/dashboard/tables/slow_routes.rb +6 -0
- data/app/models/rails_pulse/queries/cards/average_query_times.rb +10 -6
- data/app/models/rails_pulse/queries/cards/execution_rate.rb +16 -10
- data/app/models/rails_pulse/queries/cards/percentile_query_times.rb +10 -6
- data/app/models/rails_pulse/queries/charts/average_query_times.rb +6 -3
- data/app/models/rails_pulse/queries/tables/index.rb +12 -2
- data/app/models/rails_pulse/requests/charts/average_response_times.rb +13 -7
- data/app/models/rails_pulse/routes/cards/average_response_times.rb +10 -6
- data/app/models/rails_pulse/routes/cards/error_rate_per_route.rb +10 -6
- data/app/models/rails_pulse/routes/cards/percentile_response_times.rb +10 -6
- data/app/models/rails_pulse/routes/cards/request_count_totals.rb +10 -6
- data/app/models/rails_pulse/routes/charts/average_response_times.rb +10 -6
- data/app/models/rails_pulse/routes/tables/index.rb +12 -2
- data/app/models/rails_pulse/summary.rb +55 -0
- data/app/views/layouts/rails_pulse/_global_filters.html.erb +9 -2
- data/app/views/rails_pulse/components/_active_filters.html.erb +36 -0
- data/app/views/rails_pulse/components/_metric_card.html.erb +2 -2
- data/app/views/rails_pulse/components/_page_header.html.erb +4 -0
- data/app/views/rails_pulse/components/_sparkline_stats.html.erb +1 -1
- data/app/views/rails_pulse/components/_table_pagination.html.erb +8 -6
- data/app/views/rails_pulse/csp_test/show.html.erb +1 -1
- data/app/views/rails_pulse/dashboard/charts/_bar_chart.html.erb +1 -1
- data/app/views/rails_pulse/dashboard/index.html.erb +8 -3
- data/app/views/rails_pulse/queries/index.html.erb +3 -2
- data/app/views/rails_pulse/queries/show.html.erb +2 -1
- data/app/views/rails_pulse/requests/index.html.erb +1 -1
- data/app/views/rails_pulse/routes/index.html.erb +3 -2
- data/app/views/rails_pulse/routes/show.html.erb +2 -1
- data/app/views/rails_pulse/tags/_tag_manager.html.erb +2 -2
- data/config/importmap.rb +1 -1
- data/lib/rails_pulse/cleanup_service.rb +8 -0
- data/lib/rails_pulse/engine.rb +0 -5
- data/lib/rails_pulse/version.rb +1 -1
- data/public/rails-pulse-assets/csp-test.js +10 -10
- data/public/rails-pulse-assets/rails-pulse.css +1 -1
- data/public/rails-pulse-assets/rails-pulse.css.map +1 -1
- data/public/rails-pulse-assets/rails-pulse.js +48 -48
- data/public/rails-pulse-assets/rails-pulse.js.map +4 -4
- metadata +7 -26
- data/app/models/concerns/taggable.rb +0 -61
- data/config/initializers/rails_charts_csp_patch.rb +0 -75
|
@@ -2,18 +2,21 @@ module RailsPulse
|
|
|
2
2
|
module Queries
|
|
3
3
|
module Charts
|
|
4
4
|
class AverageQueryTimes
|
|
5
|
-
def initialize(ransack_query:, period_type: nil, query: nil, start_time: nil, end_time: nil, start_duration: nil)
|
|
5
|
+
def initialize(ransack_query:, period_type: nil, query: nil, start_time: nil, end_time: nil, start_duration: nil, disabled_tags: [], show_non_tagged: true)
|
|
6
6
|
@ransack_query = ransack_query
|
|
7
7
|
@period_type = period_type
|
|
8
8
|
@query = query
|
|
9
9
|
@start_time = start_time
|
|
10
10
|
@end_time = end_time
|
|
11
11
|
@start_duration = start_duration
|
|
12
|
+
@disabled_tags = disabled_tags
|
|
13
|
+
@show_non_tagged = show_non_tagged
|
|
12
14
|
end
|
|
13
15
|
|
|
14
|
-
def
|
|
15
|
-
# The ransack query already contains the correct filters, just add period_type
|
|
16
|
+
def to_chart_data
|
|
17
|
+
# The ransack query already contains the correct filters, just add period_type and tag filters
|
|
16
18
|
summaries = @ransack_query.result(distinct: false)
|
|
19
|
+
.with_tag_filters(@disabled_tags, @show_non_tagged)
|
|
17
20
|
.where(period_type: @period_type)
|
|
18
21
|
.group(:period_start)
|
|
19
22
|
.having("AVG(avg_duration) > ?", @start_duration || 0)
|
|
@@ -2,13 +2,14 @@ module RailsPulse
|
|
|
2
2
|
module Queries
|
|
3
3
|
module Tables
|
|
4
4
|
class Index
|
|
5
|
-
def initialize(ransack_query:, period_type: nil, start_time:, params:, query: nil, disabled_tags: [])
|
|
5
|
+
def initialize(ransack_query:, period_type: nil, start_time:, params:, query: nil, disabled_tags: [], show_non_tagged: true)
|
|
6
6
|
@ransack_query = ransack_query
|
|
7
7
|
@period_type = period_type
|
|
8
8
|
@start_time = start_time
|
|
9
9
|
@params = params
|
|
10
10
|
@query = query
|
|
11
11
|
@disabled_tags = disabled_tags
|
|
12
|
+
@show_non_tagged = show_non_tagged
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def to_table
|
|
@@ -23,10 +24,19 @@ module RailsPulse
|
|
|
23
24
|
)
|
|
24
25
|
|
|
25
26
|
# Apply tag filters by excluding queries with disabled tags
|
|
26
|
-
|
|
27
|
+
# Separate "non_tagged" from actual tags (it's a virtual tag)
|
|
28
|
+
actual_disabled_tags = @disabled_tags.reject { |tag| tag == "non_tagged" }
|
|
29
|
+
|
|
30
|
+
# Exclude queries with actual disabled tags
|
|
31
|
+
actual_disabled_tags.each do |tag|
|
|
27
32
|
base_query = base_query.where.not("rails_pulse_queries.tags LIKE ?", "%#{tag}%")
|
|
28
33
|
end
|
|
29
34
|
|
|
35
|
+
# Exclude non-tagged queries if show_non_tagged is false
|
|
36
|
+
unless @show_non_tagged
|
|
37
|
+
base_query = base_query.where("rails_pulse_queries.tags IS NOT NULL AND rails_pulse_queries.tags != '[]'")
|
|
38
|
+
end
|
|
39
|
+
|
|
30
40
|
base_query = base_query.where(summarizable_id: @query.id) if @query
|
|
31
41
|
|
|
32
42
|
# Apply grouping and aggregation
|
|
@@ -2,21 +2,27 @@ module RailsPulse
|
|
|
2
2
|
module Requests
|
|
3
3
|
module Charts
|
|
4
4
|
class AverageResponseTimes
|
|
5
|
-
def initialize(ransack_query:, period_type: nil, route: nil, start_time: nil, end_time: nil, start_duration: nil)
|
|
5
|
+
def initialize(ransack_query:, period_type: nil, route: nil, start_time: nil, end_time: nil, start_duration: nil, disabled_tags: [], show_non_tagged: true)
|
|
6
6
|
@ransack_query = ransack_query
|
|
7
7
|
@period_type = period_type
|
|
8
8
|
@route = route
|
|
9
9
|
@start_time = start_time
|
|
10
10
|
@end_time = end_time
|
|
11
11
|
@start_duration = start_duration
|
|
12
|
+
@disabled_tags = disabled_tags
|
|
13
|
+
@show_non_tagged = show_non_tagged
|
|
12
14
|
end
|
|
13
15
|
|
|
14
|
-
def
|
|
15
|
-
summaries
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
def to_chart_data
|
|
17
|
+
# Note: Overall request summaries (summarizable_id: 0) are not filtered by tags
|
|
18
|
+
# as they aggregate all requests regardless of route tags
|
|
19
|
+
summaries = @ransack_query.result(distinct: false)
|
|
20
|
+
.with_tag_filters(@disabled_tags, @show_non_tagged)
|
|
21
|
+
.where(
|
|
22
|
+
summarizable_type: "RailsPulse::Request",
|
|
23
|
+
summarizable_id: 0, # Overall request summaries
|
|
24
|
+
period_type: @period_type
|
|
25
|
+
)
|
|
20
26
|
|
|
21
27
|
summaries = summaries
|
|
22
28
|
.group(:period_start)
|
|
@@ -2,8 +2,10 @@ module RailsPulse
|
|
|
2
2
|
module Routes
|
|
3
3
|
module Cards
|
|
4
4
|
class AverageResponseTimes
|
|
5
|
-
def initialize(route:)
|
|
5
|
+
def initialize(route:, disabled_tags: [], show_non_tagged: true)
|
|
6
6
|
@route = route
|
|
7
|
+
@disabled_tags = disabled_tags
|
|
8
|
+
@show_non_tagged = show_non_tagged
|
|
7
9
|
end
|
|
8
10
|
|
|
9
11
|
def to_metric_card
|
|
@@ -11,11 +13,13 @@ module RailsPulse
|
|
|
11
13
|
previous_7_days = 14.days.ago.beginning_of_day
|
|
12
14
|
|
|
13
15
|
# Single query to get all aggregated metrics with conditional sums
|
|
14
|
-
base_query = RailsPulse::Summary
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
base_query = RailsPulse::Summary
|
|
17
|
+
.with_tag_filters(@disabled_tags, @show_non_tagged)
|
|
18
|
+
.where(
|
|
19
|
+
summarizable_type: "RailsPulse::Route",
|
|
20
|
+
period_type: "day",
|
|
21
|
+
period_start: 2.weeks.ago.beginning_of_day..Time.current
|
|
22
|
+
)
|
|
19
23
|
base_query = base_query.where(summarizable_id: @route.id) if @route
|
|
20
24
|
|
|
21
25
|
metrics = base_query.select(
|
|
@@ -2,8 +2,10 @@ module RailsPulse
|
|
|
2
2
|
module Routes
|
|
3
3
|
module Cards
|
|
4
4
|
class ErrorRatePerRoute
|
|
5
|
-
def initialize(route: nil)
|
|
5
|
+
def initialize(route: nil, disabled_tags: [], show_non_tagged: true)
|
|
6
6
|
@route = route
|
|
7
|
+
@disabled_tags = disabled_tags
|
|
8
|
+
@show_non_tagged = show_non_tagged
|
|
7
9
|
end
|
|
8
10
|
|
|
9
11
|
def to_metric_card
|
|
@@ -11,11 +13,13 @@ module RailsPulse
|
|
|
11
13
|
previous_7_days = 14.days.ago.beginning_of_day
|
|
12
14
|
|
|
13
15
|
# Single query to get all error metrics with conditional aggregation
|
|
14
|
-
base_query = RailsPulse::Summary
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
base_query = RailsPulse::Summary
|
|
17
|
+
.with_tag_filters(@disabled_tags, @show_non_tagged)
|
|
18
|
+
.where(
|
|
19
|
+
summarizable_type: "RailsPulse::Route",
|
|
20
|
+
period_type: "day",
|
|
21
|
+
period_start: 2.weeks.ago.beginning_of_day..Time.current
|
|
22
|
+
)
|
|
19
23
|
base_query = base_query.where(summarizable_id: @route.id) if @route
|
|
20
24
|
|
|
21
25
|
metrics = base_query.select(
|
|
@@ -2,8 +2,10 @@ module RailsPulse
|
|
|
2
2
|
module Routes
|
|
3
3
|
module Cards
|
|
4
4
|
class PercentileResponseTimes
|
|
5
|
-
def initialize(route: nil)
|
|
5
|
+
def initialize(route: nil, disabled_tags: [], show_non_tagged: true)
|
|
6
6
|
@route = route
|
|
7
|
+
@disabled_tags = disabled_tags
|
|
8
|
+
@show_non_tagged = show_non_tagged
|
|
7
9
|
end
|
|
8
10
|
|
|
9
11
|
def to_metric_card
|
|
@@ -11,11 +13,13 @@ module RailsPulse
|
|
|
11
13
|
previous_7_days = 14.days.ago.beginning_of_day
|
|
12
14
|
|
|
13
15
|
# Single query to get all P95 metrics with conditional aggregation
|
|
14
|
-
base_query = RailsPulse::Summary
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
base_query = RailsPulse::Summary
|
|
17
|
+
.with_tag_filters(@disabled_tags, @show_non_tagged)
|
|
18
|
+
.where(
|
|
19
|
+
summarizable_type: "RailsPulse::Route",
|
|
20
|
+
period_type: "day",
|
|
21
|
+
period_start: 2.weeks.ago.beginning_of_day..Time.current
|
|
22
|
+
)
|
|
19
23
|
base_query = base_query.where(summarizable_id: @route.id) if @route
|
|
20
24
|
|
|
21
25
|
metrics = base_query.select(
|
|
@@ -2,8 +2,10 @@ module RailsPulse
|
|
|
2
2
|
module Routes
|
|
3
3
|
module Cards
|
|
4
4
|
class RequestCountTotals
|
|
5
|
-
def initialize(route: nil)
|
|
5
|
+
def initialize(route: nil, disabled_tags: [], show_non_tagged: true)
|
|
6
6
|
@route = route
|
|
7
|
+
@disabled_tags = disabled_tags
|
|
8
|
+
@show_non_tagged = show_non_tagged
|
|
7
9
|
end
|
|
8
10
|
|
|
9
11
|
def to_metric_card
|
|
@@ -11,11 +13,13 @@ module RailsPulse
|
|
|
11
13
|
previous_7_days = 14.days.ago.beginning_of_day
|
|
12
14
|
|
|
13
15
|
# Single query to get all count metrics with conditional aggregation
|
|
14
|
-
base_query = RailsPulse::Summary
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
base_query = RailsPulse::Summary
|
|
17
|
+
.with_tag_filters(@disabled_tags, @show_non_tagged)
|
|
18
|
+
.where(
|
|
19
|
+
summarizable_type: "RailsPulse::Route",
|
|
20
|
+
period_type: "day",
|
|
21
|
+
period_start: 2.weeks.ago.beginning_of_day..Time.current
|
|
22
|
+
)
|
|
19
23
|
base_query = base_query.where(summarizable_id: @route.id) if @route
|
|
20
24
|
|
|
21
25
|
metrics = base_query.select(
|
|
@@ -2,20 +2,24 @@ module RailsPulse
|
|
|
2
2
|
module Routes
|
|
3
3
|
module Charts
|
|
4
4
|
class AverageResponseTimes
|
|
5
|
-
def initialize(ransack_query:, period_type: nil, route: nil, start_time: nil, end_time: nil, start_duration: nil)
|
|
5
|
+
def initialize(ransack_query:, period_type: nil, route: nil, start_time: nil, end_time: nil, start_duration: nil, disabled_tags: [], show_non_tagged: true)
|
|
6
6
|
@ransack_query = ransack_query
|
|
7
7
|
@period_type = period_type
|
|
8
8
|
@route = route
|
|
9
9
|
@start_time = start_time
|
|
10
10
|
@end_time = end_time
|
|
11
11
|
@start_duration = start_duration
|
|
12
|
+
@disabled_tags = disabled_tags
|
|
13
|
+
@show_non_tagged = show_non_tagged
|
|
12
14
|
end
|
|
13
15
|
|
|
14
|
-
def
|
|
15
|
-
summaries = @ransack_query.result(distinct: false)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
def to_chart_data
|
|
17
|
+
summaries = @ransack_query.result(distinct: false)
|
|
18
|
+
.with_tag_filters(@disabled_tags, @show_non_tagged)
|
|
19
|
+
.where(
|
|
20
|
+
summarizable_type: "RailsPulse::Route",
|
|
21
|
+
period_type: @period_type
|
|
22
|
+
)
|
|
19
23
|
|
|
20
24
|
summaries = summaries.where(summarizable_id: @route.id) if @route
|
|
21
25
|
summaries = summaries
|
|
@@ -2,12 +2,13 @@ module RailsPulse
|
|
|
2
2
|
module Routes
|
|
3
3
|
module Tables
|
|
4
4
|
class Index
|
|
5
|
-
def initialize(ransack_query:, period_type: nil, start_time:, params:, disabled_tags: [])
|
|
5
|
+
def initialize(ransack_query:, period_type: nil, start_time:, params:, disabled_tags: [], show_non_tagged: true)
|
|
6
6
|
@ransack_query = ransack_query
|
|
7
7
|
@period_type = period_type
|
|
8
8
|
@start_time = start_time
|
|
9
9
|
@params = params
|
|
10
10
|
@disabled_tags = disabled_tags
|
|
11
|
+
@show_non_tagged = show_non_tagged
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def to_table
|
|
@@ -24,10 +25,19 @@ module RailsPulse
|
|
|
24
25
|
)
|
|
25
26
|
|
|
26
27
|
# Apply tag filters by excluding routes with disabled tags
|
|
27
|
-
|
|
28
|
+
# Separate "non_tagged" from actual tags (it's a virtual tag)
|
|
29
|
+
actual_disabled_tags = @disabled_tags.reject { |tag| tag == "non_tagged" }
|
|
30
|
+
|
|
31
|
+
# Exclude routes with actual disabled tags
|
|
32
|
+
actual_disabled_tags.each do |tag|
|
|
28
33
|
base_query = base_query.where.not("rails_pulse_routes.tags LIKE ?", "%#{tag}%")
|
|
29
34
|
end
|
|
30
35
|
|
|
36
|
+
# Exclude non-tagged routes if show_non_tagged is false
|
|
37
|
+
unless @show_non_tagged
|
|
38
|
+
base_query = base_query.where("rails_pulse_routes.tags IS NOT NULL AND rails_pulse_routes.tags != '[]'")
|
|
39
|
+
end
|
|
40
|
+
|
|
31
41
|
base_query = base_query.where(summarizable_id: @route.id) if @route
|
|
32
42
|
|
|
33
43
|
# Apply grouping and aggregation
|
|
@@ -33,6 +33,61 @@ module RailsPulse
|
|
|
33
33
|
where(summarizable_type: "RailsPulse::Request", summarizable_id: 0)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
# Tag filtering scope for charts and metrics
|
|
37
|
+
# Filters summaries based on disabled tags in the underlying route/query
|
|
38
|
+
scope :with_tag_filters, ->(disabled_tags = [], show_non_tagged = true) {
|
|
39
|
+
# Separate "non_tagged" from actual tags (it's a virtual tag)
|
|
40
|
+
actual_disabled_tags = disabled_tags.reject { |tag| tag == "non_tagged" }
|
|
41
|
+
|
|
42
|
+
# Return early if no filters are applied
|
|
43
|
+
return all if actual_disabled_tags.empty? && show_non_tagged
|
|
44
|
+
|
|
45
|
+
# Determine which table to join based on summarizable_type
|
|
46
|
+
# We need to handle both Route and Query summaries
|
|
47
|
+
relation = all
|
|
48
|
+
|
|
49
|
+
# Filter route summaries
|
|
50
|
+
route_ids = RailsPulse::Route.all
|
|
51
|
+
|
|
52
|
+
# Exclude routes with disabled tags
|
|
53
|
+
actual_disabled_tags.each do |tag|
|
|
54
|
+
route_ids = route_ids.where.not("tags LIKE ?", "%#{tag}%")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Exclude non-tagged routes if show_non_tagged is false
|
|
58
|
+
route_ids = route_ids.where("tags IS NOT NULL AND tags != '[]'") unless show_non_tagged
|
|
59
|
+
|
|
60
|
+
route_ids = route_ids.pluck(:id)
|
|
61
|
+
|
|
62
|
+
# Filter query summaries
|
|
63
|
+
query_ids = RailsPulse::Query.all
|
|
64
|
+
|
|
65
|
+
# Exclude queries with disabled tags
|
|
66
|
+
actual_disabled_tags.each do |tag|
|
|
67
|
+
query_ids = query_ids.where.not("tags LIKE ?", "%#{tag}%")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Exclude non-tagged queries if show_non_tagged is false
|
|
71
|
+
query_ids = query_ids.where("tags IS NOT NULL AND tags != '[]'") unless show_non_tagged
|
|
72
|
+
|
|
73
|
+
query_ids = query_ids.pluck(:id)
|
|
74
|
+
|
|
75
|
+
# Apply filters: include only summaries for filtered routes/queries
|
|
76
|
+
# If no routes/queries match the filter, we need to ensure nothing is returned
|
|
77
|
+
# Use -1 as an impossible ID instead of 0 (which might be used for aggregates)
|
|
78
|
+
relation = relation.where(
|
|
79
|
+
"(" \
|
|
80
|
+
" (summarizable_type = 'RailsPulse::Route' AND summarizable_id IN (?)) OR " \
|
|
81
|
+
" (summarizable_type = 'RailsPulse::Query' AND summarizable_id IN (?)) OR " \
|
|
82
|
+
" (summarizable_type = 'RailsPulse::Request')" \
|
|
83
|
+
")",
|
|
84
|
+
route_ids.presence || [ -1 ],
|
|
85
|
+
query_ids.presence || [ -1 ]
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
relation
|
|
89
|
+
}
|
|
90
|
+
|
|
36
91
|
# Ransack configuration
|
|
37
92
|
def self.ransackable_attributes(auth_object = nil)
|
|
38
93
|
%w[
|
|
@@ -15,8 +15,15 @@
|
|
|
15
15
|
<div data-rails-pulse--global-filters-target="wrapper" data-action="click->rails-pulse--global-filters#closeOnClickOutside" style="display: none; position: fixed; inset: 0; background-color: rgba(0, 0, 0, 0.8); z-index: 1000; align-items: center; justify-content: center;">
|
|
16
16
|
<div class="dialog" data-rails-pulse--global-filters-target="dialog" style="position: relative; opacity: 1; transform: scale(1);">
|
|
17
17
|
<div class="dialog__content">
|
|
18
|
-
<
|
|
19
|
-
|
|
18
|
+
<div class="flex items-start justify-between">
|
|
19
|
+
<div>
|
|
20
|
+
<h2 class="text-lg font-semibold mbe-4">Global Filters</h2>
|
|
21
|
+
<p class="text-sm text-subtle">Set default time filters that persist across all pages. These can be overridden by page-specific filters.</p>
|
|
22
|
+
</div>
|
|
23
|
+
<%= link_to '#', "aria-label": "Close", data: { action: "rails-pulse--global-filters#close" }, class: "text-subtle hover:text-default" do %>
|
|
24
|
+
<%= rails_pulse_icon 'x', width: '20' %>
|
|
25
|
+
<% end %>
|
|
26
|
+
</div>
|
|
20
27
|
|
|
21
28
|
<%= form_with url: settings_global_filters_path, method: :patch, local: true, data: { action: "submit->rails-pulse--global-filters#submit" } do |form| %>
|
|
22
29
|
<div class="flex flex-col gap mb-4">
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<% global_filters = session_global_filters %>
|
|
2
|
+
<% disabled_tags = global_filters['disabled_tags'] || [] %>
|
|
3
|
+
<% has_date_filters = global_filters['start_time'].present? && global_filters['end_time'].present? %>
|
|
4
|
+
<% has_performance_filter = global_filters['performance_threshold'].present? %>
|
|
5
|
+
<% has_tag_filters = disabled_tags.any? || session[:show_non_tagged] == false %>
|
|
6
|
+
<% has_any_filters = has_date_filters || has_performance_filter || has_tag_filters %>
|
|
7
|
+
|
|
8
|
+
<% if has_any_filters %>
|
|
9
|
+
<div class="flex items-center gap text-sm">
|
|
10
|
+
Filtered:
|
|
11
|
+
<% if has_date_filters %>
|
|
12
|
+
<% start_time = Time.parse(global_filters['start_time']) %>
|
|
13
|
+
<% end_time = Time.parse(global_filters['end_time']) %>
|
|
14
|
+
<span class="badge badge--secondary"><%= start_time.strftime("%b %d, %Y %-I:%M %p") %> - <%= end_time.strftime("%b %d, %Y %-I:%M %p") %></span>
|
|
15
|
+
<% end %>
|
|
16
|
+
|
|
17
|
+
<% if has_performance_filter %>
|
|
18
|
+
<% threshold_label = case global_filters['performance_threshold']
|
|
19
|
+
when 'slow' then 'Slow and Above'
|
|
20
|
+
when 'very_slow' then 'Very Slow and Above'
|
|
21
|
+
when 'critical' then 'Critical'
|
|
22
|
+
else global_filters['performance_threshold'].titleize
|
|
23
|
+
end %>
|
|
24
|
+
<span class="badge badge--secondary"><%= threshold_label %></span>
|
|
25
|
+
<% end %>
|
|
26
|
+
|
|
27
|
+
<% if has_tag_filters %>
|
|
28
|
+
<% disabled_tags.each do |tag| %>
|
|
29
|
+
<span class="badge badge--secondary"><%= tag.humanize %></span>
|
|
30
|
+
<% end %>
|
|
31
|
+
<% if session[:show_non_tagged] == false %>
|
|
32
|
+
<span class="badge badge--secondary">Non tagged hidden</span>
|
|
33
|
+
<% end %>
|
|
34
|
+
<% end %>
|
|
35
|
+
</div>
|
|
36
|
+
<% end %>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
trend_amount = data[:trend_amount]
|
|
10
10
|
trend_text = data[:trend_text]
|
|
11
11
|
%>
|
|
12
|
-
<div class="grid-item"
|
|
12
|
+
<div class="grid-item" id="<%= id %>">
|
|
13
13
|
<%= render 'rails_pulse/components/panel', { title: title, card_classes: 'card-compact' } do %>
|
|
14
14
|
<div class="row mbs-2" style="--columns: 2; align-items: center; margin-bottom: 0;">
|
|
15
15
|
<div class="grid-item">
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
}
|
|
39
39
|
)
|
|
40
40
|
%>
|
|
41
|
-
<%=
|
|
41
|
+
<%= render_stimulus_chart chart_data, type: 'bar', height: "100%", options: chart_options %>
|
|
42
42
|
</div>
|
|
43
43
|
</div>
|
|
44
44
|
</div>
|
|
@@ -16,5 +16,9 @@
|
|
|
16
16
|
<div class="breadcrumb-tags">
|
|
17
17
|
<%= render 'rails_pulse/tags/tag_manager', taggable: taggable %>
|
|
18
18
|
</div>
|
|
19
|
+
<% elsif defined?(show_active_filters) && show_active_filters %>
|
|
20
|
+
<div class="breadcrumb-tags">
|
|
21
|
+
<%= render 'rails_pulse/components/active_filters' %>
|
|
22
|
+
</div>
|
|
19
23
|
<% end %>
|
|
20
24
|
</div>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<h4 class="text-xl mbs-1 font-bold"><%= summary %></h4>
|
|
3
3
|
</div>
|
|
4
4
|
<div class="chart-container chart-container--slim">
|
|
5
|
-
<%=
|
|
5
|
+
<%= render_stimulus_chart chart_data, type: 'bar', height: "100%", options: sparkline_chart_options %>
|
|
6
6
|
</div>
|
|
7
7
|
<div>
|
|
8
8
|
<span class="badge badge--<%= trend_direction == "down" ? "positive" : "negative" %>-inverse p-0">
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
data-rails-pulse--pagination-url-value="<%= rails_pulse.pagination_limit_path %>">
|
|
8
8
|
<label for="pagination_limit" class="text-sm font-medium">Rows per page</label>
|
|
9
9
|
<%= select_tag :limit,
|
|
10
|
-
options_for_select([[10, 10], [20, 20], [30, 30], [40, 40], [50, 50]], @pagy
|
|
10
|
+
options_for_select([[10, 10], [20, 20], [30, 30], [40, 40], [50, 50]], pagy_items(@pagy)),
|
|
11
11
|
{
|
|
12
12
|
id: "pagination_limit",
|
|
13
13
|
class: "input",
|
|
@@ -21,22 +21,24 @@
|
|
|
21
21
|
%>
|
|
22
22
|
</div>
|
|
23
23
|
|
|
24
|
-
<div class="text-sm font-medium"><%= "Page #{@pagy.page} of #{@pagy.
|
|
24
|
+
<div class="text-sm font-medium"><%= "Page #{@pagy.page} of #{@pagy.last}" %></div>
|
|
25
25
|
|
|
26
26
|
<nav class="flex items-center gap shrink-0" style="--btn-padding: .5rem;" aria-label="Pagination">
|
|
27
|
-
|
|
27
|
+
<% previous_page = pagy_previous(@pagy) %>
|
|
28
|
+
<% next_page = pagy_next(@pagy) %>
|
|
29
|
+
<%= link_to pagy_page_url(@pagy, 1), class: "btn", aria: { disabled: previous_page.nil? }.compact_blank do %>
|
|
28
30
|
<%= rails_pulse_icon 'chevrons-left', width: '16', height: '16' %>
|
|
29
31
|
<span class="sr-only">Go to first page</span>
|
|
30
32
|
<% end %>
|
|
31
|
-
<%= link_to
|
|
33
|
+
<%= link_to pagy_page_url(@pagy, previous_page || @pagy.page), class: "btn", aria: { disabled: previous_page.nil? }.compact_blank do %>
|
|
32
34
|
<%= rails_pulse_icon 'chevron-left', width: '16', height: '16' %>
|
|
33
35
|
<span class="sr-only">Go to previous page</span>
|
|
34
36
|
<% end %>
|
|
35
|
-
<%= link_to
|
|
37
|
+
<%= link_to pagy_page_url(@pagy, next_page || @pagy.page), class: "btn", aria: { disabled: next_page.nil? }.compact_blank do %>
|
|
36
38
|
<%= rails_pulse_icon 'chevron-right', width: '16', height: '16' %>
|
|
37
39
|
<span class="sr-only">Go to next page</span>
|
|
38
40
|
<% end %>
|
|
39
|
-
<%= link_to
|
|
41
|
+
<%= link_to pagy_page_url(@pagy, @pagy.last), class: "btn", aria: { disabled: next_page.nil? }.compact_blank do %>
|
|
40
42
|
<%= rails_pulse_icon 'chevrons-right', width: '16', height: '16' %>
|
|
41
43
|
<span class="sr-only">Go to last page</span>
|
|
42
44
|
<% end %>
|
|
@@ -171,7 +171,7 @@
|
|
|
171
171
|
<div class="card">
|
|
172
172
|
<div class="p-4">
|
|
173
173
|
<h2 class="text-lg font-semibold mb-3">Chart Component Test</h2>
|
|
174
|
-
<p class="text-subtle mb-4">Testing
|
|
174
|
+
<p class="text-subtle mb-4">Testing chart CSP compliance:</p>
|
|
175
175
|
|
|
176
176
|
<div id="chart-container" class="bg-shade border border-main rounded-md p-4 text-center">
|
|
177
177
|
<span class="text-subtle">Chart components would render here in a real dashboard</span>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<%=
|
|
1
|
+
<%= render_stimulus_chart @component_data, type: 'bar', height: "100%", options: bar_chart_options(units: "ms") %>
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
<div class="flex justify-end mb-1">
|
|
2
|
+
<%= render 'rails_pulse/components/active_filters' %>
|
|
3
|
+
</div>
|
|
4
|
+
|
|
1
5
|
<div class="row">
|
|
2
6
|
<%= render 'rails_pulse/components/metric_card', { class: "grid-item block", data: @average_query_times_metric_card } %>
|
|
3
7
|
<%= render 'rails_pulse/components/metric_card', { class: "grid-item block", data: @percentile_response_times_metric_card } %>
|
|
@@ -16,9 +20,9 @@
|
|
|
16
20
|
} do %>
|
|
17
21
|
<% if @average_response_time_chart_data.present? %>
|
|
18
22
|
<div class="chart-container chart-container--slim">
|
|
19
|
-
<%=
|
|
23
|
+
<%= render_stimulus_chart(
|
|
20
24
|
@average_response_time_chart_data,
|
|
21
|
-
|
|
25
|
+
type: 'bar',
|
|
22
26
|
id: "dashboard_average_response_time_chart",
|
|
23
27
|
height: "100%",
|
|
24
28
|
options: bar_chart_options(
|
|
@@ -40,8 +44,9 @@
|
|
|
40
44
|
} do %>
|
|
41
45
|
<% if @p95_response_time_chart_data.present? %>
|
|
42
46
|
<div class="chart-container chart-container--slim">
|
|
43
|
-
<%=
|
|
47
|
+
<%= render_stimulus_chart(
|
|
44
48
|
@p95_response_time_chart_data,
|
|
49
|
+
type: 'bar',
|
|
45
50
|
code: false,
|
|
46
51
|
id: "dashboard_p95_response_time_chart",
|
|
47
52
|
height: "100%",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%= render 'rails_pulse/components/page_header' %>
|
|
1
|
+
<%= render 'rails_pulse/components/page_header', show_active_filters: true %>
|
|
2
2
|
|
|
3
3
|
<% unless turbo_frame_request? %>
|
|
4
4
|
<div class="row">
|
|
@@ -32,8 +32,9 @@
|
|
|
32
32
|
class="chart-container chart-container--slim"
|
|
33
33
|
data-rails-pulse--index-target="chart"
|
|
34
34
|
>
|
|
35
|
-
<%=
|
|
35
|
+
<%= render_stimulus_chart(
|
|
36
36
|
@chart_data,
|
|
37
|
+
type: 'bar',
|
|
37
38
|
code: false,
|
|
38
39
|
id: "average_query_times_chart",
|
|
39
40
|
height: "100%",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%= render 'rails_pulse/components/page_header' %>
|
|
1
|
+
<%= render 'rails_pulse/components/page_header', show_active_filters: true %>
|
|
2
2
|
|
|
3
3
|
<% unless turbo_frame_request? %>
|
|
4
4
|
<div class="row">
|
|
@@ -34,8 +34,9 @@
|
|
|
34
34
|
class="chart-container chart-container--slim"
|
|
35
35
|
data-rails-pulse--index-target="chart"
|
|
36
36
|
>
|
|
37
|
-
<%=
|
|
37
|
+
<%= render_stimulus_chart(
|
|
38
38
|
@chart_data,
|
|
39
|
+
type: 'bar',
|
|
39
40
|
code: false,
|
|
40
41
|
id: "average_response_times_chart",
|
|
41
42
|
height: "100%",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
>
|
|
12
12
|
<div class="tag-list">
|
|
13
13
|
<% current_tags.each do |tag| %>
|
|
14
|
-
<span class="
|
|
14
|
+
<span class="badge badge--secondary font-normal">
|
|
15
15
|
<%= tag %>
|
|
16
16
|
<%= button_to remove_tag_path(taggable_type, taggable.id, tag: tag),
|
|
17
17
|
method: :delete,
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
<button
|
|
30
30
|
type="button"
|
|
31
31
|
id="tag_menu_button_<%= taggable_type %>_<%= taggable.id %>"
|
|
32
|
-
class="
|
|
32
|
+
class="badge badge--positive tag-add-button font-normal"
|
|
33
33
|
data-rails-pulse--popover-target="button"
|
|
34
34
|
data-action="rails-pulse--popover#toggle"
|
|
35
35
|
aria-haspopup="true"
|
data/config/importmap.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
pin "application", to: "rails_pulse/application.js"
|
|
2
2
|
|
|
3
|
-
# echarts is
|
|
3
|
+
# echarts is used for chart rendering
|
|
4
4
|
pin "echarts", to: "echarts.min.js"
|
|
5
5
|
# pin "echarts/theme/inspired", to: "echarts/theme/inspired.js"
|
|
6
6
|
pin "rails_pulse/theme", to: "rails_pulse/theme.js"
|