LANCommander/LANCommander.Server/UI/Components/ScriptEditorDialog.razor
Pat Hartl 20731f355a Fix certain taxonomies (tag, genre, platform) being removed from game on save
Fixes the action, custom field, multiplayer mode, and save path editors from clearing out taxonomies when saving. Also passes the Game/Server/Redistributable ID as a cascading parameter.
2025-12-08 00:51:32 -06:00

216 lines
6.6 KiB
Text

@using LANCommander.SDK.Enums
@inherits FeedbackComponent<ScriptEditorOptions, Script>
@inject ScriptService ScriptService
@inject ArchiveService ArchiveService
@inject ServerService ServerService
@inject ModalService ModalService
@inject IMessageService MessageService
@inject ILogger<ScriptEditorDialog> Logger
<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 (_archive != null)
{
<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="Save" />
</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 => Options.AllowedTypes == null || Options.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 {
Guid Id = Guid.NewGuid();
Form<Script> Form;
MonacoCodeEditor? Editor;
RegToPowerShell RegToPowerShell;
IEnumerable<Snippet> Snippets { get; set; }
Archive? _archive;
StandaloneEditorConstructionOptions EditorConstructionOptions(StandaloneCodeEditor editor)
{
return new StandaloneEditorConstructionOptions
{
AutomaticLayout = true,
Language = "powershell",
Value = Script.Contents,
Theme = "vs-dark",
};
}
Script Script = new();
protected override async Task OnInitializedAsync()
{
if (Options.ScriptId != Guid.Empty)
Script = await ScriptService.GetAsync(Options.ScriptId);
else if (Options.GameId != Guid.Empty)
{
Script = new Script
{
GameId = Options.GameId
};
_archive = await ArchiveService.GetLatestArchiveAsync(a => a.GameId == Options.GameId);
}
else if (Options.RedistributableId != Guid.Empty)
{
Script = new Script()
{
RedistributableId = Options.RedistributableId
};
_archive = await ArchiveService.GetLatestArchiveAsync(a => a.RedistributableId == Options.RedistributableId);
}
else if (Options.ServerId != Guid.Empty)
{
Script = new Script()
{
ServerId = Options.ServerId
};
var server = await ServerService.GetAsync(Options.ServerId.Value);
_archive = await ArchiveService.GetLatestArchiveAsync(a => a.GameId == server.GameId);
}
Snippets = ScriptService.GetSnippets();
}
public override async Task OnFeedbackOkAsync(ModalClosingEventArgs args)
{
var success = await Save();
if (success)
await base.OkCancelRefWithResult!.OnOk(Script);
else
args.Reject();
}
async Task<bool> Save()
{
try
{
if (Form.Validate())
{
if (Script.Id == Guid.Empty)
Script = await ScriptService.AddAsync(Script);
else
Script = await ScriptService.UpdateAsync(Script);
MessageService.Success("Script saved!");
return true;
}
return false;
}
catch (Exception ex)
{
MessageService.Error("Script could not be saved!");
Logger.LogError(ex, "Script could not be saved!");
return false;
}
}
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 = _archive?.Id ?? Guid.Empty,
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 line = await Editor.GetPosition();
var range = new BlazorMonaco.Range(line.LineNumber, 1, line.LineNumber, 1);
var currentSelections = await Editor.GetSelections();
await Editor.ExecuteEdits("ScriptEditor", new List<IdentifiedSingleEditOperation>()
{
new IdentifiedSingleEditOperation
{
Range = range,
Text = text,
ForceMoveMarkers = true
}
}, currentSelections);
}
async Task InsertSnippet(Snippet snippet)
{
await InsertText(snippet.Content);
}
}