Ejemplo n.º 1
0
    def rich_report(self):
        results = [task.report_table() for task in self.tasks]
        successes = [x[0] for x in results]

        if not self._is_secret() or any(successes):
            table = Table.grid(expand=True, padding=(0, 2))
            table.add_column()
            table.add_column()
            table.add_column(style='red', overflow='fold', ratio=1)
            for result, name, msg, print_if_failed in results:
                if not print_if_failed and not result:
                    continue
                emoji = ":green_heart:" if result else ":no_entry_sign:"
                name = f"[green]{name}" if result else f"[red]{name}"
                table.add_row(f"[{emoji}]", name, msg)
            if self.name == "":
                title = Text(self.__doc__, justify='center')
            else:
                title = Text(self.name, justify='center')
            success_num = successes.count(True)
            summary_line = Text(
                f"{success_num} Successful out of {len(results)}",
                justify='right')
            panel_text = RenderGroup(title, table, '', summary_line)
            border_style = "green" if all(successes) else "red"
            panel = Panel(panel_text,
                          highlight=True,
                          border_style=border_style,
                          width=100)
            print(panel)
        return successes
Ejemplo n.º 2
0
def make_sponsor_message() -> Panel:
    """Some example content."""
    sponsor_message = Table.grid(padding=1)
    sponsor_message.add_column(style="green", justify="right")
    sponsor_message.add_column(no_wrap=True)
    sponsor_message.add_row(
        "✔ GitHub 🤓 ",
        "[u blue link=https://github.com/jiaulislam]https://github.com/jiaulislam",
    )

    intro_message = Text.from_markup(
        """Consider supporting my work via Github 🤘 🤘 🤘. - Jiaul Islam"""
    )

    message = Table.grid(padding=1)
    message.add_column()
    message.add_column(no_wrap=True)
    message.add_row(intro_message, sponsor_message)

    message_panel = Panel(
        Align.center(
            RenderGroup(intro_message, "\n", Align.center(sponsor_message)),
            vertical="middle",
        ),
        box=box.ROUNDED,
        padding=(1, 2),
        title="[b red]Thanks for using my application!",
        border_style="bright_blue",
    )
    return message_panel
Ejemplo n.º 3
0
    def get_pretty_failure_for_in(self, err: TestFailure) -> RenderableType:
        lhs_msg = Text.assemble(
            ("The ", "default"),
            ("item ", "pass.textonly"),
            *self.of_type(err.lhs),
        )
        lhs = Panel(
            Pretty(err.lhs),
            title=lhs_msg,
            title_align="left",
            border_style="pass.textonly",
            padding=1,
        )

        rhs_msg = Text.assemble(
            ("was not " if err.operator is Comparison.In else "was ", "bold default"),
            ("found in the ", "default"),
            ("container ", "fail.textonly"),
            *self.of_type(err.rhs),
        )
        rhs = Panel(
            Pretty(err.rhs),
            title=rhs_msg,
            title_align="left",
            border_style="fail.textonly",
            padding=1,
        )

        return Padding(RenderGroup(lhs, rhs), pad=(0, 0, 1, 2))
Ejemplo n.º 4
0
def main() -> None:
    previous: list[str] = [""] * 20
    with Live() as live:
        while True:
            mvp, non_mvp = get_idols()

            above = Table.grid(expand=True)
            above.add_column(width=2)
            above.add_column(width=3)
            above.add_column()
            for i, player in enumerate(mvp):
                above.add_row(*format_row(i, player, previous))

            noodle = r"[yellow]\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/"

            below = Table.grid(expand=True)
            below.add_column(width=2)
            below.add_column(width=3)
            below.add_column()
            for j, player in enumerate(non_mvp):
                below.add_row(*format_row(i + j + 1, player, previous))

            live.update(Panel(RenderGroup(above, noodle, below)))
            previous = mvp + non_mvp
            time.sleep(30)
Ejemplo n.º 5
0
    def generate_renderable() -> RenderGroup:
        """
        Function called to update the live display, fetches data from htcondor, does the processing and
        returns a RenderGroup with both Panels.
        """
        condor_string = query_condor_q()
        user_tasks, cluster_info = read_condor_q(condor_string)
        owner = user_tasks[0].owner if user_tasks else "User"

        tasks_table = make_tasks_table(user_tasks)
        cluster_table = make_cluster_table(owner, cluster_info)
        return RenderGroup(
            Panel(
                tasks_table,
                title=f"Scheduler: {cluster_info.scheduler_id}.cern.ch",
                expand=False,
                border_style="scope.border",
            ),
            Panel(
                cluster_table,
                title=f"{cluster_info.scheduler_id} Statistics",
                expand=False,
                border_style="scope.border",
            ),
        )
Ejemplo n.º 6
0
        async def plugin_command(ctx):

            all = []

            doc = self.get_plugin_doc(name)
            doc.extract_metadata("examples")

            desc_string = f"## Mogrifier: **{name}**\n"
            if doc.get_short_help(default=None):
                desc_string += doc.get_short_help() + "\n\n"

            desc_string += f"\n## Input Arguments\n\nThis is the list of arguments the *{name}* mogrifier accepts as input:\n"
            desc = Markdown(
                desc_string,
                style=bring_style,
                code_theme=bring_code_theme,
                justify="left",
            )
            all.append(desc)

            plugin = self.get_plugin(name)
            if hasattr(plugin, "_requires"):
                args = plugin._requires
            else:
                args = plugin.requires(None)
            record_arg = self._arg_hive.create_record_arg(childs=args)
            arg_table = to_rich_table(record_arg)
            all.append(arg_table)

            desc_string = f"\n## Output Arguments\n\nThis is the list of arguments the *{name}* mogrifier provides as output:\n"
            desc = Markdown(
                desc_string,
                style=bring_style,
                code_theme=bring_code_theme,
                justify="left",
            )
            all.append(desc)

            if hasattr(plugin, "_provides"):
                args = plugin._provides
            else:
                args = plugin.provides(None)
            record_arg = self._arg_hive.create_record_arg(childs=args)
            arg_table = to_rich_table(record_arg)
            all.append(arg_table)

            desc_string = await create_pkg_type_markdown_string(
                bring=self.bring, plugin_doc=doc)

            desc = Markdown(
                desc_string,
                style=bring_style,
                code_theme=bring_code_theme,
                justify="left",
            )
            all.append(desc)

            group = RenderGroup(*all)
            console.print(Panel(Panel(group, box=box.SIMPLE)))
Ejemplo n.º 7
0
def display_notebook(notebook):
    row = notebook.row
    renders = notebook.get_renders_in_range(row,
                                            row + _METADATA["term_height"])

    notebook.needs_redraw = False

    return Panel(RenderGroup(*renders))
Ejemplo n.º 8
0
class Content:
    """
    This class represents a per CLI invocation "canvas" which will hold the data
    that gets displayed on the CLI. All content updates happen by updating the
    value of the instance's RenderGroup
    """

    rg: RenderGroup = RenderGroup()

    def __rich__(self) -> RenderGroup:
        return self.rg
Ejemplo n.º 9
0
def little_game(game: Game) -> Panel:
    weather = Weather.load_one(game.weather).name

    grid = Table.grid(expand=True)
    grid.add_column()
    grid.add_column(justify="right")
    grid.add_row(inning(game), weather)
    grid.add_row(game.away_team_nickname, f"{game.away_score:g}")
    grid.add_row(game.home_team_nickname, f"{game.home_score:g}")

    style = highlight(game)
    return Panel(RenderGroup(grid, update(game)), width=30, border_style=style)
Ejemplo n.º 10
0
def pad_renderable(renderable, offset):
    """
    Pad a renderable, subject to a particular truncation offset.
    """
    if offset < 0:
        raise Exception("invalid offset!")
    if offset == 0:
        return RenderGroup(_RULE, Padding(renderable, 1))
    if offset == 1:
        return Padding(renderable, 1)
    else:
        return Padding(renderable, (0, 1, 1, 1))
Ejemplo n.º 11
0
 def get_pretty_comparison_failure(
     self, err: TestAssertionFailure
 ) -> RenderableType:
     diff = self.get_diff(err)
     parts = [
         self.get_operands(err) if not diff else None,
         diff,
     ]
     return Padding(
         RenderGroup(*(part for part in parts if part)),
         pad=(0, 0, 1, 2),
     )
Ejemplo n.º 12
0
def print_probe(probe: VideoProbe) -> None:
    format_panel = PropertyPanel(probe.format, "Format", expand=True)
    if probe.metadata:
        format_panel.add_section(
            PropertyPanel(probe.metadata, "Metadata", expand=True))

    stream_group = RenderGroup()
    for i, stream in enumerate(probe.streams, 1):
        stream_group.renderables.append(
            PropertyPanel(stream, f"Stream {i}", expand=True))

    print(Columns([format_panel, stream_group]))
Ejemplo n.º 13
0
    def create_info_table(self, live_infos):
        dct = {0: 0, 1: 100, 2: 50, 4: 10}
        dct2 = {0: 0, 1: 100, 2: 50, 3: 30}
        infos = sorted([
            self.generate_info(rid, live_infos[key])
            for key, rid in zip(live_infos.keys(), range(len(live_infos)))
        ],
                       key=lambda i: dct[i.live_status] * 100 + 100 * dct2[
                           i.record_status] - i.row_id + i.queue_status,
                       reverse=True)
        table1 = Table("行号",
                       "房间ID",
                       "主播",
                       "直播标题",
                       "直播状态",
                       "录制状态",
                       "开播时间",
                       "录制时长",
                       "队列情况",
                       "完成时间",
                       title="%s" %
                       datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                       box=box.SIMPLE)

        for info in infos:
            table1.add_row(str(info.row_id), info.room_id_map, info.anchor_map,
                           info.title_map, info.live_status_map,
                           info.record_status_map, info.start_time_map,
                           info.record_time, info.queue_status_map,
                           info.finish_time_map)

        table2 = Table("CPU", "Memory", "NetSent", "NetRecv", box=box.SIMPLE)

        time_now = datetime.datetime.now()
        now_recv = psutil.net_io_counters().bytes_recv
        now_sent = psutil.net_io_counters().bytes_sent

        table2.add_row(
            str(psutil.cpu_percent(None)) + '%' + '  %.2fGHz' %
            (psutil.cpu_freq().current / 1000.0),
            str(psutil.virtual_memory().percent) + '%' + '  %s/%s' %
            (bytes2human(psutil.virtual_memory().used),
             bytes2human(psutil.virtual_memory().total)),
            bytes2human((now_sent - self.last_net_sent) /
                        (time_now - self.last_time).total_seconds()) + '/s',
            bytes2human((now_recv - self.last_net_recv) /
                        (time_now - self.last_time).total_seconds()) + '/s')

        self.last_time = time_now
        self.last_net_sent = now_sent
        self.last_net_recv = now_recv

        return RenderGroup(table1, table2)
Ejemplo n.º 14
0
 def __init__(
     self,
     data: Optional[Dict[str, Any]] = None,
     title: Optional[str] = None,
     title_align: AlignValues = "center",
     expand: bool = False,
 ) -> None:
     self.table = PropertyTable(data)
     self.group = RenderGroup(self.table)
     super().__init__(self.group,
                      title=title,
                      title_align=title_align,
                      expand=expand)
Ejemplo n.º 15
0
def render_pr(pr):
    labels = ", ".join([label.name for label in pr.get_labels()])
    body = Markdown(pr.body)
    pr_panel = Panel(
        RenderGroup(
            Panel(f"Title: {pr.title}"),
            Panel(f"Labels: {labels}"),
            Panel(body, title="Body"),
        ),
        title=f"PR #{pr.number}",
    )

    console.print(pr_panel)
Ejemplo n.º 16
0
    def createInfoTable(self, liveInfos):
        infos = sorted([
            self.generateInfo(rid, liveInfos[key])
            for key, rid in zip(liveInfos.keys(), range(len(liveInfos)))
        ],
                       key=lambda i: i.state * 10 - i.rowID,
                       reverse=True)
        table1 = Table("行号",
                       "房间ID",
                       "主播",
                       "分区",
                       "直播标题",
                       "直播状态",
                       "开播时间",
                       "录制时间",
                       "转码用时",
                       "上传用时",
                       "当前状态",
                       title="%s" %
                       datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                       box=box.SIMPLE)

        for info in infos:
            table1.add_row(str(info.rowID), info.roomID,
                           info.uname, info.areaName, info.title,
                           str(info.liveStatus), info.liveStartTimeMap,
                           info.recordTimeMap, info.decodeTimeMap,
                           info.uploadTimeMap, info.stateMap)

        table2 = Table("CPU", "Memory", "NetSent", "NetRecv", box=box.SIMPLE)

        time_now = datetime.datetime.now()
        now_recv = psutil.net_io_counters().bytes_recv
        now_sent = psutil.net_io_counters().bytes_sent

        table2.add_row(
            str(psutil.cpu_percent(None)) + '%',
            str(psutil.virtual_memory().percent) + '%' + '  %s/%s' %
            (bytes2human(psutil.virtual_memory().used),
             bytes2human(psutil.virtual_memory().total)),
            bytes2human((now_sent - self.last_net_sent) /
                        (time_now - self.last_time).total_seconds()) + '/s',
            bytes2human((now_recv - self.last_net_recv) /
                        (time_now - self.last_time).total_seconds()) + '/s')

        self.last_time = time_now
        self.last_net_sent = now_sent
        self.last_net_recv = now_recv

        return RenderGroup(table1, table2)
Ejemplo n.º 17
0
def timing_stats_expected_panel(expected_table=timing_stats_expected_table):
    return Panel(
        RenderGroup(
            Padding(
                "Median: [b]4000.00[/b]ms"
                " [muted]|[/muted] "
                "99th Percentile: [b]5000.00[/b]ms",
                pad=(0, 0, 1, 0),
            ),
            expected_table,
        ),
        title="[b white]3 Slowest Tests[/b white]",
        style="none",
        border_style="rule.line",
    )
Ejemplo n.º 18
0
    def get_detail_renderable(self, item_id):

        # ┌────────────────────────────────────────────────────────────────────────────┐
        # │ GET ITEM                                                                   │
        # └────────────────────────────────────────────────────────────────────────────┘

        # Get item by ID
        item = self.get(id=int(item_id))

        # Define panel kwargs
        panel_kwargs = {"title_align": "right"}

        # Get display detail by
        display_detail_by = self.display_detail_by

        # Initialize columns
        columns = []

        # Iterate over rows in display detail by
        for row in display_detail_by:

            # Initialize columns
            cols = []

            # Iterate over columns in row
            for field, display in row.items():

                # Get value
                value = getattr(item, field, "N/A")

                # Stringify value
                value = str(value)

                # Add Panel to columns
                cols.append(Panel(value, title=display, **panel_kwargs))

            # Append row of columns
            columns.append(Columns(cols, expand=True))

        # Create renderable
        renderable = RenderGroup(*columns)

        # Pad renderable
        renderable = Padding(renderable, (1, 1))

        # Return renderable
        return renderable
Ejemplo n.º 19
0
 def print_grade_table(self):
     table = self.generate_assignment_table()
     p_table = self.generate_overall_grade_table()
     console.print(
         Panel(
             RenderGroup(
                 Columns(
                     (table, ),
                     align="center",
                     expand=True,
                 ), Columns(
                     (p_table, ),
                     align="center",
                     expand=True,
                 )),
             title=f"[white bold]{self.title}",
         ))
Ejemplo n.º 20
0
    async def run(self):
        """Create and refresh the dashboard every n seconds"""
        while not self.tasks_running():
            await trio.sleep(0.5)
        with Live(transient=True, refresh_per_second=1
                  ) as live, self.create_progress_bar() as progress:
            task = progress.add_task("resolving")
            while self.tasks_running():
                table = await self.generate_tasks_table()
                pbar = self.generate_progress(progress, task)
                statistics = self.generate_statistics()
                panel_group = RenderGroup(
                    Panel(table, title="Tasks"), Panel(pbar, title="Progress"),
                    Panel(statistics, title="Query statistics"))

                live.update(panel_group)
                await trio.sleep(1)
Ejemplo n.º 21
0
    def get_pretty_failure_for_equals(self, err: TestFailure) -> RenderableType:
        diff_msg = Text.assemble(
            ("LHS ", "pass.textonly"),
            ("vs ", "default"),
            ("RHS ", "fail.textonly"),
            ("shown below", "default"),
        )

        diff = Diff(
            err.lhs,
            err.rhs,
            width=self.terminal_size.width - 24,
            show_symbols=self.show_diff_symbols,
        )

        return RenderGroup(
            Padding(diff_msg, pad=(0, 0, 1, 2)),
            Padding(diff, pad=(0, 0, 1, 4)),
        )
Ejemplo n.º 22
0
    def __rich_console__(self, c: Console, co: ConsoleOptions) -> RenderResult:
        def sort_key(r: TestResult) -> float:
            assert r.test.timer, "test must've been run already"
            return r.test.timer.duration

        test_results = sorted(self.all_tests_in_session, key=sort_key, reverse=True)
        grid = Table.grid(padding=(0, 2, 0, 0))
        grid.add_column(justify="right")  # Time taken
        grid.add_column()  # Test ID
        grid.add_column()  # Test description

        for result in test_results[: self.num_tests_to_show]:
            assert result.test.timer, "test must've been run already"
            time_taken_secs = result.test.timer.duration
            time_taken_millis = time_taken_secs * 1000
            test_id = format_test_id(result)
            description = result.test.description
            grid.add_row(
                f"[b]{time_taken_millis:.0f}[/b]ms",
                Text(test_id, style="muted"),
                description,
            )

        num_slowest_displayed = min(
            len(self.all_tests_in_session), self.num_tests_to_show
        )
        panel = Panel(
            RenderGroup(
                Padding(
                    f"Median: [b]{self._median_secs * 1000:.2f}[/b]ms"
                    f" [muted]|[/muted] "
                    f"99th Percentile: [b]{self._percentile99_secs * 1000:.2f}[/b]ms",
                    pad=(0, 0, 1, 0),
                ),
                grid,
            ),
            title=f"[b white]{num_slowest_displayed} Slowest Tests[/b white]",
            style="none",
            border_style="rule.line",
        )

        yield panel
Ejemplo n.º 23
0
    def update(self, current_model=None):
        """
        Make a new table, and return it
         along with text to display under the table.

        Args:
            current_model (sklearn.estinator, optional): Estimator. Defaults to None.

        Returns:
            console.RenderGroup: Rendergroup to print to terminal.
        """
        if current_model is None:
            return Text("Training ...", justify="center")
        
        table = self.make_performance_table()
        last_ = Text("*** = Best Model  ", style="bold green", justify="right") \
        if current_model == list(self.trainer.grid.keys())[-1] \
        else Text("Training ...", justify="center")

        return RenderGroup( table, last_ )
Ejemplo n.º 24
0
def _render_job_attributes(data):
    style = "[bold #31DDCF]"
    tags = get_tags_str(data["tags"])
    name = data["observable_name"] if data["observable_name"] else data["file_name"]
    clsfn = (
        data["observable_classification"]
        if data["observable_classification"]
        else data["file_mimetype"]
    )
    status: str = get_status_text(data["status"], as_text=False)
    r = RenderGroup(
        f"{style}Job ID:[/] {str(data['id'])}",
        f"{style}User:[/] {data['source']}",
        f"{style}MD5:[/] {data['md5']}",
        f"{style}Name:[/] {name}",
        f"{style}Classification:[/] {clsfn}",
        f"{style}Tags:[/] {tags}",
        f"{style}Status:[/] {status}",
    )
    return Panel(r, title="Job attributes")
Ejemplo n.º 25
0
def make_sponsor_message() -> Panel:
    """Some example content."""
    sponsor_message = Table.grid(padding=1)
    sponsor_message.add_column(style="green", justify="right")
    sponsor_message.add_column(no_wrap=True)
    sponsor_message.add_row(
        "Sponsor me",
        "[u blue link=https://github.com/sponsors/willmcgugan]https://github.com/sponsors/willmcgugan",
    )
    sponsor_message.add_row(
        "Buy me a :coffee:",
        "[u blue link=https://ko-fi.com/willmcgugan]https://ko-fi.com/willmcgugan",
    )
    sponsor_message.add_row(
        "Twitter",
        "[u blue link=https://twitter.com/willmcgugan]https://twitter.com/willmcgugan",
    )
    sponsor_message.add_row(
        "Blog", "[u blue link=https://www.willmcgugan.com]https://www.willmcgugan.com"
    )

    intro_message = Text.from_markup(
        """Consider supporting my work via Github Sponsors (ask your company / organization), or buy me a coffee to say thanks. - Will McGugan"""
    )

    message = Table.grid(padding=1)
    message.add_column()
    message.add_column(no_wrap=True)
    message.add_row(intro_message, sponsor_message)

    message_panel = Panel(
        Align.center(
            RenderGroup(intro_message, "\n", Align.center(sponsor_message)),
            vertical="middle",
        ),
        box=box.ROUNDED,
        padding=(1, 2),
        title="[b red]Thanks for trying out Rich!",
        border_style="bright_blue",
    )
    return message_panel
Ejemplo n.º 26
0
def make_memory_panel(debugger) -> Panel:
    addr = 0
    mem_bytes = debugger.executor.vm_context.memory_read_bytes(0, 16 * 8)
    byte = ''.join(['%02X' % b for b in mem_bytes])
    res = hexdump(byte, start=int(addr), to_list=True)
    mem_table = Table.grid(padding=0)

    for i in res:
        mem_table.add_row(i)

    memory_panel = Panel(
        Align.center(
            RenderGroup('', "\n", Align.center(mem_table)),
            vertical="top",
        ),
        box=box.ROUNDED,
        padding=(0, 1),
        title="[b red]Memory",
        border_style="bright_blue",
    )
    return memory_panel
Ejemplo n.º 27
0
def make_message():
    message = Table.grid(padding=1)
    message.add_column(style="green", justify="right")
    message.add_column(no_wrap=True)

    intro_message = Text.from_markup("""Thanks for trying out!""")
    message.add_row("Check the Repository on GitHub",
                    ("[u blue link=https://github.com/samborba/rich-terminal]"
                     "https://github.com/samborba/rich-terminal"))

    message_panel = Panel(
        Align.center(
            RenderGroup(intro_message, "\n", Align.center(message)),
            vertical="middle",
        ),
        box=box.ROUNDED,
        title="[b white]RICH TERMINAL",
        border_style="bright_blue",
    )

    return message_panel
Ejemplo n.º 28
0
        async def plugin_command(ctx):

            all = []

            doc = self.get_plugin_doc(name)
            doc.extract_metadata("examples")

            desc_string = f"## Package type: **{name}**\n"
            if doc.get_short_help(default=None):
                desc_string += doc.get_short_help() + "\n\n"

            desc_string += f"\n## Arguments\n\nThis is the list of arguments that can be used to describe a package of the *{name}* type:\n"
            desc = Markdown(
                desc_string,
                style=bring_style,
                code_theme=bring_code_theme,
                justify="left",
            )
            all.append(desc)

            plugin = self.get_plugin(name)

            args = plugin.get_args()
            record_arg = self._arg_hive.create_record_arg(childs=args)
            arg_table = to_rich_table(record_arg)
            all.append(arg_table)

            desc_string = await create_pkg_type_markdown_string(
                bring=self.bring, plugin_doc=doc)

            desc = Markdown(
                desc_string,
                style=bring_style,
                code_theme=bring_code_theme,
                justify="left",
            )
            all.append(desc)

            group = RenderGroup(*all)
            console.print(Panel(Panel(group, box=box.SIMPLE)))
Ejemplo n.º 29
0
def messages(cli_args):
    r = requests.get(
        "https://passio3.com/www/goServices.php?getAlertMessages=1&json=%7B%22systemSelected0%22%3A%2276%22%2C%22amount%22%3A1%2C%22routesAmount%22%3A0%7D"
    )
    messages_data = r.json()
    messages_data = messages_data["msgs"]

    messages_data_new = [{
        "title": m["name"],
        "html": m["html"],
        "date_from": m["from"],
        "date_to": m["to"]
    } for m in messages_data]

    console = Console()
    console.print(Panel(Text("Messages", justify="center", style="bold")))
    for m in messages_data_new:
        group = RenderGroup(
            Text(m["title"], justify="center", style="bold"),
            Text(m["date_from"] + " to " + m["date_to"], justify="center"),
            Padding(Text(m["html"]), (1, 0, 0, 0)))
        console.print(Panel(group, expand=True))
Ejemplo n.º 30
0
def generate_panel(notes, note_choice, note_played, color, score):

    if note_choice not in notes:
        # it means note_choice is 'Good job!' when the player hits the note
        play_note_row = note_choice
    else:
        play_note_row = f'Play this note: [blue bold]{note_choice}[/]'
    note_played_row = f'You played: [{color} bold]{note_played}[/]'

    all_notes_row = Text.assemble(('\nAll available notes: ', 'grey53 bold'),
                                  ((', ').join(notes), 'grey53'))

    current_score_text = Text(f'\nCurrent score: {score}\n')
    current_score_text.stylize('yellow bold', 16)

    quit_text = Text('\n\n(press ctrl+C to quit at any time)')
    quit_text.stylize('grey37')

    panel_group = RenderGroup(current_score_text, Panel(play_note_row),
                              Panel(note_played_row), all_notes_row, quit_text)

    return Panel(panel_group, title='FRETBOARD LEARNER', box=box.ASCII)