5c3dc79b8a
Move composition CRUD off the TemplateEdit page and onto the tree context menu, matching Aveva's Template Toolbox flow. - New ComposeIntoDialog: pick a parent template, slot name (defaults to the source template's name). - "Compose into…" on every base template's context menu (kebab + right click) opens the dialog and calls AddCompositionAsync. - "Rename…" on composition leaves opens a prompt and calls TemplateService.RenameCompositionAsync. The owning composition row AND its owned derived template are renamed atomically; duplicate slot names or derived-name collisions abort with a clear error. - "Delete" on composition leaves confirms + cascade-deletes the composition (and its derived template via DeleteCompositionAsync). - "New Derived Template" menu item renamed to "New Inheriting Template" to disambiguate from the new derive-on-compose meaning. TemplateEdit's Compositions tab, Add Composition form, and Add/DeleteComposition handlers + state fields are deleted — the tree is now the single source of truth.
69 lines
3.0 KiB
Plaintext
69 lines
3.0 KiB
Plaintext
@if (IsVisible)
|
|
{
|
|
<div class="modal show d-block" tabindex="-1" style="background: rgba(0,0,0,0.4);">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h6 class="modal-title">Compose '@SourceName' into…</h6>
|
|
<button type="button" class="btn-close" @onclick="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label small text-muted mb-1">Parent template</label>
|
|
<select class="form-select form-select-sm" @bind="_parentTemplateId">
|
|
<option value="0" disabled selected>Select a parent template…</option>
|
|
@foreach (var opt in ParentOptions)
|
|
{
|
|
<option value="@opt.Id">@opt.Label</option>
|
|
}
|
|
</select>
|
|
</div>
|
|
<div class="mb-1">
|
|
<label class="form-label small text-muted mb-1">Slot name</label>
|
|
<input type="text" class="form-control form-control-sm"
|
|
placeholder="Slot name"
|
|
@bind="_slotName" />
|
|
</div>
|
|
@if (!string.IsNullOrEmpty(ErrorMessage)) { <div class="text-danger small mt-2">@ErrorMessage</div> }
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button class="btn btn-outline-secondary btn-sm" @onclick="Close">Cancel</button>
|
|
<button class="btn btn-primary btn-sm" @onclick="Submit" disabled="@(_parentTemplateId == 0 || string.IsNullOrWhiteSpace(_slotName))">Compose</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
@code {
|
|
[Parameter] public bool IsVisible { get; set; }
|
|
[Parameter] public EventCallback<bool> IsVisibleChanged { get; set; }
|
|
[Parameter] public int SourceTemplateId { get; set; }
|
|
[Parameter] public string SourceName { get; set; } = string.Empty;
|
|
[Parameter] public IEnumerable<(int Id, string Label)> ParentOptions { get; set; } = Array.Empty<(int, string)>();
|
|
[Parameter] public string? ErrorMessage { get; set; }
|
|
[Parameter] public EventCallback<(int SourceTemplateId, int ParentTemplateId, string SlotName)> OnSubmit { get; set; }
|
|
|
|
private bool _wasVisible;
|
|
private int _parentTemplateId;
|
|
private string _slotName = string.Empty;
|
|
|
|
protected override void OnParametersSet()
|
|
{
|
|
if (IsVisible && !_wasVisible)
|
|
{
|
|
_parentTemplateId = 0;
|
|
_slotName = SourceName;
|
|
}
|
|
_wasVisible = IsVisible;
|
|
}
|
|
|
|
private async Task Close() => await IsVisibleChanged.InvokeAsync(false);
|
|
|
|
private async Task Submit()
|
|
{
|
|
if (_parentTemplateId == 0 || string.IsNullOrWhiteSpace(_slotName)) return;
|
|
await OnSubmit.InvokeAsync((SourceTemplateId, _parentTemplateId, _slotName.Trim()));
|
|
}
|
|
}
|