d7b05b40e9ec58d595f5be89c5fbd38176aecc0e
7 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
783da8e21a |
feat(ui): structured editors for script schemas and alarm triggers
Replace raw-JSON text inputs with rich UI: script parameter/return types use a JSON Schema builder (SchemaBuilder + JsonSchemaShapeParser, with a migration to convert existing definitions); alarm trigger config uses a type-aware editor with a flattened attribute picker (AlarmTriggerEditor). AlarmActor gains optional direction (rising/falling/either) on RateOfChange triggers. |
||
|
|
0b24b4537d |
feat(ui/scripts): editor support for self/child/parent accessors
Phases 3+4 of the script-scope rollout. Wires the runtime accessors
landed in
|
||
|
|
0528c65cba |
feat(ui/scripts): format, inlay hints, problems panel, type diagnostic
Three more editor features rolled in:
1. Roslyn Format command.
New POST /api/script-analysis/format runs Formatter.Format() from
Microsoft.CodeAnalysis.CSharp.Workspaces on the parsed script
tree. monaco-init.js registers a DocumentFormattingEditProvider
so Ctrl/Cmd-Shift-F and the toolbar "Format" button both work.
2. Inlay hints with parameter names.
New POST /api/script-analysis/inlay-hints walks CallShared /
CallScript invocations and emits InlayHint records positioned at
each argument with the matching parameter's name (e.g. "name:").
Ghost text appears via Monaco's InlayHintsProvider.
3. SCADA005 argument-type diagnostic.
Literal type vs. declared parameter type check on every
CallShared/CallScript argument. Float accepts Integer literals;
Object/List accept anything; null only matches reference-ish
types. Legacy lowercase types ("string" etc) from the DB are
normalized to the canonical set before comparison so existing
data doesn't false-negative. Non-literal args (variables,
expressions) are skipped — out of scope for a cheap pass.
4. Parameters["name"] hover.
Hover endpoint now also resolves Parameters["X"] element-access
keys against the form's DeclaredParameterShapes and returns
"parameter `name: String`"-style markdown. MonacoEditor surfaces
the new DeclaredParameterShapes parameter; ScriptParameterNames
gets a ParseShapes companion.
5. Problems panel.
Bootstrap card under the editor listing every marker with
severity badge, line number, message, and SCADA / CS code. Click
a row to scroll the editor to that line and focus. JS now
invokes OnMarkersChanged on the .NET side whenever
setModelMarkers fires, so the panel stays in sync with the
editor.
6. Editor toolbar.
Small top-right strip on each editor with Format / Wrap /
Minimap / Theme toggles. New MonacoBlazor.format,
setEditorOption, and revealLine JS APIs back the buttons and the
problems-panel scroll-to-line.
Contracts:
- FormatRequest / FormatResponse
- InlayHintsRequest / InlayHintsResponse / InlayHint
- HoverRequest.DeclaredParameters
- MonacoEditor.DeclaredParameterShapes parameter
- MonacoEditor.MarkersChanged callback
- ScadaContext.DeclaredParameterShapes
10 new xUnit tests covering format, inlay hints, SCADA005 (string-
expects-integer, integer-expects-string, float-accepts-integer,
object-accepts-anything, non-literal-skipped), and Parameters key
hover. Total: 139 -> 149.
Microsoft.CodeAnalysis.CSharp.Workspaces 4.13.0 added to pull in
Formatter and AdhocWorkspace.
Browser-verified: typing `CallShared("Greet", 42)` now shows the
"name:" inlay hint and a SCADA005 squiggle on `42`; Parameters["typo"]
shows SCADA003 as before; the toolbar buttons all work.
|
||
|
|
004c5da582 |
feat(ui/scripts): shape-aware Monaco features for script calls
Now that the form holds parameter + return shapes for declared
parameters, sibling scripts (template Scripts tab), and shared
scripts (via SharedScriptCatalog), the editor leverages them four
ways:
1. Snippet expansion on accept.
Picking a CallShared or CallScript completion inserts the full
call template with tabstops, e.g. `Greet", ${1:name})`. The JS
provider extends the completion range over Monaco's auto-closed
`")` so the snippet replaces the closing pair cleanly. Items
carry insertTextRules=4 (InsertAsSnippet) and a command to
immediately trigger parameter hints after acceptance.
2. Hover info.
Hovering the script name token inside CallShared("X") or
CallScript("Y") shows a markdown tooltip with the call signature
and return type. New endpoint POST /api/script-analysis/hover.
3. Signature help.
Inside CallShared(...) / CallScript(...) Monaco shows the
parameter strip with the active parameter highlighted. The
service walks up from the cursor to the nearest enclosing
InvocationExpression and resolves which argument index the
cursor is on. New endpoint POST /api/script-analysis/signature-help.
4. Argument-count diagnostic (SCADA004) and unknown-Parameters-key
diagnostic (SCADA003). The Diagnose pipeline now consults the
declared parameters and sibling/shared shapes to flag:
- Parameters["typo"] when "typo" isn't on the form (warn)
- CallScript("Calc", 1) when Calc declares 2 required args (err)
- CallShared("Greet", 1, 2, 3) when Greet declares 1 arg (err)
Optional parameters relax the required-count bound.
Contract changes:
- ScriptShape / ParameterShape records
- ISharedScriptCatalog.GetShapesAsync (replaces GetNamesAsync)
- new HoverRequest/Response, SignatureHelpRequest/Response
- CompletionsRequest.SiblingScripts: string[] -> ScriptShape[]
- DiagnoseRequest gains DeclaredParameters + SiblingScripts
- CompletionItem gains InsertTextRules (Monaco snippet rule)
Form wiring:
- TemplateEdit passes ScriptShapeParser.Parse(...) per sibling
- MonacoEditor surfaces SiblingScripts: IReadOnlyList<ScriptShape>
- GetContext returns shapes to JS on each completion/hover/sig
request
10 new ScriptAnalysisServiceTests covering all four features plus
optional-parameter edge cases. Existing tests updated for the
contract changes. Total: 113 -> 139.
Browser-verified via direct curl + Monaco marker readback:
- SCADA003 squiggle on Parameters["typo"]
- Snippet item Greet", ${1:name}) with insertTextRules=4
- Hover markdown shape signature
- Signature help parameter strip
|
||
|
|
cd0ec583e1 |
refactor(ui/scripts): cache diagnostics + semantic forbidden-API check
Two pre-flagged follow-ups from the Monaco integration: 1. IMemoryCache for diagnostics keyed by SHA256 of the script body. Same-code Diagnose() now short-circuits the Roslyn compile and forbidden-API walk. SizeLimit 200 entries with 5-minute sliding expiration. Completions aren't cached — position + form context vary too much for a useful hit rate. 2. Forbidden-API analyzer now resolves identifiers through the SemanticModel instead of matching names. A user identifier named File / Thread / Process / etc. no longer false-positives — only references that resolve to a NamedTypeSymbol whose containing namespace is on the banned list are flagged. The diagnostic message now names the offending namespace, e.g. "Type 'File' from forbidden namespace 'System.IO' is not allowed in scripts." Refactor: extracted ISharedScriptCatalog so ScriptAnalysisService can be unit-tested without standing up SharedScriptService's EF chain. Concrete SharedScriptCatalog wraps the existing service. 16 new xUnit tests in ScriptAnalysisServiceTests: - Empty / clean / missing-semicolon paths - SCADA001 on each banned using namespace (theory) - SCADA002 on real File.ReadAllText through System.IO - No-false-positive checks for user-defined File / Thread locals - Cache returns the same response instance on repeat - Different code → different cache entries - String-literal completions for Parameters / CallScript / CallShared - General completion at file scope returns ScriptHost members Total CentralUI test count: 113 -> 129. |
||
|
|
225817eac9 |
feat(ui/scripts): SCADA-specific Monaco extensions
Wave 3 of the Monaco/Roslyn integration. Adds the four extensions
agreed in the design Q&A:
1. Parameters["..."] keys — when the cursor is inside a string
literal that's the index of a Parameters[] element-access,
completions return the parameter names declared in the form's
ParameterListEditor.
2. CallShared("...") names — when the cursor is inside a string
literal argument to a CallShared(...) invocation, completions
return the names of all shared scripts (resolved server-side
via SharedScriptService).
3. CallScript("...") names — same shape, but uses sibling-script
names passed from the form (TemplateEdit's _scripts list).
4. Forbidden-API diagnostic — squiggles uses of the documented
script trust model bans: System.IO / Diagnostics / Reflection /
Net / Threading.Thread namespaces, plus the named types File,
Directory, Process, Thread, Socket, etc. New diagnostic codes
SCADA001 (using directive) and SCADA002 (type identifier).
ScriptAnalysisService gains a SharedScriptService dependency
(scoped, hence the analyzer is now scoped too); CompletionsRequest
carries DeclaredParameters and SiblingScripts; Complete is now async.
MonacoEditor.razor exposes DeclaredParameters / SiblingScripts
parameters plus a [JSInvokable] GetContext() so the JS side asks
for the latest form state on every completion request. The
provider in monaco-init.js looks up the owning editor from the
internal editors map and forwards the context.
ScriptParameterNames helper parses the ParameterListEditor JSON
into a name list — used by SharedScriptForm, ApiMethodForm, and
TemplateEdit's Add-Script form to populate the Monaco context.
Smoke-verified via direct fetch + Monaco trigger:
- var x = Parameters[" → popup: "name" (declared parameter)
- var y = CallShared(" → popup: GetWeather, Greet
- using System.IO; → SCADA001 squiggle
- Process.Start(...) → SCADA002 squiggle
- File.ReadAllText(...) → SCADA002 squiggle
Also fixed: ScriptAnalysisService scoped (was singleton, broke DI
because SharedScriptService is scoped); JS normalizes Pascal-case
context keys from Blazor's record serialization to camel-case for
the request body.
|
||
|
|
cf9548e9ed |
feat(ui/scripts): Roslyn-backed C# completions + diagnostics for Monaco
Adds Microsoft.CodeAnalysis.CSharp.Scripting (4.13.0). Scripts are
compiled as C# script fragments against a ScriptHost globals type
that mirrors what the runtime exposes (Parameters bag, CallShared,
CallScript) — Roslyn reads the signatures so those identifiers are
in scope for analysis without executing anything.
ScriptAnalysisService:
- Diagnose(code): Compilation.GetDiagnostics() projected to
Monaco-shaped DiagnosticMarker records (severity 8/4/2/1).
- Complete(code, line, col): dot-member lookup via SemanticModel
when the token at position is part of a MemberAccessExpression;
falls back to LookupSymbols at position for the general case.
Two endpoints exposed by the existing CentralUI endpoint pipeline,
both behind RequireDesign policy:
POST /api/script-analysis/diagnostics
POST /api/script-analysis/completions
monaco-init.js registers a csharp CompletionItemProvider with dot/
paren/quote trigger chars, plus a 500 ms debounced diagnostics pass
on every keystroke that pushes markers via setModelMarkers. Initial
pass fires on editor create so existing scripts surface errors right
away. Auth uses the existing cookie via credentials: same-origin.
Smoke-verified:
- Typing `DateTimeOffset.UtcNow` (no semicolon) shows the missing
semicolon squiggle in real time.
- Ctrl-Space at file scope returns the full type universe
(AccessViolationException, Action, Akka, AppDomain, ...).
Wave 2 of three. SCADA-specific extensions (declared param keys,
shared/sibling script names, forbidden-API diagnostic) follow.
|