feat: group multi-browser output by source
Testing / remote-protocol-compat (0.9.3) (push) Successful in 52s
Testing / test (push) Successful in 1m2s
Testing / remote-protocol-compat (0.9.5) (push) Successful in 1m0s
Package Extension / package-extension (push) Successful in 1m11s
Build & Publish Package / publish (push) Successful in 1m7s
Testing / remote-protocol-compat (0.9.3) (push) Successful in 52s
Testing / test (push) Successful in 1m2s
Testing / remote-protocol-compat (0.9.5) (push) Successful in 1m0s
Package Extension / package-extension (push) Successful in 1m11s
Build & Publish Package / publish (push) Successful in 1m7s
- Add browser source grouping metadata to SDK-created tabs, groups, list results, and aggregate count results. - Render grouped local/remote browser tables consistently for clients, tabs, groups, windows, sessions, and remote status output. - Document remote control, auth, HTTP gateway usage, and the refreshed project structure in the README. - Add coverage for grouped output and BrowserCounts browser_groups. - Bump the Python package, extension manifest, and lockfile to 0.15.6. - Add a just publish helper for building and publishing release artifacts.
This commit is contained in:
+101
-94
@@ -11,107 +11,114 @@ from typing import Any, Protocol, cast
|
||||
|
||||
from browser_cli.models import Group, Tab
|
||||
|
||||
def _target_group(target) -> str | None:
|
||||
if target is None:
|
||||
return None
|
||||
return getattr(target, "display_group", None) or ("local" if target.remote is None else None)
|
||||
|
||||
class _FactoryClient(Protocol):
|
||||
_key: str | None
|
||||
_key: str | None
|
||||
|
||||
class FactoryMixin:
|
||||
"""Turn raw response dicts into bound ``Tab``/``Group`` objects.
|
||||
"""Turn raw response dicts into bound ``Tab``/``Group`` objects.
|
||||
|
||||
Mixed into :class:`~browser_cli.BrowserCLI`; relies on the client providing
|
||||
``_browser``/``_remote``/``_key`` and being constructible via ``type(self)``.
|
||||
"""
|
||||
Mixed into :class:`~browser_cli.BrowserCLI`; relies on the client providing
|
||||
``_browser``/``_remote``/``_key`` and being constructible via ``type(self)``.
|
||||
"""
|
||||
|
||||
def tab_from(
|
||||
self,
|
||||
data: dict,
|
||||
*,
|
||||
browser_profile: str | None = None,
|
||||
browser_name: str | None = None,
|
||||
browser_remote: str | None = None,
|
||||
browser_type: str | None = None,
|
||||
browser_group: str | None = None,
|
||||
) -> Tab:
|
||||
tab = Tab(
|
||||
id=data["id"],
|
||||
window_id=data.get("windowId", 0),
|
||||
active=data.get("active", False),
|
||||
muted=data.get("muted", False),
|
||||
title=data.get("title") or "",
|
||||
url=data.get("url") or "",
|
||||
group_id=data.get("groupId") or None,
|
||||
index=data.get("index", 0) or 0,
|
||||
browser=browser_name,
|
||||
browser_name=browser_type,
|
||||
browser_group=browser_group,
|
||||
)
|
||||
client = cast(_FactoryClient, self)
|
||||
tab._browser = self if browser_profile is None else cast(Any, type(self))(
|
||||
browser=browser_profile,
|
||||
remote=browser_remote,
|
||||
key=client._key,
|
||||
_command_sender=getattr(self, "_command_sender", None),
|
||||
)
|
||||
return tab
|
||||
def tab_from(
|
||||
self,
|
||||
data: dict,
|
||||
*,
|
||||
browser_profile: str | None = None,
|
||||
browser_name: str | None = None,
|
||||
browser_remote: str | None = None,
|
||||
browser_type: str | None = None,
|
||||
browser_group: str | None = None,
|
||||
) -> Tab:
|
||||
tab = Tab(
|
||||
id=data["id"],
|
||||
window_id=data.get("windowId", 0),
|
||||
active=data.get("active", False),
|
||||
muted=data.get("muted", False),
|
||||
title=data.get("title") or "",
|
||||
url=data.get("url") or "",
|
||||
group_id=data.get("groupId") or None,
|
||||
index=data.get("index", 0) or 0,
|
||||
browser=browser_name,
|
||||
browser_name=browser_type,
|
||||
browser_group=browser_group,
|
||||
)
|
||||
client = cast(_FactoryClient, self)
|
||||
tab._browser = self if browser_profile is None else cast(Any, type(self))(
|
||||
browser=browser_profile,
|
||||
remote=browser_remote,
|
||||
key=client._key,
|
||||
_command_sender=getattr(self, "_command_sender", None),
|
||||
)
|
||||
return tab
|
||||
|
||||
def require_tab_response(self, data, error: str) -> Tab:
|
||||
"""Build a bound Tab from a tab-shaped response, or raise ``RuntimeError(error)``."""
|
||||
if not isinstance(data, dict) or "id" not in data:
|
||||
raise RuntimeError(error)
|
||||
return self.tab_from(data)
|
||||
def require_tab_response(self, data, error: str) -> Tab:
|
||||
"""Build a bound Tab from a tab-shaped response, or raise ``RuntimeError(error)``."""
|
||||
if not isinstance(data, dict) or "id" not in data:
|
||||
raise RuntimeError(error)
|
||||
return self.tab_from(data)
|
||||
|
||||
def group_from(
|
||||
self,
|
||||
data: dict,
|
||||
*,
|
||||
browser_profile: str | None = None,
|
||||
browser_name: str | None = None,
|
||||
browser_remote: str | None = None,
|
||||
browser_type: str | None = None,
|
||||
browser_group: str | None = None,
|
||||
) -> Group:
|
||||
group = Group(
|
||||
id=data["id"],
|
||||
title=data.get("title") or "",
|
||||
color=data.get("color") or "",
|
||||
collapsed=data.get("collapsed", False),
|
||||
tab_count=data.get("tabCount", 0),
|
||||
window_id=data.get("windowId"),
|
||||
browser=browser_name,
|
||||
browser_name=browser_type,
|
||||
browser_group=browser_group,
|
||||
)
|
||||
client = cast(_FactoryClient, self)
|
||||
group._browser = self if browser_profile is None else cast(Any, type(self))(
|
||||
browser=browser_profile,
|
||||
remote=browser_remote,
|
||||
key=client._key,
|
||||
_command_sender=getattr(self, "_command_sender", None),
|
||||
)
|
||||
return group
|
||||
def group_from(
|
||||
self,
|
||||
data: dict,
|
||||
*,
|
||||
browser_profile: str | None = None,
|
||||
browser_name: str | None = None,
|
||||
browser_remote: str | None = None,
|
||||
browser_type: str | None = None,
|
||||
browser_group: str | None = None,
|
||||
) -> Group:
|
||||
group = Group(
|
||||
id=data["id"],
|
||||
title=data.get("title") or "",
|
||||
color=data.get("color") or "",
|
||||
collapsed=data.get("collapsed", False),
|
||||
tab_count=data.get("tabCount", 0),
|
||||
window_id=data.get("windowId"),
|
||||
browser=browser_name,
|
||||
browser_name=browser_type,
|
||||
browser_group=browser_group,
|
||||
)
|
||||
client = cast(_FactoryClient, self)
|
||||
group._browser = self if browser_profile is None else cast(Any, type(self))(
|
||||
browser=browser_profile,
|
||||
remote=browser_remote,
|
||||
key=client._key,
|
||||
_command_sender=getattr(self, "_command_sender", None),
|
||||
)
|
||||
return group
|
||||
|
||||
def tab_from_target(self, data: dict, target) -> Tab:
|
||||
"""Build a Tab, tagging it with *target* in multi-browser mode (``None`` = local)."""
|
||||
return self.tab_from(
|
||||
data,
|
||||
browser_profile=target.profile if target else None,
|
||||
browser_name=target.display_name if target else None,
|
||||
browser_remote=target.remote if target else None,
|
||||
browser_type=getattr(target, "browser_name", None) if target else None,
|
||||
browser_group=getattr(target, "display_group", None) if target else None,
|
||||
)
|
||||
def tab_from_target(self, data: dict, target) -> Tab:
|
||||
"""Build a Tab, tagging it with *target* in multi-browser mode (``None`` = local)."""
|
||||
return self.tab_from(
|
||||
data,
|
||||
browser_profile=target.profile if target else None,
|
||||
browser_name=target.display_name if target else None,
|
||||
browser_remote=target.remote if target else None,
|
||||
browser_type=getattr(target, "browser_name", None) if target else None,
|
||||
browser_group=_target_group(target),
|
||||
)
|
||||
|
||||
def group_from_target(self, data: dict, target) -> Group:
|
||||
"""Build a Group, tagging it with *target* in multi-browser mode (``None`` = local)."""
|
||||
return self.group_from(
|
||||
data,
|
||||
browser_profile=target.profile if target else None,
|
||||
browser_name=target.display_name if target else None,
|
||||
browser_remote=target.remote if target else None,
|
||||
browser_type=getattr(target, "browser_name", None) if target else None,
|
||||
browser_group=getattr(target, "display_group", None) if target else None,
|
||||
)
|
||||
def group_from_target(self, data: dict, target) -> Group:
|
||||
"""Build a Group, tagging it with *target* in multi-browser mode (``None`` = local)."""
|
||||
return self.group_from(
|
||||
data,
|
||||
browser_profile=target.profile if target else None,
|
||||
browser_name=target.display_name if target else None,
|
||||
browser_remote=target.remote if target else None,
|
||||
browser_type=getattr(target, "browser_name", None) if target else None,
|
||||
browser_group=_target_group(target),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def tag_browser(item: dict, target) -> dict:
|
||||
"""Return *item* as-is locally, or with a ``browser`` key in multi-browser mode."""
|
||||
return item if target is None else {**item, "browser": target.display_name}
|
||||
@staticmethod
|
||||
def tag_browser(item: dict, target) -> dict:
|
||||
"""Return *item* as-is locally, or with browser metadata in multi-browser mode."""
|
||||
if target is None:
|
||||
return item
|
||||
return {**item, "browser": target.display_name, "browserGroup": _target_group(target)}
|
||||
|
||||
Reference in New Issue
Block a user