def _show_failed_notifications(self): if not self.parameters()["show_failed_notifications"]: return failed_notifications = notifications.number_of_failed_notifications( after=notifications.acknowledged_time() ) if not failed_notifications: return html.open_div(class_="spacertop") html.open_div(class_="tacticalalert") confirm_url = makeuri_contextless(request, [], filename="clear_failed_notifications.py") html.icon_button(confirm_url, _("Confirm failed notifications"), "delete", target="main") view_url = makeuri_contextless( request, [("view_name", "failed_notifications")], filename="view.py", ) html.a(_("%d failed notifications") % failed_notifications, target="main", href=view_url) html.close_div() html.close_div()
def write_snapin_exception(e: Exception) -> None: html.open_div(class_=["snapinexception"]) html.h2(_("Error")) html.p(str(e)) html.div(traceback.format_exc().replace("\n", "<br>"), style="display:none;") html.close_div()
def _show_form(self) -> None: assert user.id is not None credentials = load_two_factor_credentials(user.id) credential_id = request.get_ascii_input_mandatory("_edit") credential = credentials["webauthn_credentials"].get(credential_id) if credential is None: raise MKUserError("_edit", _("The credential does not exist")) html.begin_form("profile", method="POST") html.prevent_password_auto_completion() html.open_div(class_="wato") self._valuespec(credential).render_input( "profile", { "registered_at": credential["registered_at"], "alias": credential["alias"], }, ) forms.end() html.close_div() html.hidden_field("_edit", credential_id) html.hidden_fields() html.end_form() html.footer()
def show(self): html.open_div(class_="speedometer") html.img(theme.url("images/speedometer.svg"), id_="speedometerbg") html.canvas("", width=str(snapin_width), height="146", id_="speedometer") html.close_div() html.javascript("cmk.sidebar.speedometer_show_speed(0, 0, 0);")
def jqm_page_navfooter(items: NavigationBar, current: str, page_id: str) -> None: html.close_div() # close content html.open_div( **{ "data-role": "footer", "data-position": "fixed", "data-tap-toggle": "false", "data-hide-during-focus": "", } ) html.open_div(**{"data-role": "navbar"}) html.open_ul() for href, title, icon, custom_css in items: href = makeuri(request, [("page", href), ("search", "Search")]) if current == href: custom_css += " ui-state-persist ui-btn-active" else: html.open_li() html.a( title, href=href, class_=custom_css, **{ "data-transition": "slide", "data-icon": icon, "data-iconpos": "bottom", }, ) html.close_li() html.close_ul() html.close_div() html.close_div() html.close_div() # close page-div
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 render_user_message_table(what: str) -> None: html.open_div() with table_element( "user_messages", sortable=False, searchable=False, omit_if_empty=True ) as table: for entry in sorted(message.get_gui_messages(), key=lambda e: e["time"], reverse=True): if what not in entry["methods"]: continue table.row() msg_id = entry["id"] datetime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(entry["time"])) msg = entry["text"].replace("\n", " ") table.cell(_("Actions"), css=["buttons"], sortable=False) onclick = ( "cmk.utils.delete_user_message('%s', this);cmk.utils.reload_whole_page();" % msg_id if what == "gui_hint" else "cmk.utils.delete_user_message('%s', this);" % msg_id ) html.icon_button( "", _("Delete"), "delete", onclick=onclick, ) table.cell(_("Message"), msg) table.cell(_("Date"), datetime) html.close_div()
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_sidebar(self) -> None: if not user.may("general.see_sidebar"): html.div("", id_="check_mk_navigation") return user_config = UserSidebarConfig(user, active_config.sidebar) html.open_div( id_="check_mk_navigation", class_="min" if user.get_attribute("nav_hide_icons_title") else None, ) self._show_sidebar_head() html.close_div() assert user.id is not None sidebar_position = cmk.gui.userdb.load_custom_attr( user_id=user.id, key="ui_sidebar_position", parser=lambda x: None if x == "None" else "left", ) html.open_div( id_="check_mk_sidebar", class_=[] if sidebar_position is None else [sidebar_position]) self._show_snapin_bar(user_config) html.close_div() if user_config.folded: html.final_javascript("cmk.sidebar.fold_sidebar();")
def show(self): failed_notifications = notifications.number_of_failed_notifications( after=notifications.acknowledged_time()) if not failed_notifications: return html.open_div(class_="has_failed_notifications") html.open_div(class_="failed_notifications_inner") confirm_url = makeuri_contextless( request, [], filename="clear_failed_notifications.py") html.icon_button(confirm_url, _("Clear failed notifications"), "closetimewarp", target="main") view_url = makeuri_contextless( request, [("view_name", "failed_notifications")], filename="view.py", ) html.a(_("%d failed notifications") % failed_notifications, href=view_url) html.close_div() html.close_div()
def _show_tree(self): tree_spec = self._trees[self._current_tree_id]["tree_spec"] tree = self._compute_tag_tree(tree_spec) html.open_div(class_="tag_tree") self._render_tag_tree_level(tree_spec, [], self._current_tree_path, _("Virtual Host Tree"), tree) html.close_div()
def _show_add_snapin_button(self) -> None: html.open_div(id_="add_snapin") html.open_a(href=makeuri_contextless(request, [], filename="sidebar_add_snapin.py"), target="main") html.icon("add", title=_("Add elements to your sidebar")) html.close_a() html.close_div()
def _show_audit_log_options_controls(self): html.open_div(class_="side_popup_controls") html.open_div(class_="update_buttons") html.button("apply", _("Apply"), "submit") html.buttonlink(makeuri(request, [], remove_prefix="options_"), _("Reset")) html.close_div() html.close_div()
def show(self, page_state: PageState) -> None: html.open_div(class_=self._get_css_classes(page_state), title=page_state.tooltip_text) if page_state.url: html.open_a(page_state.url) self._show_content(page_state) html.close_a() else: self._show_content(page_state) html.close_div()
def _show_output_box(title: str, content: bytes) -> None: html.h3(title, class_="table") html.open_div(class_="log_output") html.write_html( HTML( escaping.escape_attribute( content.decode(errors="surrogateescape")).replace( "\n", "<br>").replace(" ", " "))) html.close_div()
def show(self, breadcrumb: Breadcrumb) -> None: html.open_div(class_="breadcrumb") for item in breadcrumb: if item.url: html.a(escape_to_html(str(item.title)), href=item.url) else: html.span(escape_to_html(str(item.title))) html.close_div()
def action(self) -> ActionResult: if request.var("_action") != "discard": return None if not transactions.check_transaction(): return None if not self._may_discard_changes(): return None if not self.has_changes(): return None # Now remove all currently pending changes by simply restoring the last automatically # taken snapshot. Then activate the configuration. This should revert all pending changes. file_to_restore = self._get_last_wato_snapshot_file() if not file_to_restore: raise MKUserError(None, _("There is no WATO snapshot to be restored.")) msg = _("Discarded pending changes (Restored %s)") % file_to_restore # All sites and domains can be affected by a restore: Better restart everything. _changes.add_change( "changes-discarded", msg, domains=ABCConfigDomain.enabled_domains(), need_restart=True, ) self._extract_snapshot(file_to_restore) activate_changes.execute_activate_changes([ d.get_domain_request([]) for d in ABCConfigDomain.enabled_domains() ]) for site_id in activation_sites(): self.confirm_site_changes(site_id) build_index_background() make_header( html, self.title(), breadcrumb=self.breadcrumb(), show_body_start=display_options.enabled(display_options.H), show_top_heading=display_options.enabled(display_options.T), ) html.open_div(class_="wato") html.show_message(_("Successfully discarded all pending changes.")) html.javascript("hide_changes_buttons();") html.footer() return FinalizeRequest(code=200)
def _show_entry(self, entry: PageMenuEntry) -> None: classes = ["entry"] classes += self._get_entry_css_classes(entry) html.open_div( class_=classes, id_="menu_entry_%s" % entry.name if entry.name else None, title=entry.disabled_tooltip if not entry.is_enabled else None, ) DropdownEntryRenderer().show(entry) html.close_div()
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 display(self, value: FilterHTTPVariables) -> None: html.open_div(class_="multigroup") DualListChoice(choices=self._options(self.info), rows=4, enlarge_active=True).render_input( self.query_filter.request_vars[0], self.query_filter.selection(value)) if self.query_filter.negateable: checkbox_component(self.query_filter.request_vars[1], value, _("negate")) html.close_div()
def _get_mega_menu_content(self, menu_item: MainMenuItem) -> str: with output_funnel.plugged(): menu = mega_menu_registry[menu_item.name] html.open_div( id_="popup_menu_%s" % menu_item.name, class_=(["popup_menu", "main_menu_popup"] + (["min"] if user.get_attribute("nav_hide_icons_title") else [])), ) MegaMenuRenderer().show(menu) html.close_div() return output_funnel.drain()
def page(self) -> None: html.open_div(class_="rulesets") packed = self._packed_agents() if packed: self._download_table(_("Packaged Agents"), packed) titles = { "": _("Agents"), "/plugins": _("Plugins"), "/cfg_examples": _("Example Configurations"), "/cfg_examples/systemd": _("Example configuration for systemd"), "/windows": _("Windows Agent"), "/windows/plugins": _("Plugins"), "/windows/mrpe": _("Scripts to integrate Nagios plugis"), "/windows/cfg_examples": _("Example Configurations"), "/windows/ohm": _("OpenHardwareMonitor (headless)"), "/z_os": _("z/OS"), "/sap": _("SAP R/3"), } banned_paths = self._exclude_paths() other_sections = [] for root, _dirs, files in os.walk(self._walk_base_dir()): file_paths = [] relpath = root.split("agents")[1] if relpath in banned_paths: continue title = titles.get(relpath, relpath) for filename in files: rel_file_path = relpath + "/" + filename if rel_file_path in banned_paths: continue if self._exclude_by_pattern(rel_file_path): continue path = root + "/" + filename if path not in packed and "deprecated" not in path: file_paths.append(path) other_sections.append((title, file_paths)) for title, file_paths in sorted(other_sections): useful_file_paths = [ p for p in file_paths if not p.endswith("/CONTENTS") ] if useful_file_paths: self._download_table(title, sorted(useful_file_paths)) html.close_div()
def _show_view_as_dashlet(self, view_spec: ViewSpec): html.add_body_css_class("view") html.open_div(id_="dashlet_content_wrapper") is_reload = request.has_var("_reload") view_display_options = "SIXLW" if not is_reload: view_display_options += "HR" request.set_var("display_options", view_display_options) request.set_var("_display_options", view_display_options) html.add_body_css_class("dashlet") # Need to be loaded before processing the painter_options below. # TODO: Make this dependency explicit display_options.load_from_html(request, html) painter_options = PainterOptions.get_instance() painter_options.load(self._dashlet_spec["name"]) # Here the linked view default context has the highest priority # linkedview default>dashlet>url active filter> dashboard. However views # have the "show_filters" default to prefill the filtermenu with empty # valued filters(UX). Those need to be cleared out. Otherwise those # empty filters are the highest priority filters and the user can never # filter the view. view_context = { filtername: filtervalues for filtername, filtervalues in view_spec["context"].items() if { var: value for var, value in filtervalues.items() # These are the filters request variables. Keep set values # For the TriStateFilters unset == ignore == "-1" # all other cases unset is an empty string if (var.startswith("is_") and value != "-1" ) # TriState filters except ignore or (not var.startswith("is_") and value ) # Rest of filters with some value } } context = visuals.get_merged_context(self.context, view_context) view = views.View(self._dashlet_spec["name"], view_spec, context) view.row_limit = views.get_limit() view.only_sites = visuals.get_only_sites_from_context(context) view.user_sorters = views.get_user_sorters() views.process_view(views.GUIViewRenderer(view, show_buttons=False)) html.close_div()
def show(self): html.open_div(class_="mainmenu") for item in self._items: if not item.may_see(): continue html.open_a(href=item.get_url(), onfocus="if (this.blur) this.blur();") html.icon(item.icon, item.title) html.div(item.title, class_="title") html.div(item.description, class_="subtitle") html.close_a() html.close_div()
def update(self): import cmk.gui.sidebar as sidebar # pylint: disable=import-outside-toplevel dashlet = self._dashlet_spec snapin = sidebar.snapin_registry.get(self._dashlet_spec["snapin"]) if not snapin: raise MKUserError(None, _("The configured element does not exist.")) snapin_instance = snapin() html.browser_reload = self.refresh_interval() html.html_head(_("Sidebar element")) html.open_body(class_="side", data_theme=theme.get()) html.open_div(id_="check_mk_sidebar") html.open_div(id_="side_content") html.open_div(id_="snapin_container_%s" % dashlet["snapin"], class_="snapin") html.open_div(id_="snapin_%s" % dashlet["snapin"], class_="content") styles = snapin_instance.styles() if styles: html.style(styles) snapin_instance.show() html.close_div() html.close_div() html.close_div() html.close_div() html.body_end()
def page(self) -> cmk.gui.pages.PageResult: breadcrumb = make_simple_page_breadcrumb( mega_menu_registry["help_links"], _("Info")) make_header( html, self._title(), breadcrumb=breadcrumb, ) html.open_div(id_="info_title") html.h1(_("Your monitoring machine")) html.a( HTMLWriter.render_img(theme.url("images/tribe29.svg")), "https://tribe29.com", target="_blank", ) html.close_div() html.div(None, id_="info_underline") html.open_div(id_="info_intro_text") html.span(_("Open. Effective. Awesome.")) html.span( _("May we present? Monitoring as it's supposed to be: " "incredibly quick to install, infinetely scalable, highly customizable and " "designed for admins.")) html.span( _("Visit our %s to learn more about Checkmk and about the %s.") % ( HTMLWriter.render_a( _("website"), "https://checkmk.com", target="_blank"), HTMLWriter.render_a( _("latest version"), "https://checkmk.com/product/latest-version", target="_blank", ), )) html.close_div() version_major_minor = re.sub(r".\d+$", "", Version(__version__).version_base) if version_major_minor: current_version_link = "https://checkmk.com/product/checkmk-%s" % version_major_minor else: current_version_link = "https://checkmk.com/product/latest-version" html.open_div(id="info_image") html.open_a(href=current_version_link, target="_blank") html.img(theme.url("images/monitoring-machine.png")) html.close_a() html.close_div() html.close_div() html.open_div(id_="info_footer") html.span( _("© %s tribe29 GmbH. All Rights Reserved.") % time.strftime("%Y")) html.a(_("License agreement"), href="https://checkmk.com/legal.html", target="_blank") html.close_div()
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 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()