rails_mini_profiler 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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