@implements IAsyncDisposable @using RobotNet10.ScriptEditor.Clients @using RobotNet10.ScriptEditor.Models @using RobotNet10.ScriptEditor.Dialogs @using Microsoft.JSInterop @using Microsoft.JSInterop.Implementation @using Microsoft.AspNetCore.Components.Web @using RobotNet10.ScriptEditor.Services @using RobotNet10.ScriptEngine.Shared @inject IJSRuntime JSRuntime @inject IScriptEngineResource ScriptResource @inject FileManagerHubClient FileManagerClient @inject ScriptManagerHubClient ScriptManagerClient @inject ScriptResourceResolver ResourceResolver @inject ScriptWorkspace Workspace @inject NavigationManager NavigationManager @inject IDialogService DialogService @using MudBlazor
@code { private int _sidebarWidth = 250; // Chiều rộng mặc định của sidebar (px) private IJSObjectReference? _jsModule; protected override void OnInitialized() { // Subscribe to edit permission revoked event FileManagerClient.EditPermissionRevoked += OnEditPermissionRevoked; } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { try { _jsModule = await JSRuntime.InvokeAsync( "import", "./_content/RobotNet10.ScriptEditor/scriptEditorResize.js"); if (_jsModule != null) { await _jsModule.InvokeVoidAsync("initializeLayout"); } await FileManagerClient.StartAsync(); await ScriptManagerClient.StartAsync(); // Request edit permission before initializing workspace // This will always succeed and force out any previous connection try { await FileManagerClient.RequestEditPermissionAsync(); // Check if we actually have edit permission (depends on state) var hasPermission = await FileManagerClient.HasEditPermissionAsync(); Workspace.IsReadOnly = !hasPermission; } catch (Exception) { // If request fails, set to read-only Workspace.IsReadOnly = true; } var references = await ResourceResolver.GetMetadataReferences(ScriptResource.Modules.ToArray(), ScriptResource.DocModules.ToArray()); var rootFolder = await FileManagerClient.GetRootFolderAsync(); Workspace.Initialize(references, ScriptResource.UsingNamespaces.ToArray(), ScriptResource.AppGlobalType, rootFolder); StateHasChanged(); } catch (JSException) { // JavaScript module chưa được load, sẽ được xử lý sau } catch (Exception) { // Ignore other exceptions but don't crash the component // Mono runtime assertions (e.g., debugger-agent) are non-fatal } } } private async void OnEditPermissionRevoked(string? userId) { // Lock the workspace when permission is revoked Workspace.IsReadOnly = true; StateHasChanged(); // Show dialog to inform user // User can only close by clicking reload button, not by clicking outside or pressing Escape var options = new DialogOptions { CloseButton = false, CloseOnEscapeKey = false, BackdropClick = false, MaxWidth = MaxWidth.Small, FullWidth = true }; var parameters = new DialogParameters { { x => x.OnReload, new Action(() => NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true)) } }; await DialogService.ShowAsync("Edit Permission Revoked", parameters, options); } public async ValueTask DisposeAsync() { // Unsubscribe from events FileManagerClient.EditPermissionRevoked -= OnEditPermissionRevoked; if (_jsModule != null) { try { await _jsModule.InvokeVoidAsync("cleanupLayout"); await _jsModule.DisposeAsync(); // Revoke edit permission before stopping connection if (FileManagerClient.IsConnected) { try { await FileManagerClient.RevokeEditPermissionAsync(); } catch (Exception) { // Ignore errors when revoking permission during dispose } } await FileManagerClient.StopAsync(); await ScriptManagerClient.StopAsync(); } catch (JSDisconnectedException) { // Ignore khi JS context đã bị disconnect } } } }