diff --git a/docs/plans/2026-05-11-templates-folder-hierarchy-design.md b/docs/plans/2026-05-11-templates-folder-hierarchy-design.md
index d81a9b6..9656d31 100644
--- a/docs/plans/2026-05-11-templates-folder-hierarchy-design.md
+++ b/docs/plans/2026-05-11-templates-folder-hierarchy-design.md
@@ -6,7 +6,7 @@
## Goal
-Replace the current single-list view at `/design/templates` with a tree-organized authoring surface modeled on the Wonderware ArchestrA Template Toolbox. Users organize templates into nested folders, see composition children inline under their owning template, and edit templates in a persistent split-pane layout.
+Replace the current single-list view at `/design/templates` with a tree-organized browser modeled on the Wonderware ArchestrA Template Toolbox. Users organize templates into nested folders, see composition children inline under their owning template, and navigate to a dedicated edit page (`/design/templates/{id}`) when authoring a specific template. The tree page itself does not host the editor.
## Reference
@@ -22,13 +22,14 @@ Inheritance is **not** rendered as tree nesting in the image, and it is not rend
| Decision | Choice |
|---|---|
-| Inheritance in tree | Not shown as nesting; shown as text on the template node label. |
+| Inheritance in tree | Not shown as nesting; **not shown on the node label either** (label is name only). Inheritance is visible in the TemplateEdit page when a template is selected. |
| Folder model | New `TemplateFolder` entity with self-referencing `ParentFolderId`. `Template.FolderId` nullable. |
-| Reorganization UX | Context menus + native HTML5 drag-drop. |
+| Reorganization UX | **Right-click context menus only** (no drag-drop). Modal dialog pickers for move targets. |
| Composition rendering | Read-only leaves with navigation; right-click → Open composed template / Remove composition. |
| Root-level templates | Allowed (`FolderId` nullable). Existing templates migrate with `FolderId = null`. |
| Folder delete with contents | Blocked; structured error lists child counts. |
-| Page layout | Persistent split pane: tree on left (~25–33% width), template detail/editor on right. |
+| Page layout | **Tree browser only** — no split-pane editor. Selecting a template navigates to `/design/templates/{id}` (TemplateEdit page); creating navigates to `/design/templates/create`. |
+| Tree node visuals | Per `Component-TreeView.md` Visual Design Guide V7: Bootstrap Icons (`bi-folder` / `bi-folder2-open` / `bi-file-earmark-text` / `bi-arrow-return-right`), name-only labels (no count/inherit badges on template nodes), folder child-count pill, composition `→ $Target` muted secondary text. |
## Data model
@@ -138,72 +139,65 @@ private record TmplNode(
| `KeySelector` | `n => (object)n.Key` |
| `StorageKey` | `"templates-tree"` (preserved from current usage) |
| `Selectable` | `true` |
-| `SelectedKeyChanged` | dispatch on key prefix: `t:` → load template into right pane; `f:` → no-op; `c:` → reveal + select composed template |
+| `SelectedKeyChanged` | dispatch on key prefix: `t:` → `NavigationManager.NavigateTo($"/design/templates/{id}")` (TemplateEdit page); `f:` → no-op; `c:` → `NavigateTo` the composed template's edit page |
-**Inline node labels:**
-- Folder: glyph + name + child-count badge.
-- Template: `$Name` + optional "inherits $Parent" muted text + existing attr/alarm/script/comp count badges.
-- Composition: `InstanceName` + muted `→ $ComposedTemplateName`.
+**Inline node labels** (see `Component-TreeView.md` V7 for the canonical recipe):
+- Folder: `` (closed) or `` (expanded) + name (semibold when has children) + count-pill badge of direct children.
+- Template: `` + `$Name` (semibold when has compositions). **No** inheritance hint, **no** attr/alarm/script count, **no** composition count on the node.
+- Composition: `` + composition instance name + muted `→ $ComposedTemplateName` secondary text.
**Search/filter:** out of scope for v1; the underlying component supports external filtering (per `Component-TreeView.md` R8) so it can be added later without component changes.
## Page layout
-Two-column split inside the existing page container:
+`/design/templates` is a **single-column tree browser** — no inline editor, no split pane.
```
-+-------------------------------+----------------------------------------+
-| Templates | $TestMachine |
-| [+Folder][+Template][Expand] | inherits $gMachine |
-| | [Properties] [Validate] |
-| ▶ 📁 _Default Templates | |
-| ▼ 📁 Dev | Tabs: Attributes | Alarms | Scripts |
-| $TestMachine | | Compositions |
-| DelmiaReceiver → ... | ... |
-| MESReceiver → ... | |
-| $TestObject | |
-| ▶ 📁 System | |
-| $UnfiledTemplate | |
-+-------------------------------+----------------------------------------+
++--------------------------------------------+
+| Templates |
+| [+Folder] [+Template] [Expand] [Collapse] |
+| |
+| ▶ 📁 _Default Templates |
+| ▼ 📂 Dev |
+| 📄 $TestMachine |
+| ↪ DelmiaReceiver → $DelmiaSvc |
+| ↪ MESReceiver → $MesSvc |
+| 📄 $TestObject |
+| ▶ 📁 System |
+| 📄 $UnfiledTemplate |
++--------------------------------------------+
```
-- Left column: ~25–33% (`col-md-4 col-lg-3`), scrollable (`max-height: calc(100vh - 160px); overflow-y: auto`).
-- Right column: existing template properties card, validation block, four-tab editor (Attributes / Alarms / Scripts / Compositions) lifted unchanged into `RenderTemplateDetail()`.
-- "Back to List" button is removed — the tree is always visible.
-- Empty state in the right column when nothing is selected.
-- URL contract preserved: `/design/templates/{id}` selects + reveals the template on load via `TreeView.RevealNode("t:" + id, select: true)`.
+- Tree scrollable region: `max-height: calc(100vh - 160px); overflow-y: auto`. The 25–33% sidebar width constraint is removed; the tree uses the page's main container width.
+- Selecting a template node navigates to `/design/templates/{id}` (TemplateEdit page).
+- Selecting a composition node navigates to the composed template's edit page.
+- Selecting a folder node is a no-op (still allowed; expansion and context-menu still work).
+- Creating a template: toolbar "+ Template" button (or folder context-menu "New Template") navigates to `/design/templates/create?folderId={id}`. After successful create, the create page navigates to `/design/templates/{newId}`.
+- URL contract for deep links: `/design/templates/{id}` resolves to the TemplateEdit page directly — the browser doesn't need to be on the tree page first.
## Context menus
-Per-node-kind `ContextMenu` fragment driven by `node.Kind`:
+The context menu is the **only** reorganization mechanism. Per-node-kind `ContextMenu` fragment driven by `node.Kind`:
-**Folder:** New Folder · New Template · Rename · Delete
-**Template:** Edit · Move to Folder… (modal with folder-only mini-tree, "(Root)" option) · Delete
+**Folder:** New Folder · New Template · Rename · Move to Folder… · Delete
+**Template:** Edit · Move to Folder… · Delete
**Composition:** Open composed template · Remove composition
-The "New Template" modal collects name + description and creates with `FolderId = thisFolder.Id`. Root-level "+Folder" and "+Template" buttons live in the tree-sidebar toolbar above the tree.
+- **Move to Folder…** opens a modal (`MoveFolderDialog` / `MoveTemplateDialog`) with a flat folder picker. The list includes "(Root)" as the first entry. For folder-move, the dialog client-side prunes the folder being moved and its descendants from the candidate list to prevent obvious cycles; the server still validates (authoritative). For template-move, all folders are valid targets.
+- **Edit** on a template navigates to `/design/templates/{id}` (TemplateEdit page) — equivalent to clicking the node, kept in the menu for discoverability.
+- Root-level "+ Folder" and "+ Template" buttons live in the toolbar above the tree.
-## Drag-drop
-
-Native HTML5 drag-drop, no library.
-
-**Draggability:** folders and templates are `draggable="true"`. Composition nodes are not draggable.
-**Drop targets:** folder nodes and the root sidebar wrapper. Template/composition nodes are not drop targets in v1.
-**Payload:** `_dragPayload = (kind, id)` held in component state on `@ondragstart`.
-**Visual feedback:** CSS `drag-over` class toggled via `@ondragenter` / `@ondragleave`; compositions dimmed to 0.5 opacity while drag in progress.
-
-**Server-side validation (authoritative):**
+**Server-side validation (authoritative)**:
- Folder onto descendant → reject (cycle).
-- Folder onto itself → no-op.
-- Drop on a composition → ignored.
-- Template-onto-template → **ignored** (no sibling reordering, no surprising "drop into parent's folder").
+- Folder onto itself → no-op (client prunes).
+- Template-onto-template → not a valid target (templates aren't shown in the folder picker).
## Edge cases
-- Deep-link route reveals ancestors via `RevealNode`.
+- Deep-link route `/design/templates/{id}` resolves directly to the TemplateEdit page; the tree page is not involved. If the user navigates back, the tree's sessionStorage-persisted expansion state is restored.
- Stale `f:{id}` keys in `sessionStorage` after folder delete are harmless (ignored on next render).
- Selected template moved to another folder → tree rebuilds; selection preserved by stable key.
-- Selected template deleted → right pane clears to empty state.
+- Template deleted from the TemplateEdit page → page navigates back to `/design/templates`; the tree rebuilds without the deleted node.
- Last-write-wins on concurrent folder edits, matching existing template policy.
- Tree fully rebuilt on every CRUD; expected scale (dozens to low hundreds) makes this trivially cheap.
@@ -226,14 +220,16 @@ Native HTML5 drag-drop, no library.
**bUnit (`tests/ScadaLink.CentralUI.Tests/`):**
- Tree renders folders / templates / compositions in correct nesting.
-- Empty state when no selection.
-- Selecting a template node loads the detail pane.
-- Selecting a composition reveals + selects the composed template.
-- Right-click menus differ by node kind.
-- Folder-delete-non-empty surfaces structured error toast.
-- Deep link selects + reveals.
+- Empty state when no roots exist (no folders, no root templates).
+- Selecting a template node invokes `NavigationManager.NavigateTo($"/design/templates/{id}")`.
+- Selecting a composition node invokes `NavigateTo` for the composed template's edit page.
+- Selecting a folder node is a no-op (no navigation).
+- Right-click menus differ by node kind (Folder / Template / Composition each have distinct items).
+- Folder context menu includes "Move to Folder…"; the dialog excludes the folder being moved and its descendants from candidates.
+- Folder-delete-non-empty surfaces a structured error toast.
+- Bootstrap Icons render in the glyph slot for each node kind (`bi-folder` / `bi-folder2-open` / `bi-file-earmark-text` / `bi-arrow-return-right`).
-**Manual smoke (per `CLAUDE.md`):** nested folder creation, drag-drop reorg, cycle rejection, refresh persistence, composition navigation.
+**Manual smoke (per `CLAUDE.md`):** nested folder creation, context-menu reorg (folder + template Move-to-Folder dialogs), cycle rejection, refresh persistence, composition navigation, navigation from tree to TemplateEdit and back.
## Documentation updates
@@ -247,6 +243,6 @@ Native HTML5 drag-drop, no library.
- Tree search / filter input (component already supports it; add when needed).
- CLI commands for folder operations (message contracts make this trivial later).
-- Sibling reorder via drag-drop (sort stays alphabetical).
+- Sibling reorder (sort stays alphabetical).
- Root context menu (right-click in empty tree area).
-- Bootstrap Icons CDN — current pages don't use it, so this design uses Unicode glyphs.
+- (Removed from out-of-scope.) Bootstrap Icons are now adopted (static files at `wwwroot/lib/bootstrap-icons/`) — see `Component-TreeView.md` V4.
diff --git a/docs/requirements/Component-TreeView.md b/docs/requirements/Component-TreeView.md
index 18addcf..6d327ba 100644
--- a/docs/requirements/Component-TreeView.md
+++ b/docs/requirements/Component-TreeView.md
@@ -64,10 +64,9 @@ The `NodeContent` fragment receives the `TItem` and is responsible for rendering
### R4 — Indentation and Visual Structure
-- Each depth level is indented by a fixed amount (default 24px, configurable via `IndentPx` parameter).
-- Vertical guide lines connect parent to children at each depth level (thin left-border or CSS pseudo-element).
-- The toggle icon is inline with the node content, left-aligned at the current depth.
-- Leaf nodes align with sibling branch labels (the content starts at the same horizontal position, with empty space where the toggle would be).
+The component renders the structural chrome: indent gutters per depth, the toggle slot, and ancestor guide lines. Leaf nodes render an empty toggle placeholder so labels align across siblings.
+
+The exact tokens (indent unit, toggle glyph, guide-line treatment) are specified in **V2** of the Visual Design Guide.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
@@ -132,12 +131,11 @@ This keeps filter logic in the page (domain-specific) while the component handle
### R9 — Styling
-- Uses Bootstrap 5 utility classes only (no third-party frameworks).
-- No hardcoded colors — uses standard Bootstrap text/background utilities.
-- Toggle icons: Unicode characters (`+` / `−`) in a `` with `cursor: pointer`, or a small SVG chevron. No icon library dependency.
-- Compact row height for dense data (matching `table-sm` density).
-- Hover effect on rows: subtle background highlight (`bg-light` or similar).
-- CSS scoped to the component via Blazor CSS isolation (`TreeView.razor.css`).
+- Uses Bootstrap 5 utility classes and CSS variables. No third-party Blazor component frameworks.
+- Adds one icon-library dependency: **Bootstrap Icons** (static files at `wwwroot/lib/bootstrap-icons/`). Distribution rules in **V4** of the Visual Design Guide.
+- Hardcoded colors are forbidden; use Bootstrap utility classes (`bg-primary bg-opacity-10`, `text-muted`) or CSS variables (`var(--bs-tertiary-bg)`, `var(--bs-border-color)`).
+- Component-local CSS lives in `TreeView.razor.css` (Blazor CSS isolation).
+- All visual tokens (row density, indent, state visuals, glyphs, labels, badges) are specified in the **Visual Design Guide** (V1–V7). This requirement is non-normative summary; the Guide is authoritative.
### R10 — No Internal Scrolling
@@ -296,7 +294,183 @@ Future enhancement. Single selection (R5) covers current needs. A future version
- Shift+click for range select, Ctrl+click for toggle
- Use case: bulk operations (select multiple instances → deploy/disable all)
-## Component API Summary
+## Visual Design Guide
+
+This section is the canonical visual specification for the TreeView. It is normative: any change to the chrome (row layout, indentation, glyphs, state visuals, badge styling) must update this section. Consumers' `NodeContent` fragments follow the label and badge recipes in V5–V6; `/design/templates` is the worked example in V7.
+
+R4 and R9 above describe *that* the component renders structural chrome and uses Bootstrap utilities. This section says *exactly how*.
+
+### V1 — Density & Row Anatomy
+
+Each `
` renders one row. The row is a flexbox so trailing meta can right-align cleanly and the entire row width is a hover/selected/drop-target surface.
+
+**Row container** (replaces today's `.tv-row` styling):
+
+```html
+
+ …chevron or placeholder…
+ …Bootstrap Icon or placeholder…
+ …primary + secondary…
+ …badges…
+
+```
+
+| Token | Value | Notes |
+|---|---|---|
+| Row vertical padding | `py-1` (0.25rem top/bottom) | Yields ~32px row height at base font-size + line-height 1.5. |
+| Row horizontal padding | `px-2` (0.5rem left/right) | Selected/hover background spans full row including this padding. |
+| Inter-slot gap | `gap: .25rem` | Between toggle, glyph, label. The meta slot is offset by `margin-left: auto`. |
+| Font size | inherits (1rem base) | Compact pages may opt into `small` per-page, not at the component level. |
+| Line height | inherits (1.5) | Aligns the chevron, glyph, and label baselines correctly. |
+| Toggle slot width | 20px (`width: 1.25rem`) | Always present, even on leaves (which render an empty placeholder). |
+| Glyph slot width | 20px (`width: 1.25rem`) | Always present; consumer may render an empty span to preserve alignment. |
+| Label slot | `flex: 1 1 auto; min-width: 0;` | `min-width: 0` is required for ellipsis truncation to work in a flex child. |
+| Meta slot | `margin-left: auto;` | Pushes badges to the right edge of the row. |
+
+**Hit semantics**:
+- The full row (`tv-row`) is the surface for hover, selected, focus-visible, and drop-target backgrounds.
+- Click-to-select fires only on the **label slot** (preserves R5: toggle clicks do not select).
+- The toggle slot's invisible tap target is enlarged by negative margins inside the 20px slot so it remains a comfortable 24×24px target.
+
+### V2 — Depth, Indent & Guide Lines
+
+| Token | Value |
+|---|---|
+| Indent per depth | 24px (`IndentPx` default, unchanged) |
+| Toggle glyph (collapsed) | `` |
+| Toggle glyph (expanded) | `` (or `bi-chevron-right` rotated 90° via CSS) |
+| Guide line color | `var(--bs-border-color)` |
+| Guide line width | 1px |
+| Guide line style | solid, vertical-only (no horizontal stubs) |
+| Guide line position | one line per ancestor depth, drawn down the indent column (left edge of each 24px indent slot) |
+| Guide lines enabled | `ShowGuideLines` parameter (default true) |
+| Leaf alignment | identical depth gutter as siblings; the toggle slot renders an empty placeholder so glyphs and labels align across leaves and branches |
+
+Implementation note: guide lines are drawn by repeating a `linear-gradient` background or by stacking `border-left` on indent spacers — both are pure CSS, no extra DOM. The current `tv-guides` class is the hook.
+
+### V3 — State Visuals
+
+States compose: focus rings layer on top of hover/selected; drop-target overrides hover and selected. All states paint the full row width (V1).
+
+| State | Visual | Implementation |
+|---|---|---|
+| Default | none | — |
+| Hover | full-row tint | `background: var(--bs-tertiary-bg);` on `:hover` of `.tv-row` |
+| Focus-visible | inset 2px primary ring | `box-shadow: inset 0 0 0 2px var(--bs-primary);` on `:focus-visible` |
+| Selected | full-row primary tint | `class="bg-primary bg-opacity-10"` (existing `SelectedCssClass` default, unchanged) |
+| Selected + hover | selected tint persists; hover does not deepen | hover background applies only when not selected (`:hover:not(.bg-primary)`) |
+| Selected + focus | tint + ring both visible | focus ring layers via box-shadow |
+| Drop-target (valid) | `bg-info bg-opacity-25` | overrides hover/selected backgrounds; opt-in per consumer |
+| Drop-target (invalid) | cursor `not-allowed`, no tint change | absence of valid-tint is the cue |
+| Dragging source | `opacity: 0.5` | applied to the row currently being dragged |
+| Dimmed (non-droppable while a drag is in progress) | `opacity: 0.5` | applied to nodes the consumer marks as unsuitable drop targets |
+
+Drag-drop is **not** part of the TreeView component's intrinsic behavior — it is opt-in per consuming page. The drag-related state visuals (drop-target, dragging, dimmed) are documented here so consumers that *do* implement DnD share the same visual language. The `/design/templates` page (V7) explicitly does **not** use drag-drop; reorganization happens via the right-click context menu.
+
+### V4 — Glyph & Icon System
+
+**Distribution**: Bootstrap Icons ships as static files under `src/ScadaLink.CentralUI/wwwroot/lib/bootstrap-icons/` (`bootstrap-icons.css` + `fonts/*.woff2`). Referenced once from `MainLayout.razor`:
+
+```html
+
+```
+
+No CDN dependency — works on air-gapped industrial deployments. Version pinned in the file path or filename.
+
+**Rules**:
+- Glyphs are inline `` elements inside the 20px glyph slot.
+- Branches render an **open/closed pair**: a `closed` glyph when collapsed, an `open` glyph when expanded (consumer chooses both via `NodeContent`). The chevron toggle reinforces the same state.
+- Leaves render a single static glyph or no glyph (empty span preserves alignment).
+- **Color**: glyphs inherit `color` from their row. Default is body text; consumers may apply `text-muted` for de-emphasis. Kind is communicated by *shape*, not by color, to keep the palette available for status badges.
+- **Size**: glyphs render at `1em` (inherits row font-size). No fixed pixel size.
+
+### V5 — Label Recipe & Typography
+
+The label slot contains, in order: **[primary] [secondary modifiers]**. Trailing meta lives in the separate `.tv-meta` slot (V1).
+
+| Element | Style |
+|---|---|
+| Primary label (branches) | `class="fw-semibold"` |
+| Primary label (leaves) | normal weight |
+| Secondary modifiers | `class="text-muted small ms-1"` |
+| Overflow handling | `.tv-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }` |
+| Tooltip | `title` attribute on the primary label span, set to the full name on every row (cheap, helps when the row is narrower than the name) |
+
+**Rule of thumb**: font-weight tracks *has children*, not *kind*. A folder with no children renders regular weight; a leaf-template promoted to a branch by adding compositions becomes semibold automatically.
+
+### V6 — Badge Taxonomy
+
+Three semantic badge roles. The meta slot holds **at most two** badges per row. All badges live in `.tv-meta`, right-aligned (V1).
+
+| Role | Purpose | Markup | Examples |
+|---|---|---|---|
+| Count | numeric child aggregation | `@N` | folder child count; area instance count |
+| Status | semantic state | `@Label` | Enabled / Disabled / Stale / Error |
+| Kind | category / type tag | same filled semantic style, used sparingly | Protocol (OPC UA), Source (Inherited) |
+
+**Rules**:
+- Counts represent **direct children only**. Never transitive descendants.
+- A count of 0 **renders nothing** — no badge at all.
+- Status uses Bootstrap semantic colors; do not introduce custom palettes.
+- The component does not enforce the 2-badge cap; it is a documented convention. PR review should catch violations.
+
+### V7 — Worked Example: `/design/templates`
+
+**Page model**: the templates page is a **tree browser only**. Selecting a template in the tree navigates to a dedicated edit page (`/design/templates/{id}`); creating a template navigates to `/design/templates/create`. No split-pane editor. Reorganization (move folder, move template) happens exclusively through the **right-click context menu** with modal dialog pickers — there is no drag-and-drop on this page.
+
+Three node kinds; concrete recipes following V1–V6.
+
+| Kind | Glyph (collapsed) | Glyph (expanded) | Primary | Secondary | Badges |
+|---|---|---|---|---|---|
+| Folder | `bi-folder` | `bi-folder2-open` | folder name (semibold when has children, regular otherwise) | — | count of direct children (subtle pill), only if ≥ 1 |
+| Template | `bi-file-earmark-text` | same (templates with compositions still use the same glyph — chevron carries state) | `$Name` (semibold when has compositions, regular otherwise) | — | none |
+| Composition | `bi-arrow-return-right` | n/a (leaf, no expanded state) | composition instance name (regular weight) | `→ $TargetName` | none |
+
+**`NodeContent` fragment** for the templates page (replaces the current `RenderNodeLabel` in `Templates.razor`):
+
+```razor
+@switch (node.Kind)
+{
+ case TmplNodeKind.Folder:
+ var folderOpen = _tree.IsExpanded(node.Key);
+
+ @node.Label
+ @if (node.Children.Count > 0)
+ {
+
+ @node.Children.Count
+
+ }
+ break;
+
+ case TmplNodeKind.Template:
+
+ @node.Label
+ break;
+
+ case TmplNodeKind.Composition:
+ var composedName = _templates.FirstOrDefault(t => t.Id == node.Composition!.ComposedTemplateId)?.Name
+ ?? $"#{node.Composition!.ComposedTemplateId}";
+
+
+ @node.Label
+ → @composedName
+
+ break;
+}
+```
+
+**Locked subtractions from the previous design**:
+- Template node "inherits $Parent" muted text — **removed**. Inheritance is shown in the right pane only.
+- Template node "X attr, Y alm, Z scr" compound badge — **removed**.
+- Template node "N comp" accent badge — **removed**.
+
+These subtractions are deliberate: templates are leaves-from-the-tree's-perspective (their inner attributes/alarms/scripts are not tree-navigable), so the tree row should carry only what's needed to identify and pick the template. All counts and inheritance information live in the right detail pane.
+
+
```csharp
@typeparam TItem
diff --git a/src/ScadaLink.CentralUI/Components/Pages/Design/TemplateCreate.razor b/src/ScadaLink.CentralUI/Components/Pages/Design/TemplateCreate.razor
index dd5ccac..d8551a2 100644
--- a/src/ScadaLink.CentralUI/Components/Pages/Design/TemplateCreate.razor
+++ b/src/ScadaLink.CentralUI/Components/Pages/Design/TemplateCreate.razor
@@ -56,6 +56,8 @@
@code {
+ [SupplyParameterFromQuery] public int? FolderId { get; set; }
+
private List _templates = new();
private bool _loading = true;
@@ -87,11 +89,12 @@
var user = await GetCurrentUserAsync();
var result = await TemplateService.CreateTemplateAsync(
_createName.Trim(), _createDescription?.Trim(),
- _createParentId == 0 ? null : _createParentId, user);
+ _createParentId == 0 ? null : _createParentId, user,
+ folderId: FolderId);
if (result.IsSuccess)
{
- NavigationManager.NavigateTo("/design/templates");
+ NavigationManager.NavigateTo($"/design/templates/{result.Value.Id}");
}
else
{
diff --git a/src/ScadaLink.CentralUI/Components/Pages/Design/TemplateEdit.razor b/src/ScadaLink.CentralUI/Components/Pages/Design/TemplateEdit.razor
new file mode 100644
index 0000000..1a14f48
--- /dev/null
+++ b/src/ScadaLink.CentralUI/Components/Pages/Design/TemplateEdit.razor
@@ -0,0 +1,860 @@
+@page "/design/templates/{Id:int}"
+@using ScadaLink.Security
+@using ScadaLink.Commons.Entities.Templates
+@using ScadaLink.Commons.Interfaces.Repositories
+@using ScadaLink.Commons.Types.Enums
+@using ScadaLink.TemplateEngine
+@using ScadaLink.TemplateEngine.Services
+@using ScadaLink.TemplateEngine.Validation
+@attribute [Authorize(Policy = AuthorizationPolicies.RequireDesign)]
+@inject ITemplateEngineRepository TemplateEngineRepository
+@inject TemplateService TemplateService
+@inject AuthenticationStateProvider AuthStateProvider
+@inject NavigationManager NavigationManager
+
+