Files
UnrealEngine/Engine/Source/Editor/StorageServerWidgets/Private/SZenServiceStatus.cpp
2025-05-18 13:04:45 +08:00

424 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SZenServiceStatus.h"
#include "Experimental/ZenServerInterface.h"
#include "Internationalization/FastDecimalFormat.h"
#include "Math/BasicMathExpressionEvaluator.h"
#include "Math/UnitConversion.h"
#include "Misc/ExpressionParser.h"
#include "Styling/StyleColors.h"
#include "Widgets/Images/SImage.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Input/SHyperlink.h"
#include "Widgets/Layout/SGridPanel.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/Text/STextBlock.h"
#define LOCTEXT_NAMESPACE "ZenDashboard"
void SZenServiceStatus::Construct(const FArguments& InArgs)
{
ZenServiceInstance = InArgs._ZenServiceInstance;
this->ChildSlot
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0, 0, 0, 0)
.Expose(GridSlot)
[
GetGridPanel()
]
];
UpdateState(0.0, 0.0);
RegisterActiveTimer(0.5f, FWidgetActiveTimerDelegate::CreateSP(this, &SZenServiceStatus::UpdateState));
}
EActiveTimerReturnType SZenServiceStatus::UpdateState(double InCurrentTime, float InDeltaTime)
{
uint32 LastStateIndex = ActiveStateIndex.load(std::memory_order_relaxed);
uint32 NextStateIndex = (LastStateIndex + 1)%NumState;
FState& NextState = State[NextStateIndex];
NextState.bGotRunContext = UE::Zen::TryGetLocalServiceRunContext(NextState.RunContext);
NextState.Version = UE::Zen::GetLocalServiceInstallVersion(false);
if (NextState.bGotRunContext)
{
NextState.bIsRunning = UE::Zen::IsLocalServiceRunning(*NextState.RunContext.GetDataPath(), &NextState.LocalPort);
}
NextState.GCStatus = UE::Zen::FGCStatus{};
NextState.bHaveStats = false;
if (NextState.bIsRunning)
{
if (TSharedPtr<UE::Zen::FZenServiceInstance> ServiceInstance = ZenServiceInstance.Get())
{
ServiceInstance->GetGCStatus(NextState.GCStatus);
if (ServiceInstance->GetCacheStats(NextState.ZenCacheStats) && ServiceInstance->GetProjectStats(NextState.ZenProjectStats))
{
NextState.bHaveStats = true;
}
}
}
ActiveStateIndex.compare_exchange_weak(LastStateIndex, NextStateIndex, std::memory_order_relaxed);
return EActiveTimerReturnType::Continue;
}
FReply SZenServiceStatus::ExploreDataPath_OnClicked()
{
const FState& CurrentState = GetCurrentState();
if (CurrentState.bGotRunContext)
{
FString FullPath(FPaths::ConvertRelativePathToFull(CurrentState.RunContext.GetDataPath()));
FPlatformProcess::ExploreFolder(*FullPath);
return FReply::Handled();
}
return FReply::Unhandled();
}
FReply SZenServiceStatus::ExploreExecutablePath_OnClicked()
{
const FState& CurrentState = GetCurrentState();
if (CurrentState.bGotRunContext)
{
FString FullPath(FPaths::ConvertRelativePathToFull(FPaths::GetPath(CurrentState.RunContext.GetExecutable())));
FPlatformProcess::ExploreFolder(*FullPath);
return FReply::Handled();
}
return FReply::Unhandled();
}
const SZenServiceStatus::FState& SZenServiceStatus::GetCurrentState() const
{
return State[ActiveStateIndex.load(std::memory_order_relaxed)];
}
TSharedRef<SWidget> SZenServiceStatus::GetGridPanel()
{
TSharedRef<SGridPanel> Panel = SNew(SGridPanel);
const static FNumberFormattingOptions SingleDecimalFormatting = FNumberFormattingOptions()
.SetUseGrouping(true)
.SetMinimumFractionalDigits(1)
.SetMaximumFractionalDigits(1);
int32 Row = 0;
const float RowMargin = 0.0f;
const float ColumnMargin = 10.0f;
const FSlateColor TitleColor = FStyleColors::AccentWhite;
const FSlateFontInfo TitleFont = FCoreStyle::GetDefaultFontStyle("Bold", 10);
Panel->AddSlot(0, Row)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.ColorAndOpacity(TitleColor)
.Font(TitleFont)
.Text(LOCTEXT("ServiceStatus_Status", "Status"))
];
Panel->AddSlot(1, Row)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.Text_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
FText ServiceStatus = LOCTEXT("ServiceStatus_NotInstalled", "Not installed");
if (CurrentState.bGotRunContext)
{
if (CurrentState.bIsRunning && (CurrentState.LocalPort != 0))
{
ServiceStatus = LOCTEXT("ServiceStatus_Running", "Running");
}
else
{
ServiceStatus = LOCTEXT("ServiceStatus_Stopped", "Stopped");
}
}
return ServiceStatus;
})
];
++Row;
Panel->AddSlot(0, Row)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.ColorAndOpacity(TitleColor)
.Font(TitleFont)
.Text(LOCTEXT("ServiceStatus_Version", "Version"))
];
Panel->AddSlot(1, Row)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.Text_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
return FText::FromString(CurrentState.Version);
})
];
++Row;
Panel->AddSlot(0, Row)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.ColorAndOpacity(TitleColor)
.Font(TitleFont)
.Text(LOCTEXT("ServiceStatus_Port", "Port"))
];
Panel->AddSlot(1, Row)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.Text_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
return CurrentState.LocalPort == 0 ? LOCTEXT("ServiceStatus_NoPortValue", "-") : FText::AsNumber(CurrentState.LocalPort, &FNumberFormattingOptions::DefaultNoGrouping());
})
];
++Row;
Panel->AddSlot(0, Row)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.ColorAndOpacity(TitleColor)
.Font(TitleFont)
.Text(LOCTEXT("ServiceStatus_Browse", "Browse"))
];
Panel->AddSlot(1, Row)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.MaxWidth(350)
.Padding(FMargin(ColumnMargin, RowMargin))
.VAlign(VAlign_Bottom)
[
SNew(SHyperlink)
.Style(FAppStyle::Get(), TEXT("NavigationHyperlink"))
.Text_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
FText BrowseText = LOCTEXT("ServiceStatus_NoBrowseValue", "-");
if (CurrentState.bGotRunContext && CurrentState.bIsRunning && (CurrentState.LocalPort != 0))
{
BrowseText = FText::Format(LOCTEXT("ServiceStatus_BrowseLink", "http://localhost:{0}/dashboard/"),
FText::AsNumber(CurrentState.LocalPort, &FNumberFormattingOptions::DefaultNoGrouping()));
}
return BrowseText;
})
.OnNavigate_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
if (CurrentState.bGotRunContext && CurrentState.bIsRunning && (CurrentState.LocalPort != 0))
{
FPlatformProcess::LaunchURL(*FString::Printf(TEXT("http://localhost:%d/dashboard/"), CurrentState.LocalPort), nullptr, nullptr);
}
})
]
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Bottom)
[
SNew(SButton)
.ButtonStyle(&FAppStyle::Get().GetWidgetStyle<FButtonStyle>("SimpleButton"))
.ToolTipText(LOCTEXT("ServiceStatus_BrowseToolTip", "Browse the contents of zenserver in your web browser"))
.IsEnabled_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
return CurrentState.bGotRunContext && CurrentState.bIsRunning && (CurrentState.LocalPort != 0);
})
.OnClicked_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
if (CurrentState.bGotRunContext && CurrentState.bIsRunning && (CurrentState.LocalPort != 0))
{
FPlatformProcess::LaunchURL(*FString::Printf(TEXT("http://localhost:%d/dashboard/"), CurrentState.LocalPort), nullptr, nullptr);
return FReply::Handled();
}
return FReply::Unhandled();
})
[
SNew(SImage)
.Image(FAppStyle::Get().GetBrush("Zen.WebBrowser"))
.ColorAndOpacity(FSlateColor::UseForeground())
]
]
];
++Row;
Panel->AddSlot(0, Row)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.ColorAndOpacity(TitleColor)
.Font(TitleFont)
.Text(LOCTEXT("ServiceStatus_GCStatus", "GC Status"))
];
Panel->AddSlot(1, Row)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.Text_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
return CurrentState.LocalPort == 0 ? LOCTEXT("ServiceStatus_NoGCStatusValue", "-") : FText::FromString(CurrentState.GCStatus.Description);
})
];
++Row;
Panel->AddSlot(0, Row)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.ColorAndOpacity(TitleColor)
.Font(TitleFont)
.Text(LOCTEXT("ServiceStatus_DiskSpace", "Disk Space"))
];
Panel->AddSlot(1, Row)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.Text_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
const uint64 TotalDiskSpace = uint64(CurrentState.ZenCacheStats.General.Size.Disk) + uint64(CurrentState.ZenProjectStats.General.Size.Disk) + uint64(CurrentState.ZenCacheStats.CID.Size.Total);
return CurrentState.bHaveStats ? FText::AsMemory(TotalDiskSpace, (TotalDiskSpace > 1024) ? &SingleDecimalFormatting : nullptr, nullptr, EMemoryUnitStandard::IEC) : LOCTEXT("UnavailableValue", "-");
})
];
++Row;
Panel->AddSlot(0, Row)
.VAlign(VAlign_Bottom)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.ColorAndOpacity(TitleColor)
.Font(TitleFont)
.Text(LOCTEXT("ServiceStatus_DataPath", "Data path"))
];
Panel->AddSlot(1, Row)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.MaxWidth(350)
.VAlign(VAlign_Bottom)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.OverflowPolicy(ETextOverflowPolicy::MiddleEllipsis)
.Text_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
return CurrentState.bGotRunContext ? FText::FromString(CurrentState.RunContext.GetDataPath()) : LOCTEXT("ServiceStatus_NoDataPathValue", "-");
})
]
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Bottom)
[
SNew(SButton)
.ButtonStyle(&FAppStyle::Get().GetWidgetStyle<FButtonStyle>("SimpleButton"))
.ToolTipText(LOCTEXT("ExploreDataPathButtonToolTip", "Explore the Data Path"))
.IsEnabled_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
return CurrentState.bGotRunContext;
})
.OnClicked(this, &SZenServiceStatus::ExploreDataPath_OnClicked)
[
SNew(SImage)
.Image(FAppStyle::Get().GetBrush("Zen.FolderExplore"))
.ColorAndOpacity(FSlateColor::UseForeground())
]
]
];
++Row;
Panel->AddSlot(0, Row)
.VAlign(VAlign_Bottom)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.ColorAndOpacity(TitleColor)
.Font(TitleFont)
.Text(LOCTEXT("ServiceStatus_ExecutablePath", "Executable path"))
];
Panel->AddSlot(1, Row)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
//.MaxWidth(350)
.VAlign(VAlign_Bottom)
[
SNew(STextBlock)
.Margin(FMargin(ColumnMargin, RowMargin))
.OverflowPolicy(ETextOverflowPolicy::MiddleEllipsis)
.Text_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
return CurrentState.bGotRunContext ? FText::FromString(FPaths::GetPath(CurrentState.RunContext.GetExecutable())) : LOCTEXT("ServiceStatus_NoExecutablePathValue", "-");
})
]
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Bottom)
[
SNew(SButton)
.ButtonStyle(&FAppStyle::Get().GetWidgetStyle<FButtonStyle>("SimpleButton"))
.ToolTipText(LOCTEXT("ExploreExecutablePathButtonToolTip", "Explore the Executable Path"))
.IsEnabled_Lambda([this]
{
const FState& CurrentState = GetCurrentState();
return CurrentState.bGotRunContext;
})
.OnClicked(this, &SZenServiceStatus::ExploreExecutablePath_OnClicked)
[
SNew(SImage)
.Image(FAppStyle::Get().GetBrush("Zen.FolderExplore"))
.ColorAndOpacity(FSlateColor::UseForeground())
]
]
];
++Row;
return Panel;
}
#undef LOCTEXT_NAMESPACE