Manages drill-down/back-out navigation state
| 154 | |
| 155 | |
| 156 | class NavigationState: |
| 157 | """Manages drill-down/back-out navigation state""" |
| 158 | |
| 159 | _PREFIX_DISPLAY = _NAV_PREFIX_DISPLAY |
| 160 | _LATENCY_SUFFIX_LABELS = _NAV_LATENCY_SUFFIX_LABELS |
| 161 | _UNIT_SUFFIXES = _NAV_UNIT_SUFFIXES |
| 162 | _LABEL_OVERRIDES = _NAV_LABEL_OVERRIDES |
| 163 | |
| 164 | def __init__(self): |
| 165 | """Initialize navigation state""" |
| 166 | self.history: List[NavigationFrame] = [] |
| 167 | self.current_frame: Optional[NavigationFrame] = None |
| 168 | self.max_history = 100 # Prevent unlimited history growth |
| 169 | self.grouping_history: List[List[str]] = [] # Track grouping changes for undo |
| 170 | |
| 171 | @staticmethod |
| 172 | def _canonical(column: str) -> str: |
| 173 | """Normalize column keys for consistent comparisons.""" |
| 174 | if column is None: |
| 175 | raise ValueError("Column name cannot be None") |
| 176 | return str(column).strip().lower() |
| 177 | |
| 178 | @staticmethod |
| 179 | def _normalize_values(values: Any) -> List[Any]: |
| 180 | """Ensure filter values are stored as lists.""" |
| 181 | if values is None: |
| 182 | return [] |
| 183 | if isinstance(values, list): |
| 184 | return list(values) |
| 185 | if isinstance(values, (tuple, set)): |
| 186 | return list(values) |
| 187 | return [values] |
| 188 | |
| 189 | @staticmethod |
| 190 | def _format_value(value: Any) -> str: |
| 191 | """Format a value for human-readable display.""" |
| 192 | if value is None: |
| 193 | return "NULL" |
| 194 | if isinstance(value, str): |
| 195 | return f"'{value}'" if ' ' in value else value |
| 196 | return str(value) |
| 197 | |
| 198 | @classmethod |
| 199 | def _format_values_short(cls, values: List[Any]) -> str: |
| 200 | """Short display for a list of values.""" |
| 201 | if not values: |
| 202 | return "[]" |
| 203 | if len(values) == 1: |
| 204 | return cls._format_value(values[0]) |
| 205 | if len(values) <= 3: |
| 206 | formatted = ", ".join(cls._format_value(v) for v in values) |
| 207 | return f"[{formatted}]" |
| 208 | preview = ", ".join(cls._format_value(v) for v in values[:3]) |
| 209 | remaining = len(values) - 3 |
| 210 | return f"[{preview}, ... +{remaining} more]" |
| 211 | |
| 212 | @classmethod |
| 213 | def _format_label(cls, column: str) -> str: |
no outgoing calls