solid_queue_monitor 0.5.0 → 1.0.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 (25) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +37 -8
  3. data/app/controllers/solid_queue_monitor/jobs_controller.rb +72 -0
  4. data/app/controllers/solid_queue_monitor/overview_controller.rb +11 -0
  5. data/app/controllers/solid_queue_monitor/queues_controller.rb +73 -2
  6. data/app/controllers/solid_queue_monitor/scheduled_jobs_controller.rb +9 -0
  7. data/app/controllers/solid_queue_monitor/workers_controller.rb +74 -0
  8. data/app/presenters/solid_queue_monitor/base_presenter.rb +7 -0
  9. data/app/presenters/solid_queue_monitor/failed_jobs_presenter.rb +3 -7
  10. data/app/presenters/solid_queue_monitor/in_progress_jobs_presenter.rb +2 -1
  11. data/app/presenters/solid_queue_monitor/job_details_presenter.rb +696 -0
  12. data/app/presenters/solid_queue_monitor/jobs_presenter.rb +3 -3
  13. data/app/presenters/solid_queue_monitor/queue_details_presenter.rb +194 -0
  14. data/app/presenters/solid_queue_monitor/queues_presenter.rb +1 -1
  15. data/app/presenters/solid_queue_monitor/ready_jobs_presenter.rb +2 -2
  16. data/app/presenters/solid_queue_monitor/recurring_jobs_presenter.rb +1 -1
  17. data/app/presenters/solid_queue_monitor/scheduled_jobs_presenter.rb +2 -2
  18. data/app/presenters/solid_queue_monitor/workers_presenter.rb +319 -0
  19. data/app/services/solid_queue_monitor/chart_data_service.rb +100 -0
  20. data/app/services/solid_queue_monitor/chart_presenter.rb +239 -0
  21. data/app/services/solid_queue_monitor/html_generator.rb +169 -8
  22. data/app/services/solid_queue_monitor/stylesheet_generator.rb +650 -33
  23. data/config/routes.rb +9 -0
  24. data/lib/solid_queue_monitor/version.rb +1 -1
  25. metadata +8 -1
@@ -8,9 +8,35 @@ module SolidQueueMonitor
8
8
  --primary-color: #3b82f6;
9
9
  --success-color: #10b981;
10
10
  --error-color: #ef4444;
11
+ --warning-color: #f59e0b;
11
12
  --text-color: #1f2937;
13
+ --text-muted: #6b7280;
12
14
  --border-color: #e5e7eb;
13
15
  --background-color: #f9fafb;
16
+ --card-background: #ffffff;
17
+ --card-shadow: 0 1px 3px rgba(0,0,0,0.1);
18
+ --input-background: #ffffff;
19
+ --input-border: #d1d5db;
20
+ --hover-background: #f3f4f6;
21
+ --code-background: #f5f5f5;
22
+ }
23
+
24
+ /* Dark theme */
25
+ .solid_queue_monitor.dark-theme {
26
+ --primary-color: #60a5fa;
27
+ --success-color: #34d399;
28
+ --error-color: #f87171;
29
+ --warning-color: #fbbf24;
30
+ --text-color: #f9fafb;
31
+ --text-muted: #9ca3af;
32
+ --border-color: #2d2d2d;
33
+ --background-color: #000000;
34
+ --card-background: #121212;
35
+ --card-shadow: 0 1px 3px rgba(0,0,0,0.5);
36
+ --input-background: #1e1e1e;
37
+ --input-border: #3d3d3d;
38
+ --hover-background: #1e1e1e;
39
+ --code-background: #1e1e1e;
14
40
  }
15
41
 
16
42
  .solid_queue_monitor * { box-sizing: border-box; margin: 0; padding: 0; }
@@ -23,7 +49,8 @@ module SolidQueueMonitor
23
49
  }
24
50
 
25
51
  .solid_queue_monitor .container {
26
- max-width: 1200px;
52
+ width: 95%;
53
+ max-width: 1800px;
27
54
  margin: 0 auto;
28
55
  padding: 2rem;
29
56
  }
@@ -52,8 +79,8 @@ module SolidQueueMonitor
52
79
  color: var(--text-color);
53
80
  padding: 0.5rem 1rem;
54
81
  border-radius: 0.375rem;
55
- background: white;
56
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
82
+ background: var(--card-background);
83
+ box-shadow: var(--card-shadow);
57
84
  transition: all 0.2s;
58
85
  }
59
86
 
@@ -74,6 +101,29 @@ module SolidQueueMonitor
74
101
  background: var(--background-color);
75
102
  }
76
103
 
104
+ .solid_queue_monitor .section-header-row {
105
+ display: flex;
106
+ justify-content: space-between;
107
+ align-items: center;
108
+ margin-bottom: 1.5rem;
109
+ padding: 1rem;
110
+ background: var(--card-background);
111
+ border-radius: 0.5rem;
112
+ box-shadow: var(--card-shadow);
113
+ }
114
+
115
+ .solid_queue_monitor .section-header-left {
116
+ display: flex;
117
+ align-items: center;
118
+ gap: 1rem;
119
+ }
120
+
121
+ .solid_queue_monitor .section-header-right {
122
+ display: flex;
123
+ align-items: center;
124
+ gap: 0.5rem;
125
+ }
126
+
77
127
  .solid_queue_monitor .stats-container {
78
128
  margin-bottom: 2rem;
79
129
  }
@@ -89,15 +139,15 @@ module SolidQueueMonitor
89
139
  .solid_queue_monitor .stat-card {
90
140
  flex: 1 1 0;
91
141
  min-width: 150px;
92
- background: white;
142
+ background: var(--card-background);
93
143
  padding: 1.5rem 1rem;
94
144
  border-radius: 0.5rem;
95
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
145
+ box-shadow: var(--card-shadow);
96
146
  text-align: center;
97
147
  }
98
148
 
99
149
  .solid_queue_monitor .stat-card h3 {
100
- color: #6b7280;
150
+ color: var(--text-muted);
101
151
  font-size: 0.875rem;
102
152
  text-transform: uppercase;
103
153
  letter-spacing: 0.05em;
@@ -137,11 +187,12 @@ module SolidQueueMonitor
137
187
  }
138
188
 
139
189
  .solid_queue_monitor th {
140
- background: var(--background-color);
190
+ background: var(--hover-background);
141
191
  font-weight: 500;
142
192
  font-size: 0.875rem;
143
193
  text-transform: uppercase;
144
194
  letter-spacing: 0.05em;
195
+ color: var(--text-muted);
145
196
  }
146
197
 
147
198
  .solid_queue_monitor .status-badge {
@@ -242,7 +293,7 @@ module SolidQueueMonitor
242
293
  .solid_queue_monitor footer {
243
294
  text-align: center;
244
295
  padding: 2rem 0;
245
- color: #6b7280;
296
+ color: var(--text-muted);
246
297
  }
247
298
 
248
299
  .solid_queue_monitor .pagination {
@@ -289,7 +340,7 @@ module SolidQueueMonitor
289
340
  }
290
341
 
291
342
  .solid_queue_monitor .pagination-link {
292
- background: white;
343
+ background: var(--card-background);
293
344
  color: var(--text-color);
294
345
  border: 1px solid var(--border-color);
295
346
  }
@@ -320,7 +371,7 @@ module SolidQueueMonitor
320
371
  max-height: 100px;
321
372
  overflow-y: auto;
322
373
  padding: 8px;
323
- background: #f5f5f5;
374
+ background: var(--code-background);
324
375
  border-radius: 4px;
325
376
  font-size: 0.9em;
326
377
  }
@@ -328,7 +379,7 @@ module SolidQueueMonitor
328
379
  .solid_queue_monitor .args-single-line {
329
380
  display: inline-block;
330
381
  padding: 4px 8px;
331
- background: #f5f5f5;
382
+ background: var(--code-background);
332
383
  border-radius: 4px;
333
384
  font-size: 0.9em;
334
385
  }
@@ -399,10 +450,10 @@ module SolidQueueMonitor
399
450
  }
400
451
 
401
452
  .solid_queue_monitor .filter-form-container {
402
- background: white;
453
+ background: var(--card-background);
403
454
  padding: 1rem;
404
455
  border-radius: 0.5rem;
405
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
456
+ box-shadow: var(--card-shadow);
406
457
  flex: 3;
407
458
  }
408
459
 
@@ -411,9 +462,9 @@ module SolidQueueMonitor
411
462
  flex-direction: row;
412
463
  gap: 0.75rem;
413
464
  padding: 1rem;
414
- background: white;
465
+ background: var(--card-background);
415
466
  border-radius: 0.5rem;
416
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
467
+ box-shadow: var(--card-shadow);
417
468
  flex: 2;
418
469
  align-items: center;
419
470
  justify-content: center;
@@ -453,16 +504,18 @@ module SolidQueueMonitor
453
504
  margin-bottom: 0.5rem;
454
505
  font-size: 0.875rem;
455
506
  font-weight: 500;
456
- color: #4b5563;
507
+ color: var(--text-muted);
457
508
  }
458
509
 
459
510
  .solid_queue_monitor .filter-group input,
460
511
  .solid_queue_monitor .filter-group select {
461
512
  width: 100%;
462
513
  padding: 0.5rem;
463
- border: 1px solid #d1d5db;
514
+ border: 1px solid var(--input-border);
464
515
  border-radius: 0.375rem;
465
516
  font-size: 0.875rem;
517
+ background: var(--input-background);
518
+ color: var(--text-color);
466
519
  }
467
520
 
468
521
  .solid_queue_monitor .filter-actions {
@@ -486,9 +539,9 @@ module SolidQueueMonitor
486
539
  }
487
540
 
488
541
  .solid_queue_monitor .reset-button {
489
- background: #f3f4f6;
490
- color: #4b5563;
491
- border: 1px solid #d1d5db;
542
+ background: var(--hover-background);
543
+ color: var(--text-muted);
544
+ border: 1px solid var(--border-color);
492
545
  padding: 0.5rem 1rem;
493
546
  border-radius: 0.375rem;
494
547
  font-size: 0.875rem;
@@ -498,7 +551,7 @@ module SolidQueueMonitor
498
551
  }
499
552
 
500
553
  .solid_queue_monitor .reset-button:hover {
501
- background: #e5e7eb;
554
+ background: var(--border-color);
502
555
  }
503
556
 
504
557
  .solid_queue_monitor .action-button {
@@ -560,7 +613,7 @@ module SolidQueueMonitor
560
613
  white-space: pre-wrap;
561
614
  max-height: 200px;
562
615
  overflow-y: auto;
563
- background: #f3f4f6;
616
+ background: var(--code-background);
564
617
  padding: 0.5rem;
565
618
  border-radius: 0.25rem;
566
619
  margin-top: 0.5rem;
@@ -572,12 +625,12 @@ module SolidQueueMonitor
572
625
 
573
626
  .solid_queue_monitor summary {
574
627
  cursor: pointer;
575
- color: #6b7280;
628
+ color: var(--text-muted);
576
629
  font-size: 0.75rem;
577
630
  }
578
631
 
579
632
  .solid_queue_monitor summary:hover {
580
- color: #4b5563;
633
+ color: var(--text-color);
581
634
  }
582
635
 
583
636
  .solid_queue_monitor .job-checkbox,
@@ -590,10 +643,10 @@ module SolidQueueMonitor
590
643
  display: flex;
591
644
  gap: 0.75rem;
592
645
  margin: 1rem 0;
593
- background: white;
646
+ background: var(--card-background);
594
647
  padding: 0.75rem;
595
648
  border-radius: 0.5rem;
596
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
649
+ box-shadow: var(--card-shadow);
597
650
  }
598
651
 
599
652
  .solid_queue_monitor .bulk-actions-bar .action-button {
@@ -625,11 +678,11 @@ module SolidQueueMonitor
625
678
  align-items: center;
626
679
  gap: 0.5rem;
627
680
  padding: 0.375rem 0.625rem;
628
- background: white;
681
+ background: var(--card-background);
629
682
  border-radius: 2rem;
630
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
683
+ box-shadow: var(--card-shadow);
631
684
  font-size: 0.75rem;
632
- color: #6b7280;
685
+ color: var(--text-muted);
633
686
  cursor: default;
634
687
  }
635
688
 
@@ -682,7 +735,7 @@ module SolidQueueMonitor
682
735
  width: 6px;
683
736
  height: 6px;
684
737
  border-radius: 50%;
685
- background: #d1d5db;
738
+ background: var(--border-color);
686
739
  flex-shrink: 0;
687
740
  }
688
741
 
@@ -726,7 +779,7 @@ module SolidQueueMonitor
726
779
  left: 0;
727
780
  right: 0;
728
781
  bottom: 0;
729
- background-color: #d1d5db;
782
+ background-color: var(--border-color);
730
783
  transition: 0.2s;
731
784
  border-radius: 18px;
732
785
  }
@@ -738,7 +791,7 @@ module SolidQueueMonitor
738
791
  width: 14px;
739
792
  left: 2px;
740
793
  bottom: 2px;
741
- background-color: white;
794
+ background-color: var(--card-background);
742
795
  transition: 0.2s;
743
796
  border-radius: 50%;
744
797
  box-shadow: 0 1px 2px rgba(0,0,0,0.2);
@@ -761,7 +814,7 @@ module SolidQueueMonitor
761
814
  padding: 0.25rem;
762
815
  border-radius: 0.25rem;
763
816
  cursor: pointer;
764
- color: #9ca3af;
817
+ color: var(--text-muted);
765
818
  transition: all 0.2s;
766
819
  }
767
820
 
@@ -786,6 +839,570 @@ module SolidQueueMonitor
786
839
  display: none;
787
840
  }
788
841
  }
842
+
843
+ /* Navigation active state */
844
+ .solid_queue_monitor .nav-link.active {
845
+ background: var(--primary-color);
846
+ color: white;
847
+ border-left: 3px solid #1d4ed8;
848
+ }
849
+
850
+ /* Chart styles */
851
+ .solid_queue_monitor .chart-section {
852
+ background: var(--card-background);
853
+ border-radius: 0.5rem;
854
+ box-shadow: var(--card-shadow);
855
+ padding: 1rem 1.5rem;
856
+ margin-bottom: 2rem;
857
+ }
858
+
859
+ .solid_queue_monitor .chart-section.collapsed {
860
+ padding-bottom: 1rem;
861
+ }
862
+
863
+ .solid_queue_monitor .chart-header {
864
+ display: flex;
865
+ justify-content: space-between;
866
+ align-items: center;
867
+ flex-wrap: wrap;
868
+ gap: 0.75rem;
869
+ }
870
+
871
+ .solid_queue_monitor .chart-header-left {
872
+ display: flex;
873
+ align-items: center;
874
+ gap: 0.5rem;
875
+ flex-wrap: wrap;
876
+ }
877
+
878
+ .solid_queue_monitor .chart-header h3 {
879
+ font-size: 1rem;
880
+ font-weight: 600;
881
+ color: var(--text-color);
882
+ margin: 0;
883
+ }
884
+
885
+ .solid_queue_monitor .chart-toggle-btn {
886
+ display: flex;
887
+ align-items: center;
888
+ justify-content: center;
889
+ width: 28px;
890
+ height: 28px;
891
+ background: var(--hover-background);
892
+ border: 1px solid var(--border-color);
893
+ border-radius: 0.375rem;
894
+ cursor: pointer;
895
+ color: var(--text-muted);
896
+ transition: all 0.2s;
897
+ }
898
+
899
+ .solid_queue_monitor .chart-toggle-btn:hover {
900
+ background: var(--border-color);
901
+ color: var(--text-color);
902
+ }
903
+
904
+ .solid_queue_monitor .chart-toggle-icon {
905
+ transition: transform 0.2s;
906
+ }
907
+
908
+ .solid_queue_monitor .chart-section.collapsed .chart-toggle-icon {
909
+ transform: rotate(-90deg);
910
+ }
911
+
912
+ .solid_queue_monitor .chart-summary {
913
+ display: flex;
914
+ align-items: center;
915
+ gap: 0.5rem;
916
+ font-size: 0.8rem;
917
+ color: var(--text-muted);
918
+ margin-left: 0.5rem;
919
+ padding-left: 0.75rem;
920
+ border-left: 1px solid var(--border-color);
921
+ }
922
+
923
+ .solid_queue_monitor .summary-item {
924
+ white-space: nowrap;
925
+ }
926
+
927
+ .solid_queue_monitor .summary-created {
928
+ color: #3b82f6;
929
+ }
930
+
931
+ .solid_queue_monitor .summary-completed {
932
+ color: #10b981;
933
+ }
934
+
935
+ .solid_queue_monitor .summary-failed {
936
+ color: #ef4444;
937
+ }
938
+
939
+ .solid_queue_monitor .summary-separator {
940
+ color: var(--border-color);
941
+ }
942
+
943
+ .solid_queue_monitor .chart-time-select-wrapper {
944
+ position: relative;
945
+ }
946
+
947
+ .solid_queue_monitor .chart-time-select {
948
+ appearance: none;
949
+ padding: 0.5rem 2rem 0.5rem 0.75rem;
950
+ font-size: 0.8rem;
951
+ color: var(--text-color);
952
+ background: var(--input-background);
953
+ border: 1px solid var(--border-color);
954
+ border-radius: 0.375rem;
955
+ cursor: pointer;
956
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
957
+ background-repeat: no-repeat;
958
+ background-position: right 0.5rem center;
959
+ background-size: 14px;
960
+ min-width: 140px;
961
+ }
962
+
963
+ .solid_queue_monitor .chart-time-select:hover {
964
+ border-color: var(--text-muted);
965
+ }
966
+
967
+ .solid_queue_monitor .chart-time-select:focus {
968
+ outline: none;
969
+ border-color: var(--primary-color);
970
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
971
+ }
972
+
973
+ .solid_queue_monitor .chart-collapsible {
974
+ overflow: hidden;
975
+ transition: max-height 0.3s ease-out, opacity 0.2s ease-out, margin-top 0.3s ease-out;
976
+ max-height: 500px;
977
+ opacity: 1;
978
+ margin-top: 1rem;
979
+ }
980
+
981
+ .solid_queue_monitor .chart-section.collapsed .chart-collapsible {
982
+ max-height: 0;
983
+ opacity: 0;
984
+ margin-top: 0;
985
+ }
986
+
987
+ .solid_queue_monitor .chart-container {
988
+ width: 100%;
989
+ overflow-x: auto;
990
+ overflow-y: hidden;
991
+ }
992
+
993
+ .solid_queue_monitor .chart-container svg {
994
+ display: block;
995
+ width: 100%;
996
+ height: auto;
997
+ }
998
+
999
+ .solid_queue_monitor .job-activity-chart {
1000
+ width: 100%;
1001
+ height: auto;
1002
+ min-height: 250px;
1003
+ }
1004
+
1005
+ .solid_queue_monitor .grid-line {
1006
+ stroke: var(--border-color);
1007
+ stroke-width: 1;
1008
+ stroke-dasharray: 4 4;
1009
+ }
1010
+
1011
+ .solid_queue_monitor .axis-line {
1012
+ stroke: var(--border-color);
1013
+ stroke-width: 1;
1014
+ }
1015
+
1016
+ .solid_queue_monitor .axis-label {
1017
+ font-size: 11px;
1018
+ fill: var(--text-muted);
1019
+ }
1020
+
1021
+ .solid_queue_monitor .x-label {
1022
+ text-anchor: middle;
1023
+ }
1024
+
1025
+ .solid_queue_monitor .y-label {
1026
+ text-anchor: end;
1027
+ }
1028
+
1029
+ .solid_queue_monitor .chart-line {
1030
+ stroke-linecap: round;
1031
+ stroke-linejoin: round;
1032
+ }
1033
+
1034
+ .solid_queue_monitor .data-point {
1035
+ cursor: pointer;
1036
+ transition: r 0.2s;
1037
+ }
1038
+
1039
+ .solid_queue_monitor .data-point:hover {
1040
+ r: 6;
1041
+ }
1042
+
1043
+ .solid_queue_monitor .chart-legend {
1044
+ display: flex;
1045
+ justify-content: center;
1046
+ gap: 1.5rem;
1047
+ margin-top: 1rem;
1048
+ flex-wrap: wrap;
1049
+ }
1050
+
1051
+ .solid_queue_monitor .legend-item {
1052
+ display: flex;
1053
+ align-items: center;
1054
+ gap: 0.375rem;
1055
+ font-size: 0.875rem;
1056
+ color: var(--text-muted);
1057
+ }
1058
+
1059
+ .solid_queue_monitor .legend-color {
1060
+ width: 12px;
1061
+ height: 12px;
1062
+ border-radius: 2px;
1063
+ }
1064
+
1065
+ .solid_queue_monitor .chart-tooltip {
1066
+ position: fixed;
1067
+ background: #1f2937;
1068
+ color: white;
1069
+ padding: 0.5rem 0.75rem;
1070
+ border-radius: 0.375rem;
1071
+ font-size: 0.75rem;
1072
+ pointer-events: none;
1073
+ z-index: 1000;
1074
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
1075
+ }
1076
+
1077
+ .solid_queue_monitor .tooltip-label {
1078
+ font-weight: 500;
1079
+ margin-bottom: 0.25rem;
1080
+ }
1081
+
1082
+ .solid_queue_monitor .tooltip-value {
1083
+ color: #d1d5db;
1084
+ }
1085
+
1086
+ .solid_queue_monitor .chart-empty {
1087
+ display: flex;
1088
+ align-items: center;
1089
+ justify-content: center;
1090
+ height: 200px;
1091
+ color: var(--text-muted);
1092
+ font-size: 0.875rem;
1093
+ }
1094
+
1095
+ @media (max-width: 768px) {
1096
+ .solid_queue_monitor .chart-section {
1097
+ padding: 1rem;
1098
+ }
1099
+
1100
+ .solid_queue_monitor .chart-header {
1101
+ flex-direction: column;
1102
+ align-items: flex-start;
1103
+ }
1104
+
1105
+ .solid_queue_monitor .chart-header-left {
1106
+ width: 100%;
1107
+ flex-wrap: wrap;
1108
+ }
1109
+
1110
+ .solid_queue_monitor .chart-summary {
1111
+ margin-left: 0;
1112
+ padding-left: 0;
1113
+ border-left: none;
1114
+ margin-top: 0.5rem;
1115
+ width: 100%;
1116
+ }
1117
+
1118
+ .solid_queue_monitor .chart-time-select {
1119
+ width: 100%;
1120
+ }
1121
+
1122
+ .solid_queue_monitor .job-activity-chart {
1123
+ min-height: 200px;
1124
+ }
1125
+
1126
+ .solid_queue_monitor .chart-legend {
1127
+ gap: 1rem;
1128
+ }
1129
+ }
1130
+
1131
+ /* Theme toggle button */
1132
+ .solid_queue_monitor .theme-toggle-btn {
1133
+ display: flex;
1134
+ align-items: center;
1135
+ justify-content: center;
1136
+ width: 36px;
1137
+ height: 36px;
1138
+ background: var(--card-background);
1139
+ border: 1px solid var(--border-color);
1140
+ border-radius: 50%;
1141
+ cursor: pointer;
1142
+ color: var(--text-muted);
1143
+ transition: all 0.2s;
1144
+ box-shadow: var(--card-shadow);
1145
+ }
1146
+
1147
+ .solid_queue_monitor .theme-toggle-btn:hover {
1148
+ color: var(--text-color);
1149
+ border-color: var(--text-muted);
1150
+ }
1151
+
1152
+ .solid_queue_monitor .theme-toggle-btn svg {
1153
+ width: 18px;
1154
+ height: 18px;
1155
+ }
1156
+
1157
+ /* Hide moon icon in light mode, show sun icon */
1158
+ .solid_queue_monitor .theme-icon-moon {
1159
+ display: none;
1160
+ }
1161
+
1162
+ .solid_queue_monitor .theme-icon-sun {
1163
+ display: block;
1164
+ }
1165
+
1166
+ /* In dark mode, show moon icon, hide sun icon */
1167
+ .solid_queue_monitor.dark-theme .theme-icon-moon {
1168
+ display: block;
1169
+ }
1170
+
1171
+ .solid_queue_monitor.dark-theme .theme-icon-sun {
1172
+ display: none;
1173
+ }
1174
+
1175
+ .solid_queue_monitor .header-controls {
1176
+ display: flex;
1177
+ align-items: center;
1178
+ gap: 0.75rem;
1179
+ }
1180
+
1181
+ /* Workers Page Styles */
1182
+ .solid_queue_monitor .workers-summary {
1183
+ display: grid;
1184
+ grid-template-columns: repeat(4, 1fr);
1185
+ gap: 1rem;
1186
+ margin-bottom: 1.5rem;
1187
+ }
1188
+
1189
+ .solid_queue_monitor .summary-card {
1190
+ background: var(--card-background);
1191
+ border: 1px solid var(--border-color);
1192
+ border-radius: 0.5rem;
1193
+ padding: 1rem 1.25rem;
1194
+ display: flex;
1195
+ flex-direction: column;
1196
+ align-items: center;
1197
+ gap: 0.25rem;
1198
+ border-left: 4px solid var(--border-color);
1199
+ position: relative;
1200
+ }
1201
+
1202
+ .solid_queue_monitor .summary-card .summary-label {
1203
+ font-size: 0.75rem;
1204
+ text-transform: uppercase;
1205
+ letter-spacing: 0.05em;
1206
+ color: var(--text-muted);
1207
+ }
1208
+
1209
+ .solid_queue_monitor .summary-card .summary-value {
1210
+ font-size: 1.75rem;
1211
+ font-weight: 600;
1212
+ color: var(--text-color);
1213
+ }
1214
+
1215
+ .solid_queue_monitor .summary-healthy {
1216
+ border-left-color: #10b981;
1217
+ }
1218
+
1219
+ .solid_queue_monitor .summary-healthy .summary-value {
1220
+ color: #10b981;
1221
+ }
1222
+
1223
+ .solid_queue_monitor .summary-stale {
1224
+ border-left-color: #f59e0b;
1225
+ }
1226
+
1227
+ .solid_queue_monitor .summary-stale .summary-value {
1228
+ color: #f59e0b;
1229
+ }
1230
+
1231
+ .solid_queue_monitor .summary-dead {
1232
+ border-left-color: #ef4444;
1233
+ }
1234
+
1235
+ .solid_queue_monitor .summary-dead .summary-value {
1236
+ color: #ef4444;
1237
+ }
1238
+
1239
+ .solid_queue_monitor .summary-action {
1240
+ font-size: 0.75rem;
1241
+ color: #f59e0b;
1242
+ text-decoration: none;
1243
+ border: 1px solid #f59e0b;
1244
+ padding: 0.25rem 0.5rem;
1245
+ border-radius: 0.25rem;
1246
+ margin-top: 0.5rem;
1247
+ transition: all 0.2s;
1248
+ }
1249
+
1250
+ .solid_queue_monitor .summary-action:hover {
1251
+ background: #f59e0b;
1252
+ color: #000;
1253
+ }
1254
+
1255
+ .solid_queue_monitor .kind-badge {
1256
+ display: inline-block;
1257
+ padding: 0.25rem 0.5rem;
1258
+ border-radius: 0.25rem;
1259
+ font-size: 0.75rem;
1260
+ font-weight: 500;
1261
+ }
1262
+
1263
+ .solid_queue_monitor .kind-worker {
1264
+ background: rgba(59, 130, 246, 0.15);
1265
+ color: #3b82f6;
1266
+ }
1267
+
1268
+ .solid_queue_monitor .kind-dispatcher {
1269
+ background: rgba(249, 115, 22, 0.15);
1270
+ color: #f97316;
1271
+ }
1272
+
1273
+ .solid_queue_monitor .kind-scheduler {
1274
+ background: rgba(168, 85, 247, 0.15);
1275
+ color: #a855f7;
1276
+ }
1277
+
1278
+ .solid_queue_monitor .kind-other {
1279
+ background: rgba(107, 114, 128, 0.15);
1280
+ color: #6b7280;
1281
+ }
1282
+
1283
+ .solid_queue_monitor .status-healthy {
1284
+ background: rgba(16, 185, 129, 0.15);
1285
+ color: #10b981;
1286
+ }
1287
+
1288
+ .solid_queue_monitor .status-stale {
1289
+ background: rgba(245, 158, 11, 0.15);
1290
+ color: #f59e0b;
1291
+ }
1292
+
1293
+ .solid_queue_monitor .status-dead {
1294
+ background: rgba(239, 68, 68, 0.15);
1295
+ color: #ef4444;
1296
+ }
1297
+
1298
+ .solid_queue_monitor .queue-tag {
1299
+ display: inline-block;
1300
+ background: var(--card-background);
1301
+ border: 1px solid var(--border-color);
1302
+ padding: 0.125rem 0.375rem;
1303
+ border-radius: 0.25rem;
1304
+ font-size: 0.75rem;
1305
+ margin-right: 0.25rem;
1306
+ }
1307
+
1308
+ .solid_queue_monitor .queue-more {
1309
+ color: var(--text-muted);
1310
+ font-size: 0.75rem;
1311
+ }
1312
+
1313
+ .solid_queue_monitor .jobs-idle {
1314
+ color: var(--text-muted);
1315
+ font-style: italic;
1316
+ }
1317
+
1318
+ .solid_queue_monitor .jobs-processing {
1319
+ color: #10b981;
1320
+ }
1321
+
1322
+ .solid_queue_monitor .jobs-processing .job-names {
1323
+ color: var(--text-muted);
1324
+ font-size: 0.8em;
1325
+ }
1326
+
1327
+ .solid_queue_monitor .worker-dead {
1328
+ background: rgba(239, 68, 68, 0.05);
1329
+ }
1330
+
1331
+ .solid_queue_monitor .worker-stale {
1332
+ background: rgba(245, 158, 11, 0.05);
1333
+ }
1334
+
1335
+ .solid_queue_monitor .action-placeholder {
1336
+ color: var(--text-muted);
1337
+ }
1338
+
1339
+ /* Table Link Styles */
1340
+ .solid_queue_monitor .job-class-link {
1341
+ color: var(--text-color);
1342
+ text-decoration: none;
1343
+ transition: color 0.2s;
1344
+ }
1345
+
1346
+ .solid_queue_monitor .job-class-link:hover {
1347
+ color: #3b82f6;
1348
+ text-decoration: underline;
1349
+ }
1350
+
1351
+ .solid_queue_monitor .queue-link {
1352
+ color: var(--text-color);
1353
+ text-decoration: none;
1354
+ transition: color 0.2s;
1355
+ }
1356
+
1357
+ .solid_queue_monitor .queue-link:hover {
1358
+ color: #3b82f6;
1359
+ text-decoration: underline;
1360
+ }
1361
+
1362
+ .solid_queue_monitor .back-link {
1363
+ color: var(--text-muted);
1364
+ text-decoration: none;
1365
+ display: inline-flex;
1366
+ align-items: center;
1367
+ gap: 0.25rem;
1368
+ font-size: 0.875rem;
1369
+ transition: color 0.2s;
1370
+ }
1371
+
1372
+ .solid_queue_monitor .back-link:hover {
1373
+ color: var(--text-color);
1374
+ }
1375
+
1376
+ .solid_queue_monitor .job-back-link {
1377
+ margin-bottom: 1rem;
1378
+ }
1379
+
1380
+ .solid_queue_monitor .empty-state {
1381
+ text-align: center;
1382
+ padding: 3rem 1rem;
1383
+ color: var(--text-muted);
1384
+ }
1385
+
1386
+ .solid_queue_monitor .empty-state p {
1387
+ margin: 0.5rem 0;
1388
+ }
1389
+
1390
+ .solid_queue_monitor .empty-state-hint {
1391
+ font-size: 0.875rem;
1392
+ opacity: 0.7;
1393
+ }
1394
+
1395
+ @media (max-width: 768px) {
1396
+ .solid_queue_monitor .workers-summary {
1397
+ grid-template-columns: repeat(2, 1fr);
1398
+ }
1399
+ }
1400
+
1401
+ @media (max-width: 480px) {
1402
+ .solid_queue_monitor .workers-summary {
1403
+ grid-template-columns: 1fr;
1404
+ }
1405
+ }
789
1406
  CSS
790
1407
  end
791
1408
  end