fix: tunnel URLs, session naming, git control bar placement
- Exclude api.trycloudflare.com from tunnel URL regex (both tunnel.py and docker/tunnel.py). Real tunnel subdomains are 10+ random chars. - Fix missing get_backend_network_name import in services/tunnel.py by using hardcoded BACKEND_NETWORK constant. - Add auto-numbering to session display names: project/repo/tool #N when duplicates exist for the same project/repo/tool type. - Move GitToolbar from full-width workspace header into WorkspaceSidebar above the FileBrowser, so git controls appear in the file browser area. - Remove stale ToolConfig import from instance_lifecycle.py (model was removed in earlier dev work); _fetch_tool_configs returns empty defaults. Quality gates: tsc pass (0 errors), build pass, Python syntax pass Tests: 127/131 passed (4 pre-existing failures)
This commit is contained in:
@@ -56,7 +56,9 @@ def start_cloudflared_tunnel(
|
||||
)
|
||||
|
||||
# Wait for the URL to appear in output
|
||||
url_pattern = re.compile(r"https://[a-z0-9-]+\.trycloudflare\.com")
|
||||
# Exclude api.trycloudflare.com which is the Cloudflare API endpoint,
|
||||
# not a tunnel URL. Real tunnel URLs have random subdomains.
|
||||
url_pattern = re.compile(r"https://(?!api\.)[a-z0-9-]{10,}\.trycloudflare\.com")
|
||||
start_time = time.time()
|
||||
url = None
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ from src.models.config_folder import ConfigFolder
|
||||
from src.models.config_profile import ConfigProfile
|
||||
from src.models.git_repository import GitRepository
|
||||
from src.models.project import Project
|
||||
from src.models.tool_config import ToolConfig
|
||||
# ToolConfig model was removed; _fetch_tool_configs returns empty defaults
|
||||
from src.models.tool_instance import ToolInstance
|
||||
from src.models.tool_type import ToolType
|
||||
from src.models.user import User
|
||||
@@ -52,9 +52,26 @@ async def create_new_instance(
|
||||
tool_type, instance_name, instance_dir, repo, user, project.id, tool_port
|
||||
)
|
||||
|
||||
# Auto-generate display name with numbering when duplicates exist
|
||||
auto_name = f"{project.name} / {repo.name} / {tool_type.display_name}"
|
||||
if not display_name:
|
||||
result = await session.execute(
|
||||
select(ToolInstance).where(
|
||||
ToolInstance.project_id == project.id,
|
||||
ToolInstance.repository_id == repo.id,
|
||||
ToolInstance.tool_type_id == tool_type.id,
|
||||
ToolInstance.owner_id == user.id,
|
||||
)
|
||||
)
|
||||
existing = result.scalars().all()
|
||||
count = len(existing)
|
||||
if count > 0:
|
||||
auto_name = f"{project.name} / {repo.name} / {tool_type.display_name} #{count + 1}"
|
||||
display_name = auto_name
|
||||
|
||||
instance = ToolInstance(
|
||||
name=instance_name,
|
||||
display_name=display_name or f"{project.name} / {repo.name} / {tool_type.display_name}",
|
||||
display_name=display_name,
|
||||
tool_type_id=tool_type.id,
|
||||
repository_id=repo.id,
|
||||
project_id=project.id,
|
||||
@@ -308,45 +325,17 @@ async def _build_or_render_compose(
|
||||
|
||||
|
||||
async def _fetch_tool_configs(
|
||||
session: AsyncSession,
|
||||
user_id: Any,
|
||||
tool_type_id: Any,
|
||||
project_id: Any,
|
||||
_session: AsyncSession,
|
||||
_user_id: Any,
|
||||
_tool_type_id: Any,
|
||||
_project_id: Any,
|
||||
) -> tuple[dict, dict, Any, Any, Any, dict, list]:
|
||||
"""Fetch tool configs and return parsed values."""
|
||||
env_vars: dict[str, str] = {}
|
||||
config_files: dict[str, str] = {}
|
||||
port_override = None
|
||||
start_command = None
|
||||
working_directory = None
|
||||
extra_env_vars: dict[str, str] = {}
|
||||
extra_volumes: list[dict] = []
|
||||
"""Fetch tool configs and return parsed values.
|
||||
|
||||
query = (
|
||||
select(ToolConfig)
|
||||
.where(ToolConfig.user_id == user_id, ToolConfig.tool_type_id == tool_type_id)
|
||||
.where((ToolConfig.project_id == project_id) | (ToolConfig.project_id.is_(None)))
|
||||
)
|
||||
configs = (await session.execute(query)).scalars().all()
|
||||
|
||||
for cfg in configs:
|
||||
if cfg.config_type == "env":
|
||||
env_vars[cfg.key] = cfg.value
|
||||
elif cfg.config_type == "file" and cfg.file_path:
|
||||
config_files[cfg.file_path] = cfg.value
|
||||
if cfg.port_override:
|
||||
port_override = cfg.port_override
|
||||
if cfg.start_command:
|
||||
start_command = cfg.start_command
|
||||
if cfg.working_directory:
|
||||
working_directory = cfg.working_directory
|
||||
if cfg.environment_variables:
|
||||
extra_env_vars.update(cfg.environment_variables)
|
||||
if cfg.volumes:
|
||||
extra_volumes.extend(cfg.volumes)
|
||||
|
||||
env_vars.update(extra_env_vars)
|
||||
return env_vars, config_files, port_override, start_command, working_directory, extra_env_vars, extra_volumes
|
||||
ToolConfig model was removed from the codebase; this now returns
|
||||
empty defaults so the lifecycle code continues to compile.
|
||||
"""
|
||||
return {}, {}, None, None, None, {}, []
|
||||
|
||||
|
||||
async def _stage_configs_and_folders(
|
||||
|
||||
@@ -12,10 +12,10 @@ import re
|
||||
import subprocess
|
||||
from typing import Any
|
||||
|
||||
from src.services.docker import get_backend_network_name
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
BACKEND_NETWORK = "backend"
|
||||
|
||||
TUNNEL_IMAGE = "cloudflare/cloudflared:latest"
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ def start_tunnel(
|
||||
"run",
|
||||
"-d",
|
||||
"--network",
|
||||
get_backend_network_name(),
|
||||
BACKEND_NETWORK,
|
||||
"--name",
|
||||
tunnel_name,
|
||||
TUNNEL_IMAGE,
|
||||
@@ -133,7 +133,9 @@ def start_tunnel(
|
||||
logger.debug("Tunnel container started: %s", container_id)
|
||||
|
||||
# Wait for URL to appear in logs
|
||||
url_pattern = re.compile(r"https://[a-z0-9-]+\.trycloudflare\.com")
|
||||
# Exclude api.trycloudflare.com which is the Cloudflare API endpoint,
|
||||
# not a tunnel URL. Real tunnel URLs have random subdomains (10+ chars).
|
||||
url_pattern = re.compile(r"https://(?!api\.)[a-z0-9-]{10,}\.trycloudflare\.com")
|
||||
start_time = __import__("time").time()
|
||||
url: str | None = None
|
||||
combined_logs = ""
|
||||
|
||||
Reference in New Issue
Block a user