Config UI: allow creating and saving devices with setup errors (#24091)

Co-authored-by: Michael Geers <michael@geers.tv>
This commit is contained in:
andig 2025-10-07 14:31:09 +02:00 • committed by GitHub
parent 27b2edfb39
commit aef95ce425
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 204 additions and 90 deletions

View file

@ -254,9 +254,9 @@ func deviceStatusHandler(w http.ResponseWriter, r *http.Request) {
jsonWrite(w, testInstance(instance))
}
func newDevice[T any](ctx context.Context, class templates.Class, req configReq, newFromConf newFromConfFunc[T], h config.Handler[T]) (*config.Config, error) {
func newDevice[T any](ctx context.Context, class templates.Class, req configReq, newFromConf newFromConfFunc[T], h config.Handler[T], force bool) (*config.Config, error) {
instance, err := newFromConf(ctx, req.Type, req.Other)
if err != nil {
if err != nil && !force {
return nil, err
}
@ -287,20 +287,22 @@ func newDeviceHandler(w http.ResponseWriter, r *http.Request) {
var conf *config.Config
ctx, cancel, done := startDeviceTimeout()
force := r.URL.Query().Get("force") == "true"
switch class {
case templates.Charger:
conf, err = newDevice(ctx, class, req, charger.NewFromConfig, config.Chargers())
conf, err = newDevice(ctx, class, req, charger.NewFromConfig, config.Chargers(), force)
case templates.Meter:
conf, err = newDevice(ctx, class, req, meter.NewFromConfig, config.Meters())
conf, err = newDevice(ctx, class, req, meter.NewFromConfig, config.Meters(), force)
case templates.Vehicle:
conf, err = newDevice(ctx, class, req, vehicle.NewFromConfig, config.Vehicles())
conf, err = newDevice(ctx, class, req, vehicle.NewFromConfig, config.Vehicles(), force)
case templates.Circuit:
conf, err = newDevice(ctx, class, req, func(ctx context.Context, _ string, other map[string]interface{}) (api.Circuit, error) {
return circuit.NewFromConfig(ctx, util.NewLogger("circuit"), other)
}, config.Circuits())
}, config.Circuits(), force)
}
if err != nil {
@ -325,10 +327,13 @@ func newDeviceHandler(w http.ResponseWriter, r *http.Request) {
jsonWrite(w, res)
}
func updateDevice[T any](ctx context.Context, id int, class templates.Class, req configReq, newFromConf newFromConfFunc[T], h config.Handler[T]) error {
func updateDevice[T any](ctx context.Context, id int, class templates.Class, req configReq, newFromConf newFromConfFunc[T], h config.Handler[T], force bool) error {
dev, instance, merged, err := deviceInstanceFromMergedConfig(ctx, id, class, req, newFromConf, h)
if err != nil {
return err
// allow force-updating if merged config exists
if !force || merged == nil {
return err
}
}
configurable, ok := dev.(config.ConfigurableDevice[T])
@ -363,20 +368,22 @@ func updateDeviceHandler(w http.ResponseWriter, r *http.Request) {
ctx, cancel, done := startDeviceTimeout()
force := r.URL.Query().Get("force") == "true"
switch class {
case templates.Charger:
err = updateDevice(ctx, id, class, req, charger.NewFromConfig, config.Chargers())
err = updateDevice(ctx, id, class, req, charger.NewFromConfig, config.Chargers(), force)
case templates.Meter:
err = updateDevice(ctx, id, class, req, meter.NewFromConfig, config.Meters())
err = updateDevice(ctx, id, class, req, meter.NewFromConfig, config.Meters(), force)
case templates.Vehicle:
err = updateDevice(ctx, id, class, req, vehicle.NewFromConfig, config.Vehicles())
err = updateDevice(ctx, id, class, req, vehicle.NewFromConfig, config.Vehicles(), force)
case templates.Circuit:
err = updateDevice(ctx, id, class, req, func(ctx context.Context, _ string, other map[string]interface{}) (api.Circuit, error) {
return circuit.NewFromConfig(ctx, util.NewLogger("circuit"), other)
}, config.Circuits())
}, config.Circuits(), force)
}
setConfigDirty()