def _page_not_found() -> Response: # TODO: This is a page handler. It should not be located in generic application # object. Move it to another place if request.has_var("_plain_error"): html.write_text(_("Page not found")) else: title = _("Page not found") make_header( html, title, Breadcrumb([ BreadcrumbItem( title="Nowhere", url=None, ), BreadcrumbItem( title=title, url="javascript:document.location.reload(false)", ), ]), ) html.show_error(_("This page was not found. Sorry.")) html.footer() return response
def _create_status_box( self, site_ids: Collection[livestatus.SiteId], css_class: str, site_status: str, ): html.open_div(class_="spacertop") html.open_div(class_=css_class) message_template = ungettext("%d site is %s.", "%d sites are %s.", len(site_ids)) message = message_template % (len(site_ids), site_status) tooltip_template = ungettext( "Associated hosts, services and events are not included " "in the Tactical Overview. The %s site is %s.", "Associated hosts, services and events are not included " "in the Tactical Overview. The %s sites are %s.", len(site_ids), ) tooltip = tooltip_template % (site_status, ", ".join(site_ids)) if user.may("wato.sites"): url = makeuri_contextless(request, [("mode", "sites")], filename="wato.py") html.icon_button(url, tooltip, "sites", target="main") html.a(message, target="main", href=url) else: html.icon("sites", tooltip) html.write_text(message) html.close_div() html.close_div()
def _show_item_title(self, item: TopicMenuItem) -> None: item_title: Union[HTML, str] = item.title if not item.button_title: html.write_text(item_title) return html.span(item.title) html.button(item.name, item.button_title)
def _show_start_form(self): html.begin_form("bulkinventory", method="POST") msgs = [] if self._all: vs = vs_bulk_discovery(render_form=True) else: # "Include subfolders" does not make sense for a selection of hosts # which is already given in the following situations: # - in the current folder below 'Selected hosts: Discovery' # - Below 'Bulk import' a automatic service discovery for # imported/selected hosts can be executed vs = vs_bulk_discovery(render_form=True, include_subfolders=False) msgs.append( _("You have selected <b>%d</b> hosts for bulk discovery.") % len(self._get_hosts_to_discover())) # The cast is needed for the moment, because mypy does not understand our data structure here selection = cast(Tuple[bool, bool, bool, bool], self._bulk_discovery_params["selection"]) self._bulk_discovery_params["selection"] = [False] + list( selection[1:]) msgs.append( _("The Checkmk discovery will automatically find and configure services " "to be checked on your hosts and may also discover host labels.") ) html.open_p() html.write_text(" ".join(msgs)) vs.render_input("bulkinventory", self._bulk_discovery_params) forms.end() html.hidden_fields() html.end_form()
def _show_command_form(datasource: ABCDataSource, rows: Rows) -> None: what = datasource.infos[0] html.javascript( """ $(document).ready(function() { $('.command_group').has('x').trigger('expand'); $('x').children().css('background-color', '#f84'); }); """ ) one_shown = False html.open_div(**{"data-role": "collapsible-set"}) for command_class in command_registry.values(): command = command_class() if what in command.tables and user.may(command.permission.name): html.open_div(class_=["command_group"], **{"data-role": "collapsible"}) html.h3(command.title) html.open_p() html.begin_form("actions") html.hidden_field("_do_actions", "yes") html.hidden_field("actions", "yes") command.render(what) html.hidden_fields() html.end_form() html.close_p() html.close_div() one_shown = True html.close_div() if not one_shown: html.write_text(_("No commands are possible in this view"))
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_wato(mini): if not active_config.wato_enabled: html.write_text(_("Setup is disabled.")) return False if not user.may("wato.use"): html.write_text(_("You are not allowed to use the setup.")) return False menu = get_wato_menu_items() if mini: for topic in menu: for item in topic.items: html.icon_button( url=item.url, class_=["show_more_mode"] if item.is_show_more else [], title=item.title, icon=item.icon or "wato", target="main", ) else: show_topic_menu(treename="wato", menu=menu, show_item_icons=True) pending_info = get_pending_changes_info() if pending_info: footnotelinks([(pending_info, "wato.py?mode=changelog")]) html.div("", class_="clear") return None
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): with table_element() as table: for index, connection in enumerate(load_connection_config()): table.row() table.cell(_("Actions"), css=["buttons"]) edit_url = folder_preserving_link([("mode", "edit_ldap_connection"), ("id", connection["id"])]) delete_url = make_confirm_link( url=make_action_link([("mode", "ldap_config"), ("_delete", index)]), message= _("Do you really want to delete the LDAP connection <b>%s</b>?" ) % connection["id"], ) drag_url = make_action_link([("mode", "ldap_config"), ("_move", index)]) clone_url = folder_preserving_link([ ("mode", "edit_ldap_connection"), ("clone", connection["id"]) ]) html.icon_button(edit_url, _("Edit this LDAP connection"), "edit") html.icon_button(clone_url, _("Create a copy of this LDAP connection"), "clone") html.element_dragger_url("tr", base_url=drag_url) html.icon_button(delete_url, _("Delete this LDAP connection"), "delete") table.cell("", css=["narrow"]) if connection.get("disabled"): html.icon( "disabled", _("This connection is currently not being used for synchronization." ), ) else: html.empty_icon_button() table.cell(_("ID"), connection["id"]) if cmk_version.is_managed_edition(): table.cell(_("Customer"), managed.get_customer_name(connection)) table.cell(_("Description")) url = connection.get("docu_url") if url: html.icon_button( url, _("Context information about this connection"), "url", target="_blank") html.write_text(" ") html.write_text(connection["description"])
def _call_noauth(): try: func() except Exception as e: html.write_text(str(e)) if active_config.debug: html.write_text(traceback.format_exc()) return response
def ajax_message_read(): response.set_content_type("application/json") try: message.delete_gui_message(request.var("id")) html.write_text("OK") except Exception: if active_config.debug: raise html.write_text("ERROR")
def checkbox_row(options: List[Tuple[str, str]], value: FilterHTTPVariables, title: Optional[str] = None) -> None: html.begin_checkbox_group() if title: html.write_text(title) checkbox_default = not any(value.values()) for var, text in options: html.checkbox(var, bool(value.get(var, checkbox_default)), label=text) html.end_checkbox_group()
def _show_custom_user_attr(user_spec: UserSpec, custom_attr) -> None: for name, attr in custom_attr: if attr.user_editable(): vs = attr.valuespec() forms.section(_u(vs.title())) value = user_spec.get(name, vs.default_value()) if not attr.permission() or user.may(attr.permission()): vs.render_input("ua_" + name, value) html.help(_u(vs.help())) else: html.write_text(vs.value_to_html(value))
def _show_subtree(self, tree, path, show_host): # Check if we have an assumed state: comparing assumed state (tree[1]) with state (tree[0]) if tree[1] and tree[0] != tree[1]: addclass = ["assumed"] effective_state = tree[1] else: addclass = [] effective_state = tree[0] is_leaf = self._is_leaf(tree) if is_leaf: leaf = "leaf" mc = None else: leaf = "noleaf" mc = self._get_mousecode(path) classes = [ "bibox_box", leaf, "open" if self._is_open(path) else "closed", "state", "state%d" % effective_state["state"], ] + addclass omit = self._omit_root and len(path) == 1 if not omit: html.open_span( id_="%d:%s" % (self._expansion_level or 0, self._path_id(path)), class_=classes, onclick=mc, ) if is_leaf: self._show_leaf(tree, show_host) else: html.write_text(tree[2]["title"].replace(" ", " ")) html.close_span() if not is_leaf and not self._omit_content(path): html.open_span( class_="bibox", style="display: none;" if not self._is_open(path) and not omit else "", ) for node in tree[3]: new_path = path + [node[2]["title"]] self._show_subtree(node, new_path, show_host) html.close_span()
def _show_items(self, topic_id: str, topic: TopicMenuTopic) -> None: html.open_ul() for item in sorted(topic.items, key=lambda g: g.sort_index): self._show_item(item) html.open_li(class_="show_all_items") html.open_a(href="", onclick="cmk.popup_menu.mega_menu_show_all_items('%s')" % topic_id) if user.get_attribute("icons_per_item"): html.icon("trans") html.write_text(_("Show all")) html.close_a() html.close_li() html.close_ul()
def search_form( title: Optional[str] = None, mode: Optional[str] = None, default_value: str = "" ) -> None: html.begin_form("search", add_transid=False) if title: html.write_text(title + " ") html.text_input("search", size=32, default_value=default_value) html.hidden_fields() if mode: html.hidden_field("mode", mode, add_var=True) html.set_focus("search") html.write_text(" ") html.button("_do_seach", _("Search")) html.end_form()
def page(self): # TODO: remove subclass specific things specifict things (everything with _type == 'user') html.begin_form("attr") forms.header(_("Properties")) forms.section(_("Name"), simple=not self._new, is_required=True) html.help( _( "The name of the attribute is used as an internal key. It cannot be " "changed later." ) ) if self._new: html.text_input("name", self._attr.get("name", "")) html.set_focus("name") else: html.write_text(self._name) html.set_focus("title") forms.section(_("Title") + "<sup>*</sup>", is_required=True) html.help(_("The title is used to label this attribute.")) html.text_input("title", self._attr.get("title", "")) forms.section(_("Topic")) html.help(_("The attribute is added to this section in the edit dialog.")) html.dropdown("topic", self._topics, deflt=self._attr.get("topic", self._default_topic)) forms.section(_("Help Text") + "<sup>*</sup>") html.help(_("You might want to add some helpful description for the attribute.")) html.text_area("help", self._attr.get("help", "")) forms.section(_("Data type")) html.help(_("The type of information to be stored in this attribute.")) if self._new: html.dropdown("type", custom_attr_types(), deflt=self._attr.get("type", "")) else: html.write_text(dict(custom_attr_types())[self._attr.get("type")]) self._add_extra_form_sections() self._show_in_table_option() forms.section(_("Add to monitoring configuration")) html.help(self._macro_help) html.checkbox( "add_custom_macro", self._attr.get("add_custom_macro", False), label=self._macro_label ) forms.end() html.show_localization_hint() html.hidden_fields() html.end_form()
def _show_affected_hosts(affected_hosts: List[CREHost]) -> None: html.open_ul() html.open_li() for nr, host in enumerate(affected_hosts): if nr > 20: html.write_text(_("... (%d more)") % (len(affected_hosts) - 20)) break if nr > 0: html.write_text(", ") html.a(host.name(), href=host.edit_url()) html.close_li() html.close_ul()
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_form(self) -> None: assert user.id is not None users = userdb.load_users() user_spec: Optional[UserSpec] = users.get(user.id) if user_spec is None: html.show_warning(_("Sorry, your user account does not exist.")) html.footer() return html.begin_form("profile", method="POST") html.prevent_password_auto_completion() html.open_div(class_="wato") forms.header(_("Personal settings")) forms.section(_("Username"), simple=True) html.write_text(user_spec.get("user_id", user.id)) forms.section(_("Full name"), simple=True) html.write_text(user_spec.get("alias", "")) select_language(user_spec) # Let the user configure how he wants to be notified rulebased_notifications = rulebased_notifications_enabled() if (not rulebased_notifications and user.may("general.edit_notifications") and user_spec.get("notifications_enabled")): forms.section(_("Notifications")) html.help( _("Here you can configure how you want to be notified about host and service problems and " "other monitoring events.")) get_vs_flexible_notifications().render_input( "notification_method", user_spec.get("notification_method")) if user.may("general.edit_user_attributes"): custom_user_attr_topics = get_user_attributes_by_topic() _show_custom_user_attr(user_spec, custom_user_attr_topics.get("personal", [])) forms.header(_("User interface settings")) _show_custom_user_attr( user_spec, custom_user_attr_topics.get("interface", [])) forms.end() html.close_div() html.hidden_fields() html.end_form() html.footer()
def render_unacknowleged_werks(): werks = unacknowledged_incompatible_werks() if werks and not request.has_var("show_unack"): html.open_div(class_=["warning"]) html.write_text( _("<b>Warning:</b> There are %d unacknowledged incompatible werks:" ) % len(werks)) html.br() html.br() html.a( _("Show unacknowledged incompatible werks"), href=makeuri_contextless(request, [("show_unack", "1"), ("wo_compatibility", "3")]), ) html.close_div()
def _show_link( self, entry: PageMenuEntry, url: Optional[str], onclick: Optional[str], target: Optional[str], ) -> None: html.open_a( href=url, onclick=onclick, target=target, id_=("menu_suggestion_%s" % entry.name if entry.name else None), ) html.icon(entry.icon_name or "trans") html.write_text(entry.shortcut_title or entry.title) html.close_a()
def _gen_node(self, tree, height, show_host): leaves: List[Any] = [] for node in tree[3]: if not node[2].get("hidden"): leaves += self._gen_table(node, height - 1, show_host) with output_funnel.plugged(): html.open_div(class_="aggr_tree") with self._show_node(tree, show_host): html.write_text(tree[2]["title"]) html.close_div() content = HTML(output_funnel.drain()) if leaves: leaves[0][2].append((len(leaves), content)) return leaves
def _handle_exc(self, method) -> None: try: # FIXME: These methods write to the response themselves. This needs to be refactored. method() except MKException as e: response.status_code = http_client.BAD_REQUEST html.write_text(str(e)) except Exception as e: response.status_code = http_client.INTERNAL_SERVER_ERROR if active_config.debug: raise logger.exception("error calling AJAX page handler") handle_exception_as_gui_crash_report( plain_error=True, show_crash_link=getattr(g, "may_see_crash_reports", False), ) html.write_text(str(e))
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 confirm_with_preview(msg: Union[str, HTML], confirm_options: List[Tuple[str, str]], method: str = "POST") -> Optional[bool]: """Show a confirm dialog to the user BE AWARE: In case you just want to have some action confirmed by the user, you should use the javascript powere confirm dialg (make_confirm, add_confirm_on_submit, ...). This method is used only in places where we explicitly need to show important information to the user before he can decide whether or not to confirm the action. The confirm dialog is normally not a dialog which need to be protected by a transid itselfs. It is only a intermediate step to the real action But there are use cases where the confirm dialog is used during rendering a normal page, for example when deleting a dashlet from a dashboard. In such cases, the transid must be added by the confirm dialog. """ if request.var("_do_actions") == _("Cancel"): # User has pressed "Cancel", now invalidate the unused transid transactions.check_transaction() return None # None --> "Cancel" if not any( request.has_var(varname) for _title, varname in confirm_options): mobile = is_mobile(request, response) if mobile: html.open_center() html.open_div(class_="really") html.write_text(msg) html.begin_form("confirm", method=method, add_transid=False) html.hidden_fields(add_action_vars=True) for title, varname in confirm_options: html.button(varname, title, "really") html.button("_do_actions", _("Cancel")) html.end_form() html.close_div() if mobile: html.close_center() return False # False --> "Dialog shown, no answer yet" # Now check the transaction. True: "Yes", None --> Browser reload of "yes" page return True if transactions.check_transaction() else None
def csv_export(self, rows, view, group_cells, cells): output_csv_headers(view) groups, unique_row_ids, matrix_cells = list( create_matrices(rows, group_cells, cells, num_columns=None))[0] value_counts, _row_majorities = self._matrix_find_majorities( rows, cells) painter_options = PainterOptions.get_instance() with table_element(output_format="csv") as table: for cell_nr, cell in enumerate(group_cells): table.row() table.cell("", cell.title(use_short=False)) for _group, group_row in groups: _tdclass, content = cell.render(group_row) table.cell("", content) for rid in unique_row_ids: # Omit rows where all cells have the same values if painter_options.get("matrix_omit_uniform"): at_least_one_different = False for counts in value_counts[rid].values(): if len(counts) > 1: at_least_one_different = True break if not at_least_one_different: continue table.row() _tdclass, content = cells[0].render( list(matrix_cells[rid].values())[0]) table.cell("", content) for group_id, group_row in groups: table.cell("") cell_row = matrix_cells[rid].get(group_id) if cell_row is not None: for cell_nr, cell in enumerate(cells[1:]): _tdclass, content = cell.render(cell_row) if cell_nr: html.write_text(",") html.write_text(content)
def _show_aux_tag_used_by_tags(tags: Set[cmk.utils.tags.GroupedTag]) -> None: if not tags: return html.open_ul() html.open_li() builtin_config = cmk.utils.tags.BuiltinTagConfig() for index, tag in enumerate(sorted(tags, key=lambda t: t.choice_title)): if index > 0: html.write_text(", ") # Builtin tag groups can not be edited if builtin_config.tag_group_exists(tag.group.id): html.write_text(_u(tag.choice_title)) else: edit_url = folder_preserving_link([("mode", "edit_tag"), ("edit", tag.group.id)]) html.a(_u(tag.choice_title), href=edit_url) html.close_li() html.close_ul()
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_mobile_list(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") html.open_ul(class_="mobilelist", **{"data-role": "listview"}) # Paint data rows for row in rows: html.open_li() rendered_cells = [cell.render(row) for cell in cells] if rendered_cells: # First cell (assumedly state) is left rendered_class, rendered_content = rendered_cells[0] html.p(rendered_content, class_=["ui-li-aside", "ui-li-desc", rendered_class]) if len(rendered_cells) > 1: content = HTML(" · ").join([ rendered_cell[1] for rendered_cell in rendered_cells[1:num_columns + 1] ]) html.h3(content) for rendered_cell, cell in zip( rendered_cells[num_columns + 1:], cells[num_columns + 1:]): rendered_class, rendered_content = rendered_cell html.open_p(class_="ui-li-desc") cell.paint_as_header() html.write_text(": ") html.span(rendered_content, class_=rendered_class) html.close_p() html.close_li() html.close_ul() html.javascript('$("ul.mobilelist a").attr("data-ajax", "false");')