File size: 4,717 Bytes
fae4e5b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
"""
Navigation utilities for MockTraceMind screen flow
"""

import gradio as gr
from enum import Enum
from typing import Dict, Any, Tuple


class Screen(Enum):
    """Available screens in MockTraceMind"""
    LEADERBOARD = "leaderboard"
    COMPARE = "compare"
    RUN_DETAIL = "run_detail"
    TRACE_DETAIL = "trace_detail"


class Navigator:
    """
    Manages screen navigation and state

    Screen Flow:
    - Leaderboard (Screen 1)
      - Click row → Run Detail (Screen 3)
      - Select 2+ rows + Compare → Compare View (Screen 2)
        - Click either run → Run Detail (Screen 3)
    - Run Detail (Screen 3)
      - Click test case row → Trace Detail (Screen 4)
    - Trace Detail (Screen 4)
      - Back → Run Detail (Screen 3)
    """

    def __init__(self):
        self.current_screen = Screen.LEADERBOARD
        self.navigation_stack = [Screen.LEADERBOARD]
        self.screen_context: Dict[str, Any] = {}

    def navigate_to(
        self,
        screen: Screen,
        context: Dict[str, Any] = None,
        add_to_stack: bool = True
    ) -> Tuple[Screen, Dict[str, Any]]:
        """
        Navigate to a screen with optional context

        Args:
            screen: Target screen
            context: Data to pass to the screen
            add_to_stack: Whether to add to navigation stack

        Returns:
            Tuple of (screen, context)
        """
        self.current_screen = screen

        if context:
            self.screen_context.update(context)

        if add_to_stack:
            self.navigation_stack.append(screen)

        return screen, self.screen_context

    def back(self) -> Tuple[Screen, Dict[str, Any]]:
        """
        Navigate back in the navigation stack

        Returns:
            Tuple of (previous_screen, context)
        """
        if len(self.navigation_stack) > 1:
            self.navigation_stack.pop()  # Remove current
            previous = self.navigation_stack[-1]
            self.current_screen = previous
            return previous, self.screen_context

        # Already at root
        return self.current_screen, self.screen_context

    def get_current_screen(self) -> Screen:
        """Get current active screen"""
        return self.current_screen

    def get_context(self, key: str, default: Any = None) -> Any:
        """Get value from screen context"""
        return self.screen_context.get(key, default)

    def set_context(self, key: str, value: Any) -> None:
        """Set value in screen context"""
        self.screen_context[key] = value

    def clear_context(self) -> None:
        """Clear all screen context"""
        self.screen_context.clear()

    def reset(self) -> None:
        """Reset navigation to initial state"""
        self.current_screen = Screen.LEADERBOARD
        self.navigation_stack = [Screen.LEADERBOARD]
        self.screen_context.clear()


# Gradio visibility update helpers
def show_screen(screen: Screen) -> Dict[gr.Component, gr.update]:
    """
    Generate Gradio updates to show specific screen

    Returns:
        Dictionary of component updates for gr.update
    """
    return {
        "leaderboard_container": gr.update(visible=(screen == Screen.LEADERBOARD)),
        "compare_container": gr.update(visible=(screen == Screen.COMPARE)),
        "run_detail_container": gr.update(visible=(screen == Screen.RUN_DETAIL)),
        "trace_detail_container": gr.update(visible=(screen == Screen.TRACE_DETAIL)),
    }


def create_back_button(visible: bool = True) -> gr.Button:
    """Create a consistent back button"""
    return gr.Button("⬅️ Back", visible=visible, variant="secondary", size="sm")


def create_breadcrumb(navigation_stack: list) -> str:
    """
    Create breadcrumb navigation HTML

    Args:
        navigation_stack: List of Screen enums

    Returns:
        HTML string for breadcrumb
    """
    breadcrumb_names = {
        Screen.LEADERBOARD: "Leaderboard",
        Screen.COMPARE: "Compare",
        Screen.RUN_DETAIL: "Run Detail",
        Screen.TRACE_DETAIL: "Trace Detail"
    }

    breadcrumb_items = []
    for i, screen in enumerate(navigation_stack):
        name = breadcrumb_names.get(screen, screen.value)
        if i < len(navigation_stack) - 1:
            # Not the last item - make it a link
            breadcrumb_items.append(f'<span style="color: #666;">{name}</span>')
        else:
            # Last item - current screen
            breadcrumb_items.append(f'<strong>{name}</strong>')

    breadcrumb_html = " > ".join(breadcrumb_items)

    return f"""
    <div style="padding: 10px; background-color: #f5f5f5; border-radius: 5px; margin-bottom: 10px;">
        {breadcrumb_html}
    </div>
    """