rails_mini_profiler 0.4.0 → 0.5.0

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/rails_mini_profiler/profiled_requests_controller.rb +13 -10
  3. data/app/javascript/images/check.svg +3 -0
  4. data/app/javascript/images/chevron.svg +3 -0
  5. data/app/javascript/images/filter.svg +1 -0
  6. data/app/javascript/images/logo_variant.svg +2 -2
  7. data/app/javascript/images/search.svg +4 -5
  8. data/app/javascript/js/checklist_controller.js +48 -0
  9. data/app/javascript/js/enable_controller.js +24 -0
  10. data/app/javascript/js/filter_controller.js +44 -0
  11. data/app/javascript/js/search_controller.js +18 -0
  12. data/app/javascript/js/select_controller.js +47 -0
  13. data/app/javascript/packs/rails-mini-profiler.js +23 -15
  14. data/app/javascript/stylesheets/components/page_header/page_header.scss +3 -0
  15. data/app/javascript/stylesheets/components/pagination.scss +14 -13
  16. data/app/javascript/stylesheets/components/profiled_request_table/placeholder.scss +33 -0
  17. data/app/javascript/stylesheets/components/profiled_request_table/profiled_request_table.scss +179 -0
  18. data/app/javascript/stylesheets/flamegraph.scss +3 -2
  19. data/app/javascript/stylesheets/flashes.scss +3 -5
  20. data/app/javascript/stylesheets/navbar.scss +7 -13
  21. data/app/javascript/stylesheets/profiled_requests.scss +35 -120
  22. data/app/javascript/stylesheets/rails-mini-profiler.scss +90 -61
  23. data/app/javascript/stylesheets/traces.scss +17 -17
  24. data/app/presenters/rails_mini_profiler/profiled_request_presenter.rb +8 -15
  25. data/app/search/rails_mini_profiler/base_search.rb +67 -0
  26. data/app/search/rails_mini_profiler/profiled_request_search.rb +34 -0
  27. data/app/views/rails_mini_profiler/badge.html.erb +2 -2
  28. data/app/views/rails_mini_profiler/profiled_requests/index.html.erb +8 -58
  29. data/app/views/rails_mini_profiler/profiled_requests/shared/header/_header.erb +20 -0
  30. data/app/views/rails_mini_profiler/profiled_requests/shared/table/_placeholder.erb +12 -0
  31. data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table.erb +14 -0
  32. data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table_head.erb +125 -0
  33. data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table_row.erb +21 -0
  34. data/app/views/rails_mini_profiler/profiled_requests/show.html.erb +1 -1
  35. data/lib/rails_mini_profiler/configuration.rb +3 -0
  36. data/lib/rails_mini_profiler/engine.rb +12 -8
  37. data/lib/rails_mini_profiler/middleware.rb +3 -3
  38. data/lib/rails_mini_profiler/tracing/controller_tracer.rb +15 -0
  39. data/lib/rails_mini_profiler/tracing/null_trace.rb +7 -0
  40. data/lib/rails_mini_profiler/tracing/sequel_tracer.rb +37 -0
  41. data/lib/rails_mini_profiler/tracing/sequel_tracker.rb +37 -0
  42. data/lib/rails_mini_profiler/tracing/subscriptions.rb +34 -0
  43. data/lib/rails_mini_profiler/{models → tracing}/trace.rb +10 -2
  44. data/lib/rails_mini_profiler/tracing/trace_factory.rb +37 -0
  45. data/lib/rails_mini_profiler/tracing/tracer.rb +31 -0
  46. data/lib/rails_mini_profiler/tracing/view_tracer.rb +12 -0
  47. data/lib/rails_mini_profiler/tracing.rb +11 -0
  48. data/lib/rails_mini_profiler/version.rb +1 -1
  49. data/lib/rails_mini_profiler.rb +4 -8
  50. data/vendor/assets/images/check.svg +3 -0
  51. data/vendor/assets/images/chevron.svg +3 -0
  52. data/vendor/assets/images/filter.svg +1 -0
  53. data/vendor/assets/images/logo_variant.svg +2 -2
  54. data/vendor/assets/images/search.svg +4 -5
  55. data/vendor/assets/javascripts/rails-mini-profiler.css +1 -1
  56. data/vendor/assets/javascripts/rails-mini-profiler.js +1 -1
  57. metadata +33 -4
  58. data/lib/rails_mini_profiler/tracers.rb +0 -85
@@ -4,96 +4,110 @@
4
4
  @import 'profiled_requests';
5
5
  @import 'traces';
6
6
  @import 'components/pagination';
7
-
7
+ @import 'components/page_header/page_header';
8
8
  @import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap');
9
9
 
10
10
  @font-face {
11
11
  font-family: 'Open Sans';
12
- font-weight: 400;
13
12
  font-style: normal;
13
+ font-weight: 400;
14
14
  }
15
15
 
16
16
  @font-face {
17
17
  font-family: 'Open Sans';
18
- font-weight: 600;
19
18
  font-style: normal;
19
+ font-weight: 600;
20
20
  }
21
21
 
22
22
  @font-face {
23
23
  font-family: 'Open Sans';
24
- font-weight: 700;
25
24
  font-style: normal;
25
+ font-weight: 700;
26
26
  }
27
27
 
28
28
  html {
29
29
  width: 100%;
30
30
  height: 100%;
31
- margin: 0;
32
31
  padding: 0;
32
+ margin: 0;
33
+ font-family: 'Open Sans', monospace;
33
34
 
34
- --grey-50: #F9FAFB;
35
- --grey-100: #F3F4F6;
36
- --grey-200: #E5E7EB;
37
- --grey-400: #9CA3AF;
38
- --grey-500: #6B7280;
35
+ --grey-50: #f9fafb;
36
+ --grey-100: #f3f4f6;
37
+ --grey-200: #e5e7eb;
38
+ --grey-400: #9ca3af;
39
+ --grey-500: #6b7280;
39
40
  --grey-700: #374151;
40
41
  --grey-900: #111827;
41
-
42
- --red-400: #F87171;
43
- --red-500: #EF4444;
44
- --red-600: #DC2626;
45
-
46
- --yellow-400: #FBBF24;
47
- --yellow-500: #F59E0B;
48
-
49
- --green-300: #6EE7B7;
50
- --green-400: #34D399;
51
- --green-500: #10B981;
52
-
53
- --blue-400: #60A5FA;
54
- --blue-500: #3B82F6;
55
-
42
+ --red-400: #f87171;
43
+ --red-500: #ef4444;
44
+ --red-600: #dc2626;
45
+ --yellow-400: #fbbf24;
46
+ --yellow-500: #fbbf24;
47
+ --yellow-600: #d97706;
48
+ --yellow-700: #b45309;
49
+ --green-300: #6ee7b7;
50
+ --green-400: #34d399;
51
+ --green-500: #10b981;
52
+ --blue-400: #60a5fa;
53
+ --blue-500: #3b82f6;
56
54
  --main-width: 1056px;
57
-
58
55
  --primary: var(--red-600);
59
-
60
56
  --border-color: var(--grey-200);
61
57
  --text-color: var(--grey-900);
58
+ }
62
59
 
63
- font-family: 'Open Sans', monospace;
64
-
60
+ * {
61
+ padding: 0;
62
+ margin: 0;
65
63
  }
66
64
 
67
65
  body {
68
66
  width: 100%;
69
67
  height: 100%;
70
- margin: 0;
71
68
  padding: 0;
72
-
73
- color: var(--text-color)
74
- }
75
-
76
- h1 {
77
- padding: 2rem 0 1rem;
69
+ margin: 0;
70
+ color: var(--text-color);
78
71
  }
79
72
 
80
- button {
73
+ button,
74
+ .button {
75
+ display: inline-block;
76
+ padding: 0.5em 0.5em;
81
77
  border: none;
82
- border-radius: .25rem;
83
- padding: 0.5em .5em;
78
+ border-radius: 0.25rem;
79
+ cursor: pointer;
80
+ font-size: 1rem;
84
81
  text-align: center;
85
82
  text-decoration: none;
86
- display: inline-block;
87
- font-size: 1rem;
88
- cursor: pointer;
83
+
84
+ &:disabled {
85
+ background: var(--grey-200);
86
+ cursor: not-allowed;
87
+ }
89
88
  }
90
89
 
91
90
  button:hover {
92
- box-shadow: 0 .25rem .25rem 0 var(--grey-50);
91
+ box-shadow: 0 0.25rem 0.25rem 0 var(--grey-50);
92
+ }
93
+
94
+ button.none {
95
+ padding: 0;
96
+ border: none;
97
+ background: none;
98
+ outline: none;
99
+
100
+ &:hover {
101
+ box-shadow: none;
102
+ }
93
103
  }
94
104
 
95
105
  /* --------------------------------------- */
96
106
 
107
+ .text-center {
108
+ text-align: center;
109
+ }
110
+
97
111
  .text-left {
98
112
  text-align: left;
99
113
  }
@@ -102,49 +116,61 @@ button:hover {
102
116
  text-align: right;
103
117
  }
104
118
 
119
+ .hidden {
120
+ display: none;
121
+ }
122
+
123
+ .flex-row {
124
+ display: flex;
125
+ flex-direction: row;
126
+ }
127
+
128
+ .flex-column {
129
+ display: flex;
130
+ flex-direction: column;
131
+ }
132
+
105
133
  /* --------------------------------------- */
106
134
 
107
135
  .pill {
108
- margin: .2rem 0;
109
- padding: .1rem .4rem;
136
+ padding: 0.1rem 0.4rem;
137
+ margin: 0.2rem 0;
138
+ background: var(--grey-200);
110
139
  border-radius: 5px;
111
-
112
- font-size: .9rem;
140
+ font-size: 0.9rem;
113
141
  font-weight: 600;
114
- letter-spacing: .1rem;
115
-
116
- background: var(--grey-200);
142
+ letter-spacing: 0.1rem;
117
143
  }
118
144
 
119
145
  /* --------------------------------------- */
120
146
 
121
147
  .popover {
122
148
  display: flex;
123
- flex-direction: column;
124
149
  width: 600px;
150
+ flex-direction: column;
125
151
  padding: 1em;
126
152
  color: black;
127
153
  }
128
154
 
129
155
  .popover-header {
130
156
  display: flex;
131
- padding-bottom: 1em;
132
157
  flex-direction: row;
133
- justify-content: space-between;
134
158
  align-items: center;
159
+ justify-content: space-between;
160
+ padding-bottom: 1em;
135
161
  }
136
162
 
137
163
  .popover-description {
138
- margin: 0;
139
164
  padding: 0;
165
+ margin: 0;
140
166
  }
141
167
 
142
168
  .popover-close {
143
- background: transparent;
144
169
  padding: 0;
145
- font-weight: 700;
146
- font-size: 20px;
170
+ background: transparent;
147
171
  color: var(--grey-400);
172
+ font-size: 20px;
173
+ font-weight: 700;
148
174
  }
149
175
 
150
176
  .popover-body {
@@ -157,20 +183,23 @@ button:hover {
157
183
 
158
184
  .tippy-box[data-theme~='rmp'] {
159
185
  background: white;
160
- box-shadow: 8px 0 30px 4px rgba(0, 0, 0, .2), 8px 4px 10px 0 rgba(0, 0, 0, .05);
161
- border-radius: 3px;
162
-
163
- transition: all cubic-bezier(.19,1,.22,1) .2s;
186
+ border-radius: 5px;
187
+ box-shadow: 8px 0 30px 4px rgba(0, 0, 0, 0.2), 8px 4px 10px 0 rgba(0, 0, 0, 0.05);
188
+ transition: all cubic-bezier(0.19, 1, 0.22, 1) 0.2s;
164
189
  }
190
+
165
191
  .tippy-box[data-theme~='rmp'][data-placement^='top'] > .tippy-arrow::before {
166
192
  border-top-color: white;
167
193
  }
194
+
168
195
  .tippy-box[data-theme~='rmp'][data-placement^='bottom'] > .tippy-arrow::before {
169
196
  border-bottom-color: white;
170
197
  }
198
+
171
199
  .tippy-box[data-theme~='rmp'][data-placement^='left'] > .tippy-arrow::before {
172
200
  border-left-color: white;
173
201
  }
202
+
174
203
  .tippy-box[data-theme~='rmp'][data-placement^='right'] > .tippy-arrow::before {
175
204
  border-right-color: white;
176
205
  }
@@ -1,14 +1,14 @@
1
1
  .trace-list {
2
- margin: 0;
3
2
  padding: 0;
3
+ margin: 0;
4
4
  }
5
5
 
6
6
  .trace {
7
- list-style: none;
8
7
  display: flex;
9
- padding: .25em 0;
10
8
  align-items: center;
11
9
  justify-content: flex-start;
10
+ padding: 0.25em 0;
11
+ list-style: none;
12
12
  }
13
13
 
14
14
  .trace:nth-child(odd) {
@@ -17,11 +17,11 @@
17
17
 
18
18
  .trace .trace-bar {
19
19
  position: relative;
20
- margin: 0;
21
20
  height: 16px;
22
21
  padding: 0;
23
- cursor: pointer;
22
+ margin: 0;
24
23
  background: linear-gradient(to top right, var(--grey-500), var(--grey-400));
24
+ cursor: pointer;
25
25
  }
26
26
 
27
27
  .instantiation-trace .trace-bar {
@@ -42,14 +42,14 @@
42
42
  }
43
43
 
44
44
  .trace-name {
45
- margin: 0;
46
- box-sizing: border-box;
47
- padding: 0 .5em;
48
45
  overflow: hidden;
46
+ box-sizing: border-box;
47
+ padding: 0 0.5em;
48
+ margin: 0;
49
+ color: var(--grey-400);
49
50
  font-size: 14px;
50
51
  text-align: right;
51
52
  text-overflow: ellipsis;
52
- color: var(--grey-400)
53
53
  }
54
54
 
55
55
  .trace-payload {
@@ -57,26 +57,26 @@
57
57
  }
58
58
 
59
59
  .sequel-trace-query {
60
- padding: 1em 1em;
61
- background: var(--grey-100);
62
60
  overflow: auto;
63
61
  max-height: 100px;
62
+ padding: 1em 1em;
63
+ background: var(--grey-100);
64
64
  white-space: pre-wrap;
65
65
  }
66
66
 
67
67
  .sequel-trace-binds {
68
- margin: 0 0 1em 0;
69
- padding: .5em 1em;
70
- font-size: 12px;
71
68
  overflow: auto;
72
69
  max-height: 100px;
73
- white-space: pre-wrap;
70
+ padding: 0.5em 1em;
71
+ margin: 0 0 1em 0;
74
72
  background: var(--grey-50);
73
+ font-size: 12px;
74
+ white-space: pre-wrap;
75
75
  }
76
76
 
77
77
  .trace-table {
78
- margin-top: 1em;
79
78
  width: 100%;
80
- border-collapse: collapse;
81
79
  border: hidden 1px var(--border-color);
80
+ margin-top: 1em;
81
+ border-collapse: collapse;
82
82
  }
@@ -15,21 +15,14 @@ module RailsMiniProfiler
15
15
  end
16
16
 
17
17
  def created_at
18
- time_tag(model.created_at.in_time_zone(Time.zone))
19
- end
20
-
21
- def flamegraph_icon
22
- return nil unless RailsMiniProfiler.configuration.flamegraph_enabled
23
-
24
- if model.flamegraph.present?
25
- link_to(flamegraph_path(model.id), title: 'Show Flamegraph') do
26
- inline_svg('graph.svg')
27
- end
28
- else
29
- link_to(flamegraph_path(model.id), title: 'No Flamegraph present for this request', class: 'link-disabled') do
30
- inline_svg('graph.svg')
31
- end
32
- end
18
+ from_time = Time.now
19
+ created_at = model.created_at.in_time_zone(Time.zone)
20
+ distance = if from_time - created_at < 5.minutes
21
+ 'Now'
22
+ else
23
+ "#{distance_of_time_in_words(from_time, created_at)} ago"
24
+ end
25
+ time_tag(created_at) { content_tag('span', distance) }
33
26
  end
34
27
 
35
28
  def flamegraph_button
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsMiniProfiler
4
+ class BaseSearch
5
+ def initialize(params = nil, **kwargs)
6
+ config = self.class.config
7
+ options = params&.to_h || {}
8
+ options = options.merge(kwargs)
9
+ @scope = options.delete(:scope) || (config[:scope] && instance_eval(&config[:scope]))
10
+ @options = (options.delete(:options) || config[:options]).stringify_keys
11
+ @params = options.stringify_keys.slice(*@options.keys)
12
+ end
13
+
14
+ def results
15
+ @results ||= apply
16
+ end
17
+
18
+ def results?
19
+ results.any?
20
+ end
21
+
22
+ class << self
23
+ def scope(&block)
24
+ config[:scope] = block
25
+ end
26
+
27
+ def option(name, options = {}, &block)
28
+ name = name.to_s
29
+ handler = options[:with] || block
30
+
31
+ config[:options][name] = normalize_search_handler(handler, name)
32
+
33
+ define_method(name) { @search.param name }
34
+ end
35
+
36
+ def results(**kwargs)
37
+ new(**kwargs).results
38
+ end
39
+
40
+ def config
41
+ @config ||= { options: {} }
42
+ end
43
+
44
+ private
45
+
46
+ def normalize_search_handler(handler, name)
47
+ case handler
48
+ when Symbol
49
+ ->(scope, value) { method(handler).call scope, value }
50
+ when Proc
51
+ handler
52
+ else
53
+ ->(scope, value) { scope.where name => value unless value.blank? }
54
+ end
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def apply
61
+ @params.inject(@scope) do |scope, (name, value)|
62
+ new_scope = instance_exec scope, value, &@options[name]
63
+ new_scope || scope
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsMiniProfiler
4
+ class ProfiledRequestSearch < BaseSearch
5
+ option(:id) do |scope, value|
6
+ scope.where(id: value)
7
+ end
8
+
9
+ option(:path) do |scope, value|
10
+ scope.where('request_path LIKE ?', "%#{value}%")
11
+ end
12
+
13
+ option(:method) do |scope, value|
14
+ scope.where(request_method: value)
15
+ end
16
+
17
+ option(:media_type) do |scope, value|
18
+ scope.where(response_media_type: value)
19
+ end
20
+
21
+ option(:status) do |scope, value|
22
+ value = value.map(&:to_i)
23
+ min = value.min
24
+ max = value.max + 100
25
+ scope.where('response_status >= :lower', lower: min)
26
+ .where('response_status < :upper', upper: max)
27
+ end
28
+
29
+ option(:duration) do |scope, value|
30
+ value = value.tr('>', '').to_i * 100
31
+ scope.where('duration > :duration', duration: value)
32
+ end
33
+ end
34
+ end