feat(central-ui): enlarge script modal; tab the Shared Script form

Script editor modal (TemplateEdit): the tabbed Trigger/Code/Parameters/
Return content is substantial, so the dialog now fills most of the
viewport — a .script-editor-modal class (96vw wide, ~full height) replaces
modal-xl, paired with modal-dialog-scrollable so the body scrolls.

Shared Script create/edit form (SharedScriptForm): Code, Parameters, and
Return type move from stacked sections into a tab strip, matching the
template script modal. Panels toggle via display:none so the Monaco editor
and JSONJoy island stay mounted across tab switches; Code is the default
tab. Name stays above the tabs.

Markup/CSS only — no logic change. CentralUI suite 316 green; both
verified in the browser.
This commit is contained in:
Joseph Doherty
2026-05-18 17:06:28 -04:00
parent e1a4ce4de8
commit 36c6036060
3 changed files with 63 additions and 22 deletions

View File

@@ -26,25 +26,40 @@
{
<div class="card mb-3">
<div class="card-body">
<div class="mb-2">
<div class="mb-3">
<label class="form-label small">Name</label>
<input type="text" class="form-control form-control-sm" @bind="_formName"
disabled="@(Id.HasValue)" />
</div>
<div class="mb-3">
<label class="form-label small">Parameters</label>
<SchemaBuilder Mode="object"
Value="@_formParameters"
ValueChanged="@(v => _formParameters = v)" />
</div>
<div class="mb-3">
<label class="form-label small">Return value</label>
<SchemaBuilder Mode="value"
Value="@_formReturn"
ValueChanged="@(v => _formReturn = v)" />
</div>
<div class="mb-2">
<label class="form-label small">Code</label>
@* Tabs: Code, Parameters, Return. Panels stay mounted (toggled
via display:none) so the Monaco editor 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 @(_formTab == "code" ? "active" : "")"
role="tab"
aria-selected="@(_formTab == "code" ? "true" : "false")"
@onclick='() => _formTab = "code"'>Code</button>
</li>
<li class="nav-item" role="presentation">
<button type="button"
class="nav-link @(_formTab == "parameters" ? "active" : "")"
role="tab"
aria-selected="@(_formTab == "parameters" ? "true" : "false")"
@onclick='() => _formTab = "parameters"'>Parameters</button>
</li>
<li class="nav-item" role="presentation">
<button type="button"
class="nav-link @(_formTab == "return" ? "active" : "")"
role="tab"
aria-selected="@(_formTab == "return" ? "true" : "false")"
@onclick='() => _formTab = "return"'>Return type</button>
</li>
</ul>
<div class="border border-top-0 rounded-bottom p-3">
<div style="display: @(_formTab == "code" ? "block" : "none")">
<MonacoEditor @ref="_editor" Value="@_formCode" ValueChanged="@(v => _formCode = v)"
Language="csharp" Height="320px"
DeclaredParameters="@ScriptParameterNames.Parse(_formParameters)"
@@ -52,6 +67,18 @@
MarkersChanged="@(m => { _markers = m; StateHasChanged(); })" />
<ProblemsPanel Markers="@_markers" OnNavigate="@(m => _editor?.RevealLineAsync(m.StartLineNumber, m.StartColumn) ?? Task.CompletedTask)" />
</div>
<div style="display: @(_formTab == "parameters" ? "block" : "none")">
<SchemaBuilder Mode="object"
Value="@_formParameters"
ValueChanged="@(v => _formParameters = v)" />
</div>
<div style="display: @(_formTab == "return" ? "block" : "none")">
<SchemaBuilder Mode="value"
Value="@_formReturn"
ValueChanged="@(v => _formReturn = v)" />
</div>
</div>
@if (_formError != null)
{
<div class="text-danger small mt-2">@_formError</div>
@@ -156,6 +183,7 @@
[Parameter] public int? Id { get; set; }
private bool _loading;
private string _formTab = "code"; // "code" | "parameters" | "return"
private string _formName = string.Empty;
private string _formCode = string.Empty;
private string? _formParameters;

View File

@@ -863,7 +863,7 @@
{
var editingScript = _editScriptId.HasValue;
<div class="modal show d-block" tabindex="-1" style="background: rgba(0,0,0,0.4);">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-dialog modal-dialog-scrollable script-editor-modal">
<div class="modal-content">
<div class="modal-header">
<h6 class="modal-title">@(editingScript ? "Edit Script" : "Add Script")</h6>

View File

@@ -86,3 +86,16 @@
background: var(--bs-white);
border-radius: 0.5rem;
}
/* Script editor modal — the tabbed Trigger/Code/Parameters/Return content is
substantial, so the dialog fills most of the viewport. Pairs with
.modal-dialog-scrollable so the body scrolls within the fixed height. */
.modal-dialog.script-editor-modal {
max-width: 96vw;
width: 96vw;
height: calc(100vh - 2rem);
}
.modal-dialog.script-editor-modal .modal-content {
height: 100%;
}