rails_pulse 0.1.4 → 0.2.2
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 +78 -0
- data/Rakefile +152 -3
- data/app/assets/images/rails_pulse/rails-pulse-logo.png +0 -0
- data/app/assets/stylesheets/rails_pulse/components/datepicker.css +191 -0
- data/app/assets/stylesheets/rails_pulse/components/switch.css +36 -0
- data/app/assets/stylesheets/rails_pulse/components/tags.css +98 -0
- data/app/assets/stylesheets/rails_pulse/components/utilities.css +26 -0
- data/app/controllers/concerns/response_range_concern.rb +15 -2
- data/app/controllers/concerns/tag_filter_concern.rb +26 -0
- data/app/controllers/concerns/time_range_concern.rb +27 -8
- data/app/controllers/rails_pulse/application_controller.rb +73 -0
- data/app/controllers/rails_pulse/queries_controller.rb +4 -1
- data/app/controllers/rails_pulse/requests_controller.rb +40 -8
- data/app/controllers/rails_pulse/routes_controller.rb +4 -2
- data/app/controllers/rails_pulse/tags_controller.rb +51 -0
- data/app/helpers/rails_pulse/application_helper.rb +2 -0
- data/app/helpers/rails_pulse/form_helper.rb +75 -0
- data/app/helpers/rails_pulse/tags_helper.rb +29 -0
- data/app/javascript/rails_pulse/application.js +6 -0
- data/app/javascript/rails_pulse/controllers/custom_range_controller.js +115 -0
- data/app/javascript/rails_pulse/controllers/datepicker_controller.js +48 -0
- data/app/javascript/rails_pulse/controllers/global_filters_controller.js +110 -0
- data/app/models/concerns/taggable.rb +61 -0
- data/app/models/rails_pulse/queries/tables/index.rb +10 -2
- data/app/models/rails_pulse/query.rb +2 -0
- data/app/models/rails_pulse/request.rb +9 -1
- data/app/models/rails_pulse/route.rb +2 -0
- data/app/models/rails_pulse/routes/tables/index.rb +10 -2
- data/app/services/rails_pulse/summary_service.rb +2 -0
- data/app/views/layouts/rails_pulse/_global_filters.html.erb +84 -0
- data/app/views/layouts/rails_pulse/_menu_items.html.erb +5 -5
- data/app/views/layouts/rails_pulse/application.html.erb +8 -5
- data/app/views/rails_pulse/components/_page_header.html.erb +20 -0
- data/app/views/rails_pulse/operations/show.html.erb +1 -1
- data/app/views/rails_pulse/queries/_table.html.erb +3 -1
- data/app/views/rails_pulse/queries/index.html.erb +3 -7
- data/app/views/rails_pulse/queries/show.html.erb +3 -7
- data/app/views/rails_pulse/requests/_table.html.erb +3 -1
- data/app/views/rails_pulse/requests/index.html.erb +44 -62
- data/app/views/rails_pulse/requests/show.html.erb +1 -1
- data/app/views/rails_pulse/routes/_requests_table.html.erb +3 -1
- data/app/views/rails_pulse/routes/_table.html.erb +3 -1
- data/app/views/rails_pulse/routes/index.html.erb +4 -8
- data/app/views/rails_pulse/routes/show.html.erb +3 -7
- data/app/views/rails_pulse/tags/_tag_manager.html.erb +73 -0
- data/config/routes.rb +5 -0
- data/db/rails_pulse_schema.rb +3 -0
- data/lib/generators/rails_pulse/install_generator.rb +21 -2
- data/lib/generators/rails_pulse/templates/db/rails_pulse_schema.rb +3 -0
- data/lib/generators/rails_pulse/templates/rails_pulse.rb +21 -0
- data/lib/generators/rails_pulse/upgrade_generator.rb +145 -29
- data/lib/rails_pulse/configuration.rb +16 -1
- data/lib/rails_pulse/version.rb +1 -1
- data/public/rails-pulse-assets/rails-pulse-icons.js +16 -15
- data/public/rails-pulse-assets/rails-pulse-icons.js.map +1 -1
- 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 +73 -69
- data/public/rails-pulse-assets/rails-pulse.js.map +4 -4
- metadata +17 -3
- data/app/views/rails_pulse/components/_breadcrumbs.html.erb +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8ed469f307dd71e912b46a4da0a0daa60abbdc262a8dbd12604db00a66335fe
|
4
|
+
data.tar.gz: 8af5a6bf946a86e1bc277c1d719100ace739bb429c07969fd1e4ec31887d6f70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eceb3af7e713b6049688e50a8fd79af7b2f09c7720158c8d15257235b0c7488ebe7c0eccfaab3cd5dfb5923f80e9a8bd8693d0a9fb2f4e021aca8846c4ac435c
|
7
|
+
data.tar.gz: f982a50256d99968eb68fee89e6380d3f75511e6c3e8e878ddca375919f6a68a201f9ce46c6868e2425c127ae1862ca0d1895b0e01afea89a9af6a4e85d7f0f9
|
data/README.md
CHANGED
@@ -25,6 +25,10 @@
|
|
25
25
|
- [Authentication](#authentication)
|
26
26
|
- [Authentication Setup](#authentication-setup)
|
27
27
|
- [Authentication Examples](#authentication-examples)
|
28
|
+
- [Tagging System](#tagging-system)
|
29
|
+
- [Configuring Tags](#configuring-tags)
|
30
|
+
- [Using Tags](#using-tags)
|
31
|
+
- [Filtering by Tags](#filtering-by-tags)
|
28
32
|
- [Data Management](#data-management)
|
29
33
|
- [Cleanup Strategies](#cleanup-strategies)
|
30
34
|
- [Cleanup Configuration](#cleanup-configuration)
|
@@ -58,6 +62,11 @@ Rails Pulse is a comprehensive performance monitoring and debugging gem that pro
|
|
58
62
|
- Smart caching with minimal performance overhead
|
59
63
|
- Multiple database support (SQLite, PostgreSQL, MySQL)
|
60
64
|
|
65
|
+
### Organization & Filtering
|
66
|
+
- Flexible tagging system for routes, requests, and queries
|
67
|
+
- Filter performance data by custom tags
|
68
|
+
- Organize monitoring data by environment, priority, or custom categories
|
69
|
+
|
61
70
|
## Screenshots
|
62
71
|
|
63
72
|
<table>
|
@@ -176,6 +185,9 @@ RailsPulse.configure do |config|
|
|
176
185
|
config.ignored_requests = [] # Array of request patterns to ignore
|
177
186
|
config.ignored_queries = [] # Array of query patterns to ignore
|
178
187
|
|
188
|
+
# Tagging system - define available tags for categorizing performance data
|
189
|
+
config.tags = ["production", "staging", "critical", "needs-optimization"]
|
190
|
+
|
179
191
|
# Data cleanup
|
180
192
|
config.archiving_enabled = true # Enable automatic cleanup
|
181
193
|
config.full_retention_period = 2.weeks # Delete records older than this
|
@@ -243,6 +255,72 @@ config.authentication_method = proc {
|
|
243
255
|
}
|
244
256
|
```
|
245
257
|
|
258
|
+
## Tagging System
|
259
|
+
|
260
|
+
Rails Pulse includes a flexible tagging system that allows you to categorize and organize your performance data. Tag routes, requests, and queries with custom labels to better organize and filter your monitoring data.
|
261
|
+
|
262
|
+
### Configuring Tags
|
263
|
+
|
264
|
+
Define available tags in your Rails Pulse initializer:
|
265
|
+
|
266
|
+
```ruby
|
267
|
+
RailsPulse.configure do |config|
|
268
|
+
config.tags = [
|
269
|
+
"production",
|
270
|
+
"staging",
|
271
|
+
"critical",
|
272
|
+
"needs-optimization",
|
273
|
+
"high-traffic",
|
274
|
+
"background-job"
|
275
|
+
]
|
276
|
+
end
|
277
|
+
```
|
278
|
+
|
279
|
+
### Using Tags
|
280
|
+
|
281
|
+
**Tag from the UI:**
|
282
|
+
|
283
|
+
1. Navigate to any route, request, or query detail page
|
284
|
+
2. Click the "+ tag" button next to the record
|
285
|
+
3. Select from your configured tags
|
286
|
+
4. Remove tags by clicking the × button on any tag badge
|
287
|
+
|
288
|
+
**Tag Programmatically:**
|
289
|
+
|
290
|
+
```ruby
|
291
|
+
# Tag a route
|
292
|
+
route = RailsPulse::Route.find_by(path: "/api/users")
|
293
|
+
route.add_tag("critical")
|
294
|
+
route.add_tag("high-traffic")
|
295
|
+
|
296
|
+
# Tag a query
|
297
|
+
query = RailsPulse::Query.find_by(normalized_sql: "SELECT * FROM users WHERE id = ?")
|
298
|
+
query.add_tag("needs-optimization")
|
299
|
+
|
300
|
+
# Remove a tag
|
301
|
+
route.remove_tag("critical")
|
302
|
+
|
303
|
+
# Check if has tag
|
304
|
+
route.has_tag?("production") # => true
|
305
|
+
```
|
306
|
+
|
307
|
+
### Filtering by Tags
|
308
|
+
|
309
|
+
Use the global filters modal to filter performance data by tags:
|
310
|
+
|
311
|
+
1. Click the filter icon in the top navigation
|
312
|
+
2. Select one or more tags from the tag selector
|
313
|
+
3. Apply filters to see only records with those tags
|
314
|
+
4. Tags appear as badges in all data tables for quick visual identification
|
315
|
+
|
316
|
+
**Common Tagging Strategies:**
|
317
|
+
|
318
|
+
- **By Environment**: `production`, `staging`, `development`
|
319
|
+
- **By Priority**: `critical`, `high`, `medium`, `low`
|
320
|
+
- **By Status**: `needs-optimization`, `investigating`, `resolved`
|
321
|
+
- **By Type**: `api`, `background-job`, `user-facing`, `admin`
|
322
|
+
- **By Team**: `team-frontend`, `team-backend`, `team-data`
|
323
|
+
|
246
324
|
## Data Management
|
247
325
|
|
248
326
|
Rails Pulse provides data cleanup to prevent your monitoring database from growing indefinitely while preserving essential performance insights.
|
data/Rakefile
CHANGED
@@ -85,7 +85,7 @@ task :test do
|
|
85
85
|
puts "=" * 50
|
86
86
|
puts
|
87
87
|
|
88
|
-
sh "rails test test/controllers test/helpers test/instrumentation test/jobs test/models test/services
|
88
|
+
sh "rails test test/controllers test/helpers test/instrumentation test/jobs test/models test/services"
|
89
89
|
end
|
90
90
|
|
91
91
|
desc "Setup database for specific Rails version and database"
|
@@ -137,10 +137,16 @@ task :test_matrix do
|
|
137
137
|
total_combinations = databases.size * rails_versions.size
|
138
138
|
current = 0
|
139
139
|
|
140
|
+
# Check if system tests should be included
|
141
|
+
include_system_tests = ENV['BROWSER'] == 'true'
|
142
|
+
test_paths = "test/controllers test/helpers test/instrumentation test/jobs test/models test/services"
|
143
|
+
test_paths += " test/system" if include_system_tests
|
144
|
+
|
140
145
|
puts "\n" + "=" * 60
|
141
146
|
puts "🚀 Rails Pulse Full Test Matrix"
|
142
147
|
puts "=" * 60
|
143
148
|
puts "Testing #{total_combinations} combinations..."
|
149
|
+
puts "System tests: #{include_system_tests ? 'ENABLED (BROWSER=true)' : 'DISABLED (headless mode)'}"
|
144
150
|
puts "=" * 60
|
145
151
|
|
146
152
|
databases.each do |database|
|
@@ -158,10 +164,10 @@ task :test_matrix do
|
|
158
164
|
# Then run the tests
|
159
165
|
if rails_version == "rails-8-0" && database == "sqlite3"
|
160
166
|
# Current default setup
|
161
|
-
sh "
|
167
|
+
sh "BROWSER=#{ENV['BROWSER']} rails test #{test_paths}"
|
162
168
|
else
|
163
169
|
# Use appraisal with specific database
|
164
|
-
sh "DB=#{database} bundle exec appraisal #{rails_version}
|
170
|
+
sh "DB=#{database} BROWSER=#{ENV['BROWSER']} bundle exec appraisal #{rails_version} rails test #{test_paths}"
|
165
171
|
end
|
166
172
|
|
167
173
|
puts "✅ PASSED: #{database} + #{rails_version}"
|
@@ -188,5 +194,148 @@ task :test_matrix do
|
|
188
194
|
end
|
189
195
|
end
|
190
196
|
|
197
|
+
desc "Pre-release testing with comprehensive checks"
|
198
|
+
task :test_release do
|
199
|
+
puts "\n" + "=" * 70
|
200
|
+
puts "🚀 Rails Pulse Pre-Release Validation"
|
201
|
+
puts "=" * 70
|
202
|
+
puts
|
203
|
+
|
204
|
+
failed_tasks = []
|
205
|
+
current_step = 0
|
206
|
+
total_steps = 7
|
207
|
+
|
208
|
+
# Step 1: Git status check
|
209
|
+
current_step += 1
|
210
|
+
begin
|
211
|
+
puts "\n[#{current_step}/#{total_steps}] Checking git status..."
|
212
|
+
puts "-" * 70
|
213
|
+
|
214
|
+
git_status = `git status --porcelain`.strip
|
215
|
+
if !git_status.empty?
|
216
|
+
puts "❌ Git working directory is not clean!"
|
217
|
+
puts "\nUncommitted changes:"
|
218
|
+
puts git_status
|
219
|
+
puts "\nPlease commit or stash your changes before running pre-release tests."
|
220
|
+
failed_tasks << "git_status_check"
|
221
|
+
else
|
222
|
+
puts "✅ Git working directory is clean"
|
223
|
+
end
|
224
|
+
rescue => e
|
225
|
+
puts "⚠️ Warning: Could not check git status (#{e.message})"
|
226
|
+
end
|
227
|
+
|
228
|
+
# Step 2: RuboCop linting
|
229
|
+
current_step += 1
|
230
|
+
begin
|
231
|
+
puts "\n[#{current_step}/#{total_steps}] Running RuboCop linting..."
|
232
|
+
puts "-" * 70
|
233
|
+
sh "bundle exec rubocop"
|
234
|
+
puts "✅ Code style checks passed!"
|
235
|
+
rescue => e
|
236
|
+
puts "❌ RuboCop linting failed!"
|
237
|
+
puts " Error: #{e.message}"
|
238
|
+
failed_tasks << "rubocop"
|
239
|
+
end
|
240
|
+
|
241
|
+
# Step 3: Install Node dependencies
|
242
|
+
current_step += 1
|
243
|
+
begin
|
244
|
+
puts "\n[#{current_step}/#{total_steps}] Installing Node dependencies..."
|
245
|
+
puts "-" * 70
|
246
|
+
sh "npm install"
|
247
|
+
puts "✅ Node dependencies installed!"
|
248
|
+
rescue => e
|
249
|
+
puts "❌ npm install failed!"
|
250
|
+
puts " Error: #{e.message}"
|
251
|
+
failed_tasks << "npm_install"
|
252
|
+
end
|
253
|
+
|
254
|
+
# Step 4: Build and verify assets
|
255
|
+
current_step += 1
|
256
|
+
begin
|
257
|
+
puts "\n[#{current_step}/#{total_steps}] Building production assets..."
|
258
|
+
puts "-" * 70
|
259
|
+
sh "npm run build"
|
260
|
+
|
261
|
+
# Verify assets were built
|
262
|
+
assets_dir = "public/rails-pulse-assets"
|
263
|
+
if Dir.exist?(assets_dir) && !Dir.empty?(assets_dir)
|
264
|
+
puts "✅ Assets built successfully!"
|
265
|
+
puts " Location: #{assets_dir}"
|
266
|
+
else
|
267
|
+
puts "❌ Assets directory is missing or empty!"
|
268
|
+
failed_tasks << "asset_build_verification"
|
269
|
+
end
|
270
|
+
rescue => e
|
271
|
+
puts "❌ Asset building failed!"
|
272
|
+
puts " Error: #{e.message}"
|
273
|
+
failed_tasks << "npm_build"
|
274
|
+
end
|
275
|
+
|
276
|
+
# Step 5: Verify gem builds
|
277
|
+
current_step += 1
|
278
|
+
begin
|
279
|
+
puts "\n[#{current_step}/#{total_steps}] Verifying gem builds correctly..."
|
280
|
+
puts "-" * 70
|
281
|
+
sh "gem build rails_pulse.gemspec"
|
282
|
+
|
283
|
+
# Clean up the built gem
|
284
|
+
built_gems = Dir.glob("rails_pulse-*.gem")
|
285
|
+
built_gems.each { |gem_file| File.delete(gem_file) }
|
286
|
+
|
287
|
+
puts "✅ Gem builds successfully!"
|
288
|
+
rescue => e
|
289
|
+
puts "❌ Gem build failed!"
|
290
|
+
puts " Error: #{e.message}"
|
291
|
+
failed_tasks << "gem_build"
|
292
|
+
end
|
293
|
+
|
294
|
+
# Step 6: Run generator tests
|
295
|
+
current_step += 1
|
296
|
+
begin
|
297
|
+
puts "\n[#{current_step}/#{total_steps}] Running generator tests..."
|
298
|
+
puts "-" * 70
|
299
|
+
sh "./bin/test_generators"
|
300
|
+
puts "✅ Generator tests passed!"
|
301
|
+
rescue => e
|
302
|
+
puts "❌ Generator tests failed!"
|
303
|
+
puts " Error: #{e.message}"
|
304
|
+
failed_tasks << "test_generators"
|
305
|
+
end
|
306
|
+
|
307
|
+
# Step 7: Run full test matrix with system tests
|
308
|
+
current_step += 1
|
309
|
+
begin
|
310
|
+
puts "\n[#{current_step}/#{total_steps}] Running full test matrix with system tests..."
|
311
|
+
puts "-" * 70
|
312
|
+
sh "BROWSER=true rake test_matrix"
|
313
|
+
puts "✅ Test matrix passed!"
|
314
|
+
rescue => e
|
315
|
+
puts "❌ Test matrix failed!"
|
316
|
+
puts " Error: #{e.message}"
|
317
|
+
failed_tasks << "test_matrix"
|
318
|
+
end
|
319
|
+
|
320
|
+
# Print final results
|
321
|
+
puts "\n" + "=" * 70
|
322
|
+
puts "🏁 Pre-Release Validation Results"
|
323
|
+
puts "=" * 70
|
324
|
+
|
325
|
+
if failed_tasks.empty?
|
326
|
+
puts "🎉 All pre-release checks passed!"
|
327
|
+
puts "\n✅ Ready for release!"
|
328
|
+
puts "\nNext steps:"
|
329
|
+
puts " 1. Update version in lib/rails_pulse/version.rb"
|
330
|
+
puts " 2. Update Gemfile.lock files for all Rails versions"
|
331
|
+
puts " 3. Follow the release process in docs/releasing.md"
|
332
|
+
else
|
333
|
+
puts "❌ Failed checks (#{failed_tasks.size}/#{total_steps}):"
|
334
|
+
failed_tasks.each { |task| puts " • #{task}" }
|
335
|
+
puts "\n⚠️ Fix these issues before releasing."
|
336
|
+
exit 1
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
191
340
|
|
192
341
|
task default: :test
|
Binary file
|
@@ -0,0 +1,191 @@
|
|
1
|
+
@import url("https://esm.sh/flatpickr@4.6.13/dist/flatpickr.min.css");
|
2
|
+
|
3
|
+
.flatpickr-calendar {
|
4
|
+
--calendar-size: 250px;
|
5
|
+
--container-size: 220px;
|
6
|
+
--day-size: var(--size-8);
|
7
|
+
|
8
|
+
background: var(--color-bg);
|
9
|
+
border: 1px solid var(--color-border);
|
10
|
+
border-radius: var(--rounded-md);
|
11
|
+
box-shadow: var(--shadow-md);
|
12
|
+
font-size: var(--text-sm);
|
13
|
+
inline-size: var(--calendar-size);
|
14
|
+
|
15
|
+
.flatpickr-innerContainer {
|
16
|
+
justify-content: center;
|
17
|
+
padding-block-end: var(--size-3);
|
18
|
+
}
|
19
|
+
|
20
|
+
.flatpickr-days {
|
21
|
+
inline-size: var(--container-size);
|
22
|
+
}
|
23
|
+
|
24
|
+
.dayContainer {
|
25
|
+
inline-size: var(--container-size);
|
26
|
+
min-inline-size: var(--container-size);
|
27
|
+
max-inline-size: var(--container-size);
|
28
|
+
}
|
29
|
+
|
30
|
+
.dayContainer + .dayContainer {
|
31
|
+
box-shadow: -1px 0 0 var(--color-border);
|
32
|
+
}
|
33
|
+
|
34
|
+
.flatpickr-months {
|
35
|
+
.flatpickr-month {
|
36
|
+
color: var(--color-text);
|
37
|
+
}
|
38
|
+
|
39
|
+
span.cur-month {
|
40
|
+
font-size: var(--text-sm);
|
41
|
+
font-weight: var(--font-medium);
|
42
|
+
}
|
43
|
+
|
44
|
+
svg {
|
45
|
+
fill: var(--color-border-dark);
|
46
|
+
}
|
47
|
+
|
48
|
+
.flatpickr-prev-month:hover svg {
|
49
|
+
fill: var(--color-text);
|
50
|
+
}
|
51
|
+
|
52
|
+
.flatpickr-next-month:hover svg {
|
53
|
+
fill: var(--color-text);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
.flatpickr-monthDropdown-months {
|
58
|
+
appearance: none;
|
59
|
+
border-radius: var(--rounded-md);
|
60
|
+
font-size: var(--text-sm);
|
61
|
+
font-weight: var(--font-medium);
|
62
|
+
line-height: var(--leading-normal);
|
63
|
+
padding: 0;
|
64
|
+
text-align: center;
|
65
|
+
|
66
|
+
&:hover {
|
67
|
+
background: var(--color-border-light);
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
.numInputWrapper {
|
72
|
+
input {
|
73
|
+
border-radius: var(--rounded-md);
|
74
|
+
color: var(--color-text);
|
75
|
+
font-size: var(--text-sm);
|
76
|
+
font-weight: var(--font-medium);
|
77
|
+
line-height: var(--leading-normal);
|
78
|
+
padding: 0;
|
79
|
+
text-align: center;
|
80
|
+
}
|
81
|
+
|
82
|
+
span {
|
83
|
+
border-color: var(--color-border);
|
84
|
+
}
|
85
|
+
|
86
|
+
span:hover {
|
87
|
+
background: transparent;
|
88
|
+
}
|
89
|
+
|
90
|
+
span.arrowUp::after {
|
91
|
+
border-bottom-color: var(--color-text);
|
92
|
+
}
|
93
|
+
|
94
|
+
span.arrowDown::after {
|
95
|
+
border-top-color: var(--color-text);
|
96
|
+
}
|
97
|
+
|
98
|
+
&:hover {
|
99
|
+
background: transparent;
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
.flatpickr-weekday {
|
104
|
+
color: var(--color-text-subtle);
|
105
|
+
font-weight: var(--font-normal);
|
106
|
+
}
|
107
|
+
|
108
|
+
.flatpickr-time {
|
109
|
+
.hasTime & {
|
110
|
+
border-top-color: var(--color-border);
|
111
|
+
}
|
112
|
+
|
113
|
+
.hasTime.noCalendar & {
|
114
|
+
border: 0;
|
115
|
+
}
|
116
|
+
|
117
|
+
.numInput {
|
118
|
+
background: transparent;
|
119
|
+
color: var(--color-text);
|
120
|
+
}
|
121
|
+
|
122
|
+
.flatpickr-time-separator {
|
123
|
+
color: var(--color-text);
|
124
|
+
}
|
125
|
+
|
126
|
+
.flatpickr-am-pm {
|
127
|
+
background: transparent;
|
128
|
+
color: var(--color-text);
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
.flatpickr-day {
|
133
|
+
border-radius: var(--rounded-md);
|
134
|
+
border-color: transparent !important;
|
135
|
+
box-shadow: none !important;
|
136
|
+
color: var(--color-text);
|
137
|
+
height: var(--day-size);
|
138
|
+
line-height: var(--day-size);
|
139
|
+
margin-block-start: var(--size-2);
|
140
|
+
max-width: var(--day-size);
|
141
|
+
|
142
|
+
&:is(.inRange) {
|
143
|
+
border-radius: 0;
|
144
|
+
}
|
145
|
+
|
146
|
+
&:is(.today, .inRange, :hover, :focus) {
|
147
|
+
background: var(--color-secondary);
|
148
|
+
color: var(--color-text);
|
149
|
+
}
|
150
|
+
|
151
|
+
&:is(
|
152
|
+
.flatpickr-disabled,
|
153
|
+
.flatpickr-disabled:hover,
|
154
|
+
.prevMonthDay,
|
155
|
+
.nextMonthDay,
|
156
|
+
.notAllowed,
|
157
|
+
.notAllowed.prevMonthDay,
|
158
|
+
.notAllowed.nextMonthDay
|
159
|
+
) {
|
160
|
+
color: var(--color-text-subtle);
|
161
|
+
}
|
162
|
+
|
163
|
+
&:is(
|
164
|
+
.selected,
|
165
|
+
.startRange,
|
166
|
+
.endRange,
|
167
|
+
.selected.inRange,
|
168
|
+
.startRange.inRange,
|
169
|
+
.endRange.inRange,
|
170
|
+
.selected:focus,
|
171
|
+
.startRange:focus,
|
172
|
+
.endRange:focus,
|
173
|
+
.selected:hover,
|
174
|
+
.startRange:hover,
|
175
|
+
.endRange:hover,
|
176
|
+
.selected.prevMonthDay,
|
177
|
+
.startRange.prevMonthDay,
|
178
|
+
.endRange.prevMonthDay,
|
179
|
+
.selected.nextMonthDay,
|
180
|
+
.startRange.nextMonthDay,
|
181
|
+
.endRange.nextMonthDay
|
182
|
+
) {
|
183
|
+
background: var(--color-primary);
|
184
|
+
color: var(--color-text-reversed);
|
185
|
+
}
|
186
|
+
}
|
187
|
+
|
188
|
+
&::before, &::after {
|
189
|
+
display: none;
|
190
|
+
}
|
191
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
.switch {
|
2
|
+
appearance: none;
|
3
|
+
background-color: var(--color-border);
|
4
|
+
border-color: transparent;
|
5
|
+
border-radius: var(--rounded-full);
|
6
|
+
border-width: var(--border-2);
|
7
|
+
block-size: var(--size-5);
|
8
|
+
inline-size: var(--size-9);
|
9
|
+
transition: background-color var(--time-150);
|
10
|
+
|
11
|
+
&:checked {
|
12
|
+
background-color: var(--color-primary);
|
13
|
+
}
|
14
|
+
|
15
|
+
&:checked::before {
|
16
|
+
margin-inline-start: var(--size-4);
|
17
|
+
}
|
18
|
+
|
19
|
+
&::before {
|
20
|
+
aspect-ratio: var(--aspect-square);
|
21
|
+
background-color: var(--color-text-reversed);
|
22
|
+
block-size: var(--size-full);
|
23
|
+
border-radius: var(--rounded-full);
|
24
|
+
content: "";
|
25
|
+
display: block;
|
26
|
+
transition: margin var(--time-150);
|
27
|
+
}
|
28
|
+
|
29
|
+
&:focus-visible {
|
30
|
+
outline: var(--border-2) solid var(--color-selected-dark);
|
31
|
+
}
|
32
|
+
|
33
|
+
&:disabled {
|
34
|
+
cursor: not-allowed; opacity: var(--opacity-50);
|
35
|
+
}
|
36
|
+
}
|
@@ -0,0 +1,98 @@
|
|
1
|
+
/* Tag Manager Container */
|
2
|
+
.breadcrumb-container {
|
3
|
+
display: flex;
|
4
|
+
align-items: center;
|
5
|
+
justify-content: space-between;
|
6
|
+
gap: 1rem;
|
7
|
+
flex-wrap: wrap;
|
8
|
+
}
|
9
|
+
|
10
|
+
.breadcrumb-tags {
|
11
|
+
display: flex;
|
12
|
+
align-items: center;
|
13
|
+
}
|
14
|
+
|
15
|
+
/* Tag Manager */
|
16
|
+
.tag-manager {
|
17
|
+
display: flex;
|
18
|
+
align-items: center;
|
19
|
+
gap: 0.5rem;
|
20
|
+
}
|
21
|
+
|
22
|
+
.tag-list {
|
23
|
+
display: flex;
|
24
|
+
align-items: center;
|
25
|
+
gap: 0.5rem;
|
26
|
+
flex-wrap: wrap;
|
27
|
+
}
|
28
|
+
|
29
|
+
/* Individual Tag */
|
30
|
+
.tag {
|
31
|
+
display: inline-flex;
|
32
|
+
align-items: center;
|
33
|
+
gap: 0.25rem;
|
34
|
+
padding: 0.25rem 0.5rem;
|
35
|
+
background-color: var(--color-background-secondary);
|
36
|
+
border: 1px solid var(--color-border);
|
37
|
+
border-radius: 0.375rem;
|
38
|
+
font-size: 0.875rem;
|
39
|
+
line-height: 1.25;
|
40
|
+
white-space: nowrap;
|
41
|
+
}
|
42
|
+
|
43
|
+
/* Tag Remove Button */
|
44
|
+
.tag-remove {
|
45
|
+
all: unset;
|
46
|
+
display: inline-flex;
|
47
|
+
align-items: center;
|
48
|
+
justify-content: center;
|
49
|
+
width: 1rem;
|
50
|
+
height: 1rem;
|
51
|
+
padding: 0;
|
52
|
+
margin: 0;
|
53
|
+
background: none;
|
54
|
+
border: none;
|
55
|
+
cursor: pointer;
|
56
|
+
color: currentColor;
|
57
|
+
opacity: 0.6;
|
58
|
+
transition: opacity 0.15s ease;
|
59
|
+
}
|
60
|
+
|
61
|
+
.tag-remove:hover {
|
62
|
+
opacity: 1;
|
63
|
+
}
|
64
|
+
|
65
|
+
.tag-remove span {
|
66
|
+
font-size: 1.25rem;
|
67
|
+
line-height: 1;
|
68
|
+
font-weight: bold;
|
69
|
+
}
|
70
|
+
|
71
|
+
/* Add Tag Container */
|
72
|
+
.tag-add-container {
|
73
|
+
position: relative;
|
74
|
+
display: inline-block;
|
75
|
+
}
|
76
|
+
|
77
|
+
.tag-add-button {
|
78
|
+
padding: 0.25rem 0.5rem;
|
79
|
+
font-size: 0.875rem;
|
80
|
+
line-height: 1.25;
|
81
|
+
white-space: nowrap;
|
82
|
+
}
|
83
|
+
|
84
|
+
/* Responsive Design */
|
85
|
+
@media (max-width: 768px) {
|
86
|
+
.breadcrumb-container {
|
87
|
+
flex-direction: column;
|
88
|
+
align-items: flex-start;
|
89
|
+
}
|
90
|
+
|
91
|
+
.breadcrumb-tags {
|
92
|
+
width: 100%;
|
93
|
+
}
|
94
|
+
|
95
|
+
.tag-manager {
|
96
|
+
width: 100%;
|
97
|
+
}
|
98
|
+
}
|
@@ -34,3 +34,29 @@
|
|
34
34
|
.max-w-md { max-width: 28rem; }
|
35
35
|
.max-w-lg { max-width: 32rem; }
|
36
36
|
.max-w-xl { max-width: 36rem; }
|
37
|
+
|
38
|
+
/* Global filters active indicator */
|
39
|
+
.global-filters-active {
|
40
|
+
position: relative;
|
41
|
+
}
|
42
|
+
|
43
|
+
.global-filters-active::after {
|
44
|
+
content: "";
|
45
|
+
position: absolute;
|
46
|
+
top: -2px;
|
47
|
+
right: -2px;
|
48
|
+
width: 8px;
|
49
|
+
height: 8px;
|
50
|
+
background-color: var(--color-primary);
|
51
|
+
border-radius: 50%;
|
52
|
+
border: 2px solid var(--color-bg);
|
53
|
+
}
|
54
|
+
|
55
|
+
/* Flatpickr z-index fix - ensure calendar appears above dialogs */
|
56
|
+
.flatpickr-calendar,
|
57
|
+
.flatpickr-calendar.open,
|
58
|
+
.flatpickr-calendar.inline,
|
59
|
+
.flatpickr-calendar.static,
|
60
|
+
.flatpickr-calendar.static.open {
|
61
|
+
z-index: 999999 !important;
|
62
|
+
}
|
@@ -5,9 +5,11 @@ module ResponseRangeConcern
|
|
5
5
|
ransack_params = params[:q] || {}
|
6
6
|
thresholds = RailsPulse.configuration.public_send("#{type}_thresholds")
|
7
7
|
|
8
|
-
# Check
|
9
|
-
|
8
|
+
# Check all duration-related parameters
|
9
|
+
# avg_duration for Summary, duration for Request/Operation, duration_gteq for direct Ransack filtering
|
10
|
+
duration_param = ransack_params[:avg_duration] || ransack_params[:duration] || ransack_params[:duration_gteq]
|
10
11
|
|
12
|
+
# Priority 1: Page-specific duration filter
|
11
13
|
if duration_param.present?
|
12
14
|
selected_range = duration_param
|
13
15
|
start_duration =
|
@@ -17,6 +19,17 @@ module ResponseRangeConcern
|
|
17
19
|
when :critical then thresholds[:critical]
|
18
20
|
else 0
|
19
21
|
end
|
22
|
+
# Priority 2: Global performance threshold filter
|
23
|
+
elsif (global_threshold = session_global_filters["performance_threshold"]).present?
|
24
|
+
selected_range = global_threshold.to_sym
|
25
|
+
start_duration =
|
26
|
+
case global_threshold.to_sym
|
27
|
+
when :slow then thresholds[:slow]
|
28
|
+
when :very_slow then thresholds[:very_slow]
|
29
|
+
when :critical then thresholds[:critical]
|
30
|
+
else 0
|
31
|
+
end
|
32
|
+
# Priority 3: No filter (show all)
|
20
33
|
else
|
21
34
|
start_duration = 0
|
22
35
|
selected_range = :all
|