rails_observatory 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +42 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/config/rails_observatory_manifest.js +2 -0
  5. data/app/assets/images/rails_observatory/logo.svg +8 -0
  6. data/app/assets/js/application.js +88 -0
  7. data/app/assets/js/controllers/chart_controller.js +176 -0
  8. data/app/assets/js/controllers/event_details_controller.js +15 -0
  9. data/app/assets/js/controllers/index.js +9 -0
  10. data/app/assets/js/controllers/sparkline_controller.js +72 -0
  11. data/app/assets/stylesheets/application/card.css +51 -0
  12. data/app/assets/stylesheets/application/chart.css +34 -0
  13. data/app/assets/stylesheets/application/dropdown.css +62 -0
  14. data/app/assets/stylesheets/application/global_modifiers.css +10 -0
  15. data/app/assets/stylesheets/application/query_table.css +68 -0
  16. data/app/assets/stylesheets/application/side_nav.css +62 -0
  17. data/app/assets/stylesheets/application/side_panel.css +35 -0
  18. data/app/assets/stylesheets/application/tab_nav.css +64 -0
  19. data/app/assets/stylesheets/application/table_chart.css +66 -0
  20. data/app/assets/stylesheets/application/tbd.css +70 -0
  21. data/app/assets/stylesheets/application/top_nav.css +33 -0
  22. data/app/assets/stylesheets/application.css +42 -0
  23. data/app/assets/stylesheets/elements/a.css +8 -0
  24. data/app/assets/stylesheets/elements/button.css +21 -0
  25. data/app/assets/stylesheets/elements/details.css +12 -0
  26. data/app/assets/stylesheets/elements/root.css +26 -0
  27. data/app/assets/stylesheets/elements/section.css +9 -0
  28. data/app/assets/stylesheets/errors/show/details.css +13 -0
  29. data/app/assets/stylesheets/layout/app.css +23 -0
  30. data/app/assets/stylesheets/layout/details-side-panel.css +15 -0
  31. data/app/assets/stylesheets/layout/requests.css +45 -0
  32. data/app/assets/stylesheets/layout/two-column.css +17 -0
  33. data/app/assets/stylesheets/mixins/nav_button.css +19 -0
  34. data/app/assets/stylesheets/requests/stats.css +35 -0
  35. data/app/controllers/rails_observatory/application_controller.rb +24 -0
  36. data/app/controllers/rails_observatory/errors_controller.rb +27 -0
  37. data/app/controllers/rails_observatory/jobs_controller.rb +25 -0
  38. data/app/controllers/rails_observatory/mailers_controller.rb +11 -0
  39. data/app/controllers/rails_observatory/requests_controller.rb +33 -0
  40. data/app/helpers/rails_observatory/application_helper.rb +110 -0
  41. data/app/jobs/rails_observatory/application_job.rb +4 -0
  42. data/app/mailers/rails_observatory/application_mailer.rb +6 -0
  43. data/app/views/layouts/rails_observatory/application.html.erb +93 -0
  44. data/app/views/new_user_mailer/greeting.html.erb +1 -0
  45. data/app/views/posts/index.html.erb +1 -0
  46. data/app/views/rails_observatory/application/_chart.html.erb +23 -0
  47. data/app/views/rails_observatory/application/_events_table.html.erb +24 -0
  48. data/app/views/rails_observatory/application/_sparkline.html.erb +17 -0
  49. data/app/views/rails_observatory/application/_trace.html.erb +122 -0
  50. data/app/views/rails_observatory/errors/index.html.erb +87 -0
  51. data/app/views/rails_observatory/errors/show.html.erb +193 -0
  52. data/app/views/rails_observatory/jobs/_table_chart.html.erb +29 -0
  53. data/app/views/rails_observatory/jobs/index.html.erb +20 -0
  54. data/app/views/rails_observatory/jobs/show.html.erb +8 -0
  55. data/app/views/rails_observatory/logs/index.html.erb +18 -0
  56. data/app/views/rails_observatory/mailers/index.html.erb +11 -0
  57. data/app/views/rails_observatory/mailers/show.html.erb +10 -0
  58. data/app/views/rails_observatory/requests/_text_gauge.html.erb +4 -0
  59. data/app/views/rails_observatory/requests/index.html.erb +56 -0
  60. data/app/views/rails_observatory/requests/show.html.erb +16 -0
  61. data/config/routes.rb +7 -0
  62. data/lib/rails_observatory/action_mailer_subscriber.rb +14 -0
  63. data/lib/rails_observatory/engine.rb +49 -0
  64. data/lib/rails_observatory/event_collector.rb +43 -0
  65. data/lib/rails_observatory/log_collector.rb +46 -0
  66. data/lib/rails_observatory/mailer_previews/delivered_mail_preview.rb +9 -0
  67. data/lib/rails_observatory/middleware.rb +77 -0
  68. data/lib/rails_observatory/models/error.rb +67 -0
  69. data/lib/rails_observatory/models/event_collection.rb +137 -0
  70. data/lib/rails_observatory/models/events.rb +22 -0
  71. data/lib/rails_observatory/models/job_trace.rb +28 -0
  72. data/lib/rails_observatory/models/logs.rb +9 -0
  73. data/lib/rails_observatory/models/mail_delivery.rb +33 -0
  74. data/lib/rails_observatory/models/redis_model.rb +112 -0
  75. data/lib/rails_observatory/models/request_trace.rb +29 -0
  76. data/lib/rails_observatory/railties/active_job_instrumentation.rb +48 -0
  77. data/lib/rails_observatory/railties/redis_runtime.rb +11 -0
  78. data/lib/rails_observatory/redis/logging_middleware.rb +22 -0
  79. data/lib/rails_observatory/redis/redis_client_instrumentation.rb +18 -0
  80. data/lib/rails_observatory/redis/time_series/increment_script.lua +67 -0
  81. data/lib/rails_observatory/redis/time_series/insertion.rb +73 -0
  82. data/lib/rails_observatory/redis/time_series/query_builder.rb +149 -0
  83. data/lib/rails_observatory/redis/time_series/timing_script.lua +89 -0
  84. data/lib/rails_observatory/redis/time_series.rb +91 -0
  85. data/lib/rails_observatory/serializers/event_serializer.rb +19 -0
  86. data/lib/rails_observatory/serializers/headers_serializer.rb +12 -0
  87. data/lib/rails_observatory/serializers/job_serializer.rb +11 -0
  88. data/lib/rails_observatory/serializers/mail_delivery_job_serializer.rb +14 -0
  89. data/lib/rails_observatory/serializers/request_serializer.rb +17 -0
  90. data/lib/rails_observatory/serializers/response_serializer.rb +14 -0
  91. data/lib/rails_observatory/serializers/serializer.rb +51 -0
  92. data/lib/rails_observatory/version.rb +3 -0
  93. data/lib/rails_observatory.rb +3 -0
  94. data/public/assets/js/application.js +11186 -0
  95. data/public/assets/logo_with_text.svg +21 -0
  96. data/public/assets/stylesheets/application.css +757 -0
  97. metadata +197 -0
@@ -0,0 +1,757 @@
1
+ @import "https://fonts.googleapis.com/css2?family=Fira+Sans:wght@200;400&family=Roboto+Mono:wght@200;400&display=swap";
2
+
3
+ /* app/assets/stylesheets/elements/root.css */
4
+ :root {
5
+ --red: #ba181b;
6
+ --black: #161a1d;
7
+ --black-secondary: color-mix(in oklab, var(--black) 60%, white);
8
+ --blue: #003a61;
9
+ --gray: #b1a7a6;
10
+ --white: #eee;
11
+ --divider: color-mix(in oklab, var(--black) 88%, white);
12
+ --divider-active: color-mix(in oklab, var(--black) 75%, white);
13
+ --surface-active: color-mix(in oklab, var(--black) 92%, white);
14
+ --surface-hover: color-mix(in oklab, var(--black) 96%, white);
15
+ --surface-dropdown: color-mix(in oklab, var(--black) 88%, white);
16
+ --surface-card: color-mix(in oklab, var(--black) 96%, white);
17
+ --font-mono: "Roboto Mono", monospace;
18
+ --font-weight-bold: 400;
19
+ }
20
+ html,
21
+ body {
22
+ font-family: "Fira Sans", sans-serif;
23
+ font-weight: 200;
24
+ color: var(--white);
25
+ height: 100%;
26
+ background-color: var(--black);
27
+ }
28
+
29
+ /* app/assets/stylesheets/elements/a.css */
30
+ a {
31
+ color: var(--white);
32
+ text-decoration: none;
33
+ &:hover {
34
+ text-decoration: underline;
35
+ }
36
+ }
37
+
38
+ /* app/assets/stylesheets/elements/button.css */
39
+ button {
40
+ font-family: inherit;
41
+ display: flex;
42
+ font-size: 1rem;
43
+ align-items: center;
44
+ padding: .5rem .75rem;
45
+ border-radius: .5rem;
46
+ gap: .5rem;
47
+ font-weight: 400;
48
+ &.secondary {
49
+ background-color: transparent;
50
+ border: 1px solid var(--divider);
51
+ color: var(--white);
52
+ &:hover,
53
+ &:focus-within {
54
+ border: 1px solid var(--divider-active);
55
+ background-color: var(--surface-hover);
56
+ }
57
+ }
58
+ }
59
+
60
+ /* app/assets/stylesheets/elements/details.css */
61
+ details {
62
+ .arrow-right {
63
+ transform: rotate(0deg);
64
+ transition: transform 100ms linear;
65
+ }
66
+ &[open] {
67
+ & > summary .arrow-right:first-child {
68
+ transform: rotate(90deg);
69
+ }
70
+ }
71
+ }
72
+
73
+ /* app/assets/stylesheets/elements/section.css */
74
+ section {
75
+ h2 {
76
+ font-size: 1.5rem;
77
+ font-weight: 400;
78
+ margin: 0;
79
+ padding: 2rem;
80
+ border-bottom: 1px solid var(--divider);
81
+ }
82
+ }
83
+
84
+ /* app/assets/stylesheets/layout/app.css */
85
+ @layer layout {
86
+ .layout-app {
87
+ display: grid;
88
+ grid-template-areas: "side-nav top-nav" "side-nav main";
89
+ grid-template-columns: 16rem 1fr;
90
+ grid-template-rows: auto 1fr;
91
+ margin: 0;
92
+ & > .layout-app-side-nav {
93
+ grid-area: side-nav;
94
+ }
95
+ & > .layout-app-top-nav {
96
+ grid-area: top-nav;
97
+ }
98
+ & > .layout-app-main {
99
+ grid-area: main;
100
+ overflow: auto;
101
+ }
102
+ }
103
+ }
104
+
105
+ /* app/assets/stylesheets/layout/details-side-panel.css */
106
+ .layout\/details-side-panel {
107
+ padding: 0;
108
+ display: grid;
109
+ grid-template-areas: "details side-panel";
110
+ grid-template-columns: minmax(400px, 1fr) 300px;
111
+ & > .details {
112
+ grid-area: details;
113
+ }
114
+ & > .side-panel {
115
+ grid-area: side-panel;
116
+ }
117
+ }
118
+
119
+ /* app/assets/stylesheets/layout/requests.css */
120
+ @layer layout {
121
+ .layout-requests_index {
122
+ display: grid;
123
+ grid-template-areas: "glance glance" "chart chart" "bycontroller bycontroller" "events events";
124
+ grid-template-columns: 1fr 1fr;
125
+ grid-template-rows: min-content min-content auto auto;
126
+ gap: 2rem;
127
+ & > .layout-requests_index-glance {
128
+ grid-area: glance;
129
+ }
130
+ & > .layout-requests_index-chart {
131
+ grid-area: chart;
132
+ display: grid;
133
+ grid-template-columns: subgrid;
134
+ padding-inline: 2rem;
135
+ }
136
+ & > .layout-requests_index-by_controller {
137
+ grid-area: bycontroller;
138
+ }
139
+ & > .layout-requests_index-events {
140
+ grid-area: events;
141
+ }
142
+ }
143
+ .layout-events-breakdown {
144
+ display: grid;
145
+ grid-template-rows: min-content auto;
146
+ grid-template-columns: 1fr;
147
+ gap: 1rem;
148
+ & > .layout-events-breakdown-details {
149
+ border-top: 1px solid var(--divider);
150
+ }
151
+ }
152
+ }
153
+
154
+ /* app/assets/stylesheets/layout/two-column.css */
155
+ @layer layout {
156
+ .layout-two-column {
157
+ display: grid;
158
+ grid-template-columns: minmax(0, 1fr) 300px;
159
+ grid-template-areas: "main side-panel";
160
+ gap: 2rem;
161
+ & > .layout-two-column-main {
162
+ grid-area: main;
163
+ padding: 1rem;
164
+ }
165
+ & > .layout-two-column-side-panel {
166
+ grid-area: side-panel;
167
+ }
168
+ }
169
+ }
170
+
171
+ /* app/assets/stylesheets/application/global_modifiers.css */
172
+ .--scrollable {
173
+ overflow: auto;
174
+ }
175
+ .--sticky {
176
+ position: sticky;
177
+ top: 0;
178
+ background-color: var(--black);
179
+ z-index: 1;
180
+ }
181
+
182
+ /* app/assets/stylesheets/application/card.css */
183
+ .card {
184
+ border-radius: 0.5rem;
185
+ background-color: var(--surface-card);
186
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
187
+ border: 1px solid var(--divider);
188
+ padding: 0;
189
+ & h2 {
190
+ padding: 1rem;
191
+ margin: 0;
192
+ }
193
+ &:has(> table, > .\~scrollable > table) {
194
+ & table {
195
+ width: 100%;
196
+ border-spacing: 0;
197
+ white-space: nowrap;
198
+ & th {
199
+ text-align: left;
200
+ font-weight: 400;
201
+ padding: 0.5rem 1rem;
202
+ border-bottom: 1px solid var(--divider);
203
+ &:first-child {
204
+ border-top-left-radius: .5rem;
205
+ }
206
+ &:last-child {
207
+ border-top-right-radius: .5rem;
208
+ }
209
+ }
210
+ & tr:last-child td {
211
+ border-bottom: none;
212
+ }
213
+ & td {
214
+ padding: .5rem 1rem;
215
+ border-bottom: 1px solid var(--divider);
216
+ & + & {
217
+ border-left: 1px solid var(--divider);
218
+ }
219
+ }
220
+ }
221
+ }
222
+ }
223
+
224
+ /* app/assets/stylesheets/application/dropdown.css */
225
+ .dropdown {
226
+ position: relative;
227
+ & > ul {
228
+ background-color: var(--surface-dropdown);
229
+ opacity: 0;
230
+ visibility: hidden;
231
+ transform: translate(0, -1rem);
232
+ transition:
233
+ opacity .2s ease-in-out,
234
+ visibility .2s ease-in-out,
235
+ transform .2s ease-in-out;
236
+ list-style: none;
237
+ margin: 0;
238
+ padding: 0;
239
+ position: absolute;
240
+ z-index: 100;
241
+ width: 100%;
242
+ & > li {
243
+ border-bottom: 1px solid var(--divider);
244
+ text-align: left;
245
+ &:last-child {
246
+ border-bottom: none;
247
+ }
248
+ & > a {
249
+ color: var(--white);
250
+ text-decoration: none;
251
+ font-weight: 200;
252
+ padding: .5rem .75rem;
253
+ display: flex;
254
+ align-items: center;
255
+ justify-content: space-between;
256
+ & svg {
257
+ display: none;
258
+ }
259
+ &.active {
260
+ font-weight: 400;
261
+ & svg {
262
+ display: block;
263
+ }
264
+ }
265
+ &:not(.active):hover {
266
+ background-color: var(--surface-hover);
267
+ }
268
+ }
269
+ }
270
+ }
271
+ &:focus-within {
272
+ & > ul {
273
+ opacity: 100;
274
+ visibility: visible;
275
+ transform: translate(0, 0);
276
+ }
277
+ }
278
+ }
279
+
280
+ /* app/assets/stylesheets/application/side_nav.css */
281
+ .side-nav {
282
+ border-right: 1px solid var(--divider);
283
+ padding: 1rem;
284
+ display: flex;
285
+ flex-direction: column;
286
+ gap: 1rem;
287
+ align-items: stretch;
288
+ background: rgb(0, 144, 255);
289
+ background:
290
+ radial-gradient(
291
+ ellipse 100% 4rem at top,
292
+ rgba(0, 144, 255, 0.4) 0%,
293
+ rgba(22, 26, 29, 1) 100%);
294
+ ._active {
295
+ background-color: var(--surface-active);
296
+ color: var(--white);
297
+ &:hover {
298
+ background-color: var(--surface-active);
299
+ }
300
+ }
301
+ ._redis-stats {
302
+ align-self: center;
303
+ color: var(--black-secondary);
304
+ font-size: .85rem;
305
+ }
306
+ & > img {
307
+ align-self: start;
308
+ padding-inline: .75rem;
309
+ transition: all 500ms ease-in-out;
310
+ &:hover {
311
+ filter: drop-shadow(0px 0px 1px rgba(255, 255, 255, .8));
312
+ }
313
+ }
314
+ & > ul {
315
+ list-style: none;
316
+ padding: 0;
317
+ margin: 0;
318
+ display: flex;
319
+ flex-direction: column;
320
+ gap: .25rem;
321
+ flex-grow: 1;
322
+ & a {
323
+ display: flex;
324
+ align-items: center;
325
+ padding: .5rem .75rem;
326
+ gap: .5rem;
327
+ border-radius: .5rem;
328
+ text-decoration: none;
329
+ font-weight: 400;
330
+ color: color-mix(in oklab, var(--black) 20%, white);
331
+ &:is(:hover, :focus-visible) {
332
+ background-color: var(--surface-hover);
333
+ }
334
+ }
335
+ }
336
+ }
337
+
338
+ /* app/assets/stylesheets/application/top_nav.css */
339
+ .top-nav {
340
+ grid-area: top-nav;
341
+ border-bottom: 1px solid var(--divider);
342
+ padding: 1rem 2rem;
343
+ display: flex;
344
+ justify-content: space-between;
345
+ align-items: center;
346
+ ._subtitle {
347
+ font-weight: 200;
348
+ color: var(--black-secondary);
349
+ }
350
+ & > span {
351
+ display: flex;
352
+ align-items: baseline;
353
+ gap: .5rem;
354
+ & h1 {
355
+ margin: 0;
356
+ align-items: baseline;
357
+ }
358
+ }
359
+ .status-success {
360
+ background-color: #38a238;
361
+ padding: .25rem .5rem;
362
+ border-radius: .5rem;
363
+ font-size: 1.25rem;
364
+ }
365
+ }
366
+
367
+ /* app/assets/stylesheets/application/tab_nav.css */
368
+ .tabs {
369
+ display: grid;
370
+ grid-template-rows: min-content auto;
371
+ grid-template-columns: minmax(0, 1fr);
372
+ .tabs-nav {
373
+ border-bottom: 1px solid var(--divider);
374
+ padding-block: .5rem;
375
+ padding-inline: 1.25rem;
376
+ display: flex;
377
+ gap: .25rem;
378
+ }
379
+ &:has(:nth-child(1 of .tabs-button) input:checked) {
380
+ :nth-child(1 of .tab-content) {
381
+ display: block;
382
+ }
383
+ }
384
+ &:has(:nth-child(2 of .tabs-button) input:checked) {
385
+ :nth-child(2 of .tab-content) {
386
+ display: block;
387
+ }
388
+ }
389
+ &:has(:nth-child(3 of .tabs-button) input:checked) {
390
+ :nth-child(3 of .tab-content) {
391
+ display: block;
392
+ }
393
+ }
394
+ &:has(:nth-child(4 of .tabs-button) input:checked) {
395
+ :nth-child(4 of .tab-content) {
396
+ display: block;
397
+ }
398
+ }
399
+ &:has(:nth-child(5 of .tabs-button) input:checked) {
400
+ :nth-child(5 of .tab-content) {
401
+ display: block;
402
+ }
403
+ }
404
+ &:has(:nth-child(6 of .tabs-button) input:checked) {
405
+ :nth-child(6 of .tab-content) {
406
+ display: block;
407
+ }
408
+ }
409
+ &:has(:nth-child(7 of .tabs-button) input:checked) {
410
+ :nth-child(7 of .tab-content) {
411
+ display: block;
412
+ }
413
+ }
414
+ &:has(:nth-child(8 of .tabs-button) input:checked) {
415
+ :nth-child(8 of .tab-content) {
416
+ display: block;
417
+ }
418
+ }
419
+ &:has(:nth-child(9 of .tabs-button) input:checked) {
420
+ :nth-child(9 of .tab-content) {
421
+ display: block;
422
+ }
423
+ }
424
+ .tabs-button {
425
+ & input {
426
+ position: absolute;
427
+ opacity: 0;
428
+ }
429
+ &:has(:focus-visible) {
430
+ outline: -webkit-focus-ring-color auto 1px;
431
+ }
432
+ &:has(:checked) {
433
+ background-color: var(--surface-active);
434
+ }
435
+ }
436
+ .tab-content {
437
+ display: none;
438
+ padding-bottom: 2rem;
439
+ & dd {
440
+ margin-left: 0;
441
+ }
442
+ & dt {
443
+ font-weight: 400;
444
+ color: var(--black-secondary);
445
+ margin-bottom: .75rem;
446
+ }
447
+ }
448
+ }
449
+
450
+ /* app/assets/stylesheets/application/side_panel.css */
451
+ .side-panel {
452
+ color: var(--white);
453
+ padding: 2rem;
454
+ ._occurrence_count {
455
+ font-size: 1.5rem;
456
+ font-weight: 400;
457
+ }
458
+ & dl {
459
+ margin: 0;
460
+ & dt {
461
+ font-weight: 400;
462
+ margin: 0;
463
+ color: var(--black-secondary);
464
+ font-size: 1.15rem;
465
+ }
466
+ & dd {
467
+ margin: 0;
468
+ padding-block: .5rem;
469
+ &[title] {
470
+ text-decoration: underline;
471
+ text-decoration-style: dotted;
472
+ text-decoration-color: var(--black-secondary);
473
+ }
474
+ }
475
+ & dd + dt {
476
+ margin-top: 2.5rem;
477
+ }
478
+ }
479
+ }
480
+
481
+ /* app/assets/stylesheets/application/chart.css */
482
+ [data-chart-type-value=icicle] {
483
+ .apexcharts-legend-series {
484
+ display: flex;
485
+ gap: .25rem;
486
+ align-items: center;
487
+ }
488
+ .apexcharts-legend-text {
489
+ display: flex;
490
+ flex-grow: 1;
491
+ align-items: center;
492
+ justify-content: space-between;
493
+ gap: 2rem;
494
+ padding-block: .25rem;
495
+ .percent {
496
+ display: flex;
497
+ gap: .5rem;
498
+ }
499
+ .bar {
500
+ width: 2rem;
501
+ height: 14px;
502
+ background-color: var(--surface-card);
503
+ & > div {
504
+ height: 100%;
505
+ background-color: var(--blue);
506
+ }
507
+ }
508
+ }
509
+ }
510
+ .chart {
511
+ overflow: hidden;
512
+ }
513
+
514
+ /* app/assets/stylesheets/application/table_chart.css */
515
+ .table-chart {
516
+ .table-chart-title {
517
+ font-size: 1.5rem;
518
+ font-weight: 400;
519
+ margin: 0;
520
+ padding: 1rem;
521
+ border-bottom: 1px solid var(--divider);
522
+ }
523
+ & tr:has(a.table-chart-row-action:hover) {
524
+ background-color: var(--surface-hover);
525
+ }
526
+ & a.table-chart-row-action::before {
527
+ position: absolute;
528
+ content: "";
529
+ top: 0;
530
+ left: 0;
531
+ right: 0;
532
+ bottom: 0;
533
+ }
534
+ & > table {
535
+ width: 100%;
536
+ border-spacing: 0;
537
+ white-space: nowrap;
538
+ & th {
539
+ text-align: left;
540
+ font-weight: 400;
541
+ padding: 0.5rem 1rem;
542
+ border-bottom: 1px solid var(--divider);
543
+ & + & {
544
+ border-left: 1px solid var(--divider);
545
+ }
546
+ &:first-child {
547
+ padding-left: 2rem;
548
+ }
549
+ &:last-child {
550
+ padding-right: 2rem;
551
+ }
552
+ }
553
+ & tr {
554
+ position: relative;
555
+ }
556
+ & td {
557
+ padding: .5rem 1rem;
558
+ border-bottom: 1px solid var(--divider);
559
+ & + & {
560
+ border-left: 1px solid var(--divider);
561
+ }
562
+ &:first-child {
563
+ padding-left: 2rem;
564
+ }
565
+ &:last-child {
566
+ padding-right: 2rem;
567
+ }
568
+ }
569
+ }
570
+ }
571
+
572
+ /* app/assets/stylesheets/application/query_table.css */
573
+ .query-table {
574
+ display: grid;
575
+ --column-count: 10;
576
+ grid-template-columns: repeat(var(--column-count), auto);
577
+ grid-template-rows: min-content auto;
578
+ & .query-table-column {
579
+ padding: .5rem 1rem;
580
+ border-bottom: 1px solid var(--divider);
581
+ white-space: nowrap;
582
+ & + & {
583
+ border-left: 1px solid var(--divider);
584
+ }
585
+ &:first-child {
586
+ padding-left: 2rem;
587
+ }
588
+ &:last-child {
589
+ padding-right: 2rem;
590
+ }
591
+ }
592
+ & > header {
593
+ display: grid;
594
+ grid-template-columns: subgrid;
595
+ grid-column: -1 / 1;
596
+ flex-wrap: nowrap;
597
+ font-weight: var(--font-weight-bold);
598
+ }
599
+ .query-table-body {
600
+ display: grid;
601
+ grid-template-columns: subgrid;
602
+ grid-column: -1 / 1;
603
+ }
604
+ .query-table-row {
605
+ display: grid;
606
+ grid-template-columns: subgrid;
607
+ grid-column: -1 / 1;
608
+ }
609
+ & > table {
610
+ width: 100%;
611
+ border-spacing: 0;
612
+ white-space: nowrap;
613
+ & th {
614
+ text-align: left;
615
+ font-weight: 400;
616
+ padding: 0.5rem 1rem;
617
+ border-bottom: 1px solid var(--divider);
618
+ }
619
+ & td {
620
+ padding: .5rem 1rem;
621
+ border-bottom: 1px solid var(--divider);
622
+ & + & {
623
+ border-left: 1px solid var(--divider);
624
+ }
625
+ }
626
+ }
627
+ }
628
+
629
+ /* app/assets/stylesheets/application/tbd.css */
630
+ .simple-list {
631
+ list-style: none;
632
+ padding: 0;
633
+ margin: 0;
634
+ display: flex;
635
+ flex-direction: column;
636
+ gap: .25rem;
637
+ flex-grow: 1;
638
+ .simple-list-title {
639
+ font-weight: var(--font-weight-bold);
640
+ }
641
+ & li {
642
+ padding: 2rem;
643
+ }
644
+ & li + li {
645
+ border-top: 1px solid var(--divider);
646
+ }
647
+ & a {
648
+ color: color-mix(in oklab, var(--black) 20%, white);
649
+ &:is(:hover, :focus-visible) {
650
+ background-color: var(--surface-hover);
651
+ }
652
+ }
653
+ }
654
+ .event-detail {
655
+ &:not([hidden]) {
656
+ display: flex;
657
+ flex-direction: column;
658
+ gap: 1rem;
659
+ }
660
+ max-width: 120ch;
661
+ .highlight {
662
+ border: 1px solid var(--divider);
663
+ .line {
664
+ padding: 0 1rem;
665
+ overflow: hidden;
666
+ text-overflow: ellipsis;
667
+ &:hover {
668
+ background-color: var(--surface-hover);
669
+ }
670
+ }
671
+ }
672
+ }
673
+ text-gauge {
674
+ display: flex;
675
+ align-items: center;
676
+ flex-direction: column;
677
+ padding-block: 1rem;
678
+ padding-inline: 2rem;
679
+ white-space: nowrap;
680
+ & text-gauge-title {
681
+ }
682
+ & text-gauge-value {
683
+ font-size: 3rem;
684
+ font-weight: 400;
685
+ }
686
+ }
687
+
688
+ /* app/assets/stylesheets/mixins/nav_button.css */
689
+ @layer mixin {
690
+ .tabs .tabs-button,
691
+ .mixin-nav-button {
692
+ display: flex;
693
+ align-items: center;
694
+ padding: .5rem .75rem;
695
+ gap: .5rem;
696
+ border-radius: .5rem;
697
+ text-decoration: none;
698
+ font-weight: 400;
699
+ color: color-mix(in oklab, var(--black) 20%, white);
700
+ &:is(:hover, :focus-visible) {
701
+ background-color: var(--surface-hover);
702
+ }
703
+ }
704
+ }
705
+
706
+ /* app/assets/stylesheets/errors/show/details.css */
707
+ .errors\/show\/details {
708
+ grid-area: details;
709
+ margin: 1rem;
710
+ display: flex;
711
+ flex-direction: column;
712
+ gap: 1rem;
713
+ & > h2 {
714
+ margin-block: 1rem;
715
+ padding-left: 1rem;
716
+ font-size: 1.25rem;
717
+ }
718
+ }
719
+
720
+ /* app/assets/stylesheets/requests/stats.css */
721
+ .table-bar-chart {
722
+ display: grid;
723
+ grid-template-columns: auto min-content min-content;
724
+ column-gap: 1rem;
725
+ .table-bar-row {
726
+ position: relative;
727
+ background-color: transparent;
728
+ display: grid;
729
+ grid-template-columns: subgrid;
730
+ grid-column: 1 / -1;
731
+ padding: .5rem;
732
+ &:hover {
733
+ background-color: var(--surface-hover);
734
+ }
735
+ }
736
+ .table-bar-header {
737
+ grid-column: 1 / -1;
738
+ border-bottom: 1px solid var(--divider);
739
+ font-weight: var(--font-weight-bold);
740
+ padding: .5rem 0;
741
+ }
742
+ .bar {
743
+ background-color: var(--blue);
744
+ position: absolute;
745
+ top: 0;
746
+ left: 0;
747
+ bottom: 0;
748
+ mix-blend-mode: lighten;
749
+ z-index: 0;
750
+ }
751
+ }
752
+
753
+ /* app/assets/stylesheets/application.css */
754
+ main {
755
+ grid-area: main;
756
+ overflow: auto;
757
+ }