@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 @inject NavigationManager NavigationManager @inject IDialogService Dialog

Shared Scripts

@if (_loading) { } else if (_errorMessage != null) {
@_errorMessage
} else if (_scripts.Count == 0) {

No shared scripts configured.

} else {
@if (!FilteredScripts.Any()) {

No shared scripts match the filter.

}
@foreach (var s in FilteredScripts) { var preview = s.Code.Length > 80 ? s.Code[..80] + "…" : s.Code; var paramCount = CountSchemaProperties(s.ParameterDefinitions); var returnLabel = DescribeReturnType(s.ReturnDefinition);
@s.Name
@preview
@paramCount params @(returnLabel == "void" ? "void" : $"returns {returnLabel}")
}
}
@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 string _search = ""; private ToastNotification _toast = default!; private IEnumerable FilteredScripts => string.IsNullOrWhiteSpace(_search) ? _scripts : _scripts.Where(s => (s.Name?.Contains(_search, StringComparison.OrdinalIgnoreCase) ?? false) || (s.Code?.Contains(_search, StringComparison.OrdinalIgnoreCase) ?? false)); 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 async Task DeleteScript(SharedScript script) { var confirmed = await Dialog.ConfirmAsync( "Delete Shared Script", $"Delete shared script '{script.Name}'?", danger: true); 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}"); } } /// /// Counts the parameters declared in either format: a JSON Schema object /// ({"type":"object","properties":{...}}) or the legacy flat array. /// Returns 0 for null/empty/malformed input. /// private static int CountSchemaProperties(string? json) { if (string.IsNullOrWhiteSpace(json)) return 0; try { using var doc = System.Text.Json.JsonDocument.Parse(json); var root = doc.RootElement; if (root.ValueKind == System.Text.Json.JsonValueKind.Object && root.TryGetProperty("properties", out var props) && props.ValueKind == System.Text.Json.JsonValueKind.Object) { return props.EnumerateObject().Count(); } if (root.ValueKind == System.Text.Json.JsonValueKind.Array) return root.GetArrayLength(); } catch { /* fall through */ } return 0; } /// /// Produces a short human label for a script's return type from its JSON /// Schema definition: "string", "integer", "object", "string[]", etc. /// Treats null/empty/malformed input as "void". /// private static string DescribeReturnType(string? json) { if (string.IsNullOrWhiteSpace(json)) return "void"; try { using var doc = System.Text.Json.JsonDocument.Parse(json); var root = doc.RootElement; if (root.ValueKind != System.Text.Json.JsonValueKind.Object) return "void"; if (!root.TryGetProperty("type", out var typeEl)) return "object"; var type = typeEl.GetString() ?? "object"; if (type == "array" && root.TryGetProperty("items", out var items) && items.ValueKind == System.Text.Json.JsonValueKind.Object && items.TryGetProperty("type", out var itemTypeEl)) { return $"{itemTypeEl.GetString() ?? "object"}[]"; } return type; } catch { return "void"; } } }