feat(adminui): driver-agnostic isArray/arrayLength Tag-modal control
This commit is contained in:
@@ -170,6 +170,37 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
@* Driver-agnostic array-shape intent. Merges the root `isArray` / `arrayLength`
|
||||
keys onto the canonical TagConfig via the pure TagArrayConfig seam so it composes
|
||||
with the typed editor's driver-specific fields (both preserve unknown keys). When
|
||||
checked, the server materialises a 1-D array node (ValueRank=1). Shown for EVERY
|
||||
driver once one is picked — same place/pattern as the historize control above. *@
|
||||
@if (!string.IsNullOrEmpty(_form.DriverInstanceId))
|
||||
{
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Array</label>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="tag-is-array"
|
||||
checked="@_arrayState.IsArray"
|
||||
@onchange="OnIsArrayChanged" />
|
||||
<label class="form-check-label" for="tag-is-array">This tag is an array (1-D)</label>
|
||||
</div>
|
||||
<div class="form-text">
|
||||
When checked, the server materialises this tag as a fixed-length 1-D array node.
|
||||
</div>
|
||||
@if (_arrayState.IsArray)
|
||||
{
|
||||
<div class="mt-2">
|
||||
<label class="form-label" for="tag-array-length">Array length</label>
|
||||
<input type="number" min="1" step="1" class="form-control form-control-sm mono" id="tag-array-length"
|
||||
value="@_arrayState.ArrayLength"
|
||||
@onchange="OnArrayLengthChanged" />
|
||||
<div class="form-text">Number of elements (must be a positive whole number).</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@* Native-alarm options: shown only when the TagConfig carries an `alarm` object (the tag
|
||||
is a Part 9 condition). The "Historize to AVEVA" toggle edits the alarm.historizeToAveva
|
||||
opt-out (bool?, unchecked-via-clear ⇒ absent ⇒ historize default-on at the server gate;
|
||||
@@ -255,6 +286,11 @@
|
||||
// the driver changes; the change handlers merge it back onto _form.TagConfig via TagHistorizeConfig.
|
||||
private TagHistorizeConfig.HistorizeState _historizeState;
|
||||
|
||||
// Driver-agnostic array-shape intent (root `isArray` / `arrayLength`), reflected for the array controls.
|
||||
// Re-read from _form.TagConfig whenever the modal (re)opens or the driver changes; the change handlers
|
||||
// merge it back onto _form.TagConfig via TagArrayConfig (same pattern as _historizeState above).
|
||||
private TagArrayConfig.ArrayState _arrayState;
|
||||
|
||||
// The DriverType of the currently-selected driver (drives editor dispatch). Null when no driver chosen.
|
||||
private string? SelectedDriverType =>
|
||||
Drivers.FirstOrDefault(d => d.Id == _form.DriverInstanceId).DriverType;
|
||||
@@ -285,6 +321,8 @@
|
||||
_galaxyPickedIsAlarm = false;
|
||||
// The reset TagConfig carries no history intent — reflect that in the historize controls.
|
||||
_historizeState = TagHistorizeConfig.Read(_form.TagConfig);
|
||||
// Likewise the reset TagConfig carries no array intent.
|
||||
_arrayState = TagArrayConfig.Read(_form.TagConfig);
|
||||
}
|
||||
|
||||
// The operator picked a Galaxy reference (tag_name.AttributeName); store it as the canonical
|
||||
@@ -304,10 +342,13 @@
|
||||
JsonSerializer.Serialize(new { FullName = address }),
|
||||
_historizeState.IsHistorized,
|
||||
_historizeState.HistorianTagname);
|
||||
// Re-merge any array intent for the same reason — a fresh {FullName} blob would otherwise drop it.
|
||||
config = TagArrayConfig.Set(config, _arrayState.IsArray, _arrayState.ArrayLength);
|
||||
_form.TagConfig = _galaxyPickedIsAlarm
|
||||
? NativeAlarmModel.SeedDefaultAlarm(config)
|
||||
: config;
|
||||
_historizeState = TagHistorizeConfig.Read(_form.TagConfig);
|
||||
_arrayState = TagArrayConfig.Read(_form.TagConfig);
|
||||
}
|
||||
|
||||
private IDictionary<string, object> BuildEditorParameters() => new Dictionary<string, object>
|
||||
@@ -372,6 +413,30 @@
|
||||
_historizeState = TagHistorizeConfig.Read(_form.TagConfig);
|
||||
}
|
||||
|
||||
// Toggle the root `isArray` array-shape intent in the raw TagConfig, merged via the pure TagArrayConfig
|
||||
// seam so the typed editor's driver-specific keys are preserved. Clearing it drops `arrayLength` too
|
||||
// (no orphan length), so the carried _arrayState.ArrayLength is irrelevant when unchecking.
|
||||
private void OnIsArrayChanged(ChangeEventArgs e)
|
||||
{
|
||||
var isArray = e.Value is true;
|
||||
_form.TagConfig = TagArrayConfig.Set(_form.TagConfig, isArray, _arrayState.ArrayLength);
|
||||
_arrayState = TagArrayConfig.Read(_form.TagConfig);
|
||||
}
|
||||
|
||||
// Merge the array length (root `arrayLength`) into the raw TagConfig. A blank/zero/negative/non-numeric
|
||||
// entry parses to null, so the key is dropped until a positive length is typed (and SaveAsync rejects
|
||||
// an array with no positive length).
|
||||
private void OnArrayLengthChanged(ChangeEventArgs e)
|
||||
{
|
||||
var length = ParsePositiveLength(e.Value?.ToString());
|
||||
_form.TagConfig = TagArrayConfig.Set(_form.TagConfig, _arrayState.IsArray, length);
|
||||
_arrayState = TagArrayConfig.Read(_form.TagConfig);
|
||||
}
|
||||
|
||||
// Parse the numeric-input string to a positive uint, or null for blank/zero/negative/overflow/non-numeric.
|
||||
private static uint? ParsePositiveLength(string? raw)
|
||||
=> uint.TryParse(raw, out var u) && u > 0 ? u : null;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
// Rebuild the working form whenever the host (re)opens the modal for a fresh target.
|
||||
@@ -400,6 +465,8 @@
|
||||
_galaxyAddress = ReadFullName(_form.TagConfig);
|
||||
// Seed the historize controls from any existing root isHistorized/historianTagname keys.
|
||||
_historizeState = TagHistorizeConfig.Read(_form.TagConfig);
|
||||
// Seed the array controls from any existing root isArray/arrayLength keys.
|
||||
_arrayState = TagArrayConfig.Read(_form.TagConfig);
|
||||
}
|
||||
|
||||
// Best-effort extraction of FullName from a Galaxy TagConfig; returns "" when absent or unparseable.
|
||||
@@ -436,6 +503,15 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Driver-agnostic array-shape validation: an array tag needs a positive length. Mirrors the
|
||||
// per-driver config validation above so a missing length is caught here rather than at deploy.
|
||||
var arrayError = TagArrayConfig.Validate(_arrayState.IsArray, _arrayState.ArrayLength);
|
||||
if (arrayError is not null)
|
||||
{
|
||||
_error = arrayError;
|
||||
return;
|
||||
}
|
||||
|
||||
var input = new TagInput(
|
||||
_form.TagId,
|
||||
_form.Name,
|
||||
|
||||
Reference in New Issue
Block a user