robotframework-dashboard 2.2.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 (140) hide show
  1. {robotframework_dashboard-2.2.0/robotframework_dashboard.egg-info → robotframework_dashboard-2.4.0}/PKG-INFO +5 -4
  2. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/README.md +5 -2
  3. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/arguments.py +9 -8
  4. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/css/base.css +102 -11
  5. {robotframework_dashboard-2.2.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.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dashboard.py +7 -1
  15. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/database.py +108 -15
  16. robotframework_dashboard-2.4.0/robotframework_dashboard/dependencies/bootstrap.css +6 -0
  17. robotframework_dashboard-2.4.0/robotframework_dashboard/dependencies/bootstrap.js +7 -0
  18. robotframework_dashboard-2.4.0/robotframework_dashboard/dependencies/chart.js +14 -0
  19. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies/chartjs-adapter-date-fns.js +1 -1
  20. robotframework_dashboard-2.4.0/robotframework_dashboard/dependencies/chartjs-chart-boxplot.js +2 -0
  21. robotframework_dashboard-2.4.0/robotframework_dashboard/dependencies/chartjs-chart-matrix.js +8 -0
  22. robotframework_dashboard-2.4.0/robotframework_dashboard/dependencies/chartjs-plugin-datalabels.js +7 -0
  23. robotframework_dashboard-2.4.0/robotframework_dashboard/dependencies/datatables.css +21 -0
  24. robotframework_dashboard-2.4.0/robotframework_dashboard/dependencies/datatables.js +22 -0
  25. robotframework_dashboard-2.4.0/robotframework_dashboard/dependencies/gridstack.css +1 -0
  26. robotframework_dashboard-2.4.0/robotframework_dashboard/dependencies/gridstack.js +9 -0
  27. robotframework_dashboard-2.4.0/robotframework_dashboard/dependencies/pako.js +2 -0
  28. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/dependencies.py +29 -25
  29. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/admin_page/admin_api.js +21 -3
  30. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/admin_page/admin_eventlisteners.js +0 -1
  31. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/admin_page/admin_information.js +1 -1
  32. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/common.js +38 -15
  33. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/customsections.js +0 -9
  34. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/collapsables.js +25 -0
  35. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/confirm_modal.js +41 -0
  36. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/filter_modal.js +253 -0
  37. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/graph_view_buttons.js +354 -0
  38. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/merge_profiles.js +140 -0
  39. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/overview_listeners.js +83 -0
  40. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/section_filters.js +386 -0
  41. robotframework_dashboard-2.4.0/robotframework_dashboard/js/eventlisteners/settings_modal.js +358 -0
  42. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/availability.js +269 -0
  43. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/controls.js +228 -0
  44. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/date_histogram.js +488 -0
  45. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/modal_options.js +284 -0
  46. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/pipeline.js +477 -0
  47. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/profile_merge.js +131 -0
  48. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/profiles.js +366 -0
  49. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/section_selects.js +176 -0
  50. robotframework_dashboard-2.4.0/robotframework_dashboard/js/filter/suite_path.js +106 -0
  51. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/all.js +14 -3
  52. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/chart_factory.js +0 -2
  53. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/compare.js +2 -4
  54. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/config_helpers.js +4 -5
  55. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/keyword.js +84 -4
  56. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/overview.js +112 -232
  57. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/run.js +0 -3
  58. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/suite.js +1 -5
  59. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/tables.js +19 -6
  60. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_creation/test.js +3 -4
  61. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/duration.js +0 -2
  62. robotframework_dashboard-2.4.0/robotframework_dashboard/js/graph_data/exceptions.js +94 -0
  63. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/failed.js +7 -2
  64. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/flaky.js +30 -49
  65. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/graph_config.js +6 -1
  66. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/helpers.js +80 -10
  67. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/messages.js +6 -2
  68. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/statistics.js +31 -17
  69. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/stats.js +6 -0
  70. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/tooltip_helpers.js +0 -1
  71. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/information.js +11 -1
  72. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/layout.js +12 -28
  73. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/linkwidgets.js +0 -15
  74. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/localstorage.js +3 -9
  75. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/log.js +1 -1
  76. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/main.js +4 -6
  77. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/menu.js +258 -78
  78. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/statwidgets.js +0 -25
  79. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/theme.js +0 -9
  80. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/chartconfig.js +5 -0
  81. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/data.js +3 -1
  82. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/globals.js +15 -3
  83. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/graphmetadata.js +17 -7
  84. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/information.js +40 -10
  85. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/settings.js +9 -3
  86. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/statwidgetdefs.js +3 -0
  87. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/licenses/THIRD_PARTY_LICENSES.txt +65 -56
  88. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/processors.py +114 -11
  89. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/queries.py +7 -2
  90. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/robotdashboardlistener.py +0 -6
  91. robotframework_dashboard-2.4.0/robotframework_dashboard/server.py +211 -0
  92. robotframework_dashboard-2.4.0/robotframework_dashboard/server_models.py +289 -0
  93. robotframework_dashboard-2.4.0/robotframework_dashboard/server_routes_logs.py +193 -0
  94. robotframework_dashboard-2.4.0/robotframework_dashboard/server_routes_outputs.py +275 -0
  95. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/templates/admin.html +4 -2
  96. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/templates/dashboard.html +192 -63
  97. robotframework_dashboard-2.4.0/robotframework_dashboard/version.py +1 -0
  98. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0/robotframework_dashboard.egg-info}/PKG-INFO +5 -4
  99. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard.egg-info/SOURCES.txt +29 -3
  100. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/setup.py +5 -4
  101. robotframework_dashboard-2.2.0/robotframework_dashboard/css/components.css +0 -740
  102. robotframework_dashboard-2.2.0/robotframework_dashboard/dependencies/bootstrap.css +0 -6
  103. robotframework_dashboard-2.2.0/robotframework_dashboard/dependencies/bootstrap.js +0 -7
  104. robotframework_dashboard-2.2.0/robotframework_dashboard/dependencies/chart.js +0 -20
  105. robotframework_dashboard-2.2.0/robotframework_dashboard/dependencies/chartjs-chart-boxplot.js +0 -2
  106. robotframework_dashboard-2.2.0/robotframework_dashboard/dependencies/chartjs-chart-matrix.js +0 -8
  107. robotframework_dashboard-2.2.0/robotframework_dashboard/dependencies/chartjs-plugin-datalabels.js +0 -7
  108. robotframework_dashboard-2.2.0/robotframework_dashboard/dependencies/datatables.css +0 -18
  109. robotframework_dashboard-2.2.0/robotframework_dashboard/dependencies/datatables.js +0 -25
  110. robotframework_dashboard-2.2.0/robotframework_dashboard/dependencies/gridstack.css +0 -1
  111. robotframework_dashboard-2.2.0/robotframework_dashboard/dependencies/gridstack.js +0 -9
  112. robotframework_dashboard-2.2.0/robotframework_dashboard/dependencies/pako.js +0 -2
  113. robotframework_dashboard-2.2.0/robotframework_dashboard/js/eventlisteners.js +0 -1503
  114. robotframework_dashboard-2.2.0/robotframework_dashboard/js/filter.js +0 -1629
  115. robotframework_dashboard-2.2.0/robotframework_dashboard/server.py +0 -916
  116. robotframework_dashboard-2.2.0/robotframework_dashboard/version.py +0 -1
  117. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/LICENSE +0 -0
  118. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/MANIFEST.in +0 -0
  119. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/pyproject.toml +0 -0
  120. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/__init__.py +0 -0
  121. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/abstractdb.py +0 -0
  122. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/css/dark.css +0 -0
  123. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/admin_page/admin_common.js +0 -0
  124. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/admin_page/admin_main.js +0 -0
  125. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/admin_page/admin_theme.js +0 -0
  126. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/database.js +0 -0
  127. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/donut.js +0 -0
  128. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/duration_deviation.js +0 -0
  129. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/heatmap.js +0 -0
  130. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/graph_data/time_consuming.js +0 -0
  131. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/graphs.js +0 -0
  132. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/js/variables/svg.js +0 -0
  133. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/main.py +0 -0
  134. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard/robotdashboard.py +0 -0
  135. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard.egg-info/dependency_links.txt +0 -0
  136. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard.egg-info/entry_points.txt +0 -0
  137. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard.egg-info/not-zip-safe +0 -0
  138. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard.egg-info/requires.txt +0 -0
  139. {robotframework_dashboard-2.2.0 → robotframework_dashboard-2.4.0}/robotframework_dashboard.egg-info/top_level.txt +0 -0
  140. {robotframework_dashboard-2.2.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.2.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,14 +84,15 @@ 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.
91
91
  - 🖥️ **Server Mode** - Host your dashboard for multi-user access and automatic updates.
92
92
  - 🎧 **Listener Integration** - Automatically updates dashboard after every test run.
93
- - 📝 **Message Config Support** - Group similar test failures using regex-based patterns.
94
- - ⚙️ **Configurable Defaults** - Preload dashboard settings via JSON for consistent appearance.
93
+ - 📝 **Message Config Support** - Group similar test failures using regex-based patterns.
94
+ - 🚨 **Exception Tracking** - Track exception messages caught by TRY/EXCEPT blocks across runs, with a dedicated graph and table.
95
+ - ⚙️ **Configurable Defaults** - Preload dashboard settings via JSON for consistent appearance.
95
96
 
96
97
  …and many more advanced features to help you visualize, analyze, and manage your Robot Framework test results with ease!
97
98
 
@@ -54,13 +54,15 @@ 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
+ - 🔁 **Rerun History** - Merged `--rerunfailed` outputs keep the status of every attempt per test.
60
61
  - 🛠️ **Custom Database Classes** - Extend or replace the database processor for custom backends.
61
62
  - 🖥️ **Server Mode** - Host your dashboard for multi-user access and automatic updates.
62
63
  - 🎧 **Listener Integration** - Automatically updates dashboard after every test run.
63
64
  - 📝 **Message Config Support** - Group similar test failures using regex-based patterns.
65
+ - 🚨 **Exception Tracking** - Track exception messages caught by TRY/EXCEPT blocks across runs, with a dedicated graph and table.
64
66
  - ⚙️ **Configurable Defaults** - Preload dashboard settings via JSON for consistent appearance.
65
67
 
66
68
  …and many more advanced features to help you visualize, analyze, and manage your Robot Framework test results with ease!
@@ -83,6 +85,7 @@ For detailed usage instructions, advanced examples, and full documentation, visi
83
85
  - 🗄️ [**Custom Database Class**](https://marketsquare.github.io/robotframework-dashboard/custom-database-class.html) - Extend or replace the default database backend to suit your storage needs, including SQLite, MySQL, or custom implementations.
84
86
  - 🔔 [**Listener Integration**](https://marketsquare.github.io/robotframework-dashboard/listener-integration.html) - Use a listener to automatically push test results to the dashboard for every executed run, integrating seamlessly into CI/CD pipelines.
85
87
  - 📂 [**Log Linking**](https://marketsquare.github.io/robotframework-dashboard/log-linking.html) - Enable clickable log navigation from dashboard graphs, covering file naming conventions, local and server usage, and remote log uploads.
88
+ - 🔁 [**Reruns**](https://marketsquare.github.io/robotframework-dashboard/reruns.html) - Feed merged `--rerunfailed` outputs to the dashboard and see the attempt history of every re-executed test.
86
89
  - 📈 [**Performance**](https://marketsquare.github.io/robotframework-dashboard/performance.html) - Performance results across different workload sizes, guidance on scaling to hundreds of runs, and tips for large result sets.
87
90
 
88
91
 
@@ -94,7 +97,7 @@ robotframework-dashboard is designed to stay fast even as your result set grows.
94
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.
95
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.
96
99
  - **HTML size** stays modest (~500 KB–1 MB for typical workloads) thanks to zlib compression of the embedded data.
97
- - **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.
98
101
 
99
102
  For detailed results and scaling guidance, see the [Performance docs](https://marketsquare.github.io/robotframework-dashboard/performance.html).
100
103
 
@@ -78,9 +78,8 @@ class ArgumentParser:
78
78
  lets users write the combo with the regular comma separator (e.g.
79
79
  '-r "limit=10,tag=nightly"') instead of ';'.
80
80
 
81
- Scope note (matches issue #309): only 'limit' can be scoped by tags.
82
- 'age' + 'tags' is intentionally NOT supported here — combining them
83
- just runs as two independent operations, same as on main.
81
+ Only 'limit' can be scoped by tags; 'age' + 'tags' run as two
82
+ independent operations.
84
83
 
85
84
  Rules:
86
85
  - No tags, or tags without a 'limit' partner -> no combination, every
@@ -104,8 +103,8 @@ class ArgumentParser:
104
103
  combo = limit_parts[0] + "".join(f";tag={value}" for value in tag_values)
105
104
  print(
106
105
  f" INFO: Combining 'limit' with 'tag(s)' -> keeping the {limit_value} most recent "
107
- f"run(s) tagged with [{', '.join(tag_values)}] and removing older matching runs "
108
- 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)."
109
108
  )
110
109
  # other independent options (index/run_start/alias) run before the combo
111
110
  return other_parts + [combo]
@@ -315,10 +314,11 @@ class ArgumentParser:
315
314
  " • '-r index=0,index=1:4;9,index=10'\n"
316
315
  " • '-r run_start=2024-07-30 15:27:20.184407' -> remove specified run\n"
317
316
  " • '-r alias=some_alias,tag=prod'\n"
318
- " • '-r limit=10' -> keep only the 10 most recent runs\n"
319
- " • '-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"
320
319
  " • '-r age=10d' -> remove runs older than 10 days\n"
321
320
  " • '-r age=-10d' -> remove runs younger than 10 days\n"
321
+ " • a project is a run name and every 'project_' run tag\n"
322
322
  " • (y)ear/(d)ay/(h)our/(m)inute/(s)econd supported\n"
323
323
  ),
324
324
  action="append",
@@ -410,7 +410,8 @@ class ArgumentParser:
410
410
  "--quantity",
411
411
  metavar="INT",
412
412
  help=(
413
- "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"
414
415
  " • Higher values slow initial load\n"
415
416
  "Examples:\n"
416
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 {
@@ -213,7 +222,6 @@ body.lock-scroll {
213
222
  cursor: pointer;
214
223
  }
215
224
 
216
- /* ── Info label + small icon (tooltip on label hover) ── */
217
225
  .info-label {
218
226
  display: inline-flex !important;
219
227
  align-items: center;
@@ -266,6 +274,10 @@ body.lock-scroll {
266
274
  overflow: hidden;
267
275
  }
268
276
 
277
+ #navigation {
278
+ min-height: 54px;
279
+ }
280
+
269
281
  #mainNavItems {
270
282
  white-space: nowrap;
271
283
  min-width: 0;
@@ -283,7 +295,35 @@ body.lock-scroll {
283
295
  display: block;
284
296
  }
285
297
 
286
- /* ── Sidebar (off-canvas menu for overflowed items) ── */
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
+
287
327
  .sidenav-backdrop {
288
328
  position: fixed;
289
329
  top: 0; left: 0; right: 0; bottom: 0;
@@ -345,29 +385,80 @@ body.lock-scroll {
345
385
  color: var(--color-text-muted);
346
386
  letter-spacing: 0.05em;
347
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
+ }
348
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;
349
433
  display: block;
350
- 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;
351
446
  color: var(--color-menu-text);
352
447
  text-decoration: none;
353
448
  cursor: pointer;
354
449
  white-space: nowrap;
355
450
  overflow: hidden;
356
451
  text-overflow: ellipsis;
357
- border-left: 3px solid transparent;
452
+ border-left: 2px solid transparent;
358
453
  }
359
- .sidenav-body .sidenav-nav-item:hover {
360
- background: rgba(255, 255, 255, 0.06);
454
+ .sidenav-body .sidenav-sub-item:hover {
455
+ background: var(--color-menu-hover-bg);
361
456
  color: var(--color-highlight);
362
457
  }
363
- .sidenav-body .sidenav-nav-item.active {
458
+ .sidenav-body .sidenav-sub-item.active {
364
459
  border-left-color: var(--color-highlight);
365
460
  color: var(--color-highlight);
366
461
  }
367
- .sidenav-body .sidenav-nav-submenu {
368
- padding-left: 32px;
369
- font-style: italic;
370
- }
371
462
  .sidenav-icon-row {
372
463
  display: grid;
373
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
+ }