178 lines
6.3 KiB
Plaintext
178 lines
6.3 KiB
Plaintext
@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
|
|
|
|
<div class="script-editor-container">
|
|
<!-- Phần 1: Sidebar (có thể resize ngang) -->
|
|
<div class="sidebar-container" style="width: @(_sidebarWidth)px;">
|
|
<div class="sidebar-content">
|
|
<FileExplorer />
|
|
<VariableManager />
|
|
<TaskManager />
|
|
<MissionManager />
|
|
</div>
|
|
<div class="sidebar-resizer"></div>
|
|
</div>
|
|
|
|
<!-- Phần 2 và 3: Editor Area và Console Panel (sắp xếp dọc) -->
|
|
<div class="editor-console-container">
|
|
<!-- Phần 2: Editor Area -->
|
|
<div class="editor-area" id="editor-area">
|
|
<div class="editor-area-content">
|
|
<Editor />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Resizer giữa Editor và Console -->
|
|
<div class="vertical-resizer"></div>
|
|
|
|
<!-- Phần 3: Console Panel (có thể resize dọc) -->
|
|
<div class="console-panel" id="console-panel">
|
|
<Console />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<MudOverlay Visible="@(!Workspace.IsInitialized)" DarkBackground Modal Absolute AutoClose="false">
|
|
<MudProgressCircular Color="Color.Primary" Indeterminate="true" />
|
|
</MudOverlay>
|
|
|
|
@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<IJSObjectReference>(
|
|
"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<PermissionRevokedDialog>
|
|
{
|
|
{ x => x.OnReload, new Action(() => NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true)) }
|
|
};
|
|
|
|
await DialogService.ShowAsync<PermissionRevokedDialog>("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
|
|
}
|
|
}
|
|
}
|
|
}
|