refactor: rename ScadaLink → ZB.MOM.WW.ScadaBridge (code + projects + namespaces)

Solution + 23 src projects + 26 test projects renamed; folders, csproj,
namespaces, and ScadaLinkDbContext/ScadaBridgeDbContext class updated.
ActorSystem "scadalink" → "scadabridge", Akka seed-node URLs migrated.
SQL roles/logins, LDAP domains, CLI command name, and CLI config dir
(~/.scadalink → ~/.scadabridge) also renamed.

Build green; 5 Host.Tests fail awaiting SQL login rename in next commit.
Pre-existing StaleTagMonitor timing flakes unchanged.

Rename script committed at tools/rename-to-scadabridge.sh.
This commit is contained in:
Joseph Doherty
2026-05-28 09:37:45 -04:00
parent 6d87ee3c3b
commit 7b0b9c7365
1531 changed files with 11180 additions and 11054 deletions
@@ -11,11 +11,11 @@
**Design doc:** [`docs/plans/2026-05-11-templates-folder-hierarchy-design.md`](2026-05-11-templates-folder-hierarchy-design.md)
**Conventions confirmed from codebase exploration:**
- Service file: `src/ScadaLink.TemplateEngine/Services/TemplateFolderService.cs` (matches AreaService/InstanceService/SiteService convention).
- Service file: `src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/TemplateFolderService.cs` (matches AreaService/InstanceService/SiteService convention).
- Audit signature: `IAuditService.LogAsync(user, operation, entityType, entityId, displayName, payload, ct)`.
- Repository: extend `ITemplateEngineRepository` + `TemplateEngineRepository.cs` (single concrete impl).
- DbContext: `src/ScadaLink.ConfigurationDatabase/ScadaLinkDbContext.cs`, configurations in `Configurations/`.
- Management commands: simple records in `src/ScadaLink.Commons/Messages/Management/*.cs`; auto-discovered by reflection.
- DbContext: `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/ScadaBridgeDbContext.cs`, configurations in `Configurations/`.
- Management commands: simple records in `src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/*.cs`; auto-discovered by reflection.
- ManagementActor dispatch + authorization both via `switch` on command type.
- UI injects `TemplateService` directly (and will inject `TemplateFolderService` the same way) — no HTTP round trip.
@@ -37,12 +37,12 @@ Expected: file exists.
**Step 3: Build baseline passes**
Run: `dotnet build ScadaLink.slnx`
Run: `dotnet build ZB.MOM.WW.ScadaBridge.slnx`
Expected: build succeeds with 0 errors.
**Step 4: Existing tests pass**
Run: `dotnet test ScadaLink.slnx --filter "FullyQualifiedName~TemplateEngine.Tests|FullyQualifiedName~CentralUI.Tests" --nologo`
Run: `dotnet test ZB.MOM.WW.ScadaBridge.slnx --filter "FullyQualifiedName~TemplateEngine.Tests|FullyQualifiedName~CentralUI.Tests" --nologo`
Expected: all green.
**No commit at this task** — it's verification only.
@@ -52,18 +52,18 @@ Expected: all green.
## Task 1: Add `TemplateFolder` entity + `Template.FolderId`
**Files:**
- Create: `src/ScadaLink.Commons/Entities/Templates/TemplateFolder.cs`
- Modify: `src/ScadaLink.Commons/Entities/Templates/Template.cs`
- Create: `src/ZB.MOM.WW.ScadaBridge.Commons/Entities/Templates/TemplateFolder.cs`
- Modify: `src/ZB.MOM.WW.ScadaBridge.Commons/Entities/Templates/Template.cs`
**Step 1: Write the failing test**
Add to `tests/ScadaLink.Commons.Tests/Entities/TemplateFolderTests.cs` (create new file):
Add to `tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Entities/TemplateFolderTests.cs` (create new file):
```csharp
using ScadaLink.Commons.Entities.Templates;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates;
using Xunit;
namespace ScadaLink.Commons.Tests.Entities;
namespace ZB.MOM.WW.ScadaBridge.Commons.Tests.Entities;
public class TemplateFolderTests
{
@@ -94,15 +94,15 @@ public class TemplateFolderTests
**Step 2: Run test — confirm fail**
Run: `dotnet test tests/ScadaLink.Commons.Tests/ScadaLink.Commons.Tests.csproj --filter "FullyQualifiedName~TemplateFolderTests" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/ZB.MOM.WW.ScadaBridge.Commons.Tests.csproj --filter "FullyQualifiedName~TemplateFolderTests" --nologo`
Expected: FAIL (`TemplateFolder` type not found, `Template.FolderId` not found).
**Step 3: Implement the entity**
Create `src/ScadaLink.Commons/Entities/Templates/TemplateFolder.cs`:
Create `src/ZB.MOM.WW.ScadaBridge.Commons/Entities/Templates/TemplateFolder.cs`:
```csharp
namespace ScadaLink.Commons.Entities.Templates;
namespace ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates;
public class TemplateFolder
{
@@ -120,7 +120,7 @@ public class TemplateFolder
**Step 4: Add `FolderId` to `Template`**
Edit `src/ScadaLink.Commons/Entities/Templates/Template.cs` — add this property after `ParentTemplateId`:
Edit `src/ZB.MOM.WW.ScadaBridge.Commons/Entities/Templates/Template.cs` — add this property after `ParentTemplateId`:
```csharp
public int? FolderId { get; set; }
@@ -128,15 +128,15 @@ public int? FolderId { get; set; }
**Step 5: Run tests — confirm pass**
Run: `dotnet test tests/ScadaLink.Commons.Tests/ScadaLink.Commons.Tests.csproj --filter "FullyQualifiedName~TemplateFolderTests" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/ZB.MOM.WW.ScadaBridge.Commons.Tests.csproj --filter "FullyQualifiedName~TemplateFolderTests" --nologo`
Expected: PASS.
**Step 6: Commit**
```bash
git add src/ScadaLink.Commons/Entities/Templates/TemplateFolder.cs \
src/ScadaLink.Commons/Entities/Templates/Template.cs \
tests/ScadaLink.Commons.Tests/Entities/TemplateFolderTests.cs
git add src/ZB.MOM.WW.ScadaBridge.Commons/Entities/Templates/TemplateFolder.cs \
src/ZB.MOM.WW.ScadaBridge.Commons/Entities/Templates/Template.cs \
tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Entities/TemplateFolderTests.cs
git commit -m "feat(templates): add TemplateFolder entity and Template.FolderId"
```
@@ -145,12 +145,12 @@ git commit -m "feat(templates): add TemplateFolder entity and Template.FolderId"
## Task 2: EF configuration for `TemplateFolder` + `Template.FolderId`
**Files:**
- Modify: `src/ScadaLink.ConfigurationDatabase/Configurations/TemplateConfiguration.cs`
- Modify: `src/ScadaLink.ConfigurationDatabase/ScadaLinkDbContext.cs`
- Modify: `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Configurations/TemplateConfiguration.cs`
- Modify: `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/ScadaBridgeDbContext.cs`
**Step 1: Add `DbSet<TemplateFolder>` to DbContext**
Edit `src/ScadaLink.ConfigurationDatabase/ScadaLinkDbContext.cs` — under the `// Templates` region, add:
Edit `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/ScadaBridgeDbContext.cs` — under the `// Templates` region, add:
```csharp
public DbSet<TemplateFolder> TemplateFolders => Set<TemplateFolder>();
@@ -158,7 +158,7 @@ public DbSet<TemplateFolder> TemplateFolders => Set<TemplateFolder>();
**Step 2: Add `TemplateFolderConfiguration` class**
Append to `src/ScadaLink.ConfigurationDatabase/Configurations/TemplateConfiguration.cs`:
Append to `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Configurations/TemplateConfiguration.cs`:
```csharp
public class TemplateFolderConfiguration : IEntityTypeConfiguration<TemplateFolder>
@@ -197,14 +197,14 @@ builder.HasOne<TemplateFolder>()
**Step 4: Verify build**
Run: `dotnet build src/ScadaLink.ConfigurationDatabase/ScadaLink.ConfigurationDatabase.csproj`
Run: `dotnet build src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.csproj`
Expected: 0 errors.
**Step 5: Commit**
```bash
git add src/ScadaLink.ConfigurationDatabase/Configurations/TemplateConfiguration.cs \
src/ScadaLink.ConfigurationDatabase/ScadaLinkDbContext.cs
git add src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Configurations/TemplateConfiguration.cs \
src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/ScadaBridgeDbContext.cs
git commit -m "feat(db): map TemplateFolder entity and Template.FolderId"
```
@@ -213,13 +213,13 @@ git commit -m "feat(db): map TemplateFolder entity and Template.FolderId"
## Task 3: Generate EF migration `AddTemplateFolders`
**Files:**
- Create: `src/ScadaLink.ConfigurationDatabase/Migrations/<timestamp>_AddTemplateFolders.cs` (generated)
- Create: `src/ScadaLink.ConfigurationDatabase/Migrations/<timestamp>_AddTemplateFolders.Designer.cs` (generated)
- Modify: `src/ScadaLink.ConfigurationDatabase/Migrations/ScadaLinkDbContextModelSnapshot.cs` (generated)
- Create: `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Migrations/<timestamp>_AddTemplateFolders.cs` (generated)
- Create: `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Migrations/<timestamp>_AddTemplateFolders.Designer.cs` (generated)
- Modify: `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Migrations/ScadaBridgeDbContextModelSnapshot.cs` (generated)
**Step 1: Run migration generator**
Run: `dotnet ef migrations add AddTemplateFolders --project src/ScadaLink.ConfigurationDatabase --startup-project src/ScadaLink.Host`
Run: `dotnet ef migrations add AddTemplateFolders --project src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase --startup-project src/ZB.MOM.WW.ScadaBridge.Host`
Expected: three files created/updated under `Migrations/`. Dev DB (auto-apply on startup per CLAUDE.md) will apply on next host start.
**Step 2: Inspect the generated `Up()` method**
@@ -235,13 +235,13 @@ If any are missing, the entity config in Task 2 was wrong — fix and regenerate
**Step 3: Build to verify**
Run: `dotnet build src/ScadaLink.ConfigurationDatabase/ScadaLink.ConfigurationDatabase.csproj`
Run: `dotnet build src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.csproj`
Expected: 0 errors.
**Step 4: Commit**
```bash
git add src/ScadaLink.ConfigurationDatabase/Migrations/
git add src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Migrations/
git commit -m "feat(db): EF migration AddTemplateFolders"
```
@@ -250,12 +250,12 @@ git commit -m "feat(db): EF migration AddTemplateFolders"
## Task 4: Repository methods on `ITemplateEngineRepository`
**Files:**
- Modify: `src/ScadaLink.Commons/Interfaces/Repositories/ITemplateEngineRepository.cs`
- Modify: `src/ScadaLink.ConfigurationDatabase/Repositories/TemplateEngineRepository.cs`
- Modify: `src/ZB.MOM.WW.ScadaBridge.Commons/Interfaces/Repositories/ITemplateEngineRepository.cs`
- Modify: `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Repositories/TemplateEngineRepository.cs`
**Step 1: Add interface methods**
Edit `src/ScadaLink.Commons/Interfaces/Repositories/ITemplateEngineRepository.cs`. Above the trailing `Task<int> SaveChangesAsync(...)`, insert:
Edit `src/ZB.MOM.WW.ScadaBridge.Commons/Interfaces/Repositories/ITemplateEngineRepository.cs`. Above the trailing `Task<int> SaveChangesAsync(...)`, insert:
```csharp
// TemplateFolder
@@ -270,7 +270,7 @@ Task DeleteFolderAsync(int id, CancellationToken cancellationToken = default);
**Step 2: Implement on `TemplateEngineRepository`**
Edit `src/ScadaLink.ConfigurationDatabase/Repositories/TemplateEngineRepository.cs`. Append (above the closing brace of the class):
Edit `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Repositories/TemplateEngineRepository.cs`. Append (above the closing brace of the class):
```csharp
// TemplateFolder
@@ -299,7 +299,7 @@ public async Task DeleteFolderAsync(int id, CancellationToken cancellationToken
**Step 3: Build**
Run: `dotnet build ScadaLink.slnx`
Run: `dotnet build ZB.MOM.WW.ScadaBridge.slnx`
Expected: 0 errors. Any compile failure means a mock somewhere implements `ITemplateEngineRepository` without these methods — search and fix:
Run: `grep -rln "ITemplateEngineRepository" tests/ --include="*.cs"` and confirm Moq mocks don't need stubs (Moq generates defaults).
@@ -307,8 +307,8 @@ Run: `grep -rln "ITemplateEngineRepository" tests/ --include="*.cs"` and confirm
**Step 4: Commit**
```bash
git add src/ScadaLink.Commons/Interfaces/Repositories/ITemplateEngineRepository.cs \
src/ScadaLink.ConfigurationDatabase/Repositories/TemplateEngineRepository.cs
git add src/ZB.MOM.WW.ScadaBridge.Commons/Interfaces/Repositories/ITemplateEngineRepository.cs \
src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Repositories/TemplateEngineRepository.cs
git commit -m "feat(repo): add TemplateFolder repository methods"
```
@@ -317,21 +317,21 @@ git commit -m "feat(repo): add TemplateFolder repository methods"
## Task 5: `TemplateFolderService` — CreateFolderAsync (TDD)
**Files:**
- Create: `tests/ScadaLink.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs`
- Create: `src/ScadaLink.TemplateEngine/Services/TemplateFolderService.cs`
- Create: `tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs`
- Create: `src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/TemplateFolderService.cs`
**Step 1: Write failing tests**
Create `tests/ScadaLink.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs`:
Create `tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs`:
```csharp
using Moq;
using ScadaLink.Commons.Entities.Templates;
using ScadaLink.Commons.Interfaces.Repositories;
using ScadaLink.Commons.Interfaces.Services;
using ScadaLink.TemplateEngine.Services;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
using ZB.MOM.WW.ScadaBridge.TemplateEngine.Services;
namespace ScadaLink.TemplateEngine.Tests.Services;
namespace ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests.Services;
public class TemplateFolderServiceTests
{
@@ -399,20 +399,20 @@ public class TemplateFolderServiceTests
**Step 2: Run — confirm fail**
Run: `dotnet test tests/ScadaLink.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateFolderServiceTests" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateFolderServiceTests" --nologo`
Expected: FAIL (`TemplateFolderService` not found).
**Step 3: Implement minimal service**
Create `src/ScadaLink.TemplateEngine/Services/TemplateFolderService.cs`:
Create `src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/TemplateFolderService.cs`:
```csharp
using ScadaLink.Commons.Entities.Templates;
using ScadaLink.Commons.Interfaces.Repositories;
using ScadaLink.Commons.Interfaces.Services;
using ScadaLink.Commons.Types;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
using ZB.MOM.WW.ScadaBridge.Commons.Types;
namespace ScadaLink.TemplateEngine.Services;
namespace ZB.MOM.WW.ScadaBridge.TemplateEngine.Services;
public class TemplateFolderService
{
@@ -456,14 +456,14 @@ public class TemplateFolderService
**Step 4: Run — confirm pass**
Run: `dotnet test tests/ScadaLink.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateFolderServiceTests" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateFolderServiceTests" --nologo`
Expected: PASS (4 tests).
**Step 5: Commit**
```bash
git add tests/ScadaLink.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs \
src/ScadaLink.TemplateEngine/Services/TemplateFolderService.cs
git add tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs \
src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/TemplateFolderService.cs
git commit -m "feat(template-folder): add TemplateFolderService.CreateFolderAsync with validation"
```
@@ -472,8 +472,8 @@ git commit -m "feat(template-folder): add TemplateFolderService.CreateFolderAsyn
## Task 6: `TemplateFolderService.RenameFolderAsync`
**Files:**
- Modify: `tests/ScadaLink.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs`
- Modify: `src/ScadaLink.TemplateEngine/Services/TemplateFolderService.cs`
- Modify: `tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs`
- Modify: `src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/TemplateFolderService.cs`
**Step 1: Add failing tests**
@@ -523,7 +523,7 @@ public async Task RenameFolder_DuplicateSibling_ReturnsFailure()
**Step 2: Run — confirm fail**
Run: `dotnet test tests/ScadaLink.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateFolderServiceTests.RenameFolder" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateFolderServiceTests.RenameFolder" --nologo`
Expected: FAIL (method missing).
**Step 3: Implement `RenameFolderAsync`**
@@ -559,14 +559,14 @@ public async Task<Result<TemplateFolder>> RenameFolderAsync(
**Step 4: Run — confirm pass**
Run: `dotnet test tests/ScadaLink.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateFolderServiceTests" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateFolderServiceTests" --nologo`
Expected: PASS (7 tests now).
**Step 5: Commit**
```bash
git add tests/ScadaLink.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs \
src/ScadaLink.TemplateEngine/Services/TemplateFolderService.cs
git add tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs \
src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/TemplateFolderService.cs
git commit -m "feat(template-folder): rename folder with sibling uniqueness check"
```
@@ -575,8 +575,8 @@ git commit -m "feat(template-folder): rename folder with sibling uniqueness chec
## Task 7: `TemplateFolderService.MoveFolderAsync` with cycle detection
**Files:**
- Modify: `tests/ScadaLink.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs`
- Modify: `src/ScadaLink.TemplateEngine/Services/TemplateFolderService.cs`
- Modify: `tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs`
- Modify: `src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/TemplateFolderService.cs`
**Step 1: Add failing tests**
@@ -646,7 +646,7 @@ public async Task MoveFolder_ToRoot_ReturnsSuccess()
**Step 2: Run — confirm fail**
Run: `dotnet test tests/ScadaLink.TemplateEngine.Tests/ --filter "FullyQualifiedName~MoveFolder" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/ --filter "FullyQualifiedName~MoveFolder" --nologo`
Expected: FAIL (method missing).
**Step 3: Implement**
@@ -708,14 +708,14 @@ public async Task<Result<TemplateFolder>> MoveFolderAsync(
**Step 4: Run — confirm pass**
Run: `dotnet test tests/ScadaLink.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateFolderServiceTests" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateFolderServiceTests" --nologo`
Expected: PASS (11 tests).
**Step 5: Commit**
```bash
git add tests/ScadaLink.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs \
src/ScadaLink.TemplateEngine/Services/TemplateFolderService.cs
git add tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs \
src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/TemplateFolderService.cs
git commit -m "feat(template-folder): move with cycle detection and sibling uniqueness"
```
@@ -724,8 +724,8 @@ git commit -m "feat(template-folder): move with cycle detection and sibling uniq
## Task 8: `TemplateFolderService.DeleteFolderAsync` (non-empty check)
**Files:**
- Modify: `tests/ScadaLink.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs`
- Modify: `src/ScadaLink.TemplateEngine/Services/TemplateFolderService.cs`
- Modify: `tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs`
- Modify: `src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/TemplateFolderService.cs`
**Step 1: Add failing tests**
@@ -785,7 +785,7 @@ public async Task DeleteFolder_HasTemplates_ReturnsFailure_WithCounts()
**Step 2: Run — confirm fail**
Run: `dotnet test tests/ScadaLink.TemplateEngine.Tests/ --filter "FullyQualifiedName~DeleteFolder" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/ --filter "FullyQualifiedName~DeleteFolder" --nologo`
Expected: FAIL.
**Step 3: Implement**
@@ -829,14 +829,14 @@ public async Task<Result<bool>> DeleteFolderAsync(
**Step 4: Run — confirm pass**
Run: `dotnet test tests/ScadaLink.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateFolderServiceTests" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateFolderServiceTests" --nologo`
Expected: PASS (14 tests).
**Step 5: Commit**
```bash
git add tests/ScadaLink.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs \
src/ScadaLink.TemplateEngine/Services/TemplateFolderService.cs
git add tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/Services/TemplateFolderServiceTests.cs \
src/ZB.MOM.WW.ScadaBridge.TemplateEngine/Services/TemplateFolderService.cs
git commit -m "feat(template-folder): delete folder blocked if non-empty"
```
@@ -845,12 +845,12 @@ git commit -m "feat(template-folder): delete folder blocked if non-empty"
## Task 9: `TemplateService.MoveTemplateAsync`
**Files:**
- Modify: `tests/ScadaLink.TemplateEngine.Tests/TemplateServiceTests.cs`
- Modify: `src/ScadaLink.TemplateEngine/TemplateService.cs`
- Modify: `tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/TemplateServiceTests.cs`
- Modify: `src/ZB.MOM.WW.ScadaBridge.TemplateEngine/TemplateService.cs`
**Step 1: Add failing tests**
Append to `tests/ScadaLink.TemplateEngine.Tests/TemplateServiceTests.cs` (inside the existing test class):
Append to `tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/TemplateServiceTests.cs` (inside the existing test class):
```csharp
[Fact]
@@ -897,12 +897,12 @@ public async Task MoveTemplate_TargetFolderMissing_ReturnsFailure()
**Step 2: Run — confirm fail**
Run: `dotnet test tests/ScadaLink.TemplateEngine.Tests/ --filter "FullyQualifiedName~MoveTemplate" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/ --filter "FullyQualifiedName~MoveTemplate" --nologo`
Expected: FAIL.
**Step 3: Implement on `TemplateService`**
Add to `src/ScadaLink.TemplateEngine/TemplateService.cs` (above the helper methods section):
Add to `src/ZB.MOM.WW.ScadaBridge.TemplateEngine/TemplateService.cs` (above the helper methods section):
```csharp
public async Task<Result<Template>> MoveTemplateAsync(
@@ -931,14 +931,14 @@ public async Task<Result<Template>> MoveTemplateAsync(
**Step 4: Run — confirm pass**
Run: `dotnet test tests/ScadaLink.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateServiceTests" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/ --filter "FullyQualifiedName~TemplateServiceTests" --nologo`
Expected: all pass (existing + 3 new).
**Step 5: Commit**
```bash
git add tests/ScadaLink.TemplateEngine.Tests/TemplateServiceTests.cs \
src/ScadaLink.TemplateEngine/TemplateService.cs
git add tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/TemplateServiceTests.cs \
src/ZB.MOM.WW.ScadaBridge.TemplateEngine/TemplateService.cs
git commit -m "feat(template-engine): TemplateService.MoveTemplateAsync"
```
@@ -947,7 +947,7 @@ git commit -m "feat(template-engine): TemplateService.MoveTemplateAsync"
## Task 10: DI registration
**Files:**
- Modify: `src/ScadaLink.TemplateEngine/ServiceCollectionExtensions.cs`
- Modify: `src/ZB.MOM.WW.ScadaBridge.TemplateEngine/ServiceCollectionExtensions.cs`
**Step 1: Add registration**
@@ -959,13 +959,13 @@ services.AddScoped<TemplateFolderService>();
**Step 2: Build**
Run: `dotnet build src/ScadaLink.TemplateEngine/ScadaLink.TemplateEngine.csproj`
Run: `dotnet build src/ZB.MOM.WW.ScadaBridge.TemplateEngine/ZB.MOM.WW.ScadaBridge.TemplateEngine.csproj`
Expected: 0 errors.
**Step 3: Commit**
```bash
git add src/ScadaLink.TemplateEngine/ServiceCollectionExtensions.cs
git add src/ZB.MOM.WW.ScadaBridge.TemplateEngine/ServiceCollectionExtensions.cs
git commit -m "feat(di): register TemplateFolderService"
```
@@ -974,12 +974,12 @@ git commit -m "feat(di): register TemplateFolderService"
## Task 11: Management command records
**Files:**
- Create: `src/ScadaLink.Commons/Messages/Management/TemplateFolderCommands.cs`
- Create: `src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/TemplateFolderCommands.cs`
**Step 1: Create file**
```csharp
namespace ScadaLink.Commons.Messages.Management;
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
public record ListTemplateFoldersCommand;
public record CreateTemplateFolderCommand(string Name, int? ParentFolderId);
@@ -991,16 +991,16 @@ public record MoveTemplateToFolderCommand(int TemplateId, int? NewFolderId);
**Step 2: Verify auto-registration**
Run: `dotnet test tests/ScadaLink.Commons.Tests/ --nologo` — if a `ManagementCommandRegistry` smoke test exists it picks up these new types automatically (registration is reflection-based).
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/ --nologo` — if a `ManagementCommandRegistry` smoke test exists it picks up these new types automatically (registration is reflection-based).
If no existing smoke test catches missing dispatch, this is just a build check:
Run: `dotnet build src/ScadaLink.Commons/ScadaLink.Commons.csproj`
Run: `dotnet build src/ZB.MOM.WW.ScadaBridge.Commons/ZB.MOM.WW.ScadaBridge.Commons.csproj`
Expected: 0 errors.
**Step 3: Commit**
```bash
git add src/ScadaLink.Commons/Messages/Management/TemplateFolderCommands.cs
git add src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/TemplateFolderCommands.cs
git commit -m "feat(management): add TemplateFolder command records"
```
@@ -1009,7 +1009,7 @@ git commit -m "feat(management): add TemplateFolder command records"
## Task 12: `ManagementActor` authorization + handlers
**Files:**
- Modify: `src/ScadaLink.ManagementService/ManagementActor.cs`
- Modify: `src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs`
**Step 1: Add to `GetRequiredRole`**
@@ -1086,19 +1086,19 @@ private static async Task<object?> HandleMoveTemplateToFolder(IServiceProvider s
**Step 4: Add missing `using` if needed**
If `TemplateFolderService` isn't already imported, add `using ScadaLink.TemplateEngine.Services;` near the top.
If `TemplateFolderService` isn't already imported, add `using ZB.MOM.WW.ScadaBridge.TemplateEngine.Services;` near the top.
**Step 5: Build + test**
Run: `dotnet build src/ScadaLink.ManagementService/ScadaLink.ManagementService.csproj`
Run: `dotnet build src/ZB.MOM.WW.ScadaBridge.ManagementService/ZB.MOM.WW.ScadaBridge.ManagementService.csproj`
Expected: 0 errors.
Run: `dotnet test tests/ScadaLink.ManagementService.Tests/ --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/ --nologo`
Expected: all pass.
**Step 6: Commit**
```bash
git add src/ScadaLink.ManagementService/ManagementActor.cs
git add src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs
git commit -m "feat(management): handler + authorization for TemplateFolder commands"
```
@@ -1107,7 +1107,7 @@ git commit -m "feat(management): handler + authorization for TemplateFolder comm
## Task 13: Templates.razor — extend data loading to include folders
**Files:**
- Modify: `src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor`
- Modify: `src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor`
This task only changes the `@code` block. The markup is rewritten in Task 14.
@@ -1122,7 +1122,7 @@ Near the top of the file, add:
And the using:
```razor
@using ScadaLink.TemplateEngine.Services
@using ZB.MOM.WW.ScadaBridge.TemplateEngine.Services
```
**Step 2: Add folder field**
@@ -1157,13 +1157,13 @@ private async Task LoadTemplatesAsync()
**Step 4: Build verify**
Run: `dotnet build src/ScadaLink.CentralUI/ScadaLink.CentralUI.csproj`
Run: `dotnet build src/ZB.MOM.WW.ScadaBridge.CentralUI/ZB.MOM.WW.ScadaBridge.CentralUI.csproj`
Expected: 0 errors. (`BuildTemplateTree` will be rewritten next task — current impl still compiles.)
**Step 5: Commit**
```bash
git add src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor
git add src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor
git commit -m "feat(ui/templates): load folders alongside templates"
```
@@ -1172,7 +1172,7 @@ git commit -m "feat(ui/templates): load folders alongside templates"
## Task 14: Build the new `TmplNode` tree model
**Files:**
- Modify: `src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor`
- Modify: `src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor`
**Step 1: Replace the existing `TmplTreeNode` record + `BuildTemplateTree` / `BuildTmplChildren`**
@@ -1277,7 +1277,7 @@ private static void SortChildren(List<TmplNode> children)
**Step 2: Build**
Run: `dotnet build src/ScadaLink.CentralUI/ScadaLink.CentralUI.csproj`
Run: `dotnet build src/ZB.MOM.WW.ScadaBridge.CentralUI/ZB.MOM.WW.ScadaBridge.CentralUI.csproj`
Expected: build error in the existing `<TreeView TItem="TmplTreeNode" ...>` — it references the removed type. That's expected; will be fixed in Task 15.
**Step 3: Don't commit yet — Task 15 finishes the markup change before this compiles.**
@@ -1287,7 +1287,7 @@ Expected: build error in the existing `<TreeView TItem="TmplTreeNode" ...>` —
## Task 15: Templates.razor — split-pane layout + new TreeView wiring
**Files:**
- Modify: `src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor`
- Modify: `src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor`
**Step 1: Replace the page body markup**
@@ -1448,7 +1448,7 @@ Delete `BackToList()` method and any remaining references. The "Back to List" bu
**Step 6: Build + smoke**
Run: `dotnet build src/ScadaLink.CentralUI/ScadaLink.CentralUI.csproj`
Run: `dotnet build src/ZB.MOM.WW.ScadaBridge.CentralUI/ZB.MOM.WW.ScadaBridge.CentralUI.csproj`
Expected: 0 errors.
Manual smoke (no DB changes needed beyond Task 3's migration — auto-applied on host start):
@@ -1459,7 +1459,7 @@ Expected: tree shows existing templates at the root (none in folders yet). Selec
**Step 7: Commit**
```bash
git add src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor
git add src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor
git commit -m "feat(ui/templates): split-pane layout with folder + composition tree"
```
@@ -1468,7 +1468,7 @@ git commit -m "feat(ui/templates): split-pane layout with folder + composition t
## Task 16: Per-kind context menus
**Files:**
- Modify: `src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor`
- Modify: `src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor`
**Step 1: Implement `RenderNodeContextMenu`**
@@ -1586,7 +1586,7 @@ Add inside the top-level `<div class="container-fluid mt-3">` (after `<ConfirmDi
**Step 4: Build + smoke**
Run: `dotnet build src/ScadaLink.CentralUI/ScadaLink.CentralUI.csproj`
Run: `dotnet build src/ZB.MOM.WW.ScadaBridge.CentralUI/ZB.MOM.WW.ScadaBridge.CentralUI.csproj`
Expected: 0 errors.
Manual smoke: right-click a template → Edit / Move (stub) / Delete render correctly. Right-click a (future) folder → New Folder / New Template / Rename / Delete. Rename and Delete work end-to-end.
@@ -1594,7 +1594,7 @@ Manual smoke: right-click a template → Edit / Move (stub) / Delete render corr
**Step 5: Commit**
```bash
git add src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor
git add src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor
git commit -m "feat(ui/templates): per-kind context menus + folder rename/delete"
```
@@ -1603,7 +1603,7 @@ git commit -m "feat(ui/templates): per-kind context menus + folder rename/delete
## Task 17: New-folder / new-template / move-template dialogs
**Files:**
- Modify: `src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor`
- Modify: `src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor`
**Step 1: New-folder dialog state + handler**
@@ -1825,15 +1825,15 @@ Append to the same top-level container after the rename modal:
**Step 5: Build + smoke**
Run: `dotnet build ScadaLink.slnx`
Run: `dotnet build ZB.MOM.WW.ScadaBridge.slnx`
Expected: 0 errors. Run the cluster (`bash docker/deploy.sh`), exercise the three modals manually.
**Step 6: Commit**
```bash
git add src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor \
src/ScadaLink.TemplateEngine/TemplateService.cs \
tests/ScadaLink.TemplateEngine.Tests/TemplateServiceTests.cs
git add src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor \
src/ZB.MOM.WW.ScadaBridge.TemplateEngine/TemplateService.cs \
tests/ZB.MOM.WW.ScadaBridge.TemplateEngine.Tests/TemplateServiceTests.cs
git commit -m "feat(ui/templates): new-folder, new-template, move-template dialogs"
```
@@ -1842,7 +1842,7 @@ git commit -m "feat(ui/templates): new-folder, new-template, move-template dialo
## Task 18: Drag-drop reorganization
**Files:**
- Modify: `src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor`
- Modify: `src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor`
**Step 1: Drag state**
@@ -1957,7 +1957,7 @@ Wrap the `<TreeView>` in a div that accepts drops onto the root:
**Step 4: Build + smoke**
Run: `dotnet build ScadaLink.slnx`
Run: `dotnet build ZB.MOM.WW.ScadaBridge.slnx`
Expected: 0 errors.
Manual smoke (after `bash docker/deploy.sh`):
@@ -1968,7 +1968,7 @@ Manual smoke (after `bash docker/deploy.sh`):
**Step 5: Commit**
```bash
git add src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor
git add src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor
git commit -m "feat(ui/templates): native HTML5 drag-drop reorganization"
```
@@ -1977,7 +1977,7 @@ git commit -m "feat(ui/templates): native HTML5 drag-drop reorganization"
## Task 19: Deep-link reveal on load
**Files:**
- Modify: `src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor`
- Modify: `src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor`
**Step 1: Call `RevealNode` after initial load when route param is set**
@@ -2004,7 +2004,7 @@ protected override void OnAfterRender(bool firstRender)
**Step 2: Build + smoke**
Run: `dotnet build src/ScadaLink.CentralUI/ScadaLink.CentralUI.csproj`
Run: `dotnet build src/ZB.MOM.WW.ScadaBridge.CentralUI/ZB.MOM.WW.ScadaBridge.CentralUI.csproj`
Expected: 0 errors.
Manual smoke: navigate directly to `/design/templates/{existing-id}` — the tree reveals the template and selects it.
@@ -2012,7 +2012,7 @@ Manual smoke: navigate directly to `/design/templates/{existing-id}` — the tre
**Step 3: Commit**
```bash
git add src/ScadaLink.CentralUI/Components/Pages/Design/Templates.razor
git add src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/Templates.razor
git commit -m "feat(ui/templates): reveal deep-linked template on initial render"
```
@@ -2021,7 +2021,7 @@ git commit -m "feat(ui/templates): reveal deep-linked template on initial render
## Task 20: bUnit tests for the new page
**Files:**
- Create: `tests/ScadaLink.CentralUI.Tests/TemplatesPageTests.cs`
- Create: `tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/TemplatesPageTests.cs`
**Step 1: Write rendering tests**
@@ -2032,14 +2032,14 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using ScadaLink.CentralUI.Components.Pages.Design;
using ScadaLink.Commons.Entities.Templates;
using ScadaLink.Commons.Interfaces.Repositories;
using ScadaLink.Commons.Interfaces.Services;
using ScadaLink.TemplateEngine;
using ScadaLink.TemplateEngine.Services;
using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Pages.Design;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
using ZB.MOM.WW.ScadaBridge.TemplateEngine;
using ZB.MOM.WW.ScadaBridge.TemplateEngine.Services;
namespace ScadaLink.CentralUI.Tests;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests;
public class TemplatesPageTests : BunitContext
{
@@ -2116,13 +2116,13 @@ internal class TestAuthStateProvider : AuthenticationStateProvider
**Step 2: Run**
Run: `dotnet test tests/ScadaLink.CentralUI.Tests/ --filter "FullyQualifiedName~TemplatesPageTests" --nologo`
Run: `dotnet test tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/ --filter "FullyQualifiedName~TemplatesPageTests" --nologo`
Expected: PASS (3 tests).
**Step 3: Commit**
```bash
git add tests/ScadaLink.CentralUI.Tests/TemplatesPageTests.cs
git add tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/TemplatesPageTests.cs
git commit -m "test(ui/templates): bUnit rendering tests for folder tree"
```
@@ -2170,7 +2170,7 @@ git commit -m "docs(templates): describe folder hierarchy and management command
**Step 1: Full test pass**
Run: `dotnet test ScadaLink.slnx --nologo`
Run: `dotnet test ZB.MOM.WW.ScadaBridge.slnx --nologo`
Expected: all green.
**Step 2: Build cluster image and run**