LANCommander/LANCommander.UI/Components/CodeInput/CodeInput.razor
Pat Hartl f87756243e Add support for defining PowerShell modules
Adds a new section "Scripting" in the server UI where PowerShell modules can be defined. These can be used for defining a library of functions that can be used in any script. These modules are automatically synced to the launcher and imported upon script execution.
2026-06-28 23:02:35 -05:00

194 lines
No EOL
5.7 KiB
Text

@using BlazorMonaco.Editor
@using Microsoft.JSInterop
@namespace LANCommander.UI.Components
@inject IJSRuntime JSRuntime
<StandaloneCodeEditor
@ref="_editor"
OnDidChangeModelContent="OnChangedContent"
OnDidInit="OnInit"
ConstructionOptions="_editorConstructionOptions" />
@code {
[Parameter] public EventCallback<string> OnSave { get; set; }
[Parameter] public EventCallback OnReady { get; set; }
[Parameter] public Language Language { get; set; }
[Parameter] public int Height { get; set; }
[Parameter] public string? Value { get; set; }
[Parameter] public EventCallback<string?> ValueChanged { get; set; }
[Parameter] public string? ScriptType { get; set; }
[Parameter] public IEnumerable<ModuleFunctionCompletion>? ModuleFunctions { get; set; }
static bool _completionsRegistered;
static bool _yamlCompletionsRegistered;
bool _isEditorInitialized = false;
string? _previousValue;
string? _previousScriptType;
IEnumerable<ModuleFunctionCompletion>? _previousModuleFunctions;
IJSObjectReference? _module;
StandaloneCodeEditor _editor;
StandaloneEditorConstructionOptions _editorConstructionOptions(StandaloneCodeEditor editor)
{
var options = new StandaloneEditorConstructionOptions
{
AutomaticLayout = true,
Language = Language.Id,
Theme = "vs-dark",
Value = Value,
Minimap = new EditorMinimapOptions { Enabled = false },
BracketPairColorization = new BracketPairColorizationOptions { Enabled = true },
WordWrap = "on",
FixedOverflowWidgets = true,
};
if (Height > 0)
options.Dimension = new Dimension { Height = Height };
return options;
}
protected override async Task OnParametersSetAsync()
{
if (_isEditorInitialized && ValueChanged.HasDelegate && Value != _previousValue)
{
_previousValue = Value;
await _editor.SetValue(Value);
}
if (_isEditorInitialized && _module != null && ScriptType != _previousScriptType)
{
_previousScriptType = ScriptType;
await _module.InvokeVoidAsync("setScriptType", ScriptType);
await RunValidationAsync();
}
if (_isEditorInitialized && _module != null && !ReferenceEquals(ModuleFunctions, _previousModuleFunctions))
{
await PushModuleFunctionsAsync();
}
await base.OnParametersSetAsync();
}
async Task OnInit()
{
_isEditorInitialized = true;
await _editor.AddCommand((int)BlazorMonaco.KeyMod.CtrlCmd | (int)BlazorMonaco.KeyCode.KeyS, async (editor) =>
{
if (OnSave.HasDelegate)
await OnSave.InvokeAsync();
}, null);
_module = await JSRuntime.InvokeAsync<IJSObjectReference>(
"import", "./_content/LANCommander.UI/bundle.js");
if (Language.Id == "powershell" && !_completionsRegistered)
{
_completionsRegistered = true;
await _module.InvokeVoidAsync("registerPowerShellCompletions");
}
if (Language.Id == "yaml" && !_yamlCompletionsRegistered)
{
_yamlCompletionsRegistered = true;
await _module.InvokeVoidAsync("registerYamlCompletions");
}
if (ScriptType != null)
{
_previousScriptType = ScriptType;
await _module.InvokeVoidAsync("setScriptType", ScriptType);
}
if (Language.Id == "powershell")
await _module.InvokeVoidAsync("SetupFileDropHandler");
if (Language.Id == "powershell")
await PushModuleFunctionsAsync();
if (OnReady.HasDelegate)
await OnReady.InvokeAsync();
}
async Task PushModuleFunctionsAsync()
{
if (_module == null)
return;
_previousModuleFunctions = ModuleFunctions;
await _module.InvokeVoidAsync("setModuleFunctions", ModuleFunctions ?? []);
}
public async Task LayoutAsync()
{
if (_isEditorInitialized && _editor != null)
await _editor.Layout();
}
public async Task InsertText(string text)
{
var selection = await _editor.GetSelection();
var range = new BlazorMonaco.Range(
selection.StartLineNumber, selection.StartColumn,
selection.EndLineNumber, selection.EndColumn);
await _editor.ExecuteEdits("CodeInput", new List<IdentifiedSingleEditOperation>
{
new IdentifiedSingleEditOperation
{
Range = range,
Text = text,
ForceMoveMarkers = true
}
}, (List<BlazorMonaco.Selection>)null);
}
public async Task InsertSnippet(string snippetText)
{
if (_module == null)
{
await InsertText(snippetText);
return;
}
await _module.InvokeVoidAsync("insertSnippet", snippetText);
}
public async Task<bool> InsertTemplateAsync(string scriptType)
{
if (_module == null)
return false;
var template = await _module.InvokeAsync<string?>("getScriptTemplate", scriptType);
if (template == null)
return false;
await _editor.SetValue(template);
return true;
}
async Task OnChangedContent(ModelContentChangedEvent e)
{
if (ValueChanged.HasDelegate)
{
_previousValue = await _editor.GetValue();
await ValueChanged.InvokeAsync(_previousValue);
}
await RunValidationAsync();
}
async Task RunValidationAsync()
{
if (_module == null || Language.Id != "powershell")
return;
await _module.InvokeVoidAsync("validateScript");
}
}