Expose public module catalog discovery

This commit is contained in:
2026-08-06 21:13:13 +02:00
parent 218f94fa23
commit 1e55a80d3c
7 changed files with 79 additions and 12 deletions
+3
View File
@@ -425,6 +425,9 @@ export type ModulePackageCatalogItem = {
description?: string | null;
version?: string | null;
action: "install" | "update" | "uninstall";
installed: boolean;
installed_version?: string | null;
update_available: boolean;
dependencies: string[];
optional_dependencies: string[];
migration_safety: "automatic" | "requires_review" | "forward_only" | "destructive";
@@ -489,7 +489,7 @@ export default function ModuleManagementPanel({ settings, canWrite, canAccessMai
</div>
{(packageCatalog.source || packageCatalog.path) && <p className="module-package-catalog-description">i18n:govoplan-admin.catalog.4a88d27b {packageCatalog.source_type ?? "source"}: <code>{packageCatalog.source ?? packageCatalog.path}</code>{packageCatalog.cache_used && packageCatalog.cache_path ? <> i18n:govoplan-admin.cached_from.d73c5b2a <code>{packageCatalog.cache_path}</code></> : null}</p>}
{(packageCatalog.generated_at || packageCatalog.not_before || packageCatalog.expires_at) && <p className="module-package-catalog-description">i18n:govoplan-admin.generated.a2edf57c {packageCatalog.generated_at ?? "unknown"} i18n:govoplan-admin.valid_after.c615c873 {packageCatalog.not_before ?? "now"} i18n:govoplan-admin.expires.2d21b7de {packageCatalog.expires_at ?? "unknown"}</p>}
<LicenseStatus license={packageCatalog.license} />
{(packageCatalog.license.configured || packageCatalog.license.required_features.length > 0) && <LicenseStatus license={packageCatalog.license} />}
{packageCatalog.error && <p className="alert warning">{packageCatalog.error}</p>}
{packageCatalog.warnings.map((warning) => <p key={warning} className="alert warning">{warning}</p>)}
{!packageCatalog.configured && <div className="module-install-plan-empty">i18n:govoplan-admin.no_package_catalog_configured_set_govoplan_modul.2c5fceb3</div>}
@@ -502,6 +502,7 @@ export default function ModuleManagementPanel({ settings, canWrite, canAccessMai
<strong>{item.name}</strong>
<code>{item.module_id}</code>
{item.version && <span>v{item.version}</span>}
{item.installed && <StatusBadge status={item.update_available ? "warning" : "success"} label={item.update_available ? "i18n:govoplan-admin.plan_update.86e6857a" : "i18n:govoplan-admin.installed.7bb4405c"} />}
</div>
<div className="module-management-details">
{item.python_package && <span>{item.python_package}</span>}
@@ -525,7 +526,7 @@ export default function ModuleManagementPanel({ settings, canWrite, canAccessMai
{item.recovery_notes && <p className="module-package-catalog-description">{item.recovery_notes}</p>}
{item.license_reason && <p className={`module-package-catalog-description${item.license_allowed ? "" : " alert warning"}`}>{item.license_reason}</p>}
</div>
<Button onClick={() => void addCatalogItem(item)} disabled={!canWrite || planBusy || !packageCatalog.valid || !item.license_allowed || !["install", "update"].includes(item.action)} disabledReason={planBusy ? ADMIN_INTERFACE_I18N.busy : !canWrite ? ADMIN_INTERFACE_I18N.writeRequired : !packageCatalog.valid || !item.license_allowed || !["install", "update"].includes(item.action) ? ADMIN_INTERFACE_I18N.catalogBlocked : undefined}>{catalogPlanButtonLabel(item, catalog)}</Button>
<Button onClick={() => void addCatalogItem(item)} disabled={!canWrite || planBusy || !packageCatalog.valid || !item.license_allowed || !["install", "update"].includes(item.action)} disabledReason={planBusy ? ADMIN_INTERFACE_I18N.busy : !canWrite ? ADMIN_INTERFACE_I18N.writeRequired : !packageCatalog.valid || !item.license_allowed || !["install", "update"].includes(item.action) ? ADMIN_INTERFACE_I18N.catalogBlocked : undefined}>{catalogPlanButtonLabel(item)}</Button>
</div>
)}
</div>}
@@ -958,10 +959,10 @@ function ModuleStatus({ module, desiredEnabled }: {module: ModuleCatalogItem;des
return <StatusBadge status="inactive" label="i18n:govoplan-admin.inactive.09af574c" />;
}
function catalogPlanButtonLabel(item: ModulePackageCatalogItem, catalog: ModuleCatalogResponse | null): string {
if (item.action === "update") return "i18n:govoplan-admin.plan_update.86e6857a";
const installed = catalog?.modules.some((module) => module.id === item.module_id && module.installed) ?? false;
return installed ? "i18n:govoplan-admin.plan_update.86e6857a" : "i18n:govoplan-admin.plan_install.e82bffe6";
function catalogPlanButtonLabel(item: ModulePackageCatalogItem): string {
return item.action === "update" || item.installed
? "i18n:govoplan-admin.plan_update.86e6857a"
: "i18n:govoplan-admin.plan_install.e82bffe6";
}
function sameSet(left: ReadonlySet<string>, right: ReadonlySet<string>) {