diff --git a/src/dashboard/Synapse.Dashboard/Components/DocumentDetails/Store.cs b/src/dashboard/Synapse.Dashboard/Components/DocumentDetails/Store.cs index a577475a..bd329743 100644 --- a/src/dashboard/Synapse.Dashboard/Components/DocumentDetails/Store.cs +++ b/src/dashboard/Synapse.Dashboard/Components/DocumentDetails/Store.cs @@ -33,6 +33,7 @@ public class DocumentDetailsStore(ILogger logger, ISynapse TextModel? _textModel; readonly string _textModelUri = monacoEditorHelper.GetResourceUri(); + private bool _hasTextEditorInitialized = false; /// /// Gets the service used to perform logging @@ -291,7 +292,7 @@ public async Task LoadReferencedDocumentAsync() /// public async Task ToggleTextBasedEditorLanguageAsync(string _) { - await this.OnTextBasedEditorInitAsync(); + await this.InitializeTextBasedEditorAsync(); } /// @@ -300,6 +301,17 @@ public async Task ToggleTextBasedEditorLanguageAsync(string _) /// public async Task OnTextBasedEditorInitAsync() { + this._hasTextEditorInitialized = true; + await this.InitializeTextBasedEditorAsync(); + } + + /// + /// Initializes the text editor + /// + /// + public async Task InitializeTextBasedEditorAsync() + { + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; await this.SetTextBasedEditorLanguageAsync(); await this.SetTextEditorValueAsync(); } @@ -313,10 +325,10 @@ public async Task SetTextBasedEditorLanguageAsync() try { var language = this.MonacoEditorHelper.PreferredLanguage; - if (this.TextEditor != null) + if (this.TextEditor != null && this._hasTextEditorInitialized) { this._textModel = await Global.GetModel(this.JSRuntime, this._textModelUri); - this._textModel ??= await Global.CreateModel(this.JSRuntime, "", language, this._textModelUri); + this._textModel ??= await Global.CreateModel(this.JSRuntime, " ", language, this._textModelUri); await Global.SetModelLanguage(this.JSRuntime, this._textModel, language); await this.TextEditor!.SetModel(this._textModel); } @@ -335,7 +347,7 @@ async Task SetTextEditorValueAsync() { var document = this.Get(state => state.DocumentJson); var language = this.MonacoEditorHelper.PreferredLanguage; - if (this.TextEditor != null && !string.IsNullOrWhiteSpace(document)) + if (this.TextEditor != null && !string.IsNullOrWhiteSpace(document) && this._hasTextEditorInitialized) { try { @@ -359,7 +371,7 @@ async Task SetTextEditorValueAsync() /// A awaitable task public async Task OnCopyToClipboard() { - if (this.TextEditor == null) return; + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; var text = await this.TextEditor.GetValue(); if (string.IsNullOrWhiteSpace(text)) return; try @@ -408,7 +420,7 @@ public override Task InitializeAsync() /// protected async Task OnPreferredThemeChangedAsync(string newTheme) { - if (this.TextEditor != null) + if (this.TextEditor != null && this._hasTextEditorInitialized) { await this.TextEditor.UpdateOptions(new EditorUpdateOptions() { Theme = newTheme }); } @@ -430,7 +442,7 @@ protected override void Dispose(bool disposing) this._textModel.DisposeModel(); this._textModel = null; } - if (this.TextEditor != null) + if (this.TextEditor != null && this._hasTextEditorInitialized) { this.TextEditor.Dispose(); this.TextEditor = null; diff --git a/src/dashboard/Synapse.Dashboard/Components/MonacoEditor/Store.cs b/src/dashboard/Synapse.Dashboard/Components/MonacoEditor/Store.cs index 2c2a8e57..455fba17 100644 --- a/src/dashboard/Synapse.Dashboard/Components/MonacoEditor/Store.cs +++ b/src/dashboard/Synapse.Dashboard/Components/MonacoEditor/Store.cs @@ -32,6 +32,7 @@ public class MonacoEditorStore(ILogger logger, ISynapseApiCli TextModel? _textModel; string _textModelUri = monacoEditorHelper.GetResourceUri(); + private bool _hasTextEditorInitialized = false; /// /// Gets the service used to perform logging @@ -204,18 +205,12 @@ public void SetTexModelName(string modelName) /// public async Task ToggleTextBasedEditorLanguageAsync(string _) { - if (this.TextEditor == null) - { - return; - } + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; var language = this.MonacoEditorHelper.PreferredLanguage; try { var document = await this.TextEditor.GetValue(); - if (document == null) - { - return; - } + if (document == null) return; document = language == PreferredLanguage.YAML ? this.YamlSerializer.ConvertFromJson(document) : this.YamlSerializer.ConvertToJson(document); @@ -223,7 +218,7 @@ public async Task ToggleTextBasedEditorLanguageAsync(string _) { DocumentText = document }); - await this.OnTextBasedEditorInitAsync(); + await this.InitializeTextBasedEditorAsync(); } catch (Exception ex) { @@ -238,6 +233,17 @@ public async Task ToggleTextBasedEditorLanguageAsync(string _) /// public async Task OnTextBasedEditorInitAsync() { + this._hasTextEditorInitialized = true; + await this.InitializeTextBasedEditorAsync(); + } + + /// + /// Initializes the text editor + /// + /// + public async Task InitializeTextBasedEditorAsync() + { + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; await this.SetTextBasedEditorLanguageAsync(); await this.SetTextEditorValueAsync(); } @@ -251,7 +257,7 @@ public async Task SetTextBasedEditorLanguageAsync() try { var language = this.MonacoEditorHelper.PreferredLanguage; - if (this.TextEditor != null) + if (this.TextEditor != null && this._hasTextEditorInitialized) { this._textModel = await Global.GetModel(this.JSRuntime, this._textModelUri); this._textModel ??= await Global.CreateModel(this.JSRuntime, "", language, this._textModelUri); @@ -272,7 +278,7 @@ public async Task SetTextBasedEditorLanguageAsync() async Task SetTextEditorValueAsync() { var document = this.Get(state => state.DocumentText); - if (this.TextEditor != null && !string.IsNullOrWhiteSpace(document)) + if (this.TextEditor != null && !string.IsNullOrWhiteSpace(document) && this._hasTextEditorInitialized) { await this.TextEditor.SetValue(document); } @@ -284,7 +290,7 @@ async Task SetTextEditorValueAsync() /// A awaitable task public async Task OnCopyToClipboard() { - if (this.TextEditor == null) return; + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; var text = await this.TextEditor.GetValue(); if (string.IsNullOrWhiteSpace(text)) return; try @@ -321,7 +327,7 @@ public override Task InitializeAsync() /// protected async Task OnPreferredThemeChangedAsync(string newTheme) { - if (this.TextEditor != null) + if (this.TextEditor != null && this._hasTextEditorInitialized) { await this.TextEditor.UpdateOptions(new EditorUpdateOptions() { Theme = newTheme }); } diff --git a/src/dashboard/Synapse.Dashboard/Pages/Functions/Create/Store.cs b/src/dashboard/Synapse.Dashboard/Pages/Functions/Create/Store.cs index 273ec61b..bbab2ce8 100644 --- a/src/dashboard/Synapse.Dashboard/Pages/Functions/Create/Store.cs +++ b/src/dashboard/Synapse.Dashboard/Pages/Functions/Create/Store.cs @@ -16,7 +16,6 @@ using Semver; using ServerlessWorkflow.Sdk.Models; using Synapse.Api.Client.Services; -using Synapse.Dashboard.Pages.Workflows.Create; using Synapse.Resources; namespace Synapse.Dashboard.Pages.Functions.Create; @@ -51,6 +50,7 @@ MonacoInterop monacoInterop private string _textModelUri = string.Empty; private bool _disposed = false; private bool _processingVersion = false; + private bool _hasTextEditorInitialized = false; /// /// Gets the service used to perform logging @@ -292,7 +292,7 @@ public async Task ToggleTextBasedEditorLanguageAsync(string _) { FunctionText = document }); - await this.OnTextBasedEditorInitAsync(); + await this.InitializeTextBasedEditorAsync(); } catch (Exception ex) { @@ -307,6 +307,17 @@ public async Task ToggleTextBasedEditorLanguageAsync(string _) /// public async Task OnTextBasedEditorInitAsync() { + this._hasTextEditorInitialized = true; + await this.InitializeTextBasedEditorAsync(); + } + + /// + /// Initializes the text editor + /// + /// + public async Task InitializeTextBasedEditorAsync() + { + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; await this.SetTextBasedEditorLanguageAsync(); await this.SetTextEditorValueAsync(); } @@ -317,10 +328,7 @@ public async Task OnTextBasedEditorInitAsync() /// public async Task SetTextBasedEditorLanguageAsync() { - if (this.TextEditor == null) - { - return; - } + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; try { var language = this.MonacoEditorHelper.PreferredLanguage; @@ -342,10 +350,7 @@ public async Task SetTextBasedEditorLanguageAsync() async Task SetTextEditorValueAsync() { var document = this.Get(state => state.FunctionText); - if (this.TextEditor == null || string.IsNullOrWhiteSpace(document)) - { - return; - } + if (this.TextEditor == null || string.IsNullOrWhiteSpace(document) || !this._hasTextEditorInitialized) return; try { await this.TextEditor.SetValue(document); @@ -365,7 +370,7 @@ async Task SetTextEditorValueAsync() /// An awaitable task public async Task OnDidChangeModelContent(ModelContentChangedEvent e) { - if (this.TextEditor == null) return; + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; var document = await this.TextEditor.GetValue(); this.Reduce(state => state with { @@ -379,7 +384,7 @@ public async Task OnDidChangeModelContent(ModelContentChangedEvent e) /// A new awaitable public async Task SaveCustomFunctionAsync() { - if (this.TextEditor == null) + if (this.TextEditor == null || !this._hasTextEditorInitialized) { this.Reduce(state => state with { @@ -513,6 +518,10 @@ public async Task SaveCustomFunctionAsync() /// public override async Task InitializeAsync() { + this.Loading.Where(loading => loading == true).Subscribe(loading => + { + this._hasTextEditorInitialized = false; // reset text editor state when loading + }, token: this.CancellationTokenSource.Token); this.Function.SubscribeAsync(async definition => { string document = string.Empty; if (definition != null) @@ -543,7 +552,7 @@ await this.GetCustomFunctionAsync(name!), /// protected async Task OnPreferredThemeChangedAsync(string newTheme) { - if (this.TextEditor != null) + if (this.TextEditor != null && this._hasTextEditorInitialized) { await this.TextEditor.UpdateOptions(new EditorUpdateOptions() { Theme = newTheme }); } diff --git a/src/dashboard/Synapse.Dashboard/Pages/Functions/Create/View.razor b/src/dashboard/Synapse.Dashboard/Pages/Functions/Create/View.razor index a1618b61..bb06dc9f 100644 --- a/src/dashboard/Synapse.Dashboard/Pages/Functions/Create/View.razor +++ b/src/dashboard/Synapse.Dashboard/Pages/Functions/Create/View.razor @@ -92,7 +92,7 @@ else string? version; string? chosenName; string? nameInputValue; - bool loading; + bool loading = true; bool saving; ProblemDetails? problemDetails = null; diff --git a/src/dashboard/Synapse.Dashboard/Pages/Workflows/Create/Store.cs b/src/dashboard/Synapse.Dashboard/Pages/Workflows/Create/Store.cs index 4161800e..d849a137 100644 --- a/src/dashboard/Synapse.Dashboard/Pages/Workflows/Create/Store.cs +++ b/src/dashboard/Synapse.Dashboard/Pages/Workflows/Create/Store.cs @@ -54,6 +54,7 @@ IWorkflowDefinitionValidator workflowDefinitionValidator private string _textModelUri = string.Empty; private bool _disposed = false; private bool _processingVersion = false; + private bool _hasTextEditorInitialized = false; /// /// Gets the service used to perform logging @@ -108,7 +109,7 @@ IWorkflowDefinitionValidator workflowDefinitionValidator /// /// The provider function /// - public Func StandaloneEditorConstructionOptions = monacoEditorHelper.GetStandaloneEditorConstructionOptions(string.Empty, false, monacoEditorHelper.PreferredLanguage); + public Func StandaloneEditorConstructionOptions = monacoEditorHelper.GetStandaloneEditorConstructionOptions(" ", false, monacoEditorHelper.PreferredLanguage); /// /// The reference @@ -276,18 +277,12 @@ public async Task GetWorkflowDefinitionAsync(string @namespace, string name) /// public async Task ToggleTextBasedEditorLanguageAsync(string _) { - if (this.TextEditor == null) - { - return; - } + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; var language = this.MonacoEditorHelper.PreferredLanguage; try { var document = await this.TextEditor.GetValue(); - if (document == null) - { - return; - } + if (document == null) return; document = language == PreferredLanguage.YAML ? this.YamlSerializer.ConvertFromJson(document) : this.YamlSerializer.ConvertToJson(document); @@ -295,7 +290,7 @@ public async Task ToggleTextBasedEditorLanguageAsync(string _) { WorkflowDefinitionText = document }); - await this.OnTextBasedEditorInitAsync(); + await this.InitializeTextBasedEditorAsync(); } catch (Exception ex) { @@ -310,6 +305,17 @@ public async Task ToggleTextBasedEditorLanguageAsync(string _) /// public async Task OnTextBasedEditorInitAsync() { + this._hasTextEditorInitialized = true; + await this.InitializeTextBasedEditorAsync(); + } + + /// + /// Initializes the text editor + /// + /// + public async Task InitializeTextBasedEditorAsync() + { + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; await this.SetTextBasedEditorLanguageAsync(); await this.SetTextEditorValueAsync(); } @@ -320,10 +326,7 @@ public async Task OnTextBasedEditorInitAsync() /// public async Task SetTextBasedEditorLanguageAsync() { - if (this.TextEditor == null) - { - return; - } + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; try { var language = this.MonacoEditorHelper.PreferredLanguage; @@ -345,10 +348,7 @@ public async Task SetTextBasedEditorLanguageAsync() async Task SetTextEditorValueAsync() { var document = this.Get(state => state.WorkflowDefinitionText); - if (this.TextEditor == null || string.IsNullOrWhiteSpace(document)) - { - return; - } + if (this.TextEditor == null || string.IsNullOrWhiteSpace(document) || !this._hasTextEditorInitialized) return; try { await this.TextEditor.SetValue(document); @@ -368,8 +368,7 @@ async Task SetTextEditorValueAsync() /// An awaitable task public async Task OnDidChangeModelContent(ModelContentChangedEvent e) { - if (this.TextEditor == null) return; - + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; var document = await this.TextEditor.GetValue(); this.Reduce(state => state with { @@ -383,7 +382,7 @@ public async Task OnDidChangeModelContent(ModelContentChangedEvent e) /// A new awaitable public async Task SaveWorkflowDefinitionAsync() { - if (this.TextEditor == null) + if (this.TextEditor == null || !this._hasTextEditorInitialized) { this.Reduce(state => state with { @@ -535,6 +534,10 @@ public async Task SaveWorkflowDefinitionAsync() /// public override async Task InitializeAsync() { + this.Loading.Where(loading => loading == true).Subscribe(loading => + { + this._hasTextEditorInitialized = false; // reset text editor state when loading + }, token: this.CancellationTokenSource.Token); this.WorkflowDefinition.SubscribeAsync(async definition => { string document = ""; if (definition != null) @@ -547,7 +550,7 @@ public override async Task InitializeAsync() { WorkflowDefinitionText = document }); - await this.OnTextBasedEditorInitAsync(); + await this.InitializeTextBasedEditorAsync(); }, cancellationToken: this.CancellationTokenSource.Token); Observable.CombineLatest( this.Namespace.Where(ns => !string.IsNullOrWhiteSpace(ns)), @@ -617,7 +620,7 @@ protected async Task SetValidationSchema(string? version = null) /// protected async Task OnPreferredThemeChangedAsync(string newTheme) { - if (this.TextEditor != null) + if (this.TextEditor != null && this._hasTextEditorInitialized) { await this.TextEditor.UpdateOptions(new EditorUpdateOptions() { Theme = newTheme }); } diff --git a/src/dashboard/Synapse.Dashboard/Pages/Workflows/Create/View.razor b/src/dashboard/Synapse.Dashboard/Pages/Workflows/Create/View.razor index adca02fe..72454b1d 100644 --- a/src/dashboard/Synapse.Dashboard/Pages/Workflows/Create/View.razor +++ b/src/dashboard/Synapse.Dashboard/Pages/Workflows/Create/View.razor @@ -37,10 +37,10 @@ else + ConstructionOptions="Store.StandaloneEditorConstructionOptions" + OnDidInit="Store.OnTextBasedEditorInitAsync" + OnDidChangeModelContent="Store.OnDidChangeModelContent" + CssClass="h-100" /> @if (problemDetails != null) {
@@ -80,7 +80,7 @@ else string? ns; string? name; - bool loading; + bool loading = true; bool saving; private ProblemDetails? problemDetails = null; diff --git a/src/dashboard/Synapse.Dashboard/Pages/Workflows/Details/Store.cs b/src/dashboard/Synapse.Dashboard/Pages/Workflows/Details/Store.cs index 33f012ef..b0b1c372 100644 --- a/src/dashboard/Synapse.Dashboard/Pages/Workflows/Details/Store.cs +++ b/src/dashboard/Synapse.Dashboard/Pages/Workflows/Details/Store.cs @@ -47,6 +47,7 @@ ToastService toastService private TextModel? _textModel = null; private bool _disposed; + private bool _hasTextEditorInitialized = false; /// /// Gets the service used for JS interop @@ -275,15 +276,26 @@ public async Task GetWorkflowAsync(string ns, string name) /// A awaitable task public async Task ToggleTextBasedEditorLanguageAsync(string _) { - await this.OnTextBasedEditorInitAsync(); + await this.InitializeTextBasedEditorAsync(); } /// /// Handles initialization of the text editor /// - /// A awaitable task + /// public async Task OnTextBasedEditorInitAsync() { + this._hasTextEditorInitialized = true; + await this.InitializeTextBasedEditorAsync(); + } + + /// + /// Initializes the text editor + /// + /// + public async Task InitializeTextBasedEditorAsync() + { + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; await this.SetTextBasedEditorLanguageAsync(); await this.SetTextEditorValueAsync(); } @@ -297,7 +309,7 @@ public async Task SetTextBasedEditorLanguageAsync() try { var language = this.MonacoEditorHelper.PreferredLanguage; - if (this.TextEditor != null) + if (this.TextEditor != null && this._hasTextEditorInitialized) { if (this._textModel != null) { @@ -325,7 +337,7 @@ public async Task SetTextBasedEditorLanguageAsync() /// A awaitable task public async Task OnCopyToClipboard() { - if (this.TextEditor == null) return; + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; var text = await this.TextEditor.GetValue(); if (string.IsNullOrWhiteSpace(text)) return; try @@ -510,7 +522,7 @@ public async Task DeleteWorkflowInstanceAsync(WorkflowInstance workflowInstance) public async Task SelectNodeInEditor(GraphEventArgs e) { if (e.GraphElement == null) return; - if (this.TextEditor == null) return; + if (this.TextEditor == null || !this._hasTextEditorInitialized) return; var source = await this.TextEditor.GetValue(); var pointer = e.GraphElement.Id; var language = this.MonacoEditorHelper.PreferredLanguage; @@ -564,7 +576,7 @@ public override async Task InitializeAsync() /// protected async Task OnPreferredThemeChangedAsync(string newTheme) { - if (this.TextEditor != null) + if (this.TextEditor != null && this._hasTextEditorInitialized) { await this.TextEditor.UpdateOptions(new EditorUpdateOptions() { Theme = newTheme }); } diff --git a/src/dashboard/Synapse.Dashboard/Services/SpecificationSchemaManager.cs b/src/dashboard/Synapse.Dashboard/Services/SpecificationSchemaManager.cs index 928132ee..9160b54c 100644 --- a/src/dashboard/Synapse.Dashboard/Services/SpecificationSchemaManager.cs +++ b/src/dashboard/Synapse.Dashboard/Services/SpecificationSchemaManager.cs @@ -50,7 +50,7 @@ public async Task GetLatestVersion() } /// - /// Gets the specification's JSON schema for the specificed version + /// Gets the specification's JSON schema for the specified version /// /// The version to get the schema for /// A awaitable task