diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp index e0af547..34fae01 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp @@ -15573,8 +15573,25 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() } if (VerificationDetailTextBlock != nullptr) { + const FString GeneratedLaunchRequestDetail = CachedCoachPanelState.bHasLatestGeneratedModeLaunchRequest + ? FString::Printf( + TEXT("\nGenerated request: %s @ %s | mode: %s\nSelectors: %s"), + CachedCoachPanelState.LatestGeneratedModeLaunchRequestId.IsEmpty() + ? TEXT("n/a") + : *CachedCoachPanelState.LatestGeneratedModeLaunchRequestId, + CachedCoachPanelState.LatestGeneratedModeLaunchRequestedAtUtc.IsEmpty() + ? TEXT("n/a") + : *CachedCoachPanelState.LatestGeneratedModeLaunchRequestedAtUtc, + CachedCoachPanelState.LatestGeneratedModeRuntimeModeId.IsEmpty() + ? TEXT("n/a") + : *CachedCoachPanelState.LatestGeneratedModeRuntimeModeId, + CachedCoachPanelState.LatestGeneratedModeSelectorSummaryLine.IsEmpty() + ? TEXT("none") + : *CachedCoachPanelState.LatestGeneratedModeSelectorSummaryLine + ) + : TEXT("\nGenerated request: none for active deck"); VerificationDetailTextBlock->SetText(FText::FromString(FString::Printf( - TEXT("Path: %s\nRound-trip pass: %s | Save: %s | Load: %s | Count parity: %s | State parity: %s | Integrity parity: %s\nRuns %d/%d | Learners %d/%d | Reviews %d/%d | Plans %d/%d | Queues %d/%d | History %d/%d | Notes: %s"), + TEXT("Path: %s\nRound-trip pass: %s | Save: %s | Load: %s | Count parity: %s | State parity: %s | Integrity parity: %s\nRuns %d/%d | Learners %d/%d | Reviews %d/%d | Plans %d/%d | Queues %d/%d | History %d/%d | Notes: %s%s"), CachedRepositoryRoundTripVerification.ResolvedPath.IsEmpty() ? TEXT("not yet verified") : *CachedRepositoryRoundTripVerification.ResolvedPath, @@ -15596,7 +15613,8 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() CachedRepositoryRoundTripVerification.ExpectedCoachSessionQueueCount, CachedRepositoryRoundTripVerification.LoadedCoachSessionQueueHistoryCount, CachedRepositoryRoundTripVerification.ExpectedCoachSessionQueueHistoryCount, - *VerificationNotePreview + *VerificationNotePreview, + *GeneratedLaunchRequestDetail ))); } diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp index bab4ab0..f668d23 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp @@ -106,6 +106,55 @@ namespace HyperTwistTrainingSubsystemInternal return FString::Printf(TEXT("Launch cases: %d"), CaseCount); } + FString ResolveGeneratedModeSelectorChoiceLabel( + const FHyperTwistTrainingDeck& Deck, + const FHyperTwistTrainingImportedRuntimeSelectorChoice& Choice + ) + { + const FHyperTwistTrainingImportedRuntimeSelector* MatchingSelector = + Deck.ImportedRuntimeSurface.Selectors.FindByPredicate( + [&Choice](const FHyperTwistTrainingImportedRuntimeSelector& Candidate) + { + return Candidate.SelectorId == Choice.SelectorId; + } + ); + if (MatchingSelector != nullptr && !MatchingSelector->Label.IsEmpty()) + { + return MatchingSelector->Label; + } + if (!Choice.SelectorBinding.IsEmpty()) + { + return Choice.SelectorBinding; + } + return Choice.SelectorId; + } + + FString FormatGeneratedModeSelectorSummary( + const FHyperTwistTrainingDeck& Deck, + const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest + ) + { + if (!LaunchRequest.IsStructurallyValid()) + { + return FString(); + } + + TArray SelectorParts; + for (const FHyperTwistTrainingImportedRuntimeSelectorChoice& Choice : LaunchRequest.LaunchConfig.SelectorChoices) + { + if (!Choice.IsStructurallyValid()) + { + continue; + } + + const FString Label = ResolveGeneratedModeSelectorChoiceLabel(Deck, Choice); + const FString Value = !Choice.DisplayValue.IsEmpty() ? Choice.DisplayValue : Choice.SelectedValue; + SelectorParts.Add(FString::Printf(TEXT("%s=%s"), *Label, *Value)); + } + + return SelectorParts.Num() > 0 ? FString::Join(SelectorParts, TEXT(" | ")) : TEXT("no selector choices"); + } + TArray ExtractCaseIdsFromDeck(const FHyperTwistTrainingDeck& Deck) { TArray CaseIds; @@ -1225,6 +1274,24 @@ FHyperTwistTrainingCoachPanelState UHyperTwistTrainingSubsystem::GetActiveCoachP PanelState.bRepositoryVerificationPassed = ActiveRepositoryRoundTripVerification.bDidRoundTripPass; PanelState.bRepositoryVerificationNeedsAttention = ActiveRepositoryRoundTripVerification.ResolvedPath.IsEmpty() || !ActiveRepositoryRoundTripVerification.bDidRoundTripPass; + if (HasActiveRun()) + { + FHyperTwistTrainingImportedGeneratedModeLaunchRequest LatestGeneratedModeLaunchRequest; + if (TryGetLatestGeneratedModeLaunchRequestForActiveDeck(LatestGeneratedModeLaunchRequest)) + { + PanelState.bHasLatestGeneratedModeLaunchRequest = true; + PanelState.LatestGeneratedModeLaunchRequestId = LatestGeneratedModeLaunchRequest.RequestId; + PanelState.LatestGeneratedModeLaunchRequestedAtUtc = + LatestGeneratedModeLaunchRequest.RequestedAtUtc; + PanelState.LatestGeneratedModeRuntimeModeId = + LatestGeneratedModeLaunchRequest.LaunchConfig.RuntimeModeId; + PanelState.LatestGeneratedModeSelectorSummaryLine = + HyperTwistTrainingSubsystemInternal::FormatGeneratedModeSelectorSummary( + ActiveRunState.ActiveDeck, + LatestGeneratedModeLaunchRequest + ); + } + } const FHyperTwistTrainingCoachSessionQueueStateEntry* NextRunnableEntry = HyperTwistTrainingSubsystemInternal::FindNextRunnableCoachQueueEntry(ActiveCoachSessionQueueState); diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h index bba16c9..30dc2a9 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h @@ -6723,6 +6723,21 @@ struct FHyperTwistTrainingCoachPanelState UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") FString VerificationStatusLine; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasLatestGeneratedModeLaunchRequest = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString LatestGeneratedModeLaunchRequestId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString LatestGeneratedModeLaunchRequestedAtUtc; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString LatestGeneratedModeRuntimeModeId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString LatestGeneratedModeSelectorSummaryLine; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") FString PrimaryActionLabel;