Skip to content

Commit 14f4845

Browse files
committed
trader dashboard
1 parent be8a589 commit 14f4845

File tree

6 files changed

+773
-3
lines changed

6 files changed

+773
-3
lines changed

crates/openfang-api/src/routes.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4153,15 +4153,25 @@ pub async fn hand_stats(
41534153
}
41544154
};
41554155

4156-
// Read dashboard metrics from agent's structured memory
4156+
// Read dashboard metrics from shared structured memory (memory_store uses shared namespace)
4157+
let shared_id = openfang_kernel::kernel::shared_memory_agent_id();
41574158
let mut metrics = serde_json::Map::new();
41584159
for metric in &def.dashboard.metrics {
4160+
// Try shared memory first (where memory_store tool writes), fall back to agent-specific
41594161
let value = state
41604162
.kernel
41614163
.memory
4162-
.structured_get(agent_id, &metric.memory_key)
4164+
.structured_get(shared_id, &metric.memory_key)
41634165
.ok()
41644166
.flatten()
4167+
.or_else(|| {
4168+
state
4169+
.kernel
4170+
.memory
4171+
.structured_get(agent_id, &metric.memory_key)
4172+
.ok()
4173+
.flatten()
4174+
})
41654175
.unwrap_or(serde_json::Value::Null);
41664176
metrics.insert(
41674177
metric.label.clone(),

crates/openfang-api/src/webchat.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,16 @@ const WEBCHAT_HTML: &str = concat!(
8181
include_str!("../static/vendor/github-dark.min.css"),
8282
"\n</style>\n",
8383
include_str!("../static/index_body.html"),
84-
// Vendor libs: marked + highlight first (used by app.js)
84+
// Vendor libs: marked + highlight first (used by app.js), then Chart.js
8585
"<script>\n",
8686
include_str!("../static/vendor/marked.min.js"),
8787
"\n</script>\n",
8888
"<script>\n",
8989
include_str!("../static/vendor/highlight.min.js"),
9090
"\n</script>\n",
91+
"<script>\n",
92+
include_str!("../static/vendor/chart.umd.min.js"),
93+
"\n</script>\n",
9194
// App code
9295
"<script>\n",
9396
include_str!("../static/js/api.js"),

crates/openfang-api/static/css/components.css

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3238,3 +3238,206 @@ mark.search-highlight {
32383238
.comms-event-row:hover { background: var(--bg-hover); }
32393239
.comms-event-time { min-width: 50px; text-align: right; }
32403240
.comms-event-detail { margin-left: auto; }
3241+
3242+
/* ═══════════════════════════════════════════════════════════════════════════
3243+
Trader Dashboard
3244+
═══════════════════════════════════════════════════════════════════════════ */
3245+
3246+
.trader-dashboard {
3247+
background: var(--bg-card);
3248+
border: 1px solid var(--border);
3249+
border-radius: 12px;
3250+
width: 96vw;
3251+
max-width: 1200px;
3252+
max-height: 92vh;
3253+
overflow-y: auto;
3254+
box-shadow: var(--shadow-lg);
3255+
}
3256+
.trader-dashboard-header {
3257+
display: flex;
3258+
justify-content: space-between;
3259+
align-items: center;
3260+
padding: 16px 20px;
3261+
border-bottom: 1px solid var(--border);
3262+
position: sticky;
3263+
top: 0;
3264+
background: var(--bg-card);
3265+
z-index: 10;
3266+
border-radius: 12px 12px 0 0;
3267+
}
3268+
.trader-dashboard-body {
3269+
padding: 16px 20px 24px;
3270+
display: flex;
3271+
flex-direction: column;
3272+
gap: 16px;
3273+
}
3274+
3275+
/* KPI Cards */
3276+
.trader-kpi-row {
3277+
display: grid;
3278+
grid-template-columns: repeat(6, 1fr);
3279+
gap: 10px;
3280+
}
3281+
@media (max-width: 900px) {
3282+
.trader-kpi-row { grid-template-columns: repeat(3, 1fr); }
3283+
}
3284+
@media (max-width: 540px) {
3285+
.trader-kpi-row { grid-template-columns: repeat(2, 1fr); }
3286+
}
3287+
.trader-kpi-card {
3288+
background: var(--bg);
3289+
border: 1px solid var(--border);
3290+
border-radius: 8px;
3291+
padding: 12px 14px;
3292+
text-align: center;
3293+
}
3294+
.trader-kpi-label {
3295+
font-size: 0.7rem;
3296+
color: var(--text-dim);
3297+
text-transform: uppercase;
3298+
letter-spacing: 0.5px;
3299+
margin-bottom: 4px;
3300+
}
3301+
.trader-kpi-value {
3302+
font-size: 1.15rem;
3303+
font-weight: 700;
3304+
color: var(--text);
3305+
font-family: var(--font-mono);
3306+
}
3307+
.kpi-positive { color: var(--success) !important; }
3308+
.kpi-negative { color: var(--error) !important; }
3309+
3310+
/* Chart Rows */
3311+
.trader-chart-row {
3312+
display: flex;
3313+
gap: 12px;
3314+
}
3315+
@media (max-width: 768px) {
3316+
.trader-chart-row { flex-direction: column; }
3317+
}
3318+
.trader-chart-panel {
3319+
background: var(--bg);
3320+
border: 1px solid var(--border);
3321+
border-radius: 8px;
3322+
padding: 14px 16px;
3323+
min-width: 0;
3324+
}
3325+
.trader-chart-title {
3326+
font-size: 0.75rem;
3327+
color: var(--text-dim);
3328+
text-transform: uppercase;
3329+
letter-spacing: 0.5px;
3330+
margin-bottom: 10px;
3331+
font-weight: 600;
3332+
}
3333+
.trader-chart-wrap {
3334+
position: relative;
3335+
width: 100%;
3336+
min-height: 180px;
3337+
}
3338+
.trader-chart-wrap canvas {
3339+
width: 100% !important;
3340+
height: 100% !important;
3341+
}
3342+
.trader-chart-empty {
3343+
position: absolute;
3344+
inset: 0;
3345+
display: flex;
3346+
align-items: center;
3347+
justify-content: center;
3348+
color: var(--text-dim);
3349+
font-size: 0.85rem;
3350+
}
3351+
3352+
/* Heatmap Table */
3353+
.trader-heatmap-wrap {
3354+
overflow-x: auto;
3355+
}
3356+
.trader-heatmap-table {
3357+
width: 100%;
3358+
border-collapse: collapse;
3359+
font-size: 0.8rem;
3360+
}
3361+
.trader-heatmap-table th {
3362+
text-align: left;
3363+
padding: 6px 10px;
3364+
color: var(--text-dim);
3365+
font-weight: 600;
3366+
font-size: 0.7rem;
3367+
text-transform: uppercase;
3368+
letter-spacing: 0.3px;
3369+
border-bottom: 1px solid var(--border);
3370+
}
3371+
.trader-heatmap-table td {
3372+
padding: 8px 10px;
3373+
border-bottom: 1px solid var(--border-subtle);
3374+
}
3375+
.heatmap-positive { color: var(--success); font-weight: 600; }
3376+
.heatmap-negative { color: var(--error); font-weight: 600; }
3377+
3378+
/* Signal Badges */
3379+
.signal-badge {
3380+
display: inline-block;
3381+
padding: 2px 8px;
3382+
border-radius: 4px;
3383+
font-size: 0.7rem;
3384+
font-weight: 700;
3385+
letter-spacing: 0.3px;
3386+
}
3387+
.signal-strong_buy, .signal-buy { background: rgba(34, 197, 94, 0.15); color: var(--success); }
3388+
.signal-sell, .signal-strong_sell { background: rgba(239, 68, 68, 0.15); color: var(--error); }
3389+
.signal-hold { background: rgba(245, 158, 11, 0.15); color: var(--warning); }
3390+
3391+
/* Confidence Bar */
3392+
.confidence-bar-wrap {
3393+
display: flex;
3394+
align-items: center;
3395+
gap: 6px;
3396+
min-width: 100px;
3397+
}
3398+
.confidence-bar {
3399+
height: 6px;
3400+
border-radius: 3px;
3401+
transition: width 0.3s ease;
3402+
}
3403+
.conf-high { background: var(--success); }
3404+
.conf-mid { background: var(--warning); }
3405+
.conf-low { background: var(--error); }
3406+
.confidence-label {
3407+
font-size: 0.7rem;
3408+
color: var(--text-dim);
3409+
min-width: 32px;
3410+
font-family: var(--font-mono);
3411+
}
3412+
3413+
/* Trades Table */
3414+
.trader-trades-table {
3415+
width: 100%;
3416+
border-collapse: collapse;
3417+
font-size: 0.8rem;
3418+
}
3419+
.trader-trades-table th {
3420+
text-align: left;
3421+
padding: 6px 10px;
3422+
color: var(--text-dim);
3423+
font-weight: 600;
3424+
font-size: 0.7rem;
3425+
text-transform: uppercase;
3426+
letter-spacing: 0.3px;
3427+
border-bottom: 1px solid var(--border);
3428+
}
3429+
.trader-trades-table td {
3430+
padding: 8px 10px;
3431+
border-bottom: 1px solid var(--border-subtle);
3432+
font-family: var(--font-mono);
3433+
font-size: 0.78rem;
3434+
}
3435+
.trade-side-badge {
3436+
display: inline-block;
3437+
padding: 1px 6px;
3438+
border-radius: 3px;
3439+
font-size: 0.68rem;
3440+
font-weight: 700;
3441+
}
3442+
.trade-buy { background: rgba(34, 197, 94, 0.15); color: var(--success); }
3443+
.trade-sell { background: rgba(239, 68, 68, 0.15); color: var(--error); }

0 commit comments

Comments
 (0)