feat: custom endpoint fields in new profile form (fixes #170, closes #214)

* feat: add custom endpoint fields to new profile form

* fix: skip config write tests when PyYAML not installed

The 4 unit tests for _write_endpoint_to_config imported yaml directly
without handling ImportError. Added pytest.importorskip('yaml') at
module level so the entire test class skips cleanly in environments
without PyYAML. Removed redundant per-method yaml imports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: wire frontend for custom endpoint fields in new profile form

- Add Base URL and API key inputs to the profile create form (index.html)
- Wire panels.js submitProfileCreate() to send base_url and api_key
- Clear new fields on form toggle/cancel
- Add client-side URL format validation (must start with http:// or https://)
- Add server-side URL format validation in routes.py (400 for invalid scheme)
- Add test_api_route_rejects_invalid_base_url() covering the new validation
- Base URL input has placeholder 'http://localhost:11434' per review suggestion

---------

Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
nesquena-hermes
2026-04-10 11:43:49 -07:00
committed by GitHub
parent 1e27940535
commit da160d675f
5 changed files with 209 additions and 3 deletions

View File

@@ -607,12 +607,18 @@ def handle_post(handler, parsed) -> bool:
clone_from = str(clone_from).strip()
if not _re.match(r'^[a-z0-9][a-z0-9_-]{0,63}$', clone_from):
return bad(handler, 'Invalid clone_from name')
base_url = body.get('base_url', '').strip() if body.get('base_url') else None
api_key = body.get('api_key', '').strip() if body.get('api_key') else None
if base_url and not base_url.startswith(('http://', 'https://')):
return bad(handler, 'base_url must start with http:// or https://')
try:
from api.profiles import create_profile_api
result = create_profile_api(
name,
clone_from=clone_from,
clone_config=bool(body.get('clone_config', False)),
base_url=base_url,
api_key=api_key,
)
return j(handler, {'ok': True, 'profile': result})
except (ValueError, FileExistsError, RuntimeError) as e: