From d3982a4782c0e577d9a010ed09cf390f312d5774 Mon Sep 17 00:00:00 2001 From: Kenneth Okoh Date: Tue, 4 Feb 2025 13:27:02 +0100 Subject: [PATCH] Inventory tables: Increase contrast of inactive entries SUP-21631 Change-Id: I2c99609c6a6d58d3242fa7fbc2d77859e290bb48 --- cmk/gui/views/inventory/_painters.py | 8 ++- cmk/gui/views/inventory/_tree_renderer.py | 72 ++++++++++++------- .../src/themes/facelift/scss/_variables.scss | 5 +- .../src/themes/facelift/scss/_views.scss | 11 ++- .../themes/modern-dark/scss/_variables.scss | 3 +- 5 files changed, 68 insertions(+), 31 deletions(-) diff --git a/cmk/gui/views/inventory/_painters.py b/cmk/gui/views/inventory/_painters.py index 210ea5634aa..df6101a9ebd 100644 --- a/cmk/gui/views/inventory/_painters.py +++ b/cmk/gui/views/inventory/_painters.py @@ -330,7 +330,7 @@ def _paint_host_inventory_attribute( ) -> CellSpec: if (attributes := _get_attributes(row, path)) is None: return "", "" - return SDItem( + alignment_class, _coloring_class, rendered_value = SDItem( key=key, title=title, value=attributes.pairs.get(key), @@ -338,6 +338,7 @@ def _paint_host_inventory_attribute( paint_function=paint_function, icon_path_svc_problems=theme.detect_icon_path("svc_problems", "icon_"), ).compute_cell_spec() + return alignment_class, rendered_value def attribute_painter_from_hint( @@ -399,7 +400,7 @@ def _paint_host_inventory_column( ) -> CellSpec: if ident not in row: return "", "" - return SDItem( + alignment_class, _coloring_class, rendered_value = SDItem( key=SDKey(ident), title=title, value=row[ident], @@ -407,6 +408,7 @@ def _paint_host_inventory_column( paint_function=paint_function, icon_path_svc_problems=theme.detect_icon_path("svc_problems", "icon_"), ).compute_cell_spec() + return alignment_class, rendered_value def column_painter_from_hint(ident: str, hint: ColumnDisplayHint) -> ColumnPainterFromHint: @@ -427,7 +429,7 @@ def column_painter_from_hint(ident: str, hint: ColumnDisplayHint) -> ColumnPaint sorter=ident, paint=lambda row: _paint_host_inventory_column(row, ident, hint.title, hint.paint_function), export_for_python=lambda row, cell: row.get(ident), - export_for_csv=lambda row, cell: "" if (data := row.get(ident)) is None else str(data), + export_for_csv=lambda row, cell: ("" if (data := row.get(ident)) is None else str(data)), export_for_json=lambda row, cell: row.get(ident), ) diff --git a/cmk/gui/views/inventory/_tree_renderer.py b/cmk/gui/views/inventory/_tree_renderer.py index 0e947fc5f33..f17aa6d2757 100644 --- a/cmk/gui/views/inventory/_tree_renderer.py +++ b/cmk/gui/views/inventory/_tree_renderer.py @@ -8,6 +8,7 @@ from collections.abc import Iterable, Iterator, Mapping, Sequence from dataclasses import dataclass from functools import total_ordering +from typing import Literal from livestatus import SiteId @@ -58,22 +59,26 @@ class SDItem: paint_function: PaintFunction icon_path_svc_problems: str - def compute_cell_spec(self) -> tuple[str, HTML]: - tdclass, code = self.paint_function(self.value) + def compute_cell_spec(self) -> tuple[str, Literal["", "inactive_cell"], HTML]: + # Returns a tuple of two css classes (alignment and coloring) and the HTML value + # We keep alignment and coloring classes separate as we only need the coloring within + # tables + alignment_class, code = self.paint_function(self.value) html_value = HTML.with_escaping(code) if ( not html_value or self.retention_interval is None or self.retention_interval.source == "current" ): - return tdclass, html_value + return alignment_class, "", html_value now = int(time.time()) valid_until = self.retention_interval.cached_at + self.retention_interval.cache_interval keep_until = valid_until + self.retention_interval.retention_interval if now > keep_until: return ( - tdclass, + alignment_class, + "inactive_cell", HTMLWriter.render_span( html_value + HTMLWriter.render_nbsp() @@ -84,7 +89,8 @@ def compute_cell_spec(self) -> tuple[str, HTML]: ) if now > valid_until: return ( - tdclass, + alignment_class, + "inactive_cell", HTMLWriter.render_span( html_value, title=_("Data was provided at %s and is considered valid until %s") @@ -95,7 +101,7 @@ def compute_cell_spec(self) -> tuple[str, HTML]: css=["muted_text"], ), ) - return tdclass, html_value + return alignment_class, "", html_value @dataclass(frozen=True, kw_only=True) @@ -106,21 +112,33 @@ class _SDDeltaItem: new: SDValue paint_function: PaintFunction - def compute_cell_spec(self) -> tuple[str, HTML]: + def compute_cell_spec(self) -> tuple[str, Literal["", "inactive_cell"], HTML]: + # Returns a tuple of two css classes (alignment and coloring) and the HTML value + # The coloring class is always an empty string but was added for a consistent fct signature + # between _SDDeltaItem and SDItem if self.old is None and self.new is not None: - tdclass, rendered_value = self.paint_function(self.new) - return tdclass, HTMLWriter.render_span(rendered_value, css="invnew") + alignment_class, rendered_value = self.paint_function(self.new) + return ( + alignment_class, + "", + HTMLWriter.render_span(rendered_value, css="invnew"), + ) if self.old is not None and self.new is None: - tdclass, rendered_value = self.paint_function(self.old) - return tdclass, HTMLWriter.render_span(rendered_value, css="invold") + alignment_class, rendered_value = self.paint_function(self.old) + return ( + alignment_class, + "", + HTMLWriter.render_span(rendered_value, css="invold"), + ) if self.old == self.new: - tdclass, rendered_value = self.paint_function(self.old) - return tdclass, HTML.with_escaping(rendered_value) + alignment_class, rendered_value = self.paint_function(self.old) + return alignment_class, "", HTML.with_escaping(rendered_value) if self.old is not None and self.new is not None: - tdclass, rendered_old_value = self.paint_function(self.old) - tdclass, rendered_new_value = self.paint_function(self.new) + _, rendered_old_value = self.paint_function(self.old) + alignment_class, rendered_new_value = self.paint_function(self.new) return ( - tdclass, + alignment_class, + "", HTMLWriter.render_span(rendered_old_value, css="invold") + " → " + HTMLWriter.render_span(rendered_new_value, css="invnew"), @@ -280,7 +298,9 @@ def _sort_row(row: Mapping[SDKey, SDDeltaValue]) -> Sequence[_SDDeltaItem]: min_type = _MinType() - def _sanitize(value: SDDeltaValue) -> tuple[_MinType | SDValue, _MinType | SDValue]: + def _sanitize( + value: SDDeltaValue, + ) -> tuple[_MinType | SDValue, _MinType | SDValue]: return (value.old or min_type, value.new or min_type) return ( @@ -384,9 +404,10 @@ def _show_attributes(self, sorted_pairs: Sequence[SDItem] | Sequence[_SDDeltaIte for item in sorted_pairs: html.open_tr() html.th(self._get_header(item.title, item.key)) - # TODO separate tdclass from rendered value - _tdclass, rendered_value = item.compute_cell_spec() - html.open_td() + + # TODO separate alignment_class and coloring_class from rendered value + _alignment_class, coloring_class, rendered_value = item.compute_cell_spec() + html.open_td(class_=coloring_class) html.write_html(rendered_value) html.close_td() html.close_tr() @@ -428,9 +449,9 @@ def _show_table( for row in sorted_rows: html.open_tr(class_="even0") for item in row: - # TODO separate tdclass from rendered value - tdclass, rendered_value = item.compute_cell_spec() - html.open_td(class_=tdclass) + # TODO separate alignment_class and coloring_class from rendered value + alignment_class, coloring_class, rendered_value = item.compute_cell_spec() + html.open_td(class_=" ".join([alignment_class, coloring_class])) html.write_html(rendered_value) html.close_td() html.close_tr() @@ -459,7 +480,10 @@ def _show_node(self, node: ImmutableTree | ImmutableDeltaTree, tree_id: str) -> ("site", self._site_id), ("host", self._host_name), ("raw_path", raw_path), - ("show_internal_tree_paths", "on" if self._show_internal_tree_paths else ""), + ( + "show_internal_tree_paths", + "on" if self._show_internal_tree_paths else "", + ), ("tree_id", tree_id), ], "ajax_inv_render_tree.py", diff --git a/packages/cmk-frontend/src/themes/facelift/scss/_variables.scss b/packages/cmk-frontend/src/themes/facelift/scss/_variables.scss index 4a7e0f6c1e3..e7d49a702b9 100644 --- a/packages/cmk-frontend/src/themes/facelift/scss/_variables.scss +++ b/packages/cmk-frontend/src/themes/facelift/scss/_variables.scss @@ -124,8 +124,9 @@ $popup-menu-select-bg-color: $white; $dragging-bg-color: $grey-1; -$nested-table-th-bg-color: $ux-theme-1; -$nested-table-td-bg-color: $ux-theme-0; +$nested-table-th-bg-color: $ux-theme-4; +$nested-table-td-bg-color: $white; +$nested-table-td-inactive-bg-color: $ux-theme-0; $duallist-control-a-hover-bg-color: $grey-1; diff --git a/packages/cmk-frontend/src/themes/facelift/scss/_views.scss b/packages/cmk-frontend/src/themes/facelift/scss/_views.scss index 8aee742275e..9e673b98336 100644 --- a/packages/cmk-frontend/src/themes/facelift/scss/_views.scss +++ b/packages/cmk-frontend/src/themes/facelift/scss/_views.scss @@ -950,6 +950,15 @@ td.invtree { height: 14px; padding: 2px 6px; background-color: $nested-table-td-bg-color; + + &.inactive_cell { + background-color: $nested-table-td-inactive-bg-color; + + > span { + color: $font-color; + opacity: $inactive-opacity; + } + } } th { @@ -1219,6 +1228,6 @@ td.agent_config table.rulesets td { } } -.muted_text { +span.muted_text { color: $font-color-dimmed; } diff --git a/packages/cmk-frontend/src/themes/modern-dark/scss/_variables.scss b/packages/cmk-frontend/src/themes/modern-dark/scss/_variables.scss index d0f2f0d72c9..11379b8ed66 100644 --- a/packages/cmk-frontend/src/themes/modern-dark/scss/_variables.scss +++ b/packages/cmk-frontend/src/themes/modern-dark/scss/_variables.scss @@ -126,6 +126,7 @@ $dragging-bg-color: $ux-theme-1; $nested-table-th-bg-color: $ux-theme-4; $nested-table-td-bg-color: $ux-theme-5; +$nested-table-td-inactive-bg-color: $nested-table-td-bg-color; $duallist-control-a-hover-bg-color: color.mix($white, $grey-5, 10%); @@ -208,4 +209,4 @@ $dashlet-figures-grid-color: rgb(128, 151, 177); $scatterplot-hilite-color: rgb(70, 130, 180); $gauge-span-color: $ux-theme-5; $gauge-single-value-color: $font-color; -$inactive-opacity: 0.5; +$inactive-opacity: 0.6;