Skip to content

Commit 0e03058

Browse files
💾🧩 Feat, Refactor(Debug, Blueprint): 实现蓝图逐步调试UI与数据连接器悬浮值显示
- BlueprintNodeVM 新增 IsExecuting/ExecutionCompleted/IsBreakpoint 状态及 BorderBrushOverride/ThicknessOverride 计算属性 - OnIsExecutingChanged/OnExecutionCompletedChanged/OnIsBreakpointChanged 触发边框重绘通知 - WorkflowEditorWindow 新增 WireUpDebugHighlight,直接操控 Node 控件 BorderBrush/BorderThickness 实现绿色高亮 - BlueprintNodeStyles.axaml 绑定调试高亮到 BorderBrushOverride/BorderThicknessOverride - BlueprintConnectorVM 新增 RuntimeValue 属性 - BlueprintEditorViewModel.OnDebugVariableChanged 按变量名查找连接器并设 RuntimeValue,结束后清空 - CreateConnectionFromBlueprintConnection 中注册 PubVar 名称至 _variableNameToConnector 映射 - CancelExecution 补设 IsExecuting=false 修复 Stop 按钮状态 - WorkflowEditorWindow.axaml: 连接器 DataTemplate 新增 ToolTip.Tip="{Binding RuntimeValue}" - WorkflowEditorViewModel 暴露 BlueprintVM.IsDebugging/IsPaused 等调试状态 - AppFramework.RunFramework 重构启动流程:DI→读取日志级别→配置Logger→Load配置→重配Logger
1 parent 52ab897 commit 0e03058

9 files changed

Lines changed: 487 additions & 27 deletions

KitX Dashboard/AppFramework.cs

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
using LiteDB;
2828
using ReactiveUI;
2929
using Serilog;
30+
using Serilog.Events;
31+
using System.Text.Json;
3032

3133
namespace KitX.Dashboard;
3234

@@ -65,32 +67,65 @@ public static void RunFramework()
6567
if (Design.IsDesignMode)
6668
return;
6769

68-
// Step 1: Initialize DI container first (Phase 2 refactoring)
69-
// DI container must be built before ConfigManager loads configuration,
70-
// so that all services can be resolved through DI.
70+
// Step 1: Initialize DI container first
7171
App.InitializeServiceProvider();
7272

73-
// Step 2: Load configuration through DI container
74-
// ConfigManager is registered as IConfigService singleton in DI.
75-
// Note: Log.Debug() calls in ConfigManager constructor are no-ops
76-
// before Logger initialization (handled by Serilog default config).
73+
// Step 2: Read LogLevel directly from config file (before full load,
74+
// so the logger can capture any deserialization errors during Load).
75+
var logLevel = LogEventLevel.Information;
76+
try
77+
{
78+
var cfgPath = Path.GetFullPath(Path.Combine("./Config/", "AppConfig.json"));
79+
if (File.Exists(cfgPath))
80+
{
81+
var finfo = new FileInfo(cfgPath);
82+
var trailPath = Path.Combine(finfo.DirectoryName!, "ConfigLoadTrail.log");
83+
File.AppendAllText(trailPath, $"[{DateTime.Now:O}] RunFramework START: file size={finfo.Length}, lastWrite={finfo.LastWriteTime:O}\n");
84+
85+
using var doc = JsonDocument.Parse(File.ReadAllText(cfgPath));
86+
if (doc.RootElement.TryGetProperty("Log", out var log) &&
87+
log.TryGetProperty("LogLevel", out var level))
88+
logLevel = (LogEventLevel)level.GetInt32();
89+
}
90+
}
91+
catch { }
92+
93+
// Step 3: Configure logger before Load() so Load errors are visible
94+
var logdir = "./Log/".GetFullPath();
95+
if (!Directory.Exists(logdir)) Directory.CreateDirectory(logdir);
96+
97+
Log.Logger = new LoggerConfiguration()
98+
.MinimumLevel.Is(logLevel)
99+
.WriteTo.File(
100+
$"{logdir}Log_.log",
101+
outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] {Message:lj}{NewLine}{Exception}",
102+
rollingInterval: RollingInterval.Hour,
103+
fileSizeLimitBytes: 10 * 1024 * 1024,
104+
buffered: true,
105+
flushToDiskInterval: new(0, 0, 30),
106+
restrictedToMinimumLevel: logLevel,
107+
rollOnFileSizeLimit: true,
108+
retainedFileCountLimit: 50
109+
)
110+
.CreateLogger();
111+
112+
// Step 4: Full config load (with logger now active — errors are visible)
113+
Log.Information($"[AppFramework] About to call configService.Load(), temp LogLevel={logLevel}");
77114
var configService = App.GetService<IConfigService>();
78115
configService.Load();
79116
var config = (AppConfig)configService.AppConfig;
117+
Log.Information($"[AppFramework] Load complete, LogLevel={config.Log.LogLevel}");
80118

81-
// TODO: [Architecture] Log system initialization should be moved to Core infrastructure.
82-
// Currently kept here because Serilog Logger is a process-level singleton.
83-
// Step 3: Initialize log system after configuration is loaded
84-
var logdir = config.Log.LogFilePath.GetFullPath();
85-
86-
if (!Directory.Exists(logdir))
87-
Directory.CreateDirectory(logdir);
119+
// Step 5: Reconfigure logger with full settings from loaded config
120+
var configuredLogDir = config.Log.LogFilePath.GetFullPath();
121+
if (!Directory.Exists(configuredLogDir))
122+
Directory.CreateDirectory(configuredLogDir);
88123

89124
Log.Logger = new LoggerConfiguration()
90125
.MinimumLevel.Is(config.Log.LogLevel)
91126
.WriteTo.Console(outputTemplate: config.Log.LogTemplate, restrictedToMinimumLevel: config.Log.LogLevel)
92127
.WriteTo.File(
93-
$"{logdir}Log_.log",
128+
$"{configuredLogDir}Log_.log",
94129
outputTemplate: config.Log.LogTemplate,
95130
rollingInterval: RollingInterval.Hour,
96131
fileSizeLimitBytes: config.Log.LogFileSingleMaxSize,

KitX Dashboard/Styles/BlueprintNodeStyles.axaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55

66
<!-- Global Node styling for Blueprint Editor -->
77
<Style Selector="controls|Node">
8-
<Setter Property="BorderBrush" Value="#3F3F46"/>
9-
<Setter Property="BorderThickness" Value="1"/>
8+
<!-- Debug highlighting: bind to ViewModel computed properties -->
9+
<Setter Property="BorderBrush" Value="{Binding BorderBrushOverride, TargetNullValue=#3F3F46}"/>
10+
<Setter Property="BorderThickness" Value="{Binding BorderThicknessOverride, TargetNullValue=1}"/>
1011
<Setter Property="CornerRadius" Value="6"/>
1112
<Setter Property="Padding" Value="0"/>
1213
</Style>

KitX Dashboard/ViewModels/BlueprintConnectorVM.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ public partial class BlueprintConnectorVM : ConnectorViewModelBase
2222
[ObservableProperty]
2323
private string? _defaultValue;
2424

25+
/// <summary>Runtime value set during debug execution, shown on hover</summary>
26+
[ObservableProperty]
27+
private string? _runtimeValue;
28+
2529
/// <summary>Whether this is an execution flow pin (triangle shape)</summary>
2630
public bool IsExecution => PinType == PinType.Execution;
2731

0 commit comments

Comments
 (0)