Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | 4042x 70x 70x 70x 70x 1980x 1980x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 17x 38x 17x 87x 87x 174x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x | import type { CostCurveDriverSpec, CostCurveRead } from "@/api/apiStore.gen";
import { RoleEnum, SourceOptionsEnum } from "@/api/apiStore.gen";
export type RequiredDriverSpec = {
key: string;
label: string;
unit: string;
role: RoleEnum;
variableSymbol: string;
primary: boolean;
required: boolean;
defaultManualValue: string;
sourceOptions: SourceOptionsEnum[];
};
/**
* Return the complete, display-ready driver inputs declared by a cost curve.
*
* The backend has already validated this payload through the Pydantic
* `CostCurveDriverSpec` model. If a response is malformed, callers should
* render the selected curve as invalid rather than falling back to legacy
* sizing controls.
*/
export function requiredDriverSpecsFromCurve(
curve?: CostCurveRead | null,
): RequiredDriverSpec[] {
return (curve?.required_driver_specs ?? []).flatMap(
(spec: CostCurveDriverSpec): RequiredDriverSpec[] => {
const key = spec.key.trim();
const unit = spec.unit.trim();
Iif (!key || !unit) return [];
return [
{
key,
label: spec.label.trim() || key,
unit,
role: spec.role,
variableSymbol: spec.variable_symbol?.trim() ?? "",
primary: Boolean(spec.primary),
required: Boolean(spec.required ?? true),
defaultManualValue: spec.default_manual_value?.trim() ?? "",
sourceOptions: normalizedSourceOptions(spec.source_options),
},
];
},
);
}
export function hasInvalidDriverSpecPayload(curve?: CostCurveRead | null) {
const specs = curve?.required_driver_specs;
if (!Array.isArray(specs) || specs.length === 0) return Boolean(curve);
let primaryFormulaInputs = 0;
let formulaInputs = 0;
const keys = new Set<string>();
const symbols = new Set<string>();
for (const spec of specs) {
const key = spec.key?.trim();
const unit = spec.unit?.trim();
const role = spec.role;
Iif (!key || !unit || keys.has(key)) return true;
keys.add(key);
if (role !== RoleEnum.FormulaInput && role !== RoleEnum.DiscreteSelector) {
return true;
}
if (role === RoleEnum.FormulaInput) {
const symbol = spec.variable_symbol?.trim();
Iif (!symbol || symbols.has(symbol)) return true;
symbols.add(symbol);
formulaInputs += 1;
primaryFormulaInputs += spec.primary ? 1 : 0;
} else if (spec.variable_symbol?.trim() || spec.primary) {
return true;
}
Iif (normalizedSourceOptions(spec.source_options).length === 0) return true;
}
return formulaInputs === 0 || primaryFormulaInputs !== 1;
}
export function driverSpecIsManualOnly(spec: RequiredDriverSpec) {
return (
spec.sourceOptions.length === 1 &&
spec.sourceOptions[0] === SourceOptionsEnum.Manual
);
}
export function defaultManualValueForSpec(spec: RequiredDriverSpec) {
return driverSpecIsManualOnly(spec) ? spec.defaultManualValue : "";
}
function normalizedSourceOptions(
sourceOptions: CostCurveDriverSpec["source_options"],
) {
const allowed = new Set([
SourceOptionsEnum.Property,
SourceOptionsEnum.Manual,
]);
return (
sourceOptions ?? [SourceOptionsEnum.Property, SourceOptionsEnum.Manual]
).filter((option): option is SourceOptionsEnum => allowed.has(option));
}
export function formulaDriverSpecs(
specs: readonly CostCurveDriverSpec[],
): CostCurveDriverSpec[] {
return specs.filter((spec) => spec.role === RoleEnum.FormulaInput);
}
export function selectorDriverSpecs(
specs: readonly CostCurveDriverSpec[],
): CostCurveDriverSpec[] {
return specs.filter((spec) => spec.role === RoleEnum.DiscreteSelector);
}
export function driverSpecSummary(
specs: readonly CostCurveDriverSpec[] | undefined,
) {
const normalized = specs ?? [];
Iif (normalized.length === 0) return "Inputs not declared";
const formulaInputs = formulaDriverSpecs(normalized);
const selectors = selectorDriverSpecs(normalized);
const formulaText = formulaInputs
.map((spec) => `${spec.label || spec.key} (${spec.unit})`)
.join(", ");
const selectorText = selectors
.map((spec) => `${spec.label || spec.key} (${spec.unit})`)
.join(", ");
return [
formulaText ? `Inputs: ${formulaText}` : "",
selectorText ? `Sizing inputs: ${selectorText}` : "",
]
.filter(Boolean)
.join(". ");
}
|