Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New job invocation details page #1515

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions airgun/entities/job_invocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
JobInvocationCreateView,
JobInvocationStatusView,
JobInvocationsView,
NewJobInvocationStatusView,
)


Expand All @@ -30,9 +31,10 @@ def search(self, value):
view = self.navigate_to(self, 'All')
return view.search(value)

def read(self, entity_name, host_name, widget_names=None):
def read(self, entity_name, host_name, widget_names=None, new_ui=False):
"""Read values for scheduled or already executed job"""
view = self.navigate_to(self, 'Job Status', entity_name=entity_name, host_name=host_name)
nav_step = 'Job Status' if not new_ui else 'Job Status New UI'
view = self.navigate_to(self, nav_step, entity_name=entity_name, host_name=host_name)
return view.read(widget_names=widget_names)

def wait_job_invocation_state(self, entity_name, host_name, expected_state='succeeded'):
Expand Down Expand Up @@ -124,3 +126,29 @@ def prerequisite(self, *args, **kwargs):
def step(self, *args, **kwargs):
self.parent.search(f'host = {kwargs.get("host_name")}')
self.parent.table.row(description=kwargs.get('entity_name'))['Description'].widget.click()


@navigator.register(JobInvocationEntity, 'Job Status New UI')
class NewJobStatus(NavigateStep):
"""Navigate to the new job invocation details page.
Note: `Show Experimental Labs` setting must be enabled.

Args:
entity_name: name of the job
host_name: name of the host to which job was applied
"""

VIEW = NewJobInvocationStatusView

def prerequisite(self, *args, **kwargs):
return self.navigate_to(
self.obj,
'Job Status',
entity_name=kwargs.get('entity_name'),
host_name=kwargs.get('host_name'),
)

def step(self, *args, **kwargs):
self.parent.new_ui.click()
self.view.browser.plugin.ensure_page_safe()
self.view.wait_displayed()
73 changes: 71 additions & 2 deletions airgun/views/job_invocation.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
from wait_for import wait_for
from widgetastic.widget import Text, TextInput, View
from widgetastic_patternfly import BreadCrumb
from widgetastic_patternfly4 import Button, ChipGroup, Radio, Select
from widgetastic_patternfly4.ouia import Select as OUIASelect
from widgetastic_patternfly4 import Button, ChipGroup, DescriptionList, Radio, Select
from widgetastic_patternfly4.donutchart import DonutCircle, DonutLegend
from widgetastic_patternfly4.ouia import (
Dropdown as OUIADropdown,
Select as OUIASelect,
Text as OUIAText,
)

from airgun.views.common import (
BaseLoggedInView,
Expand Down Expand Up @@ -152,6 +157,7 @@ def is_displayed(self):
job_task = Text("//a[normalize-space(.)='Job Task']")
cancel_job = Button(value='Cancel Job')
abort_job = Button(value='Abort Job')
new_ui = Text("//a[normalize-space(.)='New UI']")

@View.nested
class overview(SatTab):
Expand Down Expand Up @@ -196,3 +202,66 @@ def wait_for_result(self, timeout=600, delay=1):
delay=1,
logger=self.logger,
)


class NewJobInvocationStatusView(BaseLoggedInView):
breadcrumb = BreadCrumb()
title = OUIAText('breadcrumb_title')
create_report = Button(value='Create report')
actions = OUIADropdown('job-invocation-global-actions-dropdown')
BREADCRUMB_LENGTH = 2

@property
def is_displayed(self):
breadcrumb_loaded = self.breadcrumb.wait_displayed()
title_loaded = self.title.wait_displayed()
data_loaded, _ = wait_for(
func=lambda: self.status.is_displayed,
timeout=60,
delay=15,
fail_func=self.browser.refresh,
)
return (
breadcrumb_loaded
and title_loaded
and data_loaded
and self.breadcrumb.locations[0] == 'Jobs'
and len(self.breadcrumb.locations) == self.BREADCRUMB_LENGTH
)

@View.nested
class overall_status(DonutCircle):
"""The donut circle with the overall job status of '{succeeded hosts}/{total hosts}'"""

def read(self):
"""Return `dict` with the parsed overall status numbers, for example:
```{'succeeded_hosts': 2, 'total_hosts': 5}```
"""
succeeded_hosts, total_hosts = self.labels[0].split('/')
return {'succeeded_hosts': int(succeeded_hosts), 'total_hosts': int(total_hosts)}

@View.nested
class status(DonutLegend):
"""'System status' panel."""

ROOT = ".//div[contains(@class, 'chart-legend')]"
first_label = Text(locator="//*[@id='legend-labels-0']")

@property
def is_displayed(self):
"""Any status label is displayed after all data are loaded."""
return self.first_label.is_displayed

def read(self):
"""Return `dict` with the System status info.
Example: ```{'Succeeded': 2, 'Failed': 1, 'In Progress': 0, 'Canceled': 0}```
"""
return {item['label']: int(item['value']) for item in self.all_items}

@View.nested
class overview(DescriptionList):
ROOT = ".//div[contains(@class, 'job-overview')]"

def read(self):
"""Return `dict` without trailing ':' in the key names."""
return {key.replace(':', ''): val for key, val in super().read().items()}