Implemented admin pane + user permission

This commit is contained in:
Martino Ferrari
2026-06-22 17:49:14 +02:00
parent 73fcbe7b28
commit ac24011487
67 changed files with 5925 additions and 411 deletions
@@ -462,6 +462,65 @@ func outTypeOf(st *signalState) dsp.ValType {
return st.rg.outType
}
// TraceNode is a single node's computed value in a debug trace.
type TraceNode struct {
Value any `json:"value"`
Type string `json:"type"` // "scalar" | "array"
Approx bool `json:"approx,omitempty"`
}
// TraceResult is the per-node outcome of a single-shot evaluation of an
// (unsaved) synthetic graph, used by the editor's live/debug overlay.
type TraceResult struct {
Nodes map[string]TraceNode `json:"nodes"`
Error string `json:"error,omitempty"`
}
// Trace compiles def and evaluates it once with fresh state, returning the value
// computed for every node. Source node values are obtained via read(ds, name)
// (typically a broker ReadNow snapshot); a source that cannot be read defaults to
// scalar 0. Stateful ops are flagged Approx since their true running value
// depends on accumulated state this single-shot pass does not have. A per-node
// evaluation error is returned in Error with the partial values still populated.
func (s *Synthetic) Trace(def SignalDef, read func(ds, name string) (any, error)) (TraceResult, error) {
rg, err := compileGraph(def)
if err != nil {
return TraceResult{}, err
}
sourceVals := make(map[string]dsp.Sample, len(rg.sources))
for _, src := range rg.sources {
raw, rerr := read(src.ref.DS, src.ref.Name)
if rerr != nil || raw == nil {
sourceVals[src.id] = dsp.Scalar(0)
continue
}
sourceVals[src.id] = toSample(raw)
}
vals, evalErr := rg.evalSampleTrace(sourceVals)
opType := make(map[string]string, len(rg.order))
for _, n := range rg.order {
if n.kind == "op" && n.op != nil {
opType[n.id] = n.op.Type()
}
}
res := TraceResult{Nodes: make(map[string]TraceNode, len(vals))}
for id, sample := range vals {
tn := TraceNode{Value: sample.AsAny(), Type: "scalar"}
if sample.IsArray {
tn.Type = "array"
}
if ot, ok := opType[id]; ok && dsp.IsStateful(ot) {
tn.Approx = true
}
res.Nodes[id] = tn
}
if evalErr != nil {
res.Error = evalErr.Error()
}
return res, nil
}
// toSample coerces a datasource.Value.Data into a dsp.Sample: arrays become
// array Samples (waveforms), everything else a scalar Sample.
func toSample(v any) dsp.Sample {