- Filter variable completions and hover by script type so only relevant variables appear (e.g. $AllocatedKey only in KeyChange scripts) - Add inline validation warnings for package scripts missing New-Package and for variables used outside their valid script type - Extend debug console to support tools and redistributables, add stop button and elapsed time display - Disable minimap, enable bracket pair colorization and word wrap - Add snippet insertion via Monaco snippet controller with selection replacement support - Add script templates that auto-populate on new script creation - Add Variables dropdown in editor toolbar based on current script type - Change Add Script button to type-selection dropdown, auto-populate script name from type, remove Type field from editor dialog - Move Requires Admin checkbox to toolbar row, move toolbar and editor outside Form to prevent dropdown clicks from closing the modal - Set MaskClosable=false on script editor modals so Monaco autocomplete clicks don't dismiss the dialog
149 lines
5 KiB
Text
149 lines
5 KiB
Text
@using LANCommander.SDK.Enums
|
|
@using LANCommander.Server.Extensions;
|
|
@using LANCommander.Server.Models;
|
|
@inject ModalService ModalService
|
|
@inject ScriptService ScriptService
|
|
|
|
<Form @ref="@Form" Model="@Script" Layout="@FormLayout.Vertical">
|
|
<FormItem>
|
|
@foreach (var group in Snippets.Select(s => s.Group).Distinct())
|
|
{
|
|
<Dropdown>
|
|
<Overlay>
|
|
<Menu>
|
|
@foreach (var snippet in Snippets.Where(s => s.Group == group))
|
|
{
|
|
<MenuItem OnClick="() => InsertSnippet(snippet)">
|
|
@snippet.Name
|
|
</MenuItem>
|
|
}
|
|
</Menu>
|
|
</Overlay>
|
|
|
|
<ChildContent>
|
|
<Button Type="@ButtonType.Primary">@group</Button>
|
|
</ChildContent>
|
|
</Dropdown>
|
|
}
|
|
|
|
@if (ArchiveId != Guid.Empty)
|
|
{
|
|
<Button Icon="@IconType.Outline.FolderOpen" OnClick="BrowseForPath" Type="@ButtonType.Text">Browse</Button>
|
|
}
|
|
|
|
<Button Icon="@IconType.Outline.Build" OnClick="() => RegToPowerShell.Open()" Type="@ButtonType.Text">Import .reg</Button>
|
|
</FormItem>
|
|
|
|
<FormItem>
|
|
<MonacoCodeEditor @ref="Editor" @bind-Value="context.Contents" Id="@($"editor-{Id}")" ConstructionOptions="EditorConstructionOptions" OnSave="OnSave" ScriptType="@context.Type.ToString()" />
|
|
</FormItem>
|
|
|
|
<FormItem Label="Name" Required Rules=@(new[] { new FormValidationRule { Required = true } })>
|
|
<Input @bind-Value="@context.Name" />
|
|
</FormItem>
|
|
|
|
<FormItem Label="Type">
|
|
<Select @bind-Value="context.Type" TItem="ScriptType" TItemValue="ScriptType" DataSource="Enum.GetValues<ScriptType>().Where(st => AllowedTypes == null || AllowedTypes.Contains(st))">
|
|
<LabelTemplate Context="Value">@Value.GetDisplayName()</LabelTemplate>
|
|
<ItemTemplate Context="Value">@Value.GetDisplayName()</ItemTemplate>
|
|
</Select>
|
|
</FormItem>
|
|
|
|
<FormItem>
|
|
<Checkbox @bind-Checked="context.RequiresAdmin">Requires Admin</Checkbox>
|
|
</FormItem>
|
|
|
|
<FormItem Label="Description">
|
|
<TextArea @bind-Value="context.Description" MaxLength=500 ShowCount />
|
|
</FormItem>
|
|
</Form>
|
|
|
|
<RegToPowerShell @ref="RegToPowerShell" OnParsed="(text) => InsertText(text)" />
|
|
|
|
@code {
|
|
[Parameter] public Script Script { get; set; } = new();
|
|
[Parameter] public EventCallback<Script> ScriptChanged { get; set; }
|
|
[Parameter] public IEnumerable<ScriptType> AllowedTypes { get; set; }
|
|
[Parameter] public Guid ArchiveId { get; set; }
|
|
[Parameter] public EventCallback OnSave { get; set; }
|
|
|
|
Guid Id = Guid.NewGuid();
|
|
Form<Script> Form;
|
|
MonacoCodeEditor? Editor;
|
|
RegToPowerShell RegToPowerShell;
|
|
IEnumerable<Snippet> Snippets { get; set; }
|
|
|
|
StandaloneEditorConstructionOptions EditorConstructionOptions(StandaloneCodeEditor editor)
|
|
{
|
|
return new StandaloneEditorConstructionOptions
|
|
{
|
|
AutomaticLayout = true,
|
|
Language = "powershell",
|
|
Value = Script.Contents,
|
|
Theme = "vs-dark",
|
|
Minimap = new EditorMinimapOptions { Enabled = false },
|
|
BracketPairColorization = new BracketPairColorizationOptions { Enabled = true },
|
|
WordWrap = "on",
|
|
};
|
|
}
|
|
|
|
protected override void OnInitialized()
|
|
{
|
|
Snippets = ScriptService.GetSnippets();
|
|
}
|
|
|
|
async void BrowseForPath()
|
|
{
|
|
var modalOptions = new ModalOptions()
|
|
{
|
|
Title = "Choose Reference",
|
|
Maximizable = false,
|
|
DefaultMaximized = true,
|
|
Closable = true,
|
|
OkText = "Insert File Path"
|
|
};
|
|
|
|
var browserOptions = new FilePickerOptions()
|
|
{
|
|
ArchiveId = ArchiveId,
|
|
Select = true,
|
|
Multiple = false
|
|
};
|
|
|
|
var modalRef = await ModalService.CreateModalAsync<FilePickerDialog, FilePickerOptions, IEnumerable<IFileManagerEntry>>(modalOptions, browserOptions);
|
|
|
|
modalRef.OnOk = (results) =>
|
|
{
|
|
var path = results.FirstOrDefault().Path;
|
|
|
|
InsertText($"$InstallDirectory\\{path.Replace('/', '\\')}");
|
|
|
|
StateHasChanged();
|
|
return Task.CompletedTask;
|
|
};
|
|
}
|
|
|
|
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("ScriptEditor", new List<IdentifiedSingleEditOperation>()
|
|
{
|
|
new IdentifiedSingleEditOperation
|
|
{
|
|
Range = range,
|
|
Text = text,
|
|
ForceMoveMarkers = true
|
|
}
|
|
}, (List<BlazorMonaco.Selection>)null);
|
|
}
|
|
|
|
async Task InsertSnippet(Snippet snippet)
|
|
{
|
|
if (Editor != null)
|
|
await Editor.InsertSnippetAsync(snippet.Content);
|
|
}
|
|
}
|