def show_details(self, crash_info: CrashInfo, row) -> None: details = crash_info["details"] html.h3(_("Details"), class_="table") html.open_table(class_="data") _crash_row(_("Page"), details["page"], odd=False, legend=True) _crash_row(_("Request Method"), details.get("request_method", _("Unknown"))) html.open_tr(class_="data even0") html.td(_("HTTP Parameters"), class_="left") html.open_td() debug_vars(html, html.request, vars_=details["vars"], hide_with_mouse=False) html.close_td() html.close_tr() _crash_row(_("Referer"), details.get("referer", _("Unknown"))) _crash_row(_("Username"), details["username"], odd=False) _crash_row(_("User Agent"), details["user_agent"]) _crash_row(_("Mobile GUI"), details["is_mobile"], odd=False) _crash_row(_("SSL"), details["is_ssl_request"]) _crash_row(_("Language"), details["language"], odd=False) html.close_table()
def show_job_class_infos(cls, job_class_infos, **kwargs): """Renders all jobs from the job_class_infos in a single multi-table""" html.open_table(css="job_table data") for job_class, jobs_info in sorted(job_class_infos.items(), key=lambda x: x[0].gui_title()): html.open_tr() html.open_td(colspan=len(cls.get_headers())) html.h3(job_class.gui_title()) html.close_td() html.close_tr() if not jobs_info: html.open_tr() html.open_td(colspan=len(cls.get_headers())) html.div(_("No entries"), css="info") html.close_td() html.close_tr() continue cls.show_job_row_headers() odd = "even" for job_id, job_status in sorted(jobs_info.items(), key=lambda x: x[1]["started"], reverse=True): cls.render_job_row(job_id, job_status, odd, **kwargs) odd = "even" if odd == "odd" else "odd"
def _show_tree(self): td_style = None if self._wrap_texts == "wrap" else "white-space: nowrap;" tree = self._get_tree() depth = status_tree_depth(tree) leaves = self._gen_table(tree, depth, len(self._row["aggr_hosts"]) > 1) html.open_table(class_=["aggrtree", "ltr"]) odd = "odd" for code, colspan, parents in leaves: html.open_tr() leaf_td = HTMLWriter.render_td(code, class_=["leaf", odd], style=td_style, colspan=colspan) odd = "even" if odd == "odd" else "odd" tds = [leaf_td] for rowspan, c in parents: tds.append( HTMLWriter.render_td(c, class_=["node"], style=td_style, rowspan=rowspan)) if self._mirror: tds.reverse() html.write_html(HTML("").join(tds)) html.close_tr() html.close_table()
def _table_head( treename: str, id_: str, isopen: bool, title: str, show_more_toggle: bool, help_text: Union[str, HTML, None] = None, ) -> None: onclick = foldable_container_onclick(treename, id_, fetch_url=None) img_id = foldable_container_img_id(treename, id_) html.open_thead() html.open_tr(class_="heading") html.open_td(id_="nform.%s.%s" % (treename, id_), onclick=onclick, colspan=2) html.img( id_=img_id, class_=["treeangle", "nform", "open" if isopen else "closed"], src=theme.url("images/tree_closed.svg"), align="absbottom", ) html.write_text(title) html.help(help_text) if show_more_toggle: html.more_button("foldable_" + id_, dom_levels_up=4, with_text=True) html.close_td() html.close_tr() html.close_thead()
def render_mobile_dataset(rows, view, group_cells, cells, num_columns, show_checkboxes): if not is_mobile(request, response): html.show_error(_("This view can only be used in mobile mode.")) return painter_options = PainterOptions.get_instance() painter_options.set("ts_format", "both") for row in rows: html.open_table(class_="dataset") for cell in cells: _tdclass, content = cell.render(row) if not content: continue # Omit empty cells html.open_tr(class_="header") html.th(cell.title()) html.close_tr() html.open_tr(class_="data") cell.paint(row) html.close_tr() html.close_table() html.javascript( '$("table.dataset > tbody > tr.data > td").addClass("ui-shadow").not(".state").addClass("nonstatus");\n' '$("table.dataset > tbody > tr.data a").attr("data-ajax", "false");\n')
def render(self, rows, view, group_cells, cells, num_columns, show_checkboxes): html.open_table(class_="data single") rownum = 0 odd = "odd" while rownum < len(rows): if rownum > 0: html.open_tr(class_="gap") html.td("", class_="gap", colspan=(num_columns + 1)) html.close_tr() thispart = rows[rownum:rownum + num_columns] for cell in cells: odd = "even" if odd == "odd" else "odd" html.open_tr(class_="data %s0" % odd) if view.get("column_headers") != "off": html.td(cell.title(use_short=False), class_="left") for row in thispart: cell.paint(row) if len(thispart) < num_columns: html.td( "", class_="gap", style="border-style: none;", colspan=(1 + num_columns - len(thispart)), ) html.close_tr() rownum += num_columns html.close_table()
def create_graph(name, size, bounds, v_range, legend): html.open_table(class_="prediction") html.open_tr() html.open_td() html.canvas( "", class_="prediction", id_="content_%s" % name, style="width: %dpx; height: %dpx;" % (int(size[0] / 2.0), int(size[1] / 2.0)), width=size[0], height=size[1], ) html.close_td() html.close_tr() html.open_tr() html.open_td(class_="legend") for color, title in legend: html.div("", class_="color", style="background-color: %s" % color) html.div(title, class_="entry") html.close_td() html.close_tr() html.close_table() html.javascript( 'cmk.prediction.create_graph("content_%s", %.4f, %.4f, %.4f, %.4f);' % (name, bounds[0], bounds[1], v_range[0], v_range[1]))
def _show_header_line(self, cells, show_checkboxes): html.open_tr() if show_checkboxes: render_group_checkbox_th() for cell in cells: cell.paint_as_header() html.write_text("\n") html.close_tr()
def page(self): html.open_div(class_="diag_host") html.open_table() html.open_tr() html.open_td() html.begin_form("diag_host", method="POST") html.prevent_password_auto_completion() forms.header(_("Host Properties")) forms.section(legend=False) # The diagnose page shows both snmp variants at the same time # We need to analyse the preconfigured community and set either the # snmp_community or the snmp_v3_credentials vs_dict = {} for key, value in self._host.attributes().items(): if key == "snmp_community" and isinstance(value, tuple): vs_dict["snmp_v3_credentials"] = value continue vs_dict[key] = value vs_host = self._vs_host() vs_host.render_input("vs_host", vs_dict) html.help(vs_host.help()) forms.end() html.open_div(style="margin-bottom:10px") html.close_div() forms.header(_("Options")) value = {} forms.section(legend=False) vs_rules = self._vs_rules() vs_rules.render_input("vs_rules", value) html.help(vs_rules.help()) forms.end() # When clicking "Save & Test" on the "Edit host" page, this will be set # to immediately execute the tests using the just saved settings if request.has_var("_start_on_load"): html.final_javascript("cmk.page_menu.form_submit('diag_host', '_save');") html.hidden_fields() html.end_form() html.close_td() html.open_td(style="padding-left:10px;") self._show_diagnose_output()
def _show_group_header_table(self, group_cells, first_row): html.open_table(class_="groupheader", cellspacing="0", cellpadding="0", border="0") html.open_tr(class_="groupheader") painted = False for cell in group_cells: if painted: html.td(", ") painted = cell.paint(first_row) html.close_tr() html.close_table()
def show(self) -> None: html.open_table(cellspacing="0", class_="sitestate") sites.update_site_states_from_dead_sites() for sitename, _sitealias in user_sites.sorted_sites(): site = site_config.get_site_config(sitename) state = sites.states().get(sitename, sites.SiteStatus({})).get("state") if state is None: state = "missing" switch = "missing" text = escape_to_html(sitename) else: if state == "disabled": switch = "on" text = escape_to_html(site["alias"]) else: switch = "off" text = render_link( site["alias"], "view.py?view_name=sitehosts&site=%s" % sitename) html.open_tr() html.td(text, class_="left") html.open_td(class_="state") if switch == "missing": html.status_label(content=state, status=state, title=_("Site is missing")) else: url = makeactionuri_contextless( request, transactions, [ ("_site_switch", "%s:%s" % (sitename, switch)), ], filename="switch_site.py", ) html.status_label_button( content=state, status=state, title=_("enable this site") if state == "disabled" else _("disable this site"), onclick="cmk.sidebar.switch_site(%s)" % (json.dumps(url)), ) html.close_tr() html.close_table()
def _crash_row(title: str, infotext: HTMLContent, odd: bool = True, legend: bool = False, pre: bool = False) -> None: trclass = "data odd0" if odd else "data even0" tdclass = "left legend" if legend else "left" html.open_tr(class_=trclass) html.td(title, class_=tdclass) if pre: html.td(HTMLWriter.render_pre(infotext)) else: html.td(infotext) html.close_tr()
def test_HTMLWriter(request_context): with output_funnel.plugged(): with output_funnel.plugged(): html.open_div() text = output_funnel.drain() assert text.rstrip("\n").rstrip(" ") == "<div>" with output_funnel.plugged(): # html.open_div().write("test").close_div() html.open_div() html.write_text("test") html.close_div() assert compare_html(output_funnel.drain(), "<div>test</div>") with output_funnel.plugged(): # html.open_table().open_tr().td("1").td("2").close_tr().close_table() html.open_table() html.open_tr() html.td("1") html.td("2") html.close_tr() html.close_table() assert compare_html( output_funnel.drain(), "<table><tr><td>1</td><td>2</td></tr></table>") with output_funnel.plugged(): html.div("test", **{"</div>malicious_code<div>": "trends"}) assert compare_html( output_funnel.drain(), "<div </div>malicious_code<div>=trends>test</div>", ) a = "\u2665" with output_funnel.plugged(): assert HTMLWriter.render_a("test", href="www.test.case") HTMLWriter.render_a("test", href="www.test.case") HTMLWriter.render_a("test", href="www.test.case") HTMLWriter.render_a("test", href="www.test.case") try: assert HTMLWriter.render_a( "test", href=str("www.test.case"), id_=str("something"), class_=str("test_%s") % a, ) except Exception as e: traceback.print_exc() print(e)
def _show_diagnose_output(self): if not request.var("_save"): html.show_message( _( "You can diagnose the connection to a specific host using this dialog. " "You can either test whether your current configuration is still working " "or investigate in which ways a host can be reached. Simply configure the " "connection options you like to try on the right side of the screen and " 'press the "Test" button. The results will be displayed here.' ) ) return if user_errors: html.show_user_errors() return # TODO: Insert any vs_host valuespec validation # These tests can be called with invalid valuespec settings... # TODO: Replace hard coded icon paths with dynamic ones to old or new theme for ident, title in ModeDiagHost.diag_host_tests(): html.h3(title) html.open_table(class_=["data", "test"]) html.open_tr(class_=["data", "odd0"]) html.open_td(class_="icons") html.open_div() html.icon("reload", id_="%s_img" % ident) html.open_a(href="") html.icon( "reload", title=_("Retry this test"), cssclass="retry", id_="%s_retry" % ident ) html.close_a() html.close_div() html.close_td() html.open_td() html.div("", class_="log", id="%s_log" % ident) html.close_td() html.close_tr() html.close_table() html.javascript( "cmk.host_diagnose.start_test(%s, %s, %s)" % ( json.dumps(ident), json.dumps(self._hostname), json.dumps(transactions.fresh_transid()), ) )
def _show_suggestions(self, menu: PageMenu) -> None: entries = menu.suggestions if not entries: return html.open_tr(id_="suggestions") html.open_td(colspan=3) for entry in entries: classes = ["suggestion"] classes += self._get_entry_css_classes(entry) html.open_div(class_=classes) SuggestedEntryRenderer().show(entry) html.close_div() html.close_td() html.close_tr()
def _show_header_line(self, cells, num_columns, show_checkboxes): html.open_tr() for n in range(1, num_columns + 1): if show_checkboxes: if n == 1: render_group_checkbox_th() else: html.th("") for cell in cells: cell.paint_as_header() if n < num_columns: html.td("", class_="gap") html.close_tr()
def show(self, menu: PageMenu, hide_suggestions: bool = False) -> None: html.open_table( id_="page_menu_bar", class_=["menubar", "" if not hide_suggestions else "hide_suggestions"], ) html.open_tr() self._show_dropdowns(menu) if menu.inpage_search: self._show_inpage_search_field(menu.inpage_search) self._show_shortcuts(menu) if menu.has_pending_changes: self._show_pending_changes_icon(menu.pending_changes_tooltip) html.close_tr() self._show_suggestions(menu) html.close_table()
def display(self, value: FilterHTTPVariables): html.open_table(class_="filtertime") for what, whatname in [("from", _("From")), ("until", _("Until"))]: varprefix = self.ident + "_" + what html.open_tr() html.td("%s:" % whatname) html.open_td() html.text_input(varprefix, default_value=value.get(varprefix, "")) html.close_td() html.open_td() html.dropdown( varprefix + "_range", query_filters.time_filter_options(), deflt=value.get(varprefix + "_range", "3600"), ) html.close_td() html.close_tr() html.close_table()
def _show_labels(self, labels, object_type, label_sources): forms.section(_("Effective labels")) html.open_table(class_="setting") html.open_tr() html.open_td(class_="reason") html.i(_("Explicit, ruleset, discovered")) html.close_td() html.open_td(class_=["settingvalue", "used"]) html.write_html( cmk.gui.view_utils.render_labels(labels, object_type, with_links=False, label_sources=label_sources)) html.close_td() html.close_tr() html.close_table()
def section( title: Union[None, HTML, str] = None, checkbox: Union[None, HTML, str, Tuple[str, bool, str]] = None, section_id: Optional[str] = None, simple: bool = False, hide: bool = False, legend: bool = True, css: Optional[str] = None, is_show_more: bool = False, is_changed: bool = False, is_required: bool = False, ) -> None: global g_section_open section_close() html.open_tr( id_=section_id, class_=([] if css is None else [css]) + ["show_more_mode" if is_show_more and not is_changed else "basic"], style="display:none;" if hide else None, ) if legend: html.open_td(class_=["legend"] + (["simple"] if simple else [])) if title: html.open_div( class_=["title"] + (["withcheckbox"] if checkbox else []), title=escaping.strip_tags(title), ) html.write_text(title) html.span("." * 200, class_=["dots"] + (["required"] if is_required else [])) html.close_div() if checkbox: html.open_div(class_="checkbox") if isinstance(checkbox, (str, HTML)): html.write_text(checkbox) else: name, active, attrname = checkbox html.checkbox( name, active, onclick="cmk.wato.toggle_attribute(this, '%s')" % attrname ) html.close_div() html.close_td() html.open_td(class_=["content"] + (["simple"] if simple else [])) g_section_open = True
def _render_rule_reason(self, title, title_url, reason, reason_url, is_default, setting: Union[str, HTML]) -> None: if title_url: title = HTMLWriter.render_a(title, href=title_url) forms.section(title) if reason: reason = HTMLWriter.render_a(reason, href=reason_url) html.open_table(class_="setting") html.open_tr() if is_default: html.td(HTMLWriter.render_i(reason), class_="reason") html.td(setting, class_=["settingvalue", "unused"]) else: html.td(reason, class_="reason") html.td(setting, class_=["settingvalue", "used"]) html.close_tr() html.close_table()
def show(self): html.open_table(class_="dashlet_overview") html.open_tr() html.open_td(valign="top") html.open_a(href="https://checkmk.com/") html.img(theme.url("images/check_mk.trans.120.png"), style="margin-right: 30px;") html.close_a() html.close_td() html.open_td() html.h2("CheckMK") html.write_text( _("Welcome to Checkmk. If you want to learn more about Checkmk, please visit " 'our <a href="https://checkmk.com/" target="_blank">user manual</a>.' )) html.close_td() html.close_tr() html.close_table()
def render(self, rows, view, group_cells, cells, num_columns, show_checkboxes): # N columns. Each should contain approx the same number of entries groups = [] last_group = None for row in rows: this_group = group_value(row, group_cells) if this_group != last_group: last_group = this_group current_group: List[Tuple[str, Any]] = [] groups.append((this_group, current_group)) current_group.append((row_id(view, row), row)) # Create empty columns columns: List[List[Any]] = [] for _x in range(num_columns): columns.append([]) # First put everything into the first column for group in groups: columns[0].append(group) # Shift from left to right as long as useful did_something = True while did_something: did_something = False for i in range(0, num_columns - 1): if self._balance(columns[i], columns[i + 1]): did_something = True # render table html.open_table(class_=["boxlayout", self._css_class()]) html.open_tr() for column in columns: html.open_td(class_="boxcolumn") for header, rows_with_ids in column: self._render_group(rows_with_ids, header, view, group_cells, cells, num_columns, show_checkboxes) html.close_td() html.close_tr() html.close_table()
def _show_ruleset(self, varname): if varname not in rulespec_registry: return rulespec = rulespec_registry[varname] url = makeuri_contextless(request, [("mode", "edit_ruleset"), ("varname", varname)]) html.open_tr() html.th(_("Parameter rule set")) html.open_td() html.icon_button(url, _("Edit parameter rule set for this check type"), "check_parameters") html.a(rulespec.title, url) html.close_td() html.close_tr() html.open_tr() html.th(_("Example for Parameters")) html.open_td() vs = rulespec.valuespec vs.render_input("dummy", vs.default_value()) html.close_td() html.close_tr()
def _show_table(self, api_request): html.open_table(class_="allhosts") html.open_tbody() for map_cfg in api_request["maps"]: html.open_tr() html.open_td() html.div( "", class_=[ "statebullet", self._state_class(map_cfg), self._sub_state_class(map_cfg), self._stale_class(map_cfg), ], title=self._state_title(map_cfg), ) html.a(map_cfg["alias"], href=map_cfg["url"], class_="link", target="main") html.close_td() html.close_tr() html.close_tbody() html.close_table()
def grouped_row_title(index, group_spec, num_rows, trclass, num_cells): is_open = user.get_tree_state("grouped_rows", index, False) html.open_tr(class_=[ "data", "grouped_row_header", "closed" if not is_open else "", "%s0" % trclass ]) html.open_td( colspan=num_cells, onclick="cmk.views.toggle_grouped_rows('grouped_rows', '%s', this, %d)" % (index, num_rows), ) html.img( theme.url("images/tree_closed.svg"), align="absbottom", class_=["treeangle", "nform", "open" if is_open else "closed"], ) html.write_text("%s (%d)" % (group_spec["title"], num_rows)) html.close_td() html.close_tr() return not is_open
def render_mobile_table(rows, view, group_cells, cells, num_columns, show_checkboxes): if not is_mobile(request, response): html.show_error(_("This view can only be used in mobile mode.")) return # Force relative timestamp always. This saves space. painter_options = PainterOptions.get_instance() painter_options.set("ts_format", "rel") odd = "odd" html.open_table(class_="mobile data") # Paint header if view.get("column_headers") != "off": html.open_tr() n = 0 for cell in cells: cell.paint_as_header() html.close_tr() # Paint data rows for row in rows: odd = "even" if odd == "odd" else "odd" html.open_tr(class_="%s0" % odd) for n, cell in enumerate(cells): if n > 0 and n % num_columns == 0: html.close_tr() html.open_tr(class_="%s0" % odd) if n == len(cells) - 1 and n % num_columns != (num_columns - 1): colspan = num_columns - (n % num_columns) else: colspan = None cell.paint(row, colspan=colspan) html.close_row() html.close_table() html.javascript('$("table.mobile a").attr("data-ajax", "false");')
def _show_start_form(self): html.begin_form("parentscan", method="POST") html.hidden_fields() # Mode of action html.open_p() if not self._complete_folder: num_selected = len(get_hosts_from_checkboxes()) html.write_text(_("You have selected <b>%d</b> hosts for parent scan. ") % num_selected) html.p( _( "The parent scan will try to detect the last gateway " "on layer 3 (IP) before a host. This will be done by " "calling <tt>traceroute</tt>. If a gateway is found by " "that way and its IP address belongs to one of your " "monitored hosts, that host will be used as the hosts " "parent. If no such host exists, an artifical ping-only " "gateway host will be created if you have not disabled " "this feature." ) ) forms.header(_("Settings for Parent Scan")) self._settings = ParentScanSettings( **user.load_file( "parentscan", { "where": "subfolder", "alias": _("Created by parent scan"), "recurse": True, "select": "noexplicit", "timeout": 8, "probes": 2, "ping_probes": 5, "max_ttl": 10, "force_explicit": False, }, ) ) # Selection forms.section(_("Selection")) if self._complete_folder: html.checkbox("recurse", self._settings.recurse, label=_("Include all subfolders")) html.br() html.radiobutton( "select", "noexplicit", self._settings.select == "noexplicit", _("Skip hosts with explicit parent definitions (even if empty)") + "<br>", ) html.radiobutton( "select", "no", self._settings.select == "no", _("Skip hosts hosts with non-empty parents (also if inherited)") + "<br>", ) html.radiobutton( "select", "ignore", self._settings.select == "ignore", _("Scan all hosts") + "<br>" ) # Performance forms.section(_("Performance")) html.open_table() html.open_tr() html.open_td() html.write_text(_("Timeout for responses") + ":") html.close_td() html.open_td() html.text_input("timeout", str(self._settings.timeout), size=2, cssclass="number") html.write_text(_("sec")) html.close_td() html.close_tr() html.open_tr() html.open_td() html.write_text(_("Number of probes per hop") + ":") html.close_td() html.open_td() html.text_input("probes", str(self._settings.probes), size=2, cssclass="number") html.close_td() html.close_tr() html.open_tr() html.open_td() html.write_text(_("Maximum distance (TTL) to gateway") + ":") html.close_td() html.open_td() html.text_input("max_ttl", str(self._settings.max_ttl), size=2, cssclass="number") html.close_td() html.close_tr() html.open_tr() html.open_td() html.write_text(_("Number of PING probes") + ":") html.help( _( "After a gateway has been found, Check_MK checks if it is reachable " "via PING. If not, it is skipped and the next gateway nearer to the " "monitoring core is being tried. You can disable this check by setting " "the number of PING probes to 0." ) ) html.close_td() html.open_td() html.text_input("ping_probes", str(self._settings.ping_probes), size=2, cssclass="number") html.close_td() html.close_tr() html.close_table() # Configuring parent forms.section(_("Configuration")) html.checkbox( "force_explicit", deflt=self._settings.force_explicit, label=_( "Force explicit setting for parents even if setting matches that of the folder" ), ) # Gateway creation forms.section(_("Creation of gateway hosts")) html.write_text(_("Create gateway hosts in")) html.open_ul() html.radiobutton( "where", "subfolder", self._settings.where == "subfolder", _("in the subfolder <b>%s/Parents</b>") % Folder.current_disk_folder().title(), ) html.br() html.radiobutton( "where", "here", self._settings.where == "here", _("directly in the folder <b>%s</b>") % Folder.current_disk_folder().title(), ) html.br() html.radiobutton( "where", "there", self._settings.where == "there", _("in the same folder as the host") ) html.br() html.radiobutton( "where", "nowhere", self._settings.where == "nowhere", _("do not create gateway hosts") ) html.close_ul() html.write_text(_("Alias for created gateway hosts") + ": ") html.text_input("alias", default_value=self._settings.alias) forms.end() # Start button html.button("_start", _("Start")) html.hidden_fields() html.end_form()
def _show_rows(self): rows = self._get_rows() if bool([r for r in rows if r.stats is None]): html.center(_("No data from any site")) return html.open_table(class_=["tacticaloverview"], cellspacing="2", cellpadding="0", border="0") show_stales = self.parameters()["show_stale"] and user.may( "general.see_stales_in_tactical_overview" ) has_stale_objects = bool([r for r in rows if r.what != "events" and r.stats[-1]]) for row in rows: if row.what == "events": amount, problems, unhandled_problems = row.stats stales = 0 # no events open and disabled in local site: don't show events if amount == 0 and not active_config.mkeventd_enabled: continue else: amount, problems, unhandled_problems, stales = row.stats context_vars = get_context_url_variables(row.context) html.open_tr() html.th(row.title) html.th(_("Problems"), class_="show_more_mode") html.th( HTMLWriter.render_span(_("Unhandled"), class_="more") + HTMLWriter.render_span(_("Unhandled p."), class_="less") ) if show_stales and has_stale_objects: html.th(_("Stale")) html.close_tr() td_class = "col4" if has_stale_objects else "col3" html.open_tr() url = makeuri_contextless(request, row.views.total + context_vars, filename="view.py") html.open_td(class_=["total", td_class]) html.a("%s" % amount, href=url, target="main") html.close_td() for value, ty in [(problems, "handled"), (unhandled_problems, "unhandled")]: url = makeuri_contextless( request, getattr(row.views, ty) + context_vars, filename="view.py", ) html.open_td( class_=[td_class] + ([] if value == 0 else ["states prob"]) + ["show_more_mode" if ty == "handled" else "basic"] ) link(str(value), url) html.close_td() if show_stales and has_stale_objects: if row.views.stale: url = makeuri_contextless( request, row.views.stale + context_vars, filename="view.py", ) html.open_td(class_=[td_class] + ([] if stales == 0 else ["states prob"])) link(str(stales), url) html.close_td() else: html.td(HTMLWriter.render_span("0")) html.close_tr() html.close_table()
def _render_headers(self, actions_enabled: bool, actions_visible: bool, empty_columns: List[bool]) -> None: if self.options["omit_headers"]: return table_id = self.id html.open_tr() first_col = True for nr, header in enumerate(self.headers): if self.options["omit_empty_columns"] and empty_columns[nr]: continue if header.help_txt: header_title: HTML = HTMLWriter.render_span( header.title, title=header.help_txt) else: header_title = header.title if not isinstance(header.css, list): css_class: "CSSSpec" = [header.css] else: css_class = header.css assert isinstance(css_class, list) css_class = [("header_%s" % c) for c in css_class if c is not None] if not self.options["sortable"] or not header.sortable: html.open_th(class_=css_class) else: css_class.insert(0, "sort") reverse = 0 sort = request.get_ascii_input("_%s_sort" % table_id) if sort: sort_col, sort_reverse = map(int, sort.split(",", 1)) if sort_col == nr: reverse = 1 if sort_reverse == 0 else 0 action_uri = makeactionuri(request, transactions, [("_%s_sort" % table_id, "%d,%d" % (nr, reverse))]) html.open_th( class_=css_class, title=_("Sort by %s") % header.title, onclick="location.href='%s'" % action_uri, ) # Add the table action link if first_col: first_col = False if actions_enabled: if not header_title: header_title = HTML( " " ) # Fixes layout problem with white triangle if actions_visible: state = "0" help_txt = _("Hide table actions") img = "table_actions_on" else: state = "1" help_txt = _("Display table actions") img = "table_actions_off" html.open_div(class_=["toggle_actions"]) html.icon_button( makeuri(request, [("_%s_actions" % table_id, state)]), help_txt, img, cssclass="toggle_actions", ) html.span(header_title) html.close_div() else: html.write_text(header_title) else: html.write_text(header_title) html.close_th() html.close_tr()