Align admin optional-services billing UI with runtimes and bill RAM proportionally.

Split optional pricing vs deploy defaults and move custom domain to its own card; parse Mi as decimal GB so fractional memory scales linearly with per-GB rates. Deploy wizard hides env and optional services for WordPress and sanitizes create payloads.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
keyhan
2026-05-16 00:39:37 +03:30
parent 3a4fffcec4
commit 67b41ae311
4 changed files with 253 additions and 157 deletions
+12 -5
View File
@@ -580,7 +580,7 @@ export class PricingCatalogService implements OnModuleInit {
case PricingResourceType.CPU_PER_CORE:
return `CPU (${quantity.toFixed(2)} core)`;
case PricingResourceType.MEMORY_PER_GB:
return `Memory (${quantity.toFixed(2)} GB)`;
return `Memory (${quantity.toFixed(3)} GB billable)`;
case PricingResourceType.STORAGE_PER_GB:
return `Storage (${quantity} GB)`;
default:
@@ -616,12 +616,19 @@ export class PricingCatalogService implements OnModuleInit {
return parseFloat(cpu) || 0;
}
/**
* Billable memory quantity for rates labeled "per GB".
* Uses decimal GB so fractional Mi scales linearly (e.g. 500Mi → 0.5 × per-GB price).
* Gi values are treated as GB-sized billing units (1Gi → 1 unit).
*/
parseMemoryToGb(memory: string): number {
if (!memory) return 0;
if (memory.endsWith('Gi')) return parseFloat(memory);
if (memory.endsWith('Mi')) return parseFloat(memory) / 1024;
if (memory.endsWith('Ki')) return parseFloat(memory) / (1024 * 1024);
return parseFloat(memory) / (1024 * 1024 * 1024);
const m = memory.trim();
if (m.endsWith('Gi')) return parseFloat(m) || 0;
if (m.endsWith('Mi')) return (parseFloat(m) || 0) / 1000;
if (m.endsWith('Ki')) return (parseFloat(m) || 0) / 1_000_000;
const n = parseFloat(m);
return Number.isFinite(n) ? n / (1024 * 1024 * 1024) : 0;
}
private async upsertRuntimeRate(runtime: AppRuntime, row: PricingRateRow) {