refactor(ui/design): card grid, SMTP split, TemplateEdit vertical-stack
Templates: <h4> in flex header, Expand/Collapse moved into a Bulk actions dropdown, hover-visible kebab on tree nodes with aria-labels. TreeView CSS gets a .tv-kebab opacity-on-hover utility. TemplateCreate: form-control (not -sm) for primary inputs; accessible Back button. TemplateEdit: Properties card vertical-stacked with Save at the bottom-right and Parent rendered as readonly plaintext. Add-member forms (Attributes, Alarms, Scripts, Compositions) reflowed from horizontal row g-2 align-items-end into cards with stacked col-12 inputs (Scripts gets rows=10). Lock/Unlock badges show full words. Per-row Delete moved into a kebab dropdown. Tab nav gains role="tablist" / role="tab" / aria-selected / aria-controls and panels get role="tabpanel". Validation entries get consistent strong-and- muted styling. SharedScripts: migrated from table to card grid (col-lg-6) matching Sites; cards show code preview + param/return badges + Edit + kebab. Search filter, empty state CTA, @key. SharedScriptForm: small ?-icon tooltips next to Parameters and Return Definition labels. ExternalSystems: SMTP split out to its own page; remaining tabs ( External Systems, DB Connections, Notification Lists, API Methods, API Keys) unified as card grids with per-tab search + empty-state CTA. Tab nav gets full ARIA instrumentation. Header gains a link to the new SMTP page. New page SmtpConfiguration.razor at /design/smtp: vertical-stacked form using the existing Credentials field on the entity. ExternalSystemForm: AuthConfig placeholder updates based on the selected AuthType (None / ApiKey / BasicAuth). DbConnectionForm: form-text below Connection String noting that the value is stored in plain text and is admin-only. ApiMethodForm: Script textarea rows=10; JSON example placeholders for Params and Returns. NotificationListForm: form-control sizing on Name/email inputs; thead.table-dark -> table-light on the recipients table.
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
|
||||
<div class="container-fluid mt-3">
|
||||
<ToastNotification @ref="_toast" />
|
||||
<ConfirmDialog @ref="_confirmDialog" />
|
||||
<ConfirmDialog @ref="_confirmDialog" ConfirmButtonClass="btn-danger" />
|
||||
|
||||
<RenameFolderDialog @bind-IsVisible="_showRenameFolderDialog"
|
||||
FolderId="_renameFolderId"
|
||||
@@ -50,14 +50,30 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<h6 class="mb-2">Templates</h6>
|
||||
<div class="btn-group btn-group-sm mb-2">
|
||||
<button class="btn btn-outline-secondary" title="New folder at root"
|
||||
@onclick="() => OpenNewFolderDialog(null)">+ Folder</button>
|
||||
<button class="btn btn-outline-secondary" title="New template at root"
|
||||
@onclick='() => NavigationManager.NavigateTo("/design/templates/create")'>+ Template</button>
|
||||
<button class="btn btn-outline-secondary" @onclick="() => _tree.ExpandAll()">Expand</button>
|
||||
<button class="btn btn-outline-secondary" @onclick="() => _tree.CollapseAll()">Collapse</button>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h4 class="mb-0">Templates</h4>
|
||||
<div class="d-flex gap-2">
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary btn-sm dropdown-toggle"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Bulk actions
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
<button class="dropdown-item" @onclick="() => _tree.ExpandAll()">Expand all folders</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="dropdown-item" @onclick="() => _tree.CollapseAll()">Collapse all folders</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button class="btn btn-outline-secondary btn-sm"
|
||||
title="New folder at root"
|
||||
@onclick="() => OpenNewFolderDialog(null)">+ Folder</button>
|
||||
<button class="btn btn-primary btn-sm"
|
||||
title="New template at root"
|
||||
@onclick='() => NavigationManager.NavigateTo("/design/templates/create")'>+ Template</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="max-height: calc(100vh - 160px); overflow-y: auto; padding: 4px;">
|
||||
@@ -230,21 +246,61 @@
|
||||
<span class="badge rounded-pill bg-secondary-subtle text-secondary-emphasis">@node.Children.Count</span>
|
||||
</span>
|
||||
}
|
||||
@RenderNodeKebab(node)
|
||||
break;
|
||||
|
||||
case TmplNodeKind.Template:
|
||||
<span class="tv-glyph"><i class="bi bi-file-earmark-text"></i></span>
|
||||
<span class="tv-label @(node.Children.Count > 0 ? "fw-semibold" : "")"
|
||||
title="@node.Label">@node.Label</span>
|
||||
@RenderNodeKebab(node)
|
||||
break;
|
||||
|
||||
case TmplNodeKind.Composition:
|
||||
<span class="tv-glyph"><i class="bi bi-arrow-return-right"></i></span>
|
||||
<span class="tv-label" title="@node.Label">@node.Label</span>
|
||||
@RenderNodeKebab(node)
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
private RenderFragment RenderNodeKebab(TmplNode node) => __builder =>
|
||||
{
|
||||
<span class="tv-kebab dropdown ms-auto" @onclick:stopPropagation="true">
|
||||
<button type="button"
|
||||
class="btn btn-link btn-sm p-0 px-1 text-secondary tv-kebab-toggle"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
aria-label="@($"More actions for {node.Label}")">
|
||||
<i class="bi bi-three-dots-vertical"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
@switch (node.Kind)
|
||||
{
|
||||
case TmplNodeKind.Folder:
|
||||
<li><button class="dropdown-item" @onclick="() => OpenNewFolderDialog(node.EntityId)">New Folder</button></li>
|
||||
<li><button class="dropdown-item" @onclick='() => NavigationManager.NavigateTo($"/design/templates/create?folderId={node.EntityId}")'>New Template</button></li>
|
||||
<li><button class="dropdown-item" @onclick="() => OpenRenameFolderDialog(node.EntityId, node.Label)">Rename</button></li>
|
||||
<li><button class="dropdown-item" @onclick="() => OpenMoveFolderDialog(node.EntityId, node.Label)">Move to Folder…</button></li>
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
<li><button class="dropdown-item text-danger" @onclick="() => DeleteFolder(node.EntityId, node.Label)">Delete</button></li>
|
||||
break;
|
||||
|
||||
case TmplNodeKind.Template:
|
||||
<li><button class="dropdown-item" @onclick='() => NavigationManager.NavigateTo($"/design/templates/create?parentId={node.EntityId}")'>New Derived Template</button></li>
|
||||
<li><button class="dropdown-item" @onclick="() => OpenMoveTemplateDialog(node.EntityId, node.Label)">Move to Folder…</button></li>
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
<li><button class="dropdown-item text-danger" @onclick="() => DeleteTemplate(node.Template!)">Delete</button></li>
|
||||
break;
|
||||
|
||||
case TmplNodeKind.Composition:
|
||||
<li><button class="dropdown-item" @onclick='() => NavigationManager.NavigateTo($"/design/templates/{node.Composition!.ComposedTemplateId}")'>Open composed template</button></li>
|
||||
break;
|
||||
}
|
||||
</ul>
|
||||
</span>
|
||||
};
|
||||
|
||||
private void OnTreeNodeSelected(object? key)
|
||||
{
|
||||
if (key is not string s) return;
|
||||
|
||||
Reference in New Issue
Block a user