feat(central-ui): add Min time between runs field to the script form
The template script editor had no input for MinTimeBetweenRuns, so a WhileTrue trigger configured through the UI always saved a null interval and degraded to a single edge fire. The Add/Edit Script modal now has a "Min time between runs" number+unit (ms/sec/min) field. - Visible only for ValueChange / Conditional / Expression triggers — the auto-firing triggers MinTimeBetweenRuns throttles. Hidden for Interval (its own period is the cadence), Call (invoked explicitly, never throttled), and None. - For a WhileTrue Conditional/Expression trigger the field is labelled as the re-fire interval and shows a warning while it is blank. - Wired through the new-script and edit-script save paths (edit previously only preserved the existing value, never let the user change it). New DurationInput helper does the TimeSpan <-> number+unit conversion; ScriptTriggerConfigCodec.SupportsMinTimeBetweenRuns classifies trigger types. Both TDD'd — 21 new tests. CentralUI suite 316 green; verified end-to-end in the browser (visibility per trigger type, WhileTrue warning, save/reload round-trip).
This commit is contained in:
@@ -98,6 +98,8 @@
|
||||
private string _scriptCode = string.Empty;
|
||||
private string? _scriptTriggerType;
|
||||
private string? _scriptTriggerConfig;
|
||||
private string? _scriptMinTimeValue;
|
||||
private string _scriptMinTimeUnit = "sec";
|
||||
private string? _scriptParameters;
|
||||
private string? _scriptReturn;
|
||||
private bool _scriptIsLocked;
|
||||
@@ -880,6 +882,47 @@
|
||||
Changed="@OnScriptTriggerChanged"
|
||||
AvailableAttributes="@BuildAlarmAttributeChoices()" />
|
||||
</div>
|
||||
@if (ScriptTriggerConfigCodec.SupportsMinTimeBetweenRuns(_scriptTriggerType))
|
||||
{
|
||||
<div class="col-12">
|
||||
<label class="form-label">Min time between runs</label>
|
||||
<div class="row g-2" style="max-width: 420px;">
|
||||
<div class="col-7">
|
||||
<input type="number" min="1" step="1" class="form-control"
|
||||
placeholder="(optional)"
|
||||
@bind="_scriptMinTimeValue" @bind:event="oninput" />
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<select class="form-select" @bind="_scriptMinTimeUnit">
|
||||
<option value="ms">milliseconds</option>
|
||||
<option value="sec">seconds</option>
|
||||
<option value="min">minutes</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@if (ScriptTriggerIsWhileTrue())
|
||||
{
|
||||
<div class="form-text">
|
||||
This is the re-fire interval for the
|
||||
<strong>WhileTrue</strong> trigger above.
|
||||
</div>
|
||||
@if (DurationInput.Compose(_scriptMinTimeValue, _scriptMinTimeUnit) is null)
|
||||
{
|
||||
<div class="alert alert-warning py-1 px-2 small mt-1 mb-0">
|
||||
The WhileTrue trigger has no interval set — the script
|
||||
will fire only once. Set a value here to make it re-fire.
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="form-text">
|
||||
Optional throttle — skips trigger invocations that fire
|
||||
sooner than this.
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<div class="col-12">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" @bind="_scriptIsLocked" id="scriptLocked" />
|
||||
@@ -1461,6 +1504,19 @@
|
||||
_scriptTriggerConfig = v.Config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True when the current script trigger is a WhileTrue Conditional/Expression
|
||||
/// trigger — the case where the "Min time between runs" interval is required
|
||||
/// (it is the re-fire cadence).
|
||||
/// </summary>
|
||||
private bool ScriptTriggerIsWhileTrue()
|
||||
{
|
||||
var kind = ScriptTriggerConfigCodec.ParseKind(_scriptTriggerType);
|
||||
return kind is ScriptTriggerKind.Conditional or ScriptTriggerKind.Expression
|
||||
&& ScriptTriggerConfigCodec.Parse(_scriptTriggerConfig, kind).Mode
|
||||
== ScriptTriggerMode.WhileTrue;
|
||||
}
|
||||
|
||||
private void BeginAddScript()
|
||||
{
|
||||
_showScriptForm = true;
|
||||
@@ -1470,6 +1526,7 @@
|
||||
_scriptCode = string.Empty;
|
||||
_scriptTriggerType = null;
|
||||
_scriptTriggerConfig = null;
|
||||
(_scriptMinTimeValue, _scriptMinTimeUnit) = DurationInput.Split(null);
|
||||
_scriptParameters = null;
|
||||
_scriptReturn = null;
|
||||
_scriptIsLocked = false;
|
||||
@@ -1486,6 +1543,7 @@
|
||||
_scriptCode = script.Code;
|
||||
_scriptTriggerType = script.TriggerType;
|
||||
_scriptTriggerConfig = script.TriggerConfiguration;
|
||||
(_scriptMinTimeValue, _scriptMinTimeUnit) = DurationInput.Split(script.MinTimeBetweenRuns);
|
||||
_scriptParameters = script.ParameterDefinitions;
|
||||
_scriptReturn = script.ReturnDefinition;
|
||||
_scriptIsLocked = script.IsLocked;
|
||||
@@ -1581,7 +1639,7 @@
|
||||
ParameterDefinitions = _scriptParameters,
|
||||
ReturnDefinition = _scriptReturn,
|
||||
IsLocked = _scriptIsLocked,
|
||||
MinTimeBetweenRuns = existing.MinTimeBetweenRuns,
|
||||
MinTimeBetweenRuns = DurationInput.Compose(_scriptMinTimeValue, _scriptMinTimeUnit),
|
||||
IsInherited = existing.IsInherited,
|
||||
LockedInDerived = existing.LockedInDerived,
|
||||
};
|
||||
@@ -1606,7 +1664,8 @@
|
||||
TriggerConfiguration = _scriptTriggerConfig?.Trim(),
|
||||
ParameterDefinitions = _scriptParameters,
|
||||
ReturnDefinition = _scriptReturn,
|
||||
IsLocked = _scriptIsLocked
|
||||
IsLocked = _scriptIsLocked,
|
||||
MinTimeBetweenRuns = DurationInput.Compose(_scriptMinTimeValue, _scriptMinTimeUnit)
|
||||
};
|
||||
|
||||
var addResult = await TemplateService.AddScriptAsync(_selectedTemplate.Id, script, user);
|
||||
|
||||
Reference in New Issue
Block a user