refactor(central-ui): move script Trigger section into the tabbed panel

The Add/Edit Script modal's Trigger configuration (trigger editor + Min
time between runs) moves out of the always-visible header area and into
the tab strip as a new first tab: Trigger | Code | Parameters | Return
type. Trigger is the default selected tab.

Name and Locked remain above the tabs. The Trigger panel toggles via
display:none like the others, so the trigger expression's Monaco editor
stays mounted across tab switches. Markup-only — no logic change; verified
in the browser. CentralUI suite 316 green.
This commit is contained in:
Joseph Doherty
2026-05-18 16:51:58 -04:00
parent 01509a045f
commit e1a4ce4de8

View File

@@ -104,7 +104,7 @@
private string? _scriptReturn;
private bool _scriptIsLocked;
private string? _scriptFormError;
private string _scriptModalTab = "code"; // "code" | "parameters" | "return"
private string _scriptModalTab = "trigger"; // "trigger" | "code" | "parameters" | "return"
private MonacoEditor? _scriptEditor;
private IReadOnlyList<ScadaLink.CentralUI.ScriptAnalysis.DiagnosticMarker> _scriptMarkers
= Array.Empty<ScadaLink.CentralUI.ScriptAnalysis.DiagnosticMarker>();
@@ -876,15 +876,55 @@
<input type="text" class="form-control" @bind="_scriptName" readonly="@editingScript" />
</div>
<div class="col-12">
<label class="form-label">Trigger</label>
<div class="form-check">
<input class="form-check-input" type="checkbox" @bind="_scriptIsLocked" id="scriptLocked" />
<label class="form-check-label" for="scriptLocked">Locked</label>
</div>
</div>
</div>
@* Tabs: Trigger, Code, Parameters, Return. All panels stay
mounted (toggled via display:none) so Monaco editors and the
JSONJoy React island don't tear down on tab switch. *@
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item" role="presentation">
<button type="button"
class="nav-link @(_scriptModalTab == "trigger" ? "active" : "")"
role="tab"
aria-selected="@(_scriptModalTab == "trigger" ? "true" : "false")"
@onclick='() => _scriptModalTab = "trigger"'>Trigger</button>
</li>
<li class="nav-item" role="presentation">
<button type="button"
class="nav-link @(_scriptModalTab == "code" ? "active" : "")"
role="tab"
aria-selected="@(_scriptModalTab == "code" ? "true" : "false")"
@onclick='() => _scriptModalTab = "code"'>Code</button>
</li>
<li class="nav-item" role="presentation">
<button type="button"
class="nav-link @(_scriptModalTab == "parameters" ? "active" : "")"
role="tab"
aria-selected="@(_scriptModalTab == "parameters" ? "true" : "false")"
@onclick='() => _scriptModalTab = "parameters"'>Parameters</button>
</li>
<li class="nav-item" role="presentation">
<button type="button"
class="nav-link @(_scriptModalTab == "return" ? "active" : "")"
role="tab"
aria-selected="@(_scriptModalTab == "return" ? "true" : "false")"
@onclick='() => _scriptModalTab = "return"'>Return type</button>
</li>
</ul>
<div class="border border-top-0 rounded-bottom p-3">
<div style="display: @(_scriptModalTab == "trigger" ? "block" : "none")">
<ScriptTriggerEditor TriggerType="@_scriptTriggerType"
TriggerConfig="@_scriptTriggerConfig"
Changed="@OnScriptTriggerChanged"
AvailableAttributes="@BuildAlarmAttributeChoices()" />
</div>
@if (ScriptTriggerConfigCodec.SupportsMinTimeBetweenRuns(_scriptTriggerType))
{
<div class="col-12">
<div class="mt-3">
<label class="form-label">Min time between runs</label>
<div class="row g-2" style="max-width: 420px;">
<div class="col-7">
@@ -923,41 +963,7 @@
}
</div>
}
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" @bind="_scriptIsLocked" id="scriptLocked" />
<label class="form-check-label" for="scriptLocked">Locked</label>
</div>
</div>
</div>
@* Tabs: Code, Parameters, Return. Both editor panels stay
mounted (toggled via display:none) so Monaco and the
JSONJoy React island don't tear down on tab switch. *@
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item" role="presentation">
<button type="button"
class="nav-link @(_scriptModalTab == "code" ? "active" : "")"
role="tab"
aria-selected="@(_scriptModalTab == "code" ? "true" : "false")"
@onclick='() => _scriptModalTab = "code"'>Code</button>
</li>
<li class="nav-item" role="presentation">
<button type="button"
class="nav-link @(_scriptModalTab == "parameters" ? "active" : "")"
role="tab"
aria-selected="@(_scriptModalTab == "parameters" ? "true" : "false")"
@onclick='() => _scriptModalTab = "parameters"'>Parameters</button>
</li>
<li class="nav-item" role="presentation">
<button type="button"
class="nav-link @(_scriptModalTab == "return" ? "active" : "")"
role="tab"
aria-selected="@(_scriptModalTab == "return" ? "true" : "false")"
@onclick='() => _scriptModalTab = "return"'>Return type</button>
</li>
</ul>
<div class="border border-top-0 rounded-bottom p-3">
<div style="display: @(_scriptModalTab == "code" ? "block" : "none")">
<MonacoEditor @ref="_scriptEditor" Value="@_scriptCode" ValueChanged="@(v => _scriptCode = v)"
Language="csharp" Height="360px"
@@ -1530,7 +1536,7 @@
_scriptParameters = null;
_scriptReturn = null;
_scriptIsLocked = false;
_scriptModalTab = "code";
_scriptModalTab = "trigger";
ResetScriptTestRun();
}
@@ -1547,7 +1553,7 @@
_scriptParameters = script.ParameterDefinitions;
_scriptReturn = script.ReturnDefinition;
_scriptIsLocked = script.IsLocked;
_scriptModalTab = "code";
_scriptModalTab = "trigger";
ResetScriptTestRun();
}