class ReportWidget(Updateable): form = Form(fields=[ ("title", "//input[@id='title']"), ("description", "//input[@id='description']"), ("active", "//input[@id='enabled']"), ("filter", ShowingInputs( Select("//select[@id='filter_typ']"), Select("//select[@id='subfilter_typ']"), Select("//select[@id='repfilter_typ']"), min_values=3 )), # Might be abstracted out too ("columns", ShowingInputs( Select("//select[@id='chosen_pivot1']"), Select("//select[@id='chosen_pivot2']"), Select("//select[@id='chosen_pivot3']"), Select("//select[@id='chosen_pivot4']"), min_values=1 )), ("rows", Select("//select[@id='row_count']")), ("timer", Timer()), ("visibility", visibility_obj), ]) def __init__(self, title, description=None, active=None, filter=None, columns=None, rows=None, timer=None, visibility=None): self.title = title self.description = description self.active = active self.filter = filter self.columns = columns self.rows = rows self.timer = timer self.visibility = visibility def create(self, cancel=False): sel.force_navigate("reports_widgets_report_add") fill(self.form, self.__dict__, action=form_buttons.cancel if cancel else form_buttons.add) flash.assert_no_errors() def update(self, updates): sel.force_navigate("reports_widgets_report_edit", context={"widget": self}) fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() def delete(self, cancel=False): sel.force_navigate("reports_widgets_report", context={"widget": self}) toolbar.select("Configuration", "Delete this Widget from the Database", invokes_alert=True) sel.handle_alert(cancel) flash.assert_no_errors()
class ReportWidget(Widget): form = Form(fields=[ ("title", Input("title")), ("description", Input("description")), ("active", Input("enabled")), ("filter", ShowingInputs(Select("//select[@id='filter_typ']"), Select("//select[@id='subfilter_typ']"), Select("//select[@id='repfilter_typ']"), min_values=3)), # Might be abstracted out too ("columns", ShowingInputs(Select("//select[@id='chosen_pivot1']"), Select("//select[@id='chosen_pivot2']"), Select("//select[@id='chosen_pivot3']"), Select("//select[@id='chosen_pivot4']"), min_values=1)), ("rows", Select("//select[@id='row_count']")), ("timer", Timer()), ("visibility", visibility_obj), ]) TITLE = "Reports" pretty_attrs = ['description', 'filter', 'visibility'] def __init__(self, title, description=None, active=None, filter=None, columns=None, rows=None, timer=None, visibility=None): self.title = title self.description = description self.active = active self.filter = filter self.columns = columns self.rows = rows self.timer = timer self.visibility = visibility
class Schedule(Updateable): """Represents a schedule in Intelligence/Reports/Schedules. Args: name: Schedule name. description: Schedule description. filter: 3-tuple with filter selection (see the UI). active: Whether is this schedule active. run: Specifies how often this schedule runs. It can be either string "Once", or a tuple, which maps to the two selects in UI ("Hourly", "Every hour")... time_zone: Specify time zone. start_date: Specify the start date. start_time: Specify the start time either as a string ("0:15") or tuple ("0", "15") send_email: If specifies, turns on e-mail sending. Can be string, or list or set. """ form = Form(fields=[ ("name", "//input[@id='name']"), ("description", "//input[@id='description']"), ("active", "//input[@id='enabled']"), ("filter", ShowingInputs( Select("//select[@id='filter_typ']"), Select("//select[@id='subfilter_typ']"), Select("//select[@id='repfilter_typ']"), min_values=3 )), ("timer", Timer()), ("send_email", "//input[@id='send_email_cb']"), ("emails", EmailSelectForm()) ]) _run_mapping = { "Once": None, "Hourly": "run_hours", "Daily": "run_days", "Weekly": "run_weekly", "Monthly": "run_months" } info_block = InfoBlock("detail") def __init__( self, name, description, filter, active=None, timer=None, send_email=None): self.name = name self.description = description self.filter = filter self.active = active self.timer = timer self.send_email = send_email @property def exists(self): schedules = cfmedb["miq_schedules"] return cfmedb.session\ .query(schedules.name)\ .filter(schedules.name == self.name)\ .count() > 0 def _fill(self, action): fill( self.form, self._create_fill_dict(), action=action ) def create(self, cancel=False): sel.force_navigate("schedule_add") self._fill(form_buttons.add if not cancel else form_buttons.cancel) flash.assert_no_errors() assert self.exists, "Schedule does not exist!" def update(self, updates): sel.force_navigate("schedule_edit", context={"schedule": self}) fill(self.form, updates, action=form_buttons.save) flash.assert_no_errors() assert self.exists, "Schedule does not exist!" def delete(self, cancel=False): sel.force_navigate("schedule", context={"schedule": self}) cfg_btn("Delete this Schedule from the Database", invokes_alert=True) sel.handle_alert(cancel) flash.assert_no_errors() assert not self.exists, "Schedule does not exist!" def table_item(self, item): """Works both up- and downstream. I think this should be incorporated into InfoBlock somehow. Currently there is the fieldset issue. """ return "//td[preceding-sibling::td[contains(@class, 'key') and .='{}']]".format(item) def queue(self, wait_for_finish=False): """Queue this schedule. Args: wait_for_finish: If True, then this function blocks until the action is finished. """ if not self.exists: self.create() sel.force_navigate("schedule", context={"schedule": self}) last_run = sel.text(self.table_item("Last Run Time")).strip() cfg_btn("Queue up this Schedule to run now") flash.assert_no_errors() if wait_for_finish: wait_for( lambda: sel.text(self.table_item("Last Run Time")).strip() != last_run, delay=2, fail_func=lambda: toolbar.select("Reload current display"), message="wait for report queue finish" ) def _create_fill_dict(self): """Handle the values, create dictionary for form""" # Simple values come fields = { "name": self.name, "description": self.description, "active": self.active, "filter": self.filter, "timer": self.timer, } # Send e-mail if self.send_email is not None: fields["send_email"] = True fields["emails"] = self.send_email return fields # Methods for all schedules @classmethod def _select_schedules(cls, schedules): """Select schedules in the table. Args: schedules: Schedules to select. Raises: :py:class:`NameError` when some of the schedules were not found. """ sel.force_navigate("schedules") failed_selections = [] for schedule in schedules: if isinstance(schedule, cls): name = schedule.name else: name = str(schedule) if not schedules_table.select_row("Name", name): failed_selections.append(name) if failed_selections: raise NameError("These schedules were not found: {}.".format( ", ".join(failed_selections) )) @classmethod def _action_on_schedules(cls, action, schedules, cancel=None): """Select schedules and perform an action on them Args: action: Action in Configuration to perform. schedules: List of schedules. cancel: If specified, the nalert is expected after clicking on action and value of the variable specifies handling behaviour. Raises: :py:class:`NameError` when some of the schedules were not found. """ cls._select_schedules(schedules) if cancel is None: cfg_btn(action) else: cfg_btn(action, invokes_alert=True) sel.handle_alert(bool(cancel)) flash.assert_no_errors() @classmethod def enable_schedules(cls, *schedules): """Select and enable specified schedules. Args: *schedules: Schedules to enable. Can be objects or strings. Raises: :py:class:`NameError` when some of the schedules were not found. """ return cls._action_on_schedules("Enable the selected Schedules", schedules) @classmethod def disable_schedules(cls, *schedules): """Select and disable specified schedules. Args: *schedules: Schedules to disable. Can be objects or strings. Raises: :py:class:`NameError` when some of the schedules were not found. """ return cls._action_on_schedules("Disable the selected Schedules", schedules) @classmethod def queue_schedules(cls, *schedules): """Select and queue specified schedules. Args: *schedules: Schedules to queue. Can be objects or strings. Raises: :py:class:`NameError` when some of the schedules were not found. """ return cls._action_on_schedules("Queue up selected Schedules to run now", schedules) @classmethod def delete_schedules(cls, *schedules, **kwargs): """Select and delete specified schedules from VMDB. Args: *schedules: Schedules to delete. Can be objects or strings. Keywords: cancel: Whether to cancel the deletion (Default: False) Raises: :py:class:`NameError` when some of the schedules were not found. """ return cls._action_on_schedules( "Delete the selected Schedules from the VMDB", schedules, kwargs.get("cancel", False) )
], tab_fields={ "Columns": [ ("base_report_on", select(id="chosen_model")), ("report_fields", MultiBoxSelect( select(id="available_fields"), select(id="selected_fields"), button(alt="Move selected fields up"), button(alt="Move selected fields down"), )), ("cancel_after", select(id="chosen_queue_timeout")), ], "Consolidation": [ ("group_records", ShowingInputs( select(id="chosen_pivot1"), select(id="chosen_pivot2"), select(id="chosen_pivot3"), )), ("calculations_grouped", RecordGrouper( table_in_object("Specify Calculations of Numeric Values for Grouped Records"))), ], "Formatting": [ ("page_size", select(id="pdf_page_size")), ("headers", ColumnHeaderFormatTable(table_in_object("Specify Column Headers and Formats"))), ], "Styling": [ ("column_styles", ColumnStyleTable("styling_div")), ], "Filter": [ ("filter", Expression()),
accordion.tree("Dashboard Widgets", "All Widgets", "RSS Feeds", ctx["widget"].title), { "reports_widgets_rss_feed_delete": lambda _: toolbar.select("Configuration", "Delete this Widget from the Database"), "reports_widgets_rss_feed_edit": lambda _: toolbar.select("Configuration", "Edit this Widget"), } ], } ) visibility_obj = ShowingInputs( Select("//select[@id='visibility_typ']"), CheckboxSelect("//div[@id='form_role_visibility']//table/" "tbody/tr/td[not(contains(@class, 'key'))]/table"), min_values=1 ) class MenuWidget(Updateable): form = Form(fields=[ ("title", "//input[@id='title']"), ("description", "//input[@id='description']"), ("active", "//input[@id='enabled']"), ("shortcuts", MenuShortcuts("//select[@id='add_shortcut']")), ("visibility", visibility_obj), ]) def __init__(self, title, description=None, active=None, shortcuts=None, visibility=None): self.title = title
"Columns": [ ("base_report_on", select(id="chosen_model")), ("report_fields", MultiBoxSelect( select(id="available_fields"), select(id="selected_fields"), img(alt="Move selected fields up"), img(alt="Move selected fields down"), )), ("cancel_after", select(id="chosen_queue_timeout")), ], "Consolidation": [ ("group_records", ShowingInputs( select(id="chosen_pivot1"), select(id="chosen_pivot2"), select(id="chosen_pivot3"), )), ("calculations_grouped", RecordGrouper( table_in_object( "Specify Calculations of Numeric Values for Grouped Records" ))), ], "Formatting": [ ("page_size", select(id="pdf_page_size")), ("headers", ColumnHeaderFormatTable( table_in_object("Specify Column Headers and Formats"))), ], "Styling": [
"RSS Feeds", ctx["widget"].title), { "reports_widgets_rss_feed_delete": lambda _: toolbar.select( "Configuration", "Delete this Widget from the Database"), "reports_widgets_rss_feed_edit": lambda _: toolbar.select("Configuration", "Edit this Widget"), } ], }) visibility_obj = ShowingInputs( Select("//select[@id='visibility_typ']"), CheckboxSelect({ version.LOWEST: "//td[normalize-space(.)='User Roles']/../td/table", "5.5": "//label[normalize-space(.)='User Roles']/../div/table" }), min_values=1) class Widget(Updateable, Pretty): TITLE = None DETAIL_PAGE = None WAIT_STATES = {"Queued", "Running"} status_info = InfoBlock("Status") @property def on_widget_page(self): return sel.is_displayed(
fill("input#{}{}".format(self.vp, i), data[key]) @fill.method((AVPForm, Mapping)) def _fill_avp_form(avp, data): avp.fill(data) sim_form = Form(fields=[ ("instance", Select("select#instance_name")), ("message", Input("object_message")), ("request", Input("object_request")), ("attribute", ShowingInputs( Select("select#target_class"), Select("select#target_id"), min_values=1, )), ("execute_methods", Input("readonly")), ("avp", AVPForm()), ]) sim_btn = form_buttons.FormButton( "Submit Automation Simulation with the specified options") def simulate(**data): """Runs the simulation of specified Automate object. Args: **data: See :py:data:`sim_form` for keyword reference