robotframework-dashboard 2.3.0__tar.gz → 2.4.0__tar.gz

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 (129) hide show
  1. {robotframework_dashboard-2.3.0/robotframework_dashboard.egg-info → robotframework_dashboard-2.4.0}/PKG-INFO +2 -2
  2. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/README.md +2 -2
  3. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/arguments.py +7 -5
  4. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/css/base.css +102 -9
  5. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/css/colors.css +15 -1
  6. robotframework_dashboard-2.4.0/robotframework_dashboard/css/components/01-cards.css +78 -0
  7. robotframework_dashboard-2.4.0/robotframework_dashboard/css/components/02-filters.css +260 -0
  8. robotframework_dashboard-2.4.0/robotframework_dashboard/css/components/03-widgets.css +246 -0
  9. robotframework_dashboard-2.4.0/robotframework_dashboard/css/components/04-status-colors.css +29 -0
  10. robotframework_dashboard-2.4.0/robotframework_dashboard/css/components/05-run-cards.css +74 -0
  11. robotframework_dashboard-2.4.0/robotframework_dashboard/css/components/06-graphs.css +116 -0
  12. robotframework_dashboard-2.4.0/robotframework_dashboard/css/components/07-loading.css +121 -0
  13. robotframework_dashboard-2.4.0/robotframework_dashboard/css/components/08-section-filters-modal.css +29 -0
  14. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/database.py +55 -11
  15. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/common.js +14 -0
  16. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/collapsables.js +25 -0
  17. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/confirm_modal.js +41 -0
  18. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/filter_modal.js +253 -0
  19. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/graph_view_buttons.js +354 -0
  20. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/merge_profiles.js +140 -0
  21. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/overview_listeners.js +83 -0
  22. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/section_filters.js +386 -0
  23. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/settings_modal.js +358 -0
  24. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/availability.js +269 -0
  25. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/controls.js +228 -0
  26. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/date_histogram.js +488 -0
  27. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/modal_options.js +284 -0
  28. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/pipeline.js +477 -0
  29. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/profile_merge.js +131 -0
  30. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/profiles.js +366 -0
  31. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/section_selects.js +176 -0
  32. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/suite_path.js +106 -0
  33. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/overview.js +27 -8
  34. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/suite.js +1 -1
  35. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/information.js +10 -0
  36. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/layout.js +4 -1
  37. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/main.js +4 -6
  38. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/menu.js +249 -39
  39. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/globals.js +13 -1
  40. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/information.js +31 -5
  41. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/settings.js +6 -0
  42. robotframework_dashboard-2.4.0/robotframework_dashboard/server.py +211 -0
  43. robotframework_dashboard-2.4.0/robotframework_dashboard/server_models.py +289 -0
  44. robotframework_dashboard-2.4.0/robotframework_dashboard/server_routes_logs.py +193 -0
  45. robotframework_dashboard-2.4.0/robotframework_dashboard/server_routes_outputs.py +275 -0
  46. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/templates/admin.html +3 -1
  47. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/templates/dashboard.html +150 -48
  48. robotframework_dashboard-2.4.0/robotframework_dashboard/version.py +1 -0
  49. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0/robotframework_dashboard.egg-info}/PKG-INFO +2 -2
  50. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard.egg-info/SOURCES.txt +28 -3
  51. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/setup.py +2 -2
  52. robotframework_dashboard-2.3.0/robotframework_dashboard/css/components.css +0 -774
  53. robotframework_dashboard-2.3.0/robotframework_dashboard/js/eventlisteners.js +0 -1491
  54. robotframework_dashboard-2.3.0/robotframework_dashboard/js/filter.js +0 -1524
  55. robotframework_dashboard-2.3.0/robotframework_dashboard/server.py +0 -908
  56. robotframework_dashboard-2.3.0/robotframework_dashboard/version.py +0 -1
  57. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/LICENSE +0 -0
  58. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/MANIFEST.in +0 -0
  59. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/pyproject.toml +0 -0
  60. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/__init__.py +0 -0
  61. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/abstractdb.py +0 -0
  62. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/css/dark.css +0 -0
  63. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dashboard.py +0 -0
  64. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/bootstrap.css +0 -0
  65. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/bootstrap.js +0 -0
  66. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/chart.js +0 -0
  67. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/chartjs-adapter-date-fns.js +0 -0
  68. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/chartjs-chart-boxplot.js +0 -0
  69. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/chartjs-chart-matrix.js +0 -0
  70. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/chartjs-plugin-datalabels.js +0 -0
  71. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/datatables.css +0 -0
  72. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/datatables.js +0 -0
  73. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/gridstack.css +0 -0
  74. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/gridstack.js +0 -0
  75. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/pako.js +0 -0
  76. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies.py +0 -0
  77. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/admin_page/admin_api.js +0 -0
  78. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/admin_page/admin_common.js +0 -0
  79. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/admin_page/admin_eventlisteners.js +0 -0
  80. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/admin_page/admin_information.js +0 -0
  81. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/admin_page/admin_main.js +0 -0
  82. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/admin_page/admin_theme.js +0 -0
  83. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/customsections.js +0 -0
  84. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/database.js +0 -0
  85. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/all.js +0 -0
  86. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/chart_factory.js +0 -0
  87. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/compare.js +0 -0
  88. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/config_helpers.js +0 -0
  89. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/keyword.js +0 -0
  90. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/run.js +0 -0
  91. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/tables.js +0 -0
  92. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/test.js +0 -0
  93. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/donut.js +0 -0
  94. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/duration.js +0 -0
  95. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/duration_deviation.js +0 -0
  96. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/exceptions.js +0 -0
  97. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/failed.js +0 -0
  98. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/flaky.js +0 -0
  99. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/graph_config.js +0 -0
  100. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/heatmap.js +0 -0
  101. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/helpers.js +0 -0
  102. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/messages.js +0 -0
  103. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/statistics.js +0 -0
  104. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/stats.js +0 -0
  105. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/time_consuming.js +0 -0
  106. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/tooltip_helpers.js +0 -0
  107. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/linkwidgets.js +0 -0
  108. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/localstorage.js +0 -0
  109. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/log.js +0 -0
  110. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/statwidgets.js +0 -0
  111. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/theme.js +0 -0
  112. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/chartconfig.js +0 -0
  113. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/data.js +0 -0
  114. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/graphmetadata.js +0 -0
  115. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/graphs.js +0 -0
  116. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/statwidgetdefs.js +0 -0
  117. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/svg.js +0 -0
  118. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/licenses/THIRD_PARTY_LICENSES.txt +0 -0
  119. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/main.py +0 -0
  120. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/processors.py +0 -0
  121. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/queries.py +0 -0
  122. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/robotdashboard.py +0 -0
  123. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/robotdashboardlistener.py +0 -0
  124. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard.egg-info/dependency_links.txt +0 -0
  125. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard.egg-info/entry_points.txt +0 -0
  126. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard.egg-info/not-zip-safe +0 -0
  127. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard.egg-info/requires.txt +0 -0
  128. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard.egg-info/top_level.txt +0 -0
  129. {robotframework_dashboard-2.3.0 → robotframework_dashboard-2.4.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: robotframework-dashboard
3
- Version: 2.3.0
3
+ Version: 2.4.0
4
4
  Summary: Output processor and dashboard generator for Robot Framework output files
5
5
  Home-page: https://github.com/marketsquare/robotframework-dashboard
6
6
  Author: Tim de Groot
@@ -84,7 +84,7 @@ For all available CLI options see the [Basic CLI docs](https://marketsquare.gith
84
84
  - 📄 **Dashboard Pages** - Overview, Dashboard, and Compare pages for multi-level insights.
85
85
  - 🎛️ **Customizable Layouts** - Drag-and-drop sections with adjustable size and order.
86
86
  - 📊 **Graph Customization** - Toggle legends, axis titles, labels, and control animations.
87
- - 🔎 **Global Filters** - Filter runs by name, tags, date, metadata, or quantity.
87
+ - 🔎 **Global Filters** - Filter runs by name, tags, date, metadata, or quantity. Drag across the runs-over-time histogram to zoom into a period. Every filter option shows how many runs it still matches, and options that match none are greyed out.
88
88
  - ⚖️ **Comparison Mode** - Compare up to 4 runs side by side with visual statistics.
89
89
  - 🔗 **Automatic Log Linking** - Open Robot Framework logs directly from the dashboard.
90
90
  - 🛠️ **Custom Database Classes** - Extend or replace the database processor for custom backends.
@@ -54,7 +54,7 @@ For all available CLI options see the [Basic CLI docs](https://marketsquare.gith
54
54
  - 📄 **Dashboard Pages** - Overview, Dashboard, and Compare pages for multi-level insights.
55
55
  - 🎛️ **Customizable Layouts** - Drag-and-drop sections with adjustable size and order.
56
56
  - 📊 **Graph Customization** - Toggle legends, axis titles, labels, and control animations.
57
- - 🔎 **Global Filters** - Filter runs by name, tags, date, metadata, or quantity.
57
+ - 🔎 **Global Filters** - Filter runs by name, tags, date, metadata, or quantity (applied per project). Drag across the runs-over-time histogram to zoom into a period. Every filter option shows how many runs it still matches, and options that match none are greyed out.
58
58
  - ⚖️ **Comparison Mode** - Compare up to 4 runs side by side with visual statistics.
59
59
  - 🔗 **Automatic Log Linking** - Open Robot Framework logs directly from the dashboard.
60
60
  - 🔁 **Rerun History** - Merged `--rerunfailed` outputs keep the status of every attempt per test.
@@ -97,7 +97,7 @@ robotframework-dashboard is designed to stay fast even as your result set grows.
97
97
  - **Dashboard generation** is nearly always **under 1 second** regardless of scale — data is already aggregated in the database, so re-generating HTML after adding new runs is essentially free.
98
98
  - **Incremental processing** — output files already in the database are automatically skipped, so you can safely re-run against a folder of XMLs without re-processing old results.
99
99
  - **HTML size** stays modest (~500 KB–1 MB for typical workloads) thanks to zlib compression of the embedded data.
100
- - **Dashboard rendering** (Chart.js in the browser) depends on how many runs are displayed. The default limit is **20 runs** (near-instant). Raising it to **50 runs** takes a few seconds as Chart.js renders all graphs. At **100+ runs**, initial rendering can approach **~10 seconds or more!**. This is also affected by your suite and test size — selecting **"All Suites"** or **"All Tests"** in their respective sections amplifies render time significantly, since each unique name becomes a separate data series. Use the quantity filter to keep the displayed run count manageable.
100
+ - **Dashboard rendering** (Chart.js in the browser) depends on how many runs are displayed. The default limit is **20 runs per project** (near-instant). Raising it to **50 runs** takes a few seconds as Chart.js renders all graphs. At **100+ runs**, initial rendering can approach **~10 seconds or more!**. This is also affected by your suite and test size — selecting **"All Suites"** or **"All Tests"** in their respective sections amplifies render time significantly, since each unique name becomes a separate data series. Use the quantity filter to keep the displayed run count manageable.
101
101
 
102
102
  For detailed results and scaling guidance, see the [Performance docs](https://marketsquare.github.io/robotframework-dashboard/performance.html).
103
103
 
@@ -103,8 +103,8 @@ class ArgumentParser:
103
103
  combo = limit_parts[0] + "".join(f";tag={value}" for value in tag_values)
104
104
  print(
105
105
  f" INFO: Combining 'limit' with 'tag(s)' -> keeping the {limit_value} most recent "
106
- f"run(s) tagged with [{', '.join(tag_values)}] and removing older matching runs "
107
- f"(runs without these tags are left untouched)."
106
+ f"run(s) per project tagged with [{', '.join(tag_values)}] and removing older "
107
+ f"matching runs (runs without these tags are left untouched)."
108
108
  )
109
109
  # other independent options (index/run_start/alias) run before the combo
110
110
  return other_parts + [combo]
@@ -314,10 +314,11 @@ class ArgumentParser:
314
314
  " • '-r index=0,index=1:4;9,index=10'\n"
315
315
  " • '-r run_start=2024-07-30 15:27:20.184407' -> remove specified run\n"
316
316
  " • '-r alias=some_alias,tag=prod'\n"
317
- " • '-r limit=10' -> keep only the 10 most recent runs\n"
318
- " • '-r limit=10,tag=nightly' -> keep 10 newest 'nightly' runs, leave others\n"
317
+ " • '-r limit=10' -> keep only the 10 most recent runs per project\n"
318
+ " • '-r limit=10,tag=nightly' -> keep 10 newest 'nightly' runs per project, leave others\n"
319
319
  " • '-r age=10d' -> remove runs older than 10 days\n"
320
320
  " • '-r age=-10d' -> remove runs younger than 10 days\n"
321
+ " • a project is a run name and every 'project_' run tag\n"
321
322
  " • (y)ear/(d)ay/(h)our/(m)inute/(s)econd supported\n"
322
323
  ),
323
324
  action="append",
@@ -409,7 +410,8 @@ class ArgumentParser:
409
410
  "--quantity",
410
411
  metavar="INT",
411
412
  help=(
412
- "Number of runs shown on initial dashboard load (default: 20).\n"
413
+ "Number of runs per project shown on initial dashboard load (default: 20).\n"
414
+ " • a project is a run name and every 'project_' run tag\n"
413
415
  " • Higher values slow initial load\n"
414
416
  "Examples:\n"
415
417
  " • '-q 25'\n"
@@ -169,6 +169,15 @@ body {
169
169
  padding-right: 0px !important;
170
170
  }
171
171
 
172
+ /* Bootstrap locks the page behind a modal with overflow:hidden on <body>, but the dashboard's
173
+ scrollbar sits on <html> (.html-scroll above), so the page keeps scrolling without this.
174
+ scrollbar-gutter keeps the scrollbar width reserved, otherwise the layout jumps sideways
175
+ every time a modal opens. */
176
+ html:has(body.modal-open) {
177
+ overflow: hidden;
178
+ scrollbar-gutter: stable;
179
+ }
180
+
172
181
  h4,
173
182
  h5,
174
183
  h6 {
@@ -265,6 +274,10 @@ body.lock-scroll {
265
274
  overflow: hidden;
266
275
  }
267
276
 
277
+ #navigation {
278
+ min-height: 54px;
279
+ }
280
+
268
281
  #mainNavItems {
269
282
  white-space: nowrap;
270
283
  min-width: 0;
@@ -282,6 +295,35 @@ body.lock-scroll {
282
295
  display: block;
283
296
  }
284
297
 
298
+ .nav-tracks-hidden .nav-track {
299
+ display: none;
300
+ }
301
+ .nav-track {
302
+ display: flex;
303
+ align-items: center;
304
+ /* the navbar row stretches its flex items, which made the track fill the bar top to bottom */
305
+ align-self: center;
306
+ gap: 2px;
307
+ padding: 3px;
308
+ margin: 0 6px;
309
+ border-radius: 999px;
310
+ background: var(--color-track-bg);
311
+ border: 1px solid var(--color-track-border);
312
+ flex-shrink: 0;
313
+ }
314
+ .navbar .nav-track-item {
315
+ padding: 3px 13px;
316
+ font-size: 0.8125rem;
317
+ line-height: 1.3;
318
+ border-radius: 999px;
319
+ white-space: nowrap;
320
+ }
321
+ .navbar .nav-track-item.active,
322
+ .navbar .nav-track-item.active:hover {
323
+ background: var(--color-highlight);
324
+ color: var(--color-on-highlight);
325
+ }
326
+
285
327
  .sidenav-backdrop {
286
328
  position: fixed;
287
329
  top: 0; left: 0; right: 0; bottom: 0;
@@ -343,29 +385,80 @@ body.lock-scroll {
343
385
  color: var(--color-text-muted);
344
386
  letter-spacing: 0.05em;
345
387
  }
388
+ .sidenav-group-header {
389
+ display: flex;
390
+ align-items: center;
391
+ border-left: 3px solid transparent;
392
+ }
393
+ .sidenav-group-header:hover {
394
+ background: var(--color-menu-hover-bg);
395
+ }
396
+ .sidenav-group-header.active {
397
+ border-left-color: var(--color-highlight);
398
+ background: var(--color-highlight-tint);
399
+ }
346
400
  .sidenav-body .sidenav-nav-item {
401
+ flex: 1;
402
+ min-width: 0;
403
+ padding: 7px 4px 7px 16px;
404
+ font-weight: 500;
405
+ color: var(--color-menu-text);
406
+ text-decoration: none;
407
+ cursor: pointer;
408
+ white-space: nowrap;
409
+ overflow: hidden;
410
+ text-overflow: ellipsis;
411
+ }
412
+ .sidenav-group-header:hover .sidenav-nav-item {
413
+ color: var(--color-highlight);
414
+ }
415
+ .sidenav-group-header.active .sidenav-nav-item {
416
+ font-weight: 600;
417
+ color: var(--color-highlight);
418
+ }
419
+ .sidenav-group-toggle {
420
+ background: none;
421
+ border: none;
422
+ padding: 8px 14px 8px 8px;
423
+ color: var(--color-text-muted);
424
+ cursor: pointer;
425
+ display: flex;
426
+ }
427
+ .sidenav-group-header.active .sidenav-group-toggle {
428
+ color: var(--color-highlight);
429
+ }
430
+ .sidenav-group-toggle svg {
431
+ width: 15px;
432
+ height: 15px;
347
433
  display: block;
348
- padding: 6px 16px;
434
+ }
435
+ .sidenav-subgroup {
436
+ display: flex;
437
+ flex-direction: column;
438
+ margin: 2px 0 6px 22px;
439
+ border-left: 1px solid var(--color-border);
440
+ }
441
+ .sidenav-body .sidenav-sub-item {
442
+ display: block;
443
+ padding: 6px 12px 6px 14px;
444
+ margin-left: -1px;
445
+ font-size: 0.84375rem;
349
446
  color: var(--color-menu-text);
350
447
  text-decoration: none;
351
448
  cursor: pointer;
352
449
  white-space: nowrap;
353
450
  overflow: hidden;
354
451
  text-overflow: ellipsis;
355
- border-left: 3px solid transparent;
452
+ border-left: 2px solid transparent;
356
453
  }
357
- .sidenav-body .sidenav-nav-item:hover {
358
- background: rgba(255, 255, 255, 0.06);
454
+ .sidenav-body .sidenav-sub-item:hover {
455
+ background: var(--color-menu-hover-bg);
359
456
  color: var(--color-highlight);
360
457
  }
361
- .sidenav-body .sidenav-nav-item.active {
458
+ .sidenav-body .sidenav-sub-item.active {
362
459
  border-left-color: var(--color-highlight);
363
460
  color: var(--color-highlight);
364
461
  }
365
- .sidenav-body .sidenav-nav-submenu {
366
- padding-left: 32px;
367
- font-style: italic;
368
- }
369
462
  .sidenav-icon-row {
370
463
  display: grid;
371
464
  grid-template-columns: repeat(3, auto);
@@ -3,8 +3,15 @@
3
3
  --color-card: #ffffff;
4
4
  --color-menu-text: var(--color-text);
5
5
  --color-highlight: #3451b2;
6
+ --color-on-highlight: #ffffff;
7
+ --color-highlight-tint: rgba(52, 81, 178, 0.07);
8
+ --color-track-bg: rgba(0, 0, 0, 0.07);
9
+ --color-track-border: rgba(0, 0, 0, 0.08);
10
+ --color-menu-hover-bg: rgba(0, 0, 0, 0.05);
6
11
  --color-text: #000000;
7
- --color-text-muted: darkgrey;
12
+ --color-text-muted: #6c757d;
13
+ --color-text-disabled: #6c757d;
14
+ --color-popover-bg: #ffffff;
8
15
  --color-border: rgba(0, 0, 0, 0.175);
9
16
  --color-shadow-strong: rgba(0, 0, 0, 0.5);
10
17
  --color-shadow-soft: rgba(0, 0, 0, 0.3);
@@ -33,8 +40,15 @@
33
40
  --color-card: rgba(30, 41, 59, 0.9);
34
41
  --color-menu-text: var(--color-text);
35
42
  --color-highlight: #a8b1ff;
43
+ --color-on-highlight: #10192f;
44
+ --color-highlight-tint: rgba(168, 177, 255, 0.1);
45
+ --color-track-bg: rgba(255, 255, 255, 0.08);
46
+ --color-track-border: rgba(255, 255, 255, 0.12);
47
+ --color-menu-hover-bg: rgba(255, 255, 255, 0.06);
36
48
  --color-text: #eee;
37
49
  --color-text-muted: #9ca3af;
50
+ --color-text-disabled: #94a3b8;
51
+ --color-popover-bg: #1e293b;
38
52
  --color-border: rgba(255, 255, 255, 0.15);
39
53
  --color-shadow-strong: rgba(0, 0, 0, 0.5);
40
54
  --color-shadow-soft: rgba(0, 0, 0, 0.3);
@@ -0,0 +1,78 @@
1
+ /* The numbered prefix is the cascade order: these files are concatenated between
2
+ colors.css and dark.css in path order, so renaming one reorders the stylesheet. */
3
+
4
+ .tooltip-popup {
5
+ position: fixed;
6
+ max-width: 360px;
7
+ padding: 8px 12px;
8
+ border-radius: 8px;
9
+ background-color: var(--color-tooltip-bg);
10
+ color: var(--color-tooltip-text);
11
+ box-shadow: 0 2px 8px var(--color-shadow-soft);
12
+ font-size: 0.95rem;
13
+ white-space: pre-line;
14
+ pointer-events: none;
15
+ z-index: 9999;
16
+ box-sizing: border-box;
17
+ }
18
+
19
+ .card {
20
+ margin-bottom: 1rem;
21
+ box-shadow: 0 4px 20px var(--color-shadow-strong);
22
+ color: var(--color-text);
23
+ background: var(--color-bg);
24
+ }
25
+
26
+ .overview-card > .card {
27
+ background: var(--color-card) !important;
28
+ }
29
+
30
+ .stats {
31
+ float: right;
32
+ text-align: right;
33
+ font-size: 0.9em;
34
+ white-space: nowrap;
35
+ }
36
+
37
+ .section-filters {
38
+ display: flex;
39
+ flex: 1 1 auto;
40
+ flex-wrap: wrap;
41
+ align-items: center;
42
+ column-gap: 0.75rem;
43
+ row-gap: 6px;
44
+ }
45
+
46
+ .section-filters .filter-group {
47
+ display: flex;
48
+ align-items: center;
49
+ gap: 0.5rem;
50
+ }
51
+
52
+ .container-fluid .form-check-input,
53
+ #sectionFiltersModal .form-check-input {
54
+ margin-top: 6px;
55
+ position: static;
56
+ }
57
+
58
+ .fullscreen {
59
+ position: fixed !important;
60
+ width: 100% !important;
61
+ height: 100% !important;
62
+ left: 0 !important;
63
+ top: 0 !important;
64
+ z-index: 10 !important;
65
+ padding: 20px 20px 20px 20px !important;
66
+ border-radius: 0px !important;
67
+ background-color: var(--color-fullscreen-bg) !important;
68
+ }
69
+
70
+ .fullscreen .section-filters {
71
+ flex: 0 0 auto;
72
+ }
73
+
74
+ .fullscreen .graph-body {
75
+ flex: 1 1 0;
76
+ min-height: 0;
77
+ overflow: hidden;
78
+ }
@@ -0,0 +1,260 @@
1
+ .dropdown-menu {
2
+ width: max-content;
3
+ }
4
+
5
+ .version-selected-dot {
6
+ display: inline-block;
7
+ width: 6px;
8
+ height: 6px;
9
+ background-color: var(--color-version-dot);
10
+ border-radius: 50%;
11
+ margin-left: 5px;
12
+ margin-bottom: 2px;
13
+ vertical-align: middle;
14
+ }
15
+
16
+ .selectBox {
17
+ position: relative;
18
+ }
19
+
20
+ .selectBox select {
21
+ width: 100%;
22
+ }
23
+
24
+ .overSelect {
25
+ position: absolute;
26
+ left: 0;
27
+ right: 0;
28
+ top: 0;
29
+ bottom: 0;
30
+ }
31
+
32
+ /* The dropdown panel paints its own opaque surface: the rows inside it use
33
+ --color-card, which is semi-transparent in dark mode, so without this the modal rows
34
+ underneath the panel bleed through and nothing in the panel is readable. */
35
+ .filterCheckBoxes {
36
+ display: none;
37
+ position: absolute;
38
+ z-index: 1056;
39
+ background-color: var(--color-popover-bg);
40
+ border: 1px solid var(--color-border);
41
+ border-radius: 0.375rem;
42
+ box-shadow: 0 0.5rem 1rem var(--color-shadow-soft);
43
+ padding: 0.25rem;
44
+ }
45
+
46
+ /* the wrapper of select + panel is the anchor, so a panel flipped by set_filter_dropdown_visible
47
+ sits directly on top of its select and shrinks towards it while the list is being searched */
48
+ :has(> .filterCheckBoxes) {
49
+ position: relative;
50
+ }
51
+
52
+ .filterCheckBoxes.drop-up {
53
+ top: auto;
54
+ bottom: 100%;
55
+ margin-top: 0 !important;
56
+ margin-bottom: 0.5rem;
57
+ }
58
+
59
+ .filterCheckBoxes .list-group-item {
60
+ background-color: transparent;
61
+ border-color: transparent;
62
+ }
63
+
64
+ .filterCheckBoxes label {
65
+ display: block;
66
+ }
67
+
68
+ /* the search box scrolls with the option list, so pin it to the top of the panel */
69
+ .filterCheckBoxes > input.form-control,
70
+ .filterCheckBoxes > .filter-search-wrapper {
71
+ position: sticky;
72
+ top: 0;
73
+ z-index: 1;
74
+ background-color: var(--color-popover-bg);
75
+ }
76
+
77
+ /* filter options that match no runs with the other filters applied: still visible and
78
+ selectable, only marked so it is clear they cannot add anything to the result. No
79
+ opacity: it dims the checkbox and the count as well, and it is ignored on <option>
80
+ elements in native select popups anyway. */
81
+ .filter-option-unavailable {
82
+ color: var(--color-text-disabled);
83
+ }
84
+
85
+ li.filter-option-unavailable {
86
+ background-color: color-mix(in srgb, var(--color-text-muted) 8%, transparent);
87
+ }
88
+
89
+ li.filter-option-unavailable > label.form-check-label {
90
+ color: var(--color-text-disabled);
91
+ text-decoration: line-through;
92
+ text-decoration-thickness: 1px;
93
+ }
94
+
95
+ /* the count is the reason a row is greyed out, so it keeps full contrast and sits in its
96
+ own right-aligned column instead of trailing a label of arbitrary length */
97
+ .filter-option-count {
98
+ color: var(--color-text-muted);
99
+ font-size: 0.85em;
100
+ margin-left: auto;
101
+ padding-left: 0.5rem;
102
+ flex: 0 0 auto;
103
+ font-variant-numeric: tabular-nums;
104
+ }
105
+
106
+ li.filter-option-unavailable > .filter-option-count {
107
+ font-weight: 600;
108
+ }
109
+
110
+ .filterCheckBoxes li.list-group-item > label.form-check-label {
111
+ flex: 1 1 auto;
112
+ min-width: 0;
113
+ overflow: hidden;
114
+ text-overflow: ellipsis;
115
+ white-space: nowrap;
116
+ }
117
+
118
+ .filter-search-wrapper {
119
+ position: relative;
120
+ }
121
+
122
+ .filter-search-wrapper .form-control {
123
+ padding-right: 1.5rem;
124
+ }
125
+
126
+ .filter-search-clear {
127
+ position: absolute;
128
+ top: 0;
129
+ right: 0;
130
+ bottom: 0;
131
+ width: 1.5rem;
132
+ display: flex;
133
+ align-items: center;
134
+ justify-content: center;
135
+ padding: 0 0 0.15rem 0;
136
+ border: none;
137
+ background: none;
138
+ color: inherit;
139
+ opacity: 0.6;
140
+ font-size: 1.4rem;
141
+ line-height: 1;
142
+ cursor: pointer;
143
+ }
144
+
145
+ .filter-search-clear:hover {
146
+ opacity: 1;
147
+ }
148
+
149
+ .filter-profile-bar {
150
+ border-bottom: 1px solid var(--bs-border-color);
151
+ }
152
+
153
+ .filter-profile-editor {
154
+ border-bottom: 1px solid var(--bs-border-color);
155
+ }
156
+
157
+ .filter-profile-check {
158
+ flex-shrink: 0;
159
+ }
160
+
161
+ .filter-profile-delete {
162
+ opacity: 0.5;
163
+ font-size: 1.1rem;
164
+ line-height: 1;
165
+ padding: 0 0.3rem;
166
+ }
167
+
168
+ .filter-profile-delete:hover {
169
+ opacity: 1;
170
+ }
171
+
172
+ .date-histogram-wrapper {
173
+ position: relative;
174
+ width: 100%;
175
+ height: 160px;
176
+ /* the drag selection is a pointer gesture, so the browser may not claim it for panning */
177
+ touch-action: none;
178
+ cursor: crosshair;
179
+ }
180
+
181
+ .date-histogram-selection {
182
+ position: absolute;
183
+ top: 0;
184
+ bottom: 0;
185
+ background-color: rgba(54, 162, 235, 0.2);
186
+ border-left: 1px solid rgba(54, 162, 235, 0.8);
187
+ border-right: 1px solid rgba(54, 162, 235, 0.8);
188
+ pointer-events: none;
189
+ }
190
+
191
+ .date-histogram-bucket,
192
+ .date-histogram-empty {
193
+ font-size: 0.8rem;
194
+ color: var(--color-text-muted);
195
+ }
196
+
197
+ .date-range-row {
198
+ gap: 0.75rem 1.25rem;
199
+ }
200
+
201
+ .date-range-field {
202
+ flex: 0 0 auto;
203
+ }
204
+
205
+ .date-range-label {
206
+ margin-right: 0.5rem;
207
+ min-width: 2.5rem;
208
+ }
209
+
210
+ .date-range-input {
211
+ width: 150px;
212
+ }
213
+
214
+ /* shaped after the Chart.js tooltip the other graphs use, but an element of its own: the details
215
+ per run are taller than the chart and carry a colour per row, neither of which the tooltip on
216
+ the canvas can do */
217
+ .date-histogram-tooltip {
218
+ position: absolute;
219
+ top: 8px;
220
+ z-index: 3;
221
+ max-width: 320px;
222
+ padding: 6px 8px;
223
+ border-radius: 6px;
224
+ background-color: rgba(0, 0, 0, 0.8);
225
+ color: #fff;
226
+ font-size: 0.75rem;
227
+ line-height: 1.35;
228
+ pointer-events: none;
229
+ }
230
+
231
+ .date-histogram-tooltip-title {
232
+ font-weight: 700;
233
+ margin-bottom: 0.25rem;
234
+ }
235
+
236
+ .date-histogram-tooltip-run + .date-histogram-tooltip-run {
237
+ margin-top: 0.35rem;
238
+ }
239
+
240
+ .date-histogram-tooltip-run-name {
241
+ opacity: 0.85;
242
+ }
243
+
244
+ .date-histogram-tooltip-row {
245
+ display: flex;
246
+ align-items: center;
247
+ }
248
+
249
+ .date-histogram-tooltip-dot {
250
+ width: 9px;
251
+ height: 9px;
252
+ margin-right: 0.4rem;
253
+ border-radius: 2px;
254
+ flex-shrink: 0;
255
+ }
256
+
257
+ .date-histogram-tooltip-empty,
258
+ .date-histogram-tooltip-more {
259
+ opacity: 0.85;
260
+ }