@page "/design/shared-scripts" @using ScadaLink.Security @using ScadaLink.Commons.Entities.Scripts @using ScadaLink.Commons.Interfaces.Repositories @using ScadaLink.TemplateEngine @attribute [Authorize(Policy = AuthorizationPolicies.RequireDesign)] @inject ITemplateEngineRepository TemplateEngineRepository @inject SharedScriptService SharedScriptService @inject AuthenticationStateProvider AuthStateProvider

Shared Scripts

@if (_loading) { } else if (_errorMessage != null) {
@_errorMessage
} else { @if (_showForm) {
@(_editingScript == null ? "New Shared Script" : $"Edit: {_editingScript.Name}")
@if (_formError != null) {
@_formError
} @if (_syntaxCheckResult != null) {
@_syntaxCheckResult
}
} @if (_scripts.Count == 0) { } @foreach (var script in _scripts) { }
ID Name Code (preview) Parameters Returns Actions
No shared scripts configured.
@script.Id @script.Name @script.Code[..Math.Min(60, script.Code.Length)]@(script.Code.Length > 60 ? "..." : "") @(script.ParameterDefinitions ?? "—") @(script.ReturnDefinition ?? "—")
}
@code { private async Task GetCurrentUserAsync() { var authState = await AuthStateProvider.GetAuthenticationStateAsync(); return authState.User.FindFirst("Username")?.Value ?? "unknown"; } private List _scripts = new(); private bool _loading = true; private string? _errorMessage; private bool _showForm; private SharedScript? _editingScript; private string _formName = string.Empty; private string _formCode = string.Empty; private string? _formParameters; private string? _formReturn; private string? _formError; private string? _syntaxCheckResult; private bool _syntaxCheckPassed; private ToastNotification _toast = default!; private ConfirmDialog _confirmDialog = default!; protected override async Task OnInitializedAsync() { await LoadDataAsync(); } private async Task LoadDataAsync() { _loading = true; _errorMessage = null; try { _scripts = (await SharedScriptService.GetAllSharedScriptsAsync()).ToList(); } catch (Exception ex) { _errorMessage = $"Failed to load shared scripts: {ex.Message}"; } _loading = false; } private void ShowAddForm() { _editingScript = null; _formName = string.Empty; _formCode = string.Empty; _formParameters = null; _formReturn = null; _formError = null; _syntaxCheckResult = null; _showForm = true; } private void EditScript(SharedScript script) { _editingScript = script; _formName = script.Name; _formCode = script.Code; _formParameters = script.ParameterDefinitions; _formReturn = script.ReturnDefinition; _formError = null; _syntaxCheckResult = null; _showForm = true; } private void CancelForm() { _showForm = false; _editingScript = null; } private void CheckCompilation() { var syntaxError = ValidateSyntaxLocally(_formCode); if (syntaxError == null) { _syntaxCheckResult = "Syntax check passed."; _syntaxCheckPassed = true; } else { _syntaxCheckResult = syntaxError; _syntaxCheckPassed = false; } } private async Task SaveScript() { _formError = null; _syntaxCheckResult = null; try { if (_editingScript != null) { var user = await GetCurrentUserAsync(); var result = await SharedScriptService.UpdateSharedScriptAsync( _editingScript.Id, _formCode, _formParameters?.Trim(), _formReturn?.Trim(), user); if (result.IsSuccess) { _showForm = false; _toast.ShowSuccess($"Script '{_editingScript.Name}' updated."); await LoadDataAsync(); } else { _formError = result.Error; } } else { var user = await GetCurrentUserAsync(); var result = await SharedScriptService.CreateSharedScriptAsync( _formName.Trim(), _formCode, _formParameters?.Trim(), _formReturn?.Trim(), user); if (result.IsSuccess) { _showForm = false; _toast.ShowSuccess($"Script '{_formName}' created."); await LoadDataAsync(); } else { _formError = result.Error; } } } catch (Exception ex) { _formError = $"Save failed: {ex.Message}"; } } /// /// Basic syntax check: balanced braces/brackets/parens. /// Mirrors the internal SharedScriptService.ValidateSyntax logic. /// private static string? ValidateSyntaxLocally(string code) { if (string.IsNullOrWhiteSpace(code)) return "Script code cannot be empty."; int brace = 0, bracket = 0, paren = 0; foreach (var ch in code) { switch (ch) { case '{': brace++; break; case '}': brace--; break; case '[': bracket++; break; case ']': bracket--; break; case '(': paren++; break; case ')': paren--; break; } if (brace < 0) return "Syntax error: unmatched closing brace '}'."; if (bracket < 0) return "Syntax error: unmatched closing bracket ']'."; if (paren < 0) return "Syntax error: unmatched closing parenthesis ')'."; } if (brace != 0) return "Syntax error: unmatched opening brace '{'."; if (bracket != 0) return "Syntax error: unmatched opening bracket '['."; if (paren != 0) return "Syntax error: unmatched opening parenthesis '('."; return null; } private async Task DeleteScript(SharedScript script) { var confirmed = await _confirmDialog.ShowAsync( $"Delete shared script '{script.Name}'?", "Delete Shared Script"); if (!confirmed) return; try { var user = await GetCurrentUserAsync(); var result = await SharedScriptService.DeleteSharedScriptAsync(script.Id, user); if (result.IsSuccess) { _toast.ShowSuccess($"Script '{script.Name}' deleted."); await LoadDataAsync(); } else { _toast.ShowError(result.Error); } } catch (Exception ex) { _toast.ShowError($"Delete failed: {ex.Message}"); } } }