robotframework-dashboard 2.0.0__tar.gz → 2.2.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.
- {robotframework_dashboard-2.0.0/robotframework_dashboard.egg-info → robotframework_dashboard-2.2.0}/PKG-INFO +1 -1
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/README.md +2 -1
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/arguments.py +95 -4
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/css/base.css +16 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/css/components.css +179 -32
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/css/dark.css +0 -1
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/database.py +148 -20
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/admin_page/admin_api.js +3 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/common.js +114 -1
- robotframework_dashboard-2.2.0/robotframework_dashboard/js/customsections.js +159 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/eventlisteners.js +100 -5
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/filter.js +120 -3
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_creation/keyword.js +15 -3
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_creation/overview.js +10 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_creation/suite.js +15 -2
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_creation/test.js +28 -6
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/statistics.js +9 -4
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/layout.js +136 -2
- robotframework_dashboard-2.2.0/robotframework_dashboard/js/linkwidgets.js +196 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/localstorage.js +7 -3
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/log.js +8 -1
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/statwidgets.js +158 -63
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/theme.js +36 -1
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/variables/globals.js +7 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/variables/graphmetadata.js +26 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/variables/information.js +18 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/variables/settings.js +3 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/variables/svg.js +16 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/main.py +1 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/processors.py +9 -1
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/queries.py +2 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/robotdashboard.py +18 -1
- robotframework_dashboard-2.2.0/robotframework_dashboard/robotdashboardlistener.py +327 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/server.py +108 -14
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/templates/admin.html +12 -2
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/templates/dashboard.html +183 -13
- robotframework_dashboard-2.2.0/robotframework_dashboard/version.py +1 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0/robotframework_dashboard.egg-info}/PKG-INFO +1 -1
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard.egg-info/SOURCES.txt +3 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/setup.py +1 -1
- robotframework_dashboard-2.0.0/robotframework_dashboard/version.py +0 -1
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/LICENSE +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/MANIFEST.in +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/pyproject.toml +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/__init__.py +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/abstractdb.py +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/css/colors.css +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dashboard.py +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies/bootstrap.css +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies/bootstrap.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies/chart.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies/chartjs-adapter-date-fns.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies/chartjs-chart-boxplot.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies/chartjs-chart-matrix.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies/chartjs-plugin-datalabels.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies/datatables.css +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies/datatables.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies/gridstack.css +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies/gridstack.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies/pako.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/dependencies.py +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/admin_page/admin_common.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/admin_page/admin_eventlisteners.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/admin_page/admin_information.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/admin_page/admin_main.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/admin_page/admin_theme.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/database.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_creation/all.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_creation/chart_factory.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_creation/compare.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_creation/config_helpers.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_creation/run.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_creation/tables.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/donut.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/duration.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/duration_deviation.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/failed.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/flaky.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/graph_config.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/heatmap.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/helpers.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/messages.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/stats.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/time_consuming.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/graph_data/tooltip_helpers.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/information.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/main.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/menu.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/variables/chartconfig.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/variables/data.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/variables/graphs.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/js/variables/statwidgetdefs.js +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard/licenses/THIRD_PARTY_LICENSES.txt +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard.egg-info/dependency_links.txt +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard.egg-info/entry_points.txt +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard.egg-info/not-zip-safe +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard.egg-info/requires.txt +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/robotframework_dashboard.egg-info/top_level.txt +0 -0
- {robotframework_dashboard-2.0.0 → robotframework_dashboard-2.2.0}/setup.cfg +0 -0
|
@@ -78,6 +78,7 @@ For detailed usage instructions, advanced examples, and full documentation, visi
|
|
|
78
78
|
- 🔍 [**Filtering**](https://marketsquare.github.io/robotframework-dashboard/filtering.html) - Apply filters to analyze trends in your test data and highlight specific tags, amounts or datetime ranges.
|
|
79
79
|
- 🎨 [**Customization**](https://marketsquare.github.io/robotframework-dashboard/customization.html) - Customize dashboard sections, graph layouts, and visualizations to suit your workflow.
|
|
80
80
|
- ⚙️ [**Settings**](https://marketsquare.github.io/robotframework-dashboard/settings.html) - Configure dashboard preferences including themes, default views, graph options, and save your settings for consistent team-wide use.
|
|
81
|
+
- 📐 [**Architecture**](https://marketsquare.github.io/robotframework-dashboard/architecture.html) - See how robotdashboard is structured internally, from CLI invocation to a rendered dashboard, in both Regular Mode and Server Mode.
|
|
81
82
|
- 🖥️ [**Dashboard Server**](https://marketsquare.github.io/robotframework-dashboard/dashboard-server.html) - Host the dashboard for multi-user access, programmatic updates, and remote server integration.
|
|
82
83
|
- 🗄️ [**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.
|
|
83
84
|
- 🔔 [**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.
|
|
@@ -122,4 +123,4 @@ This project is licensed under the MIT License.
|
|
|
122
123
|
## 🎬 RoboCon Talk
|
|
123
124
|
See also my 2025 [RoboCon](https://robocon.io) talk, where I explain robotdashboard and its use cases. Note that the UI has improved significantly since then.
|
|
124
125
|
|
|
125
|
-
[](https://www.youtube.com/watch?v=olf1_pd9YfM)
|
|
126
|
+
[](https://www.youtube.com/watch?v=olf1_pd9YfM)
|
|
@@ -4,8 +4,16 @@ from sys import exit
|
|
|
4
4
|
from re import split
|
|
5
5
|
from os import getcwd
|
|
6
6
|
from os.path import join, exists
|
|
7
|
+
from typing import NamedTuple
|
|
7
8
|
from .version import __version__
|
|
8
9
|
|
|
10
|
+
_VALID_LOG_TYPES = {"run", "suite", "test", "keyword", "all"}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LogRemovedConfig(NamedTuple):
|
|
14
|
+
types: list
|
|
15
|
+
path: str
|
|
16
|
+
|
|
9
17
|
|
|
10
18
|
class dotdict(dict):
|
|
11
19
|
"""dot.notation access to dictionary attributes"""
|
|
@@ -61,6 +69,47 @@ class ArgumentParser:
|
|
|
61
69
|
print(" ERROR: Mixing --projectversion and version_ tags not supported")
|
|
62
70
|
exit(2)
|
|
63
71
|
|
|
72
|
+
def _process_remove_runs(self, parts):
|
|
73
|
+
"""Process and validate the comma-separated --removeruns parts.
|
|
74
|
+
|
|
75
|
+
Detects a scoped-retention combination ('limit' + 'tags') and rewrites
|
|
76
|
+
it into the internal 'limit=N;tag=...' form so the limit acts on the
|
|
77
|
+
tagged subset instead of running as two independent operations. This
|
|
78
|
+
lets users write the combo with the regular comma separator (e.g.
|
|
79
|
+
'-r "limit=10,tag=nightly"') instead of ';'.
|
|
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.
|
|
84
|
+
|
|
85
|
+
Rules:
|
|
86
|
+
- No tags, or tags without a 'limit' partner -> no combination, every
|
|
87
|
+
part stays independent (unchanged behavior, including 'age'+'tags').
|
|
88
|
+
- Only one 'limit' may be combined with tags (error otherwise).
|
|
89
|
+
"""
|
|
90
|
+
limit_parts = [p for p in parts if p.startswith("limit=")]
|
|
91
|
+
tag_parts = [p for p in parts if p.startswith("tag=")]
|
|
92
|
+
other_parts = [
|
|
93
|
+
p for p in parts if not (p.startswith("limit=") or p.startswith("tag="))
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
if not tag_parts or not limit_parts:
|
|
97
|
+
return parts
|
|
98
|
+
if len(limit_parts) > 1:
|
|
99
|
+
print(" ERROR: Only one 'limit' may be combined with 'tag(s)'.")
|
|
100
|
+
exit(3)
|
|
101
|
+
|
|
102
|
+
tag_values = [p.replace("tag=", "") for p in tag_parts]
|
|
103
|
+
limit_value = limit_parts[0].replace("limit=", "")
|
|
104
|
+
combo = limit_parts[0] + "".join(f";tag={value}" for value in tag_values)
|
|
105
|
+
print(
|
|
106
|
+
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)."
|
|
109
|
+
)
|
|
110
|
+
# other independent options (index/run_start/alias) run before the combo
|
|
111
|
+
return other_parts + [combo]
|
|
112
|
+
|
|
64
113
|
def _check_argument_warnings(self, arguments, outputs, outputfolderpaths, use_logs, generate_dashboard, no_autoupdate, offline_dependencies):
|
|
65
114
|
"""Checks for argument combinations that are valid but likely unintended and prints warnings"""
|
|
66
115
|
no_outputs = not outputs and not outputfolderpaths
|
|
@@ -267,11 +316,33 @@ class ArgumentParser:
|
|
|
267
316
|
" • '-r run_start=2024-07-30 15:27:20.184407' -> remove specified run\n"
|
|
268
317
|
" • '-r alias=some_alias,tag=prod'\n"
|
|
269
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"
|
|
320
|
+
" • '-r age=10d' -> remove runs older than 10 days\n"
|
|
321
|
+
" • '-r age=-10d' -> remove runs younger than 10 days\n"
|
|
322
|
+
" • (y)ear/(d)ay/(h)our/(m)inute/(s)econd supported\n"
|
|
270
323
|
),
|
|
271
324
|
action="append",
|
|
272
325
|
nargs="*",
|
|
273
326
|
default=None,
|
|
274
327
|
)
|
|
328
|
+
db_group.add_argument(
|
|
329
|
+
"--logremoved",
|
|
330
|
+
metavar="TYPES_PATH",
|
|
331
|
+
help=(
|
|
332
|
+
"Log (append if file exists) run data to jsonl before removing from the db\n"
|
|
333
|
+
" • Supply what types to log (default=all) and (optional) a path to the desired .jsonl\n"
|
|
334
|
+
"Examples:\n"
|
|
335
|
+
" • '--logremoved \"/tmp/removed_runs.jsonl\"'\n"
|
|
336
|
+
" • '--logremoved \"run:suite\"'\n"
|
|
337
|
+
" • '--logremoved \"all:/tmp/removed_runs.jsonl\"'\n"
|
|
338
|
+
),
|
|
339
|
+
action="store",
|
|
340
|
+
type=str,
|
|
341
|
+
nargs="?",
|
|
342
|
+
const="all",
|
|
343
|
+
default=None,
|
|
344
|
+
dest="logremoved",
|
|
345
|
+
)
|
|
275
346
|
db_group.add_argument(
|
|
276
347
|
"-c",
|
|
277
348
|
"--databaseclass",
|
|
@@ -502,11 +573,13 @@ class ArgumentParser:
|
|
|
502
573
|
# handles the processing of --removeruns
|
|
503
574
|
remove_runs = None
|
|
504
575
|
if arguments.removeruns:
|
|
505
|
-
|
|
576
|
+
raw_parts = []
|
|
506
577
|
for runs in arguments.removeruns:
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
578
|
+
for part in str(runs[0]).split(","):
|
|
579
|
+
part = part.strip()
|
|
580
|
+
if part:
|
|
581
|
+
raw_parts.append(part)
|
|
582
|
+
remove_runs = self._process_remove_runs(raw_parts)
|
|
510
583
|
|
|
511
584
|
# handles the boolean handling of relevant arguments
|
|
512
585
|
generate_dashboard = self._normalize_bool(
|
|
@@ -602,6 +675,23 @@ class ArgumentParser:
|
|
|
602
675
|
ssl_certfile = arguments.ssl_certfile
|
|
603
676
|
ssl_keyfile = arguments.ssl_keyfile
|
|
604
677
|
|
|
678
|
+
# handles --logremoved: "type1:type2:path" or "path" or "type1:type2"
|
|
679
|
+
log_removed = None
|
|
680
|
+
if arguments.logremoved:
|
|
681
|
+
parts = arguments.logremoved.split(":")
|
|
682
|
+
types, remaining = [], list(parts)
|
|
683
|
+
# grab element types, leave path, for windows drive letter X: parse
|
|
684
|
+
for part in parts:
|
|
685
|
+
if part in _VALID_LOG_TYPES:
|
|
686
|
+
types.append(part)
|
|
687
|
+
remaining.pop(0)
|
|
688
|
+
else:
|
|
689
|
+
break
|
|
690
|
+
if not types:
|
|
691
|
+
types = ["all"]
|
|
692
|
+
path = ":".join(remaining) if remaining else "robot_removed_runs.jsonl"
|
|
693
|
+
log_removed = LogRemovedConfig(types=types, path=path)
|
|
694
|
+
|
|
605
695
|
# validates argument combinations
|
|
606
696
|
self._check_argument_errors(arguments, outputs, outputfolderpaths, force_json_config, database_class)
|
|
607
697
|
self._check_argument_warnings(arguments, outputs, outputfolderpaths, use_logs, generate_dashboard, no_autoupdate, offline_dependencies)
|
|
@@ -637,5 +727,6 @@ class ArgumentParser:
|
|
|
637
727
|
"ssl_certfile": ssl_certfile,
|
|
638
728
|
"ssl_keyfile": ssl_keyfile,
|
|
639
729
|
"log_url": arguments.logurl,
|
|
730
|
+
"log_removed": log_removed,
|
|
640
731
|
}
|
|
641
732
|
return dotdict(provided_args)
|
|
@@ -124,6 +124,14 @@ body {
|
|
|
124
124
|
.boxplot-graph:hover svg,
|
|
125
125
|
.shown-graph:hover svg,
|
|
126
126
|
.hidden-graph:hover svg,
|
|
127
|
+
.move-to-first-graph:hover svg,
|
|
128
|
+
.move-to-last-graph:hover svg,
|
|
129
|
+
.add-stat-widget-header:hover svg,
|
|
130
|
+
.add-link-widget-header:hover svg,
|
|
131
|
+
.add-section-header:hover svg,
|
|
132
|
+
.delete-custom-stat-widget:hover svg,
|
|
133
|
+
.delete-custom-link-widget:hover svg,
|
|
134
|
+
.delete-custom-section:hover svg,
|
|
127
135
|
.shown-section:hover svg,
|
|
128
136
|
.hidden-section:hover svg,
|
|
129
137
|
.collapse-icon:hover svg,
|
|
@@ -188,6 +196,14 @@ body.lock-scroll {
|
|
|
188
196
|
.boxplot-graph,
|
|
189
197
|
.shown-graph,
|
|
190
198
|
.hidden-graph,
|
|
199
|
+
.move-to-first-graph,
|
|
200
|
+
.move-to-last-graph,
|
|
201
|
+
.add-stat-widget-header,
|
|
202
|
+
.add-link-widget-header,
|
|
203
|
+
.add-section-header,
|
|
204
|
+
.delete-custom-stat-widget,
|
|
205
|
+
.delete-custom-link-widget,
|
|
206
|
+
.delete-custom-section,
|
|
191
207
|
.shown-section,
|
|
192
208
|
.hidden-section,
|
|
193
209
|
.move-up-table,
|
|
@@ -152,53 +152,75 @@
|
|
|
152
152
|
align-items: center;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
/*
|
|
156
|
-
.
|
|
157
|
-
|
|
158
|
-
display: flex;
|
|
159
|
-
align-items: center;
|
|
160
|
-
justify-content: center;
|
|
161
|
-
border: 2px dashed var(--bs-border-color, rgba(128,128,128,0.4));
|
|
162
|
-
border-radius: 8px;
|
|
163
|
-
transition: border-color 0.15s, background-color 0.15s;
|
|
155
|
+
/* Color picker buttons inside the Add Stat Widget modal */
|
|
156
|
+
.stat-color-btn {
|
|
157
|
+
min-width: 60px;
|
|
164
158
|
}
|
|
165
159
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
160
|
+
/* "All" tab stat list inside the Add Stat Widget modal */
|
|
161
|
+
.add-all-widgets-list {
|
|
162
|
+
max-height: 60vh;
|
|
163
|
+
overflow-y: auto;
|
|
169
164
|
}
|
|
170
165
|
|
|
171
|
-
.add-
|
|
166
|
+
.add-all-widgets-row {
|
|
172
167
|
display: flex;
|
|
173
|
-
flex-direction: column;
|
|
174
168
|
align-items: center;
|
|
175
|
-
gap: 0.
|
|
176
|
-
|
|
177
|
-
user-select: none;
|
|
169
|
+
gap: 0.5rem;
|
|
170
|
+
margin-bottom: 0.5rem;
|
|
178
171
|
}
|
|
179
172
|
|
|
180
|
-
.add-
|
|
181
|
-
|
|
182
|
-
font-weight: 300;
|
|
183
|
-
line-height: 1;
|
|
173
|
+
.add-all-widgets-row .form-check {
|
|
174
|
+
margin-bottom: 0;
|
|
184
175
|
}
|
|
185
176
|
|
|
186
|
-
.add-
|
|
187
|
-
|
|
188
|
-
font-weight: 500;
|
|
177
|
+
.add-all-widgets-row .add-all-widgets-title {
|
|
178
|
+
flex: 1 1 auto;
|
|
189
179
|
}
|
|
190
180
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
181
|
+
.add-all-widgets-row .add-all-widgets-badge {
|
|
182
|
+
flex: 0 0 auto;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.add-all-widgets-group-heading {
|
|
186
|
+
font-weight: 600;
|
|
187
|
+
margin-top: 0.5rem;
|
|
188
|
+
margin-bottom: 0.25rem;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.add-all-widgets-group-heading:first-child {
|
|
192
|
+
margin-top: 0;
|
|
194
193
|
}
|
|
195
194
|
|
|
196
|
-
/*
|
|
197
|
-
.
|
|
195
|
+
/* Custom section divider bar rendered inside the unified GridStack */
|
|
196
|
+
.custom-section-divider {
|
|
197
|
+
display: flex;
|
|
198
|
+
align-items: center;
|
|
199
|
+
padding: 0 1rem;
|
|
200
|
+
border-radius: 6px;
|
|
201
|
+
height: 100%;
|
|
202
|
+
width: 100%;
|
|
203
|
+
position: relative;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.custom-section-title {
|
|
207
|
+
flex: 1;
|
|
208
|
+
font-size: 1rem;
|
|
209
|
+
font-weight: 600;
|
|
210
|
+
text-align: center;
|
|
211
|
+
user-select: none;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* Move to first/last + delete controls on custom widgets/sections — pinned to top-right,
|
|
215
|
+
out of flex flow, sized and spaced like the icons in graph headers */
|
|
216
|
+
.custom-widget-move-controls {
|
|
198
217
|
position: absolute;
|
|
199
218
|
top: 5px;
|
|
200
219
|
right: 5px;
|
|
201
220
|
z-index: 1;
|
|
221
|
+
display: flex;
|
|
222
|
+
align-items: center;
|
|
223
|
+
gap: 8px;
|
|
202
224
|
}
|
|
203
225
|
|
|
204
226
|
/* Compact flex layout for custom stat widgets — works at any GridStack size */
|
|
@@ -222,7 +244,12 @@
|
|
|
222
244
|
overflow: hidden;
|
|
223
245
|
text-overflow: ellipsis;
|
|
224
246
|
white-space: nowrap;
|
|
225
|
-
max-width:
|
|
247
|
+
max-width: 100%;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* Leave room for the move/delete controls pinned to the top-right in edit mode */
|
|
251
|
+
.stat-widget-inner:has(.custom-widget-move-controls) .stat-widget-title {
|
|
252
|
+
max-width: calc(100% - 96px);
|
|
226
253
|
}
|
|
227
254
|
|
|
228
255
|
/* When the item is very short (h=1 row ≈ 60px) switch to a side-by-side row */
|
|
@@ -242,14 +269,25 @@
|
|
|
242
269
|
.grid-stack-item[data-gs-h="1"] .stat-widget-title {
|
|
243
270
|
flex: 1 1 0;
|
|
244
271
|
text-align: left;
|
|
245
|
-
max-width: calc(100% - 40px); /*
|
|
272
|
+
max-width: calc(100% - 40px); /* leave room for the value */
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* Leave room for the move/delete controls pinned to the top-right in edit mode */
|
|
276
|
+
.grid-stack-item[gs-h="1"] .stat-widget-inner:has(.custom-widget-move-controls) .stat-widget-title,
|
|
277
|
+
.grid-stack-item[data-gs-h="1"] .stat-widget-inner:has(.custom-widget-move-controls) .stat-widget-title {
|
|
278
|
+
max-width: calc(100% - 136px); /* value + move/delete controls */
|
|
246
279
|
}
|
|
247
280
|
|
|
248
281
|
.grid-stack-item[gs-h="1"] .stat-value,
|
|
249
282
|
.grid-stack-item[data-gs-h="1"] .stat-value {
|
|
250
283
|
flex-shrink: 0;
|
|
251
284
|
font-size: 1.1rem;
|
|
252
|
-
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* Leave room for the move/delete controls pinned to the top-right in edit mode */
|
|
288
|
+
.grid-stack-item[gs-h="1"] .stat-widget-inner:has(.custom-widget-move-controls) .stat-value,
|
|
289
|
+
.grid-stack-item[data-gs-h="1"] .stat-widget-inner:has(.custom-widget-move-controls) .stat-value {
|
|
290
|
+
margin-right: 96px;
|
|
253
291
|
}
|
|
254
292
|
|
|
255
293
|
.grid-stack-item-content.blue-bg { background-color: rgba(13, 110, 253, 0.15); }
|
|
@@ -257,6 +295,92 @@
|
|
|
257
295
|
.grid-stack-item-content.red-bg { background-color: rgba(206, 62, 1, 0.2); }
|
|
258
296
|
.grid-stack-item-content.yellow-bg { background-color: rgba(254, 216, 79, 0.2); }
|
|
259
297
|
|
|
298
|
+
/* ─── Custom link widget ─────────────────────────────────────────────────── */
|
|
299
|
+
|
|
300
|
+
/* Inner layout — mirrors stat-widget-inner */
|
|
301
|
+
.link-widget-inner {
|
|
302
|
+
position: relative;
|
|
303
|
+
display: flex;
|
|
304
|
+
flex-direction: column;
|
|
305
|
+
justify-content: center;
|
|
306
|
+
align-items: center;
|
|
307
|
+
gap: 0.25rem;
|
|
308
|
+
height: 100%;
|
|
309
|
+
text-align: center;
|
|
310
|
+
overflow: hidden;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/* Label — main large text, like .stat-value */
|
|
314
|
+
.link-widget-label {
|
|
315
|
+
margin: 0;
|
|
316
|
+
font-weight: 600;
|
|
317
|
+
font-size: 1.5rem;
|
|
318
|
+
line-height: 1.2;
|
|
319
|
+
overflow: hidden;
|
|
320
|
+
text-overflow: ellipsis;
|
|
321
|
+
white-space: nowrap;
|
|
322
|
+
max-width: 100%;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* URL preview — small muted text below the label */
|
|
326
|
+
.link-widget-url {
|
|
327
|
+
font-size: 0.72rem;
|
|
328
|
+
opacity: 0.55;
|
|
329
|
+
overflow: hidden;
|
|
330
|
+
text-overflow: ellipsis;
|
|
331
|
+
white-space: nowrap;
|
|
332
|
+
max-width: 100%;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/* Leave room for the move/delete controls pinned to the top-right in edit mode */
|
|
336
|
+
.link-widget-inner:has(.custom-widget-move-controls) .link-widget-label,
|
|
337
|
+
.link-widget-inner:has(.custom-widget-move-controls) .link-widget-url {
|
|
338
|
+
max-width: calc(100% - 96px);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* Clickable in non-edit mode */
|
|
342
|
+
.link-widget-clickable {
|
|
343
|
+
cursor: pointer;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/* Same padding as stat widget tiles */
|
|
347
|
+
.grid-stack-item-content:has(.link-widget-inner) {
|
|
348
|
+
padding: 8px 12px;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* h=1 compact row — mirrors stat widget compact layout */
|
|
352
|
+
.grid-stack-item[gs-h="1"] .link-widget-inner,
|
|
353
|
+
.grid-stack-item[data-gs-h="1"] .link-widget-inner {
|
|
354
|
+
flex-direction: row;
|
|
355
|
+
justify-content: space-between;
|
|
356
|
+
align-items: center;
|
|
357
|
+
gap: 0.5rem;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.grid-stack-item[gs-h="1"] .link-widget-label,
|
|
361
|
+
.grid-stack-item[data-gs-h="1"] .link-widget-label {
|
|
362
|
+
flex: 1 1 0;
|
|
363
|
+
font-size: 1.1rem;
|
|
364
|
+
text-align: left;
|
|
365
|
+
max-width: calc(60% - 10px);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.grid-stack-item[gs-h="1"] .link-widget-url,
|
|
369
|
+
.grid-stack-item[data-gs-h="1"] .link-widget-url {
|
|
370
|
+
flex-shrink: 0;
|
|
371
|
+
font-size: 0.72rem;
|
|
372
|
+
text-align: right;
|
|
373
|
+
max-width: 40%;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/* Leave room for the move/delete controls pinned to the top-right in edit mode */
|
|
377
|
+
.grid-stack-item[gs-h="1"] .link-widget-inner:has(.custom-widget-move-controls) .link-widget-url {
|
|
378
|
+
max-width: calc(40% - 96px);
|
|
379
|
+
margin-right: 96px;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/* ─────────────────────────────────────────────────────────────────────────── */
|
|
383
|
+
|
|
260
384
|
.fullscreen .stat-value {
|
|
261
385
|
font-size: 4rem;
|
|
262
386
|
}
|
|
@@ -299,6 +423,22 @@
|
|
|
299
423
|
height: 200px;
|
|
300
424
|
}
|
|
301
425
|
|
|
426
|
+
/* relative run time, pinned to the bottom right corner of a run card without
|
|
427
|
+
affecting the layout of the stats/duration columns next to the donut */
|
|
428
|
+
.overview-card .card-body {
|
|
429
|
+
position: relative;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.run-card-run-time {
|
|
433
|
+
position: absolute;
|
|
434
|
+
right: 1rem;
|
|
435
|
+
bottom: 0.55rem;
|
|
436
|
+
color: var(--color-text-muted);
|
|
437
|
+
cursor: help;
|
|
438
|
+
font-size: 0.85em;
|
|
439
|
+
white-space: nowrap;
|
|
440
|
+
}
|
|
441
|
+
|
|
302
442
|
.overview-card {
|
|
303
443
|
cursor: pointer;
|
|
304
444
|
min-width: 300px;
|
|
@@ -363,6 +503,13 @@
|
|
|
363
503
|
gap: 8px;
|
|
364
504
|
}
|
|
365
505
|
|
|
506
|
+
/* Icon row in section card headers (add stat/link widget, add section, move/show/hide section) */
|
|
507
|
+
.section-header-icons {
|
|
508
|
+
display: flex;
|
|
509
|
+
align-items: center;
|
|
510
|
+
gap: 8px;
|
|
511
|
+
}
|
|
512
|
+
|
|
366
513
|
.grid-stack-item-content .graph-body {
|
|
367
514
|
flex: 1 1 auto;
|
|
368
515
|
display: flex;
|