feat(ui): Layer E2 OpcUaEndpointEditor gains Authentication / Advanced / Deadband sections

Three new sections inserted into <OpcUaEndpointEditor>:

1. Authentication (between the existing Connection row and Timing)
   - 'Enable Authentication' button when Config.UserIdentity is null
   - TokenType select (Anonymous / UsernamePassword / X509Certificate)
   - Conditional Username + Password inputs for UsernamePassword
   - Conditional Certificate path + Certificate password for X509Certificate
   - 'Remove Authentication' button

2. Advanced subscription (after the existing Subscription row)
   - Subscription display name (text)
   - Subscription priority (number 0-255)
   - Timestamps to return (Source / Server / Both select)
   - Discard oldest (checkbox)

3. Deadband filter (after Advanced subscription)
   - 'Enable Deadband' button when Config.Deadband is null
   - Type select (Absolute / Percent), Value number input
   - 'Remove Deadband' button

EnableAuthentication and EnableDeadband helpers complement EnableHeartbeat.
All new fields use the existing RenderFieldError helper for validator errors.

82/82 CentralUI tests pass (the 10 new editor tests drove the design).
This commit is contained in:
Joseph Doherty
2026-05-12 02:30:06 -04:00
parent f89f234558
commit 22d91c858a
2 changed files with 133 additions and 8 deletions

View File

@@ -136,9 +136,10 @@ public class OpcUaEndpointEditorTests : BunitContext
};
var cut = Render<OpcUaEndpointEditor>(p => p.Add(c => c.Config, config));
Assert.Contains("Username", cut.Markup);
Assert.Contains("Password", cut.Markup);
Assert.DoesNotContain("Certificate path", cut.Markup);
// <label>Username</label> only renders for the UsernamePassword branch
Assert.Contains(">Username<", cut.Markup);
Assert.Contains(">Password<", cut.Markup);
Assert.DoesNotContain(">Certificate path<", cut.Markup);
}
[Fact]
@@ -153,9 +154,9 @@ public class OpcUaEndpointEditorTests : BunitContext
};
var cut = Render<OpcUaEndpointEditor>(p => p.Add(c => c.Config, config));
Assert.Contains("Certificate path", cut.Markup);
Assert.Contains("Certificate password", cut.Markup);
Assert.DoesNotContain("Username", cut.Markup);
Assert.Contains(">Certificate path<", cut.Markup);
Assert.Contains(">Certificate password<", cut.Markup);
Assert.DoesNotContain(">Username<", cut.Markup);
}
[Fact]
@@ -167,8 +168,8 @@ public class OpcUaEndpointEditorTests : BunitContext
};
var cut = Render<OpcUaEndpointEditor>(p => p.Add(c => c.Config, config));
Assert.DoesNotContain("Username", cut.Markup);
Assert.DoesNotContain("Certificate path", cut.Markup);
Assert.DoesNotContain(">Username<", cut.Markup);
Assert.DoesNotContain(">Certificate path<", cut.Markup);
}
[Fact]