Skip to main content
Version: 0.0.26

Build UIControls in code (Builder API)

In addition to fetching UIControls from the backend, you can construct a complete UIControls object in code using the exported builder utilities.

If you are new to the concept, first see UIControls to learn what the structure represents. The builders simply help you produce that same structure fluently.

Quick overview

  • Use UiControlsInitRequestBuilder to build the Request section
  • Combine InputValueBuilder + InputParameterFloatBuilder / InputParameterStringBuilder to define fields
  • Group fields with InputParameterCategoryBuilder inside InputParameterCategoryGroupBuilder
  • Wrap everything into an InputParameterSetBuilder and finally UiControlsInitResponseBuilder

Exports (quick reference)

ExportKindPurposeCommon methods (subset)Produces
UiControlsInitRequestBuilderbuilderBuild the Request object used in UIControls.RequestwithProductIds, withProductGroupIds, withProductFamilyIds, withScopeSystem, withInterfaceI18n, withCalculationI18nInitRequest
UiControlsInitResponseBuilderbuilderAssemble the final UIControls response structurewithRequest, withCalcRequestURL, addInputParameterSet, addAccessoryCategory, addResultTableType, buildUIControls
InputParameterSetBuilderbuilderTop-level set holding category groupswithKey, withName, withOrder, addCategoryGroup, buildInputParameterSet
InputParameterCategoryGroupBuilderbuilderHolds one or more categories within a setwithKey, withName, withOrder, withLength, addCategory, buildCategoryGroup
InputParameterCategoryBuilderbuilderHolds input fields, calculated floats and dependencieswithGroupKey, withGroupName, withGroupOrder, addInputValue, addCalculatedFloat, addDependency, buildCategory
InputValueBuilderbuilderDefines a single field (float/string/bool) and general propsfloat(), string(), bool(), withVisible, withDisplayOn, withFieldType, withFloat, withString, buildInputValue
InputParameterFloatBuilderbuilderFloat-specific metadata (units, min/max/default/step)withUnitType, withUnit, withMinPimValue, withMaxPimValue, withDefaultPimValue, withStepSizePimValue, withDecimals, buildFloatValue
InputParameterStringBuilderbuilderString options list and defaultswithValuesKey, addValue, withDefaultValueKey, buildStringValue
InputCalculatedFloatBuilderbuilderComputed float values derived from formulaswithKey, withFormula, withValue, buildCalculatedFloat
InputDependencyBuilderbuilderDeclarative constraints/influences between inputswithKey, withDependency, withFirstValueKey, withSecondValueKey, addInfluenceValue, buildDependency
AccessoryCategoryBuilderbuilderAccessory categories containerwithKey, withName, withOrder, withCalculationRelevant, addAccessory, buildAccessoryCategory
AccessoryBuilderbuilderA single accessory incl. image and nested IPSwithId, withKey, withName, withDescription, withPrice, withImage, addInputParameterSet, buildAccessory
ImageRefBuilderbuilderCreate image references for accessorieswithId, withPath, withName, withSize, withUrl, buildImageRef
pimFloathelperConstruct PimValue for float ranges/defaultspimFloat(value, unit?, unitType?, key?)PimValue
stringValuehelperConstruct option entries for string inputsstringValue(key, name){ Key, Name }
influenceValuehelperConstruct influence rules for dependenciesinfluenceValue(key, order, direction)InfluenceValue
Exports

All builder classes and helpers are exported from the package root. You can import them directly from 'kampmann-calcgateway-frontend'.

How to use a builder

Here is a tiny example that creates one float input and one dropdown, groups them, and builds a minimal UIControls object:

import {
UiControlsInitRequestBuilder,
UiControlsInitResponseBuilder,
InputParameterSetBuilder,
InputParameterCategoryGroupBuilder,
InputParameterCategoryBuilder,
InputValueBuilder,
InputParameterFloatBuilder,
InputParameterStringBuilder,
pimFloat,
stringValue,
} from 'kampmann-calcgateway-frontend'

const req = UiControlsInitRequestBuilder.create()
.withProductGroupIds([51050])
.build()

const length = InputValueBuilder.float('length', 'Length', 1)
.withFloat(
InputParameterFloatBuilder.create()
.withUnit('mm')
.withUnitType('length')
.withMinPimValue(pimFloat(100, 'mm', 'length'))
.withMaxPimValue(pimFloat(3000, 'mm', 'length'))
.withDefaultPimValue(pimFloat(800, 'mm', 'length'))
.build()
)
.build()

const medium = InputValueBuilder.string('medium', 'Medium', 2)
.withString(
InputParameterStringBuilder.create()
.addValue(stringValue('water', 'Water'))
.addValue(stringValue('glycol', 'Glycol'))
.withDefaultValueKey('water')
.build()
)
.build()

const category = InputParameterCategoryBuilder.create()
.withGroupKey('general')
.withGroupName('General')
.withGroupOrder(1)
.addInputValue(length)
.addInputValue(medium)
.build()

const group = InputParameterCategoryGroupBuilder.create()
.withKey('general')
.withName('General')
.addCategory(category)
.build()

const ips = InputParameterSetBuilder.create()
.withKey('set1')
.withName('Standard')
.addCategoryGroup(group)
.build()

export const ui = UiControlsInitResponseBuilder.create()
.withRequest(req)
.addInputParameterSet(ips)
.build()

Advanced example

The following example demonstrates a more complete, production-like UIControls definition. It includes:

  • Multiple groups (medium, cooling, heating)
  • Float inputs with units, ranges and slider field types
  • String inputs with option lists
  • Calculated floats
  • Dependencies with influence values

You can copy/paste this example and adapt values to your needs.

import type { UIControls } from 'kampmann-calcgateway-frontend'
import {
// Components and types you might use
CalcGatewayForm,
CalculationTable,
// Builders
UiControlsInitRequestBuilder,
UiControlsInitResponseBuilder,
InputParameterSetBuilder,
InputParameterCategoryGroupBuilder,
InputParameterCategoryBuilder,
InputValueBuilder,
InputParameterFloatBuilder,
InputParameterStringBuilder,
InputCalculatedFloatBuilder,
InputDependencyBuilder,
// Helpers
pimFloat,
stringValue,
influenceValue,
// Enums / constants
RequestLanguage,
RequestRegion,
RequestUnitSystem,
ScopeSystem,
ResultTableType,
} from 'kampmann-calcgateway-frontend'

function buildExampleUIControls(): UIControls {
// Build Request
const req = UiControlsInitRequestBuilder.create()
.withProductIds([444933])
.withProductGroupIds([])
.withProductFamilyIds([])
.withScopeSystem(ScopeSystem.EXTERNAL)
.withIncludeAccessory(false)
.withInterfaceI18n({
Language: RequestLanguage.DE,
Region: RequestRegion.DE,
UnitSystem: RequestUnitSystem.METRIC
})
.withCalculationI18n({
Language: RequestLanguage.DE,
Region: RequestRegion.DE,
UnitSystem: RequestUnitSystem.METRIC
})
.build();

// Group: medium
const mediumCategory = InputParameterCategoryBuilder.create()
.withGeneralUse(true)
.withGroupOrder(0)
.addInputValue(
// medium (string dropdown)
InputValueBuilder.string('medium', 'Medium', 10)
.withVisible(true)
.withFieldType('dropDown')
.withFloat(
InputParameterFloatBuilder.create()
.withMinPimValue(pimFloat(0))
.withMaxPimValue(pimFloat(0))
.withDefaultPimValue(pimFloat(0))
.withStepSizePimValue(pimFloat(0))
.withDecimals(0)
.build()
)
.withString(
InputParameterStringBuilder.create()
.withValuesKey('MEDIUM.SEL')
.addValue(stringValue('water', 'Wasser'))
.addValue(stringValue('water_ETHYL', 'Ethylenglykol'))
.withDefaultValueKey('water')
.build()
)
.build()
)
.addInputValue(
// medium_concentration (float slider)
InputValueBuilder.float('medium_concentration', 'Konzentration', 20)
.withVisible(true)
.withDisplayOn('medium != water')
.withValueListCheck(true)
.withFieldType('slider')
.withFloat(
InputParameterFloatBuilder.create()
.withUnitType('percentage')
.withUnit('%')
.withMinPimValue({ Key: 'MINGLYKOLKONZENTRATION.NUM', Value: 30, Unit: '%', UnitType: 'percentage' })
.withMaxPimValue({ Key: 'MAXGLYKOLKONZENTRATION.NUM', Value: 30, Unit: '%', UnitType: 'percentage' })
.withDefaultPimValue({ Key: 'DEFAULTGLYKOLKONZENTRATION.NUM', Value: 30, Unit: '%', UnitType: 'percentage' })
.withStepSizePimValue({ Key: 'STEPGLYKOLKONZENTRATION.NUM', Value: 1, Unit: '%', UnitType: 'percentage' })
.withDecimals(0)
.build()
)
.withString({ Values: null } as any)
.build()
)
.build();

const mediumGroup = InputParameterCategoryGroupBuilder.create()
.withKey('medium')
.withName('Medium')
.withOrder(0)
.withLength(1)
.addCategory(mediumCategory)
.build();

// Group: cooling
const coolingCategory = InputParameterCategoryBuilder.create()
.withGroupOrder(0)
.addInputValue(
InputValueBuilder.float('flow_temperature', 'Vorlauftemperatur', 30)
.withVisible(true)
.withFieldType('slider')
.withFloat(
InputParameterFloatBuilder.create()
.withUnitType('temperature')
.withUnit('°C')
.withMinPimValue({ Key: 'MINVORLAUFKUEHLEN.NUM', Value: 5, Unit: '°C', UnitType: 'temperature' })
.withMaxPimValue({ Key: 'MAXVORLAUFKUEHLEN.NUM', Value: 18, Unit: '°C', UnitType: 'temperature' })
.withDefaultPimValue({ Key: 'DEFAULTVORLAUFKUEHLEN.NUM', Value: 7, Unit: '°C', UnitType: 'temperature' })
.withStepSizePimValue({ Key: 'STEPVORLAUFKUEHLEN.NUM', Value: 1, Unit: '°C', UnitType: 'temperature' })
.withDecimals(0)
.build()
)
.withString({ Values: null } as any)
.build()
)
.addInputValue(
InputValueBuilder.float('return_temperature', 'Rücklauftemperatur', 40)
.withVisible(true)
.withDisplayOn('false')
.withFieldType('slider')
.withFloat(
InputParameterFloatBuilder.create()
.withUnitType('temperature')
.withUnit('°C')
.withMinPimValue({ Key: 'MINRUECKLAUFKUEHLEN.NUM', Value: 10, Unit: '°C', UnitType: 'temperature' })
.withMaxPimValue({ Key: 'MAXRUECKLAUFKUEHLEN.NUM', Value: 23, Unit: '°C', UnitType: 'temperature' })
.withDefaultPimValue({ Key: 'DEFAULTRUECKLAUFKUEHLEN.NUM', Value: 12, Unit: '°C', UnitType: 'temperature' })
.withStepSizePimValue({ Key: 'STEPRUECKLAUFKUEHLEN.NUM', Value: 1, Unit: '°C', UnitType: 'temperature' })
.withDecimals(0)
.build()
)
.withString({ Values: null } as any)
.build()
)
.addInputValue(
InputValueBuilder.float('outdoor_air_temperature', 'Außenlufttemperatur', 50)
.withVisible(true)
.withFieldType('slider')
.withFloat(
InputParameterFloatBuilder.create()
.withUnitType('temperature')
.withUnit('°C')
.withMinPimValue({ Key: 'MINAUSSENTEMPERATURKUEHLEN.NUM', Value: 20, Unit: '°C', UnitType: 'temperature' })
.withMaxPimValue({ Key: 'MAXAUSSENTEMPERATURKUEHLEN.NUM', Value: 40, Unit: '°C', UnitType: 'temperature' })
.withDefaultPimValue({ Key: 'DEFAULTAUSSENTEMPERATURKUEHLEN.NUM', Value: 35, Unit: '°C', UnitType: 'temperature' })
.withStepSizePimValue({ Key: 'STEPAUSSENLUFTTEMPERATURKUEHLEN.NUM', Value: 1, Unit: '°C', UnitType: 'temperature' })
.withDecimals(0)
.build()
)
.withString({ Values: null } as any)
.build()
)
.addCalculatedFloat(
InputCalculatedFloatBuilder.create().withKey('delta_temperature').withFormula('return_temperature - flow_temperature').build()
)
.addCalculatedFloat(
InputCalculatedFloatBuilder.create().withKey('neg_delta_temperature').withFormula('flow_temperature - return_temperature').build()
)
.addCalculatedFloat(
InputCalculatedFloatBuilder.create().withKey('under_temperature').withFormula('outdoor_air_temperature - (flow_temperature + return_temperature) / 2').build()
)
.addCalculatedFloat(
InputCalculatedFloatBuilder.create().withKey('delta_air_to_return_temperature').withFormula('outdoor_air_temperature - return_temperature').build()
)
.addDependency(
InputDependencyBuilder.create()
.withKey('cooling_offset_lower_limit')
.withDependency('<=')
.withFirstValueKey('delta_temperature')
.withFirstPimValue({ Key: 'delta_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.withSecondValueKey('OFFSETRUECKLAUFKUEHLEN.NUM')
.withSecondPimValue({ Key: 'OFFSETRUECKLAUFKUEHLEN.NUM', Value: 5, Unit: '°C', UnitType: 'temperature' })
.addInfluenceValue(influenceValue('return_temperature', 0, 'lower'))
.addInfluenceValue(influenceValue('flow_temperature', 1, 'raise'))
.build()
)
.addDependency(
InputDependencyBuilder.create()
.withKey('cooling_offset_upper_limit')
.withDependency('>=')
.withFirstValueKey('delta_temperature')
.withFirstPimValue({ Key: 'delta_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.withSecondValueKey('OFFSETRUECKLAUFKUEHLEN.NUM')
.withSecondPimValue({ Key: 'OFFSETRUECKLAUFKUEHLEN.NUM', Value: 5, Unit: '°C', UnitType: 'temperature' })
.addInfluenceValue(influenceValue('return_temperature', 0, 'raise'))
.addInfluenceValue(influenceValue('flow_temperature', 1, 'lower'))
.build()
)
.addDependency(
InputDependencyBuilder.create()
.withKey('cooling_thermomode')
.withDependency('<')
.withFirstValueKey('flow_temperature')
.withFirstPimValue({ Key: 'flow_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.withSecondValueKey('return_temperature')
.withSecondPimValue({ Key: 'return_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.addInfluenceValue(influenceValue('flow_temperature', 0, 'lower'))
.build()
)
.addDependency(
InputDependencyBuilder.create()
.withKey('under_temperature_lower_limit')
.withDependency('>=')
.withFirstValueKey('under_temperature')
.withFirstPimValue({ Key: 'under_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.withSecondValueKey('INFLUMINUNTERTEMPERATURKUEHLEN.NUM')
.withSecondPimValue({ Key: 'INFLUMINUNTERTEMPERATURKUEHLEN.NUM', Value: -1.5, Unit: '°C', UnitType: 'temperature' })
.addInfluenceValue(influenceValue('flow_temperature', 0, 'lower'))
.addInfluenceValue(influenceValue('outdoor_air_temperature', 1, 'raise'))
.build()
)
.addDependency(
InputDependencyBuilder.create()
.withKey('under_temperature_upper_limit')
.withDependency('<=')
.withFirstValueKey('under_temperature')
.withFirstPimValue({ Key: 'under_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.withSecondValueKey('INFLUMAXUNTERTEMPERATURKUEHLEN.NUM')
.withSecondPimValue({ Key: 'INFLUMAXUNTERTEMPERATURKUEHLEN.NUM', Value: 33, Unit: '°C', UnitType: 'temperature' })
.addInfluenceValue(influenceValue('flow_temperature', 0, 'raise'))
.addInfluenceValue(influenceValue('outdoor_air_temperature', 1, 'lower'))
.build()
)
.addDependency(
InputDependencyBuilder.create()
.withKey('delta_air_to_return_temperature_lower_limit')
.withDependency('>=')
.withFirstValueKey('delta_air_to_return_temperature')
.withFirstPimValue({ Key: 'delta_air_to_return_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.withSecondValueKey('INFLUMINRUECKLAUFRAUMKUEHLEN.NUM')
.withSecondPimValue({ Key: 'INFLUMINRUECKLAUFRAUMKUEHLEN.NUM', Value: -3, Unit: '°C', UnitType: 'temperature' })
.addInfluenceValue(influenceValue('outdoor_air_temperature', 0, 'raise'))
.build()
)
.build();

const coolingGroup = InputParameterCategoryGroupBuilder.create()
.withKey('cooling')
.withName('Kühlen')
.withOrder(1)
.withLength(1)
.addCategory(coolingCategory)
.build();

// Group: heating
const heatingCategory = InputParameterCategoryBuilder.create()
.withGroupOrder(0)
.addInputValue(
InputValueBuilder.float('flow_temperature', 'Vorlauftemperatur', 160)
.withVisible(true)
.withFieldType('slider')
.withFloat(
InputParameterFloatBuilder.create()
.withUnitType('temperature')
.withUnit('°C')
.withMinPimValue({ Key: 'MINVORLAUFHEIZEN.NUM', Value: 35, Unit: '°C', UnitType: 'temperature' })
.withMaxPimValue({ Key: 'MAXVORLAUFHEIZEN.NUM', Value: 70, Unit: '°C', UnitType: 'temperature' })
.withDefaultPimValue({ Key: 'DEFAULTVORLAUFHEIZEN.NUM', Value: 45, Unit: '°C', UnitType: 'temperature' })
.withStepSizePimValue({ Key: 'STEPVORLAUFHEIZEN.NUM', Value: 1, Unit: '°C', UnitType: 'temperature' })
.withDecimals(0)
.build()
)
.build()
)
.addInputValue(
InputValueBuilder.float('return_temperature', 'Rücklauftemperatur', 170)
.withVisible(true)
.withDisplayOn('false')
.withFieldType('slider')
.withFloat(
InputParameterFloatBuilder.create()
.withUnitType('temperature')
.withUnit('°C')
.withMinPimValue({ Key: 'MINRUECKLAUFHEIZEN.NUM', Value: 30, Unit: '°C', UnitType: 'temperature' })
.withMaxPimValue({ Key: 'MAXRUECKLAUFHEIZEN.NUM', Value: 65, Unit: '°C', UnitType: 'temperature' })
.withDefaultPimValue({ Key: 'DEFAULTRUECKLAUFHEIZEN.NUM', Value: 40, Unit: '°C', UnitType: 'temperature' })
.withStepSizePimValue({ Key: 'STEPRUECKLAUFHEIZEN.NUM', Value: 1, Unit: '°C', UnitType: 'temperature' })
.withDecimals(0)
.build()
)
.build()
)
.addInputValue(
InputValueBuilder.float('outdoor_air_temperature', 'Außenlufttemperatur', 180)
.withVisible(true)
.withFieldType('slider')
.withFloat(
InputParameterFloatBuilder.create()
.withUnitType('temperature')
.withUnit('°C')
.withMinPimValue({ Key: 'MINAUSSENTEMPERATURHEIZEN.NUM', Value: -15, Unit: '°C', UnitType: 'temperature' })
.withMaxPimValue({ Key: 'MAXAUSSENTEMPERATURHEIZEN.NUM', Value: 15, Unit: '°C', UnitType: 'temperature' })
.withDefaultPimValue({ Key: 'DEFAULTAUSSENLUFTTEMPERATURHEIZEN.NUM', Value: 7, Unit: '°C', UnitType: 'temperature' })
.withStepSizePimValue({ Key: 'STEPAUSSENLUFTTEMPERATURHEIZEN.NUM', Value: 1, Unit: '°C', UnitType: 'temperature' })
.withDecimals(0)
.build()
)
.build()
)
.addCalculatedFloat(
InputCalculatedFloatBuilder.create().withKey('delta_temperature').withFormula('flow_temperature - return_temperature').build()
)
.addCalculatedFloat(
InputCalculatedFloatBuilder.create().withKey('neg_delta_temperature').withFormula('return_temperature - flow_temperature ').build()
)
.addCalculatedFloat(
InputCalculatedFloatBuilder.create().withKey('over_temperature').withFormula('(flow_temperature + return_temperature) / 2 - outdoor_air_temperature').build()
)
.addCalculatedFloat(
InputCalculatedFloatBuilder.create().withKey('delta_air_to_return_temperature').withFormula('return_temperature - outdoor_air_temperature').build()
)
.addDependency(
InputDependencyBuilder.create()
.withKey('heating_thermomode')
.withDependency('>')
.withFirstValueKey('flow_temperature')
.withFirstPimValue({ Key: 'flow_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.withSecondValueKey('return_temperature')
.withSecondPimValue({ Key: 'return_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.addInfluenceValue(influenceValue('flow_temperature', 0, 'raise'))
.build()
)
.addDependency(
InputDependencyBuilder.create()
.withKey('over_temperature_lower_limit')
.withDependency('>=')
.withFirstValueKey('over_temperature')
.withFirstPimValue({ Key: 'over_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.withSecondValueKey('INFLUMINUEBERTEMPERATURHEIZEN.NUM')
.withSecondPimValue({ Key: 'INFLUMINUEBERTEMPERATURHEIZEN.NUM', Value: 10, Unit: '°C', UnitType: 'temperature' })
.addInfluenceValue(influenceValue('flow_temperature', 0, 'raise'))
.addInfluenceValue(influenceValue('outdoor_air_temperature', 1, 'lower'))
.build()
)
.addDependency(
InputDependencyBuilder.create()
.withKey('over_temperature_upper_limit')
.withDependency('<=')
.withFirstValueKey('over_temperature')
.withFirstPimValue({ Key: 'over_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.withSecondValueKey('INFLUMAXUEBERTEMPERATURHEIZEN.NUM')
.withSecondPimValue({ Key: 'INFLUMAXUEBERTEMPERATURHEIZEN.NUM', Value: 85, Unit: '°C', UnitType: 'temperature' })
.addInfluenceValue(influenceValue('flow_temperature', 0, 'lower'))
.addInfluenceValue(influenceValue('outdoor_air_temperature', 1, 'raise'))
.build()
)
.addDependency(
InputDependencyBuilder.create()
.withKey('delta_air_to_return_temperature_lower_limit')
.withDependency('>=')
.withFirstValueKey('delta_air_to_return_temperature')
.withFirstPimValue({ Key: 'delta_air_to_return_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.withSecondValueKey('INFLUMINRUECKLAUFRAUMHEIZEN.NUM')
.withSecondPimValue({ Key: 'INFLUMINRUECKLAUFRAUMHEIZEN.NUM', Value: 4, Unit: '°C', UnitType: 'temperature' })
.addInfluenceValue(influenceValue('outdoor_air_temperature', 0, 'lower'))
.build()
)
.addDependency(
InputDependencyBuilder.create()
.withKey('heating_offset_lower_limit')
.withDependency('>=')
.withFirstValueKey('neg_delta_temperature')
.withFirstPimValue({ Key: 'neg_delta_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.withSecondValueKey('OFFSETRUECKLAUFHEIZEN.NUM')
.withSecondPimValue({ Key: 'OFFSETRUECKLAUFHEIZEN.NUM', Value: -5, Unit: '°C', UnitType: 'temperature' })
.addInfluenceValue(influenceValue('return_temperature', 0, 'raise'))
.build()
)
.addDependency(
InputDependencyBuilder.create()
.withKey('heating_offset_upper_limit')
.withDependency('<=')
.withFirstValueKey('neg_delta_temperature')
.withFirstPimValue({ Key: 'neg_delta_temperature', Value: 0, Unit: '°C', UnitType: 'temperature' })
.withSecondValueKey('OFFSETRUECKLAUFHEIZEN.NUM')
.withSecondPimValue({ Key: 'OFFSETRUECKLAUFHEIZEN.NUM', Value: -5, Unit: '°C', UnitType: 'temperature' })
.addInfluenceValue(influenceValue('return_temperature', 0, 'lower'))
.build()
)
.build();

const heatingGroup = InputParameterCategoryGroupBuilder.create()
.withKey('heating')
.withName('Heizen')
.withOrder(2)
.withLength(1)
.addCategory(heatingCategory)
.build();

// Build InputParameterSet
const ips = InputParameterSetBuilder.create()
.withKey('')
.withName('')
.withOrder(1)
.addCategoryGroup(mediumGroup)
.addCategoryGroup(coolingGroup)
.addCategoryGroup(heatingGroup)
.build();

// Build response
const ui = UiControlsInitResponseBuilder.create()
.withRequest(req)
.withCalcRequestURL('https://kadata-stag.kampmann.de/api/calcgateway/product-calculation/v1.0/products/calculate')
.addInputParameterSet(ips)
.addResultTableType(ResultTableType.power)
.build();

return ui;
}

Using the advanced UIControls

Here is a minimal React usage example rendering the form and (optionally) a result table after calculation:

import React, { useMemo, useState, useEffect } from 'react'
import {
CalcGatewayForm,
CalculationTable,
ScopeSystem,
type CallBack,
} from 'kampmann-calcgateway-frontend'

export default function BuilderExamplePage() {
const ui = useMemo(buildExampleUIControls, [])
const [cb, setCb] = useState<CallBack | null>(null)
const [calcResult, setCalcResult] = useState<any>(null)

useEffect(() => {
if (!cb) return

// Example: call your calculation endpoint
fetch('/api/calcgateway/cpq/v1.0/products/calculate', {
method: 'POST',
body: JSON.stringify({
...cb.requestBody,
ProductIds: [444933],
ScopeSystem: ScopeSystem.EXTERNAL,
})
})
.then(r => r.json())
.then(data => setCalcResult(data))
}, [cb])

return (
<div>
<CalcGatewayForm UIControls={ui} callback={setCb} />

{calcResult?.Responses && (
<CalculationTable
uiControls={ui}
calculationResults={calcResult.Responses}
requestUIState={cb?.requestUIState}
kapiLink={{ enabled: true }}
/>
)}
</div>
)
}

Notes and tips

  • FieldType values used by the built-in form include slider, dropDown, and others. They control how the field is rendered.
  • DisplayOn accepts simple expressions (e.g., medium != water) to conditionally display inputs.
  • ValueListCheck can be used to enforce value lists where applicable.
  • Calculated floats and dependencies allow you to encode relations between inputs and indicate how other values should be influenced.