Files
Ali Khokhar 51157f91bd Refactor admin config into catalog-driven package (#926)
## Problem

Admin config was a single responsibility hub with manually duplicated
provider metadata. Provider labels, fields, template loading,
validation, persistence, and status lived in one place.

## Changes

| Before | After |
| --- | --- |
| Admin config lived in one large `api/admin_config.py` module. | Admin
config lives in package modules for manifest, sources, values,
validation, persistence, and status. |
| Provider admin fields and UI labels were manually duplicated. |
Provider admin fields and display names derive from `PROVIDER_CATALOG`
with admin-only help overrides. |
| `fcc-init` and Admin UI loaded `.env.example` separately. | `fcc-init`
and Admin UI use shared `config.env_template` loading. |
| Architecture docs pointed to the old admin config module. |
Architecture docs describe the package owners and catalog-driven
provider manifest. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR refactors admin configuration into a catalog-driven package. The
main changes are:

- Split the former monolithic `api/admin_config.py` into manifest,
source loading, value presentation, validation, persistence, and
provider status modules.
- Generate provider admin fields and display names from
`PROVIDER_CATALOG` with admin-specific help overrides.
- Share `.env.example` loading between `fcc-init` and Admin UI defaults
through `config.env_template`.
- Update admin routes, Admin UI provider labels, architecture docs,
version metadata, and contract/API tests for the new module layout.
</details>

<h3>Confidence Score: 5/5</h3>

The refactor appears merge-safe with no code issues identified in the
reviewed changes.

The package split, catalog-driven provider metadata, shared environment
template loading, route updates, and tests/docs changes are cohesive and
covered by corresponding contract/API/CLI test updates.

<details><summary><h3><a href="https://www.greptile.com/trex"><img
alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="20" align="absmiddle"></a> T-Rex Logs</h3></summary>

**What T-Rex did**
- T-Rex ran manifest validation for catalog provider before and after
routes, capturing base and head responses and catalog-alignment checks,
and confirmed the validation completed successfully.
- T-Rex evaluated the shared-env-template scenarios, observing the
before run with no config.env\_template module and the after run with
the module present, with patched loader values and all consistency
checks passing, and the run exited with code 0.
- T-Rex executed the package-admin-workflow validation, verifying the
base and after import paths, the load/validate/write workflow produced
matching outputs, and the run completed with exit code 0.

<a
href="https://app.greptile.com/trex/runs/12529845/artifacts"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=1"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=1"><img
alt="View all artifacts"
src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=1"
height="32"></picture></a>

<sub><a href="https://www.greptile.com/trex"><img alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="14" align="absmiddle"></a> Ran code and verified through
T-Rex</sub>
</details>

<sub>Reviews (1): Last reviewed commit: ["Refactor admin config into
catalog-drive..."](https://github.com/alishahryar1/free-claude-code/commit/d6239d7953fce75d435b8d6a20536c1aff53aa88)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40315222)</sub>

<!-- /greptile_comment -->
2026-06-27 15:37:29 -07:00

62 lines
2.1 KiB
Python

"""Provider configuration status for the Admin UI."""
from __future__ import annotations
from collections.abc import Mapping
from typing import Any
from config.provider_catalog import PROVIDER_CATALOG
from .manifest import FIELDS
def provider_config_status(
state: Mapping[str, Mapping[str, Any]] | None = None,
) -> list[dict[str, Any]]:
"""Return provider configuration status without making network calls."""
if state is None:
from .values import load_value_state
state = load_value_state()
statuses: list[dict[str, Any]] = []
for provider_id, descriptor in PROVIDER_CATALOG.items():
if descriptor.credential_env is None:
base_url = ""
if descriptor.base_url_attr is not None:
base_url = _value_for_settings_attr(state, descriptor.base_url_attr)
statuses.append(
{
"provider_id": provider_id,
"display_name": descriptor.display_name,
"kind": "local",
"status": "missing_url" if not base_url.strip() else "unknown",
"label": "Missing URL" if not base_url.strip() else "Not checked",
"base_url": base_url or descriptor.default_base_url or "",
}
)
continue
value = str(state.get(descriptor.credential_env, {}).get("value", ""))
configured = bool(value.strip())
statuses.append(
{
"provider_id": provider_id,
"display_name": descriptor.display_name,
"kind": "remote",
"status": "configured" if configured else "missing_key",
"label": "Configured" if configured else "Missing key",
"credential_env": descriptor.credential_env,
}
)
return statuses
def _value_for_settings_attr(
state: Mapping[str, Mapping[str, Any]], settings_attr: str
) -> str:
for field in FIELDS:
if field.settings_attr == settings_attr:
return str(state.get(field.key, {}).get("value", field.default))
return ""