|
12 | 12 | // limitations under the License.
|
13 | 13 |
|
14 | 14 | using JsonCons.Utilities;
|
15 |
| -using Neuroglia.Collections; |
16 | 15 | using Neuroglia.Data;
|
17 | 16 | using Semver;
|
18 | 17 | using ServerlessWorkflow.Sdk.Models;
|
19 | 18 | using ServerlessWorkflow.Sdk.Validation;
|
20 | 19 | using Synapse.Api.Client.Services;
|
21 | 20 | using Synapse.Resources;
|
22 | 21 | using System.Text.RegularExpressions;
|
| 22 | +using System.Xml.Linq; |
23 | 23 |
|
24 | 24 | namespace Synapse.Dashboard.Pages.Workflows.Create;
|
25 | 25 |
|
@@ -102,7 +102,7 @@ IWorkflowDefinitionValidator workflowDefinitionValidator
|
102 | 102 | protected MonacoInterop MonacoInterop { get; } = monacoInterop;
|
103 | 103 |
|
104 | 104 | /// <summary>
|
105 |
| - /// Gets the service to to validate workflow defintions |
| 105 | + /// Gets the service to to validate workflow definitions |
106 | 106 | /// </summary>
|
107 | 107 | protected IWorkflowDefinitionValidator WorkflowDefinitionValidator { get; } = workflowDefinitionValidator;
|
108 | 108 |
|
@@ -218,6 +218,18 @@ public void SetName(string? name)
|
218 | 218 | });
|
219 | 219 | }
|
220 | 220 |
|
| 221 | + /// <summary> |
| 222 | + /// Sets the state's <see cref="CreateWorkflowViewState.IsNew"/> |
| 223 | + /// </summary> |
| 224 | + /// <param name="isNew">The new <see cref="CreateWorkflowViewState.IsNew"/> value</param> |
| 225 | + public void SetIsNew(bool isNew) |
| 226 | + { |
| 227 | + this.Reduce(state => state with |
| 228 | + { |
| 229 | + IsNew = isNew |
| 230 | + }); |
| 231 | + } |
| 232 | + |
221 | 233 | /// <summary>
|
222 | 234 | /// Sets the state's <see cref="CreateWorkflowViewState" /> <see cref="ProblemDetails"/>'s related data
|
223 | 235 | /// </summary>
|
@@ -415,57 +427,56 @@ public async Task SaveWorkflowDefinitionAsync()
|
415 | 427 | var @namespace = workflowDefinition!.Document.Namespace;
|
416 | 428 | var name = workflowDefinition.Document.Name;
|
417 | 429 | var version = workflowDefinition.Document.Version;
|
| 430 | + var isNew = this.Get(state => state.IsNew); |
418 | 431 | this.Reduce(s => s with
|
419 | 432 | {
|
420 | 433 | Saving = true
|
421 | 434 | });
|
422 | 435 | Workflow? workflow = null;
|
423 |
| - try |
424 |
| - { |
425 |
| - workflow = await this.Api.Workflows.GetAsync(name, @namespace); |
426 |
| - } |
427 |
| - catch |
| 436 | + if (isNew) |
428 | 437 | {
|
429 |
| - // Assume 404, might need actual handling |
430 |
| - } |
431 |
| - if (workflow == null) |
432 |
| - { |
433 |
| - workflow = await this.Api.Workflows.CreateAsync(new() |
434 |
| - { |
435 |
| - Metadata = new() |
436 |
| - { |
437 |
| - Namespace = workflowDefinition!.Document.Namespace, |
438 |
| - Name = workflowDefinition.Document.Name |
439 |
| - }, |
440 |
| - Spec = new() |
| 438 | + try { |
| 439 | + workflow = await this.Api.Workflows.CreateAsync(new() |
441 | 440 | {
|
442 |
| - Versions = [workflowDefinition] |
443 |
| - } |
444 |
| - }); |
445 |
| - } |
446 |
| - else |
447 |
| - { |
448 |
| - var updatedResource = workflow.Clone()!; |
449 |
| - var documentVersion = SemVersion.Parse(version, SemVersionStyles.Strict)!; |
450 |
| - var latestVersion = SemVersion.Parse(updatedResource.Spec.Versions.GetLatest().Document.Version, SemVersionStyles.Strict)!; |
451 |
| - if (updatedResource.Spec.Versions.Any(v => SemVersion.Parse(v.Document.Version, SemVersionStyles.Strict).CompareSortOrderTo(documentVersion) >= 0)) |
452 |
| - { |
453 |
| - this.Reduce(state => state with |
454 |
| - { |
455 |
| - ProblemTitle = "Invalid version", |
456 |
| - ProblemDetail = $"The specified version '{documentVersion}' must be strictly superior to the latest version '{latestVersion}'." |
| 441 | + Metadata = new() |
| 442 | + { |
| 443 | + Namespace = workflowDefinition!.Document.Namespace, |
| 444 | + Name = workflowDefinition.Document.Name |
| 445 | + }, |
| 446 | + Spec = new() |
| 447 | + { |
| 448 | + Versions = [workflowDefinition] |
| 449 | + } |
457 | 450 | });
|
| 451 | + this.NavigationManager.NavigateTo($"/workflows/details/{@namespace}/{name}/{version}"); |
458 | 452 | return;
|
459 | 453 | }
|
460 |
| - updatedResource.Spec.Versions.Add(workflowDefinition!); |
461 |
| - var jsonPatch = JsonPatch.FromDiff(this.JsonSerializer.SerializeToElement(workflow)!.Value, this.JsonSerializer.SerializeToElement(updatedResource)!.Value); |
462 |
| - var patch = this.JsonSerializer.Deserialize<Json.Patch.JsonPatch>(jsonPatch.RootElement); |
463 |
| - if (patch != null) |
| 454 | + catch (ProblemDetailsException ex) when (ex.Problem.Title == "Conflict" && ex.Problem.Detail != null && ex.Problem.Detail.EndsWith("already exists")) |
464 | 455 | {
|
465 |
| - var resourcePatch = new Patch(PatchType.JsonPatch, jsonPatch); |
466 |
| - await this.Api.ManageNamespaced<Workflow>().PatchAsync(name, @namespace, resourcePatch, null, this.CancellationTokenSource.Token); |
| 456 | + // the workflow exists, try to update it instead |
467 | 457 | }
|
468 | 458 | }
|
| 459 | + workflow = await this.Api.Workflows.GetAsync(name, @namespace); |
| 460 | + var updatedResource = workflow.Clone()!; |
| 461 | + var documentVersion = SemVersion.Parse(version, SemVersionStyles.Strict)!; |
| 462 | + var latestVersion = SemVersion.Parse(updatedResource.Spec.Versions.GetLatest().Document.Version, SemVersionStyles.Strict)!; |
| 463 | + if (updatedResource.Spec.Versions.Any(v => SemVersion.Parse(v.Document.Version, SemVersionStyles.Strict).CompareSortOrderTo(documentVersion) >= 0)) |
| 464 | + { |
| 465 | + this.Reduce(state => state with |
| 466 | + { |
| 467 | + ProblemTitle = "Invalid version", |
| 468 | + ProblemDetail = $"The specified version '{documentVersion}' must be strictly superior to the latest version '{latestVersion}'." |
| 469 | + }); |
| 470 | + return; |
| 471 | + } |
| 472 | + updatedResource.Spec.Versions.Add(workflowDefinition!); |
| 473 | + var jsonPatch = JsonPatch.FromDiff(this.JsonSerializer.SerializeToElement(workflow)!.Value, this.JsonSerializer.SerializeToElement(updatedResource)!.Value); |
| 474 | + var patch = this.JsonSerializer.Deserialize<Json.Patch.JsonPatch>(jsonPatch.RootElement); |
| 475 | + if (patch != null) |
| 476 | + { |
| 477 | + var resourcePatch = new Patch(PatchType.JsonPatch, jsonPatch); |
| 478 | + await this.Api.ManageNamespaced<Workflow>().PatchAsync(name, @namespace, resourcePatch, null, this.CancellationTokenSource.Token); |
| 479 | + } |
469 | 480 | this.NavigationManager.NavigateTo($"/workflows/details/{@namespace}/{name}/{version}");
|
470 | 481 | }
|
471 | 482 | catch (ProblemDetailsException ex)
|
|
0 commit comments