merge: maestro/tsk_0VF1URfdoe3d [tsk_0VF1URfdoe3d]
This commit is contained in:
+1
-1
@@ -25,7 +25,7 @@ export function adaptProject(p) {
|
|||||||
return {
|
return {
|
||||||
id: p.id, name: p.name, path: shortPath(p.repoPath), branch: p.defaultBranch,
|
id: p.id, name: p.name, path: shortPath(p.repoPath), branch: p.defaultBranch,
|
||||||
autonomy: p.autonomy, concurrency: p.concurrency, hue: hueFor(p.name),
|
autonomy: p.autonomy, concurrency: p.concurrency, hue: hueFor(p.name),
|
||||||
state, pending: s.attention || 0, agents: s.executing || 0,
|
state, pending: s.attention || 0, agents: s.executing || 0, blocked: s.blocked || 0,
|
||||||
// 透传给 ConfigPanel 用的原始字段
|
// 透传给 ConfigPanel 用的原始字段
|
||||||
model: p.model, verifyCmd: p.verifyCmd, maxRetries: p.maxRetries, repoPath: p.repoPath,
|
model: p.model, verifyCmd: p.verifyCmd, maxRetries: p.maxRetries, repoPath: p.repoPath,
|
||||||
logo: p.logo, budgetUsd: p.budgetUsd ?? null, budgetPeriod: p.budgetPeriod ?? 'month',
|
logo: p.logo, budgetUsd: p.budgetUsd ?? null, budgetPeriod: p.budgetPeriod ?? 'month',
|
||||||
|
|||||||
@@ -48,6 +48,17 @@ function projStateMeta(state, t) {
|
|||||||
})[state] || { color: 'var(--muted)', pulse: false, label: t.projIdle };
|
})[state] || { color: 'var(--muted)', pulse: false, label: t.projIdle };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 项目计数徽标:按优先级展示「需人工 / 运行中 / 被阻塞」,仅非零显示
|
||||||
|
function CountBadge({ value, color, title }) {
|
||||||
|
return (
|
||||||
|
<span title={title} style={{
|
||||||
|
fontFamily: 'var(--mono)', fontSize: 9.5, fontWeight: 700, lineHeight: '15px',
|
||||||
|
minWidth: 15, height: 15, textAlign: 'center', padding: '0 4px',
|
||||||
|
color: 'var(--bg-deep)', background: color, borderRadius: 8,
|
||||||
|
}}>{value}</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function ProjStatusDot({ meta, size = 7 }) {
|
function ProjStatusDot({ meta, size = 7 }) {
|
||||||
return (
|
return (
|
||||||
<span style={{
|
<span style={{
|
||||||
@@ -509,7 +520,10 @@ function Sidebar({ projects, currentId, onSelect, onNewProject, collapsed, onTog
|
|||||||
const active = p.id === currentId;
|
const active = p.id === currentId;
|
||||||
const meta = projStateMeta(p.state, t);
|
const meta = projStateMeta(p.state, t);
|
||||||
return (
|
return (
|
||||||
<li key={p.id} onClick={() => onSelect(p.id)} title={p.name + ' · ' + meta.label + (p.pending ? ' · ' + t.projPendingTip.replace('{n}', p.pending) : '')}
|
<li key={p.id} onClick={() => onSelect(p.id)} title={p.name + ' · ' + meta.label
|
||||||
|
+ (p.pending ? ' · ' + t.projPendingTip.replace('{n}', p.pending) : '')
|
||||||
|
+ (p.agents ? ' · ' + t.projAgentsTip.replace('{n}', p.agents) : '')
|
||||||
|
+ (p.blocked ? ' · ' + t.projBlockedTip.replace('{n}', p.blocked) : '')}
|
||||||
draggable={!collapsed}
|
draggable={!collapsed}
|
||||||
onDragStart={(e) => { setDragId(p.id); e.dataTransfer.effectAllowed = 'move'; }}
|
onDragStart={(e) => { setDragId(p.id); e.dataTransfer.effectAllowed = 'move'; }}
|
||||||
onDragOver={(e) => { if (dragId) { e.preventDefault(); if (p.id !== dragId && overId !== p.id) setOverId(p.id); } }}
|
onDragOver={(e) => { if (dragId) { e.preventDefault(); if (p.id !== dragId && overId !== p.id) setOverId(p.id); } }}
|
||||||
@@ -536,20 +550,16 @@ function Sidebar({ projects, currentId, onSelect, onNewProject, collapsed, onTog
|
|||||||
<span style={{ fontWeight: 600, fontSize: 13, color: active ? 'var(--green)' : 'var(--ink)' }}>{p.name}</span>
|
<span style={{ fontWeight: 600, fontSize: 13, color: active ? 'var(--green)' : 'var(--ink)' }}>{p.name}</span>
|
||||||
<span style={{ fontSize: 10.5, color: 'var(--faint)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.path}</span>
|
<span style={{ fontSize: 10.5, color: 'var(--faint)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.path}</span>
|
||||||
</span>
|
</span>
|
||||||
<span style={{ flex: 'none', display: 'flex', alignItems: 'center', gap: 6 }}>
|
<span style={{ flex: 'none', display: 'flex', alignItems: 'center', gap: 5 }}>
|
||||||
{p.pending > 0 ? (
|
{p.pending > 0 ? <CountBadge value={p.pending} color="var(--violet)" title={t.projPendingTip.replace('{n}', p.pending)} /> : null}
|
||||||
<span title={t.projPendingTip.replace('{n}', p.pending)} style={{
|
{p.agents > 0 ? <CountBadge value={p.agents} color="var(--cyan)" title={t.projAgentsTip.replace('{n}', p.agents)} /> : null}
|
||||||
fontFamily: 'var(--mono)', fontSize: 9.5, fontWeight: 700, lineHeight: '15px',
|
{p.blocked > 0 ? <CountBadge value={p.blocked} color="var(--amber)" title={t.projBlockedTip.replace('{n}', p.blocked)} /> : null}
|
||||||
minWidth: 15, height: 15, textAlign: 'center', padding: '0 4px',
|
|
||||||
color: 'var(--bg-deep)', background: 'var(--violet)', borderRadius: 8,
|
|
||||||
}}>{p.pending}</span>
|
|
||||||
) : null}
|
|
||||||
<ProjStatusDot meta={meta} />
|
<ProjStatusDot meta={meta} />
|
||||||
</span>
|
</span>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
) : (
|
) : (
|
||||||
<span style={{ position: 'absolute', top: 7, right: 9, display: 'flex', alignItems: 'center' }}>
|
<span style={{ position: 'absolute', top: 7, right: 9, display: 'flex', alignItems: 'center' }}>
|
||||||
<ProjStatusDot meta={meta} size={p.pending > 0 ? 8 : 6} />
|
<ProjStatusDot meta={meta} size={(p.pending || p.agents || p.blocked) > 0 ? 8 : 6} />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// MAESTRO 调度台 · UI kit 假数据(与 src/model 状态机对齐)
|
// MAESTRO 调度台 · UI kit 假数据(与 src/model 状态机对齐)
|
||||||
window.MAESTRO_MOCK = {
|
window.MAESTRO_MOCK = {
|
||||||
projects: [
|
projects: [
|
||||||
{ id: 'p1', name: 'maestro', path: '~/dev/maestro', branch: 'main', autonomy: 'auto-easy', concurrency: 2, hue: 140, state: 'running', pending: 1, agents: 1 },
|
{ id: 'p1', name: 'maestro', path: '~/dev/maestro', branch: 'main', autonomy: 'auto-easy', concurrency: 2, hue: 140, state: 'running', pending: 1, agents: 1, blocked: 0 },
|
||||||
{ id: 'p2', name: 'blog-engine', path: '~/dev/blog-engine', branch: 'main', autonomy: 'manual', concurrency: 1, hue: 38, state: 'paused', pending: 0, agents: 0 },
|
{ id: 'p2', name: 'blog-engine', path: '~/dev/blog-engine', branch: 'main', autonomy: 'manual', concurrency: 1, hue: 38, state: 'paused', pending: 0, agents: 0, blocked: 0 },
|
||||||
{ id: 'p3', name: 'dotfiles', path: '~/.dotfiles', branch: 'master', autonomy: 'auto-approved', concurrency: 1, hue: 265, state: 'blocked', pending: 0, agents: 0 },
|
{ id: 'p3', name: 'dotfiles', path: '~/.dotfiles', branch: 'master', autonomy: 'auto-approved', concurrency: 1, hue: 265, state: 'blocked', pending: 2, agents: 0, blocked: 2 },
|
||||||
],
|
],
|
||||||
agents: [
|
agents: [
|
||||||
{ id: 'r1', project: 'maestro', title: '把轮询改为 WS 推送', kind: 'EXECUTOR', time: '06:12', meta: 'wt-127 · claude-sonnet' },
|
{ id: 'r1', project: 'maestro', title: '把轮询改为 WS 推送', kind: 'EXECUTOR', time: '06:12', meta: 'wt-127 · claude-sonnet' },
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ window.MAESTRO_I18N = {
|
|||||||
agentSection: 'Agent 执行', agentEmpty: '无运行中的 agent', running: 'RUNNING', since: '起',
|
agentSection: 'Agent 执行', agentEmpty: '无运行中的 agent', running: 'RUNNING', since: '起',
|
||||||
projRunning: '运行中', projPaused: '暂停', projBlocked: '阻塞', projIdle: '空闲',
|
projRunning: '运行中', projPaused: '暂停', projBlocked: '阻塞', projIdle: '空闲',
|
||||||
projPendingTip: '{n} 项待你审批',
|
projPendingTip: '{n} 项待你审批',
|
||||||
|
projAgentsTip: '{n} 个 agent 运行中',
|
||||||
|
projBlockedTip: '{n} 项被阻塞',
|
||||||
gAgents: '全局 Agent', gAgentsDetail: '{p}/{P} 个项目运行 · {a} 个 agent',
|
gAgents: '全局 Agent', gAgentsDetail: '{p}/{P} 个项目运行 · {a} 个 agent',
|
||||||
apActive: '运行', apRuns: '次运行', apTokens: 'token', apWeek: '本周', apCost: '花费', apTotal: '所有项目', apPerProj: '按项目', apIdle: '空闲', apMore: '展开其余 {n} 个', apCollapse: '收起',
|
apActive: '运行', apRuns: '次运行', apTokens: 'token', apWeek: '本周', apCost: '花费', apTotal: '所有项目', apPerProj: '按项目', apIdle: '空闲', apMore: '展开其余 {n} 个', apCollapse: '收起',
|
||||||
apDetail: '详情', apDetailTitle: '用量详情', apByDay: '按天', apByWeek: '按周', apByMonth: '按月', apColProject: '项目', apColTasks: '任务数', apColModels: '模型', apEmpty: '暂无用量数据',
|
apDetail: '详情', apDetailTitle: '用量详情', apByDay: '按天', apByWeek: '按周', apByMonth: '按月', apColProject: '项目', apColTasks: '任务数', apColModels: '模型', apEmpty: '暂无用量数据',
|
||||||
@@ -74,6 +76,8 @@ window.MAESTRO_I18N = {
|
|||||||
agentSection: 'Agent runs', agentEmpty: 'No running agents', running: 'RUNNING', since: '',
|
agentSection: 'Agent runs', agentEmpty: 'No running agents', running: 'RUNNING', since: '',
|
||||||
projRunning: 'Running', projPaused: 'Paused', projBlocked: 'Blocked', projIdle: 'Idle',
|
projRunning: 'Running', projPaused: 'Paused', projBlocked: 'Blocked', projIdle: 'Idle',
|
||||||
projPendingTip: '{n} awaiting your review',
|
projPendingTip: '{n} awaiting your review',
|
||||||
|
projAgentsTip: '{n} agents running',
|
||||||
|
projBlockedTip: '{n} blocked',
|
||||||
gAgents: 'Agents', gAgentsDetail: '{p}/{P} projects · {a} agents',
|
gAgents: 'Agents', gAgentsDetail: '{p}/{P} projects · {a} agents',
|
||||||
apActive: 'active', apRuns: 'runs', apTokens: 'tokens', apWeek: 'this week', apCost: 'cost', apTotal: 'All projects', apPerProj: 'BY PROJECT', apIdle: 'idle', apMore: '+{n} more', apCollapse: 'Collapse',
|
apActive: 'active', apRuns: 'runs', apTokens: 'tokens', apWeek: 'this week', apCost: 'cost', apTotal: 'All projects', apPerProj: 'BY PROJECT', apIdle: 'idle', apMore: '+{n} more', apCollapse: 'Collapse',
|
||||||
apDetail: 'Details', apDetailTitle: 'Usage detail', apByDay: 'By day', apByWeek: 'By week', apByMonth: 'By month', apColProject: 'Project', apColTasks: 'Tasks', apColModels: 'Models', apEmpty: 'No usage data yet',
|
apDetail: 'Details', apDetailTitle: 'Usage detail', apByDay: 'By day', apByWeek: 'By week', apByMonth: 'By month', apColProject: 'Project', apColTasks: 'Tasks', apColModels: 'Models', apEmpty: 'No usage data yet',
|
||||||
@@ -126,6 +130,8 @@ window.MAESTRO_I18N = {
|
|||||||
agentSection: 'Ejecución de agents', agentEmpty: 'Sin agents en ejecución', running: 'RUNNING', since: '',
|
agentSection: 'Ejecución de agents', agentEmpty: 'Sin agents en ejecución', running: 'RUNNING', since: '',
|
||||||
projRunning: 'En curso', projPaused: 'Pausado', projBlocked: 'Bloqueado', projIdle: 'Inactivo',
|
projRunning: 'En curso', projPaused: 'Pausado', projBlocked: 'Bloqueado', projIdle: 'Inactivo',
|
||||||
projPendingTip: '{n} esperan tu revisión',
|
projPendingTip: '{n} esperan tu revisión',
|
||||||
|
projAgentsTip: '{n} agentes en curso',
|
||||||
|
projBlockedTip: '{n} bloqueadas',
|
||||||
gAgents: 'Agents globales', gAgentsDetail: '{p}/{P} proyectos · {a} agents',
|
gAgents: 'Agents globales', gAgentsDetail: '{p}/{P} proyectos · {a} agents',
|
||||||
apActive: 'activos', apRuns: 'ejecuciones', apTokens: 'tokens', apWeek: 'esta semana', apCost: 'coste', apTotal: 'Todos los proyectos', apPerProj: 'POR PROYECTO', apIdle: 'inactivo', apMore: '+{n} más', apCollapse: 'Contraer',
|
apActive: 'activos', apRuns: 'ejecuciones', apTokens: 'tokens', apWeek: 'esta semana', apCost: 'coste', apTotal: 'Todos los proyectos', apPerProj: 'POR PROYECTO', apIdle: 'inactivo', apMore: '+{n} más', apCollapse: 'Contraer',
|
||||||
apDetail: 'Detalles', apDetailTitle: 'Detalle de uso', apByDay: 'Por día', apByWeek: 'Por semana', apByMonth: 'Por mes', apColProject: 'Proyecto', apColTasks: 'Tareas', apColModels: 'Modelos', apEmpty: 'Sin datos de uso',
|
apDetail: 'Detalles', apDetailTitle: 'Detalle de uso', apByDay: 'Por día', apByWeek: 'Por semana', apByMonth: 'Por mes', apColProject: 'Proyecto', apColTasks: 'Tareas', apColModels: 'Modelos', apEmpty: 'Sin datos de uso',
|
||||||
@@ -178,6 +184,8 @@ window.MAESTRO_I18N = {
|
|||||||
agentSection: 'Agent 実行', agentEmpty: '実行中の agent はありません', running: 'RUNNING', since: '開始',
|
agentSection: 'Agent 実行', agentEmpty: '実行中の agent はありません', running: 'RUNNING', since: '開始',
|
||||||
projRunning: '実行中', projPaused: '一時停止', projBlocked: 'ブロック', projIdle: 'アイドル',
|
projRunning: '実行中', projPaused: '一時停止', projBlocked: 'ブロック', projIdle: 'アイドル',
|
||||||
projPendingTip: '{n} 件があなたの承認待ち',
|
projPendingTip: '{n} 件があなたの承認待ち',
|
||||||
|
projAgentsTip: '{n} 件のエージェント実行中',
|
||||||
|
projBlockedTip: '{n} 件ブロック中',
|
||||||
gAgents: 'グローバル Agent', gAgentsDetail: '{p}/{P} プロジェクト · {a} 個の agent',
|
gAgents: 'グローバル Agent', gAgentsDetail: '{p}/{P} プロジェクト · {a} 個の agent',
|
||||||
apActive: '実行中', apRuns: '回実行', apTokens: 'token', apWeek: '今週', apCost: 'コスト', apTotal: '全プロジェクト', apPerProj: 'プロジェクト別', apIdle: 'アイドル', apMore: '他 {n} 件', apCollapse: '折りたたむ',
|
apActive: '実行中', apRuns: '回実行', apTokens: 'token', apWeek: '今週', apCost: 'コスト', apTotal: '全プロジェクト', apPerProj: 'プロジェクト別', apIdle: 'アイドル', apMore: '他 {n} 件', apCollapse: '折りたたむ',
|
||||||
apDetail: '詳細', apDetailTitle: '使用量の詳細', apByDay: '日別', apByWeek: '週別', apByMonth: '月別', apColProject: 'プロジェクト', apColTasks: 'タスク数', apColModels: 'モデル', apEmpty: '使用量データなし',
|
apDetail: '詳細', apDetailTitle: '使用量の詳細', apByDay: '日別', apByWeek: '週別', apByMonth: '月別', apColProject: 'プロジェクト', apColTasks: 'タスク数', apColModels: 'モデル', apEmpty: '使用量データなし',
|
||||||
@@ -230,6 +238,8 @@ window.MAESTRO_I18N = {
|
|||||||
agentSection: 'Exécutions agent', agentEmpty: 'Aucun agent en cours', running: 'RUNNING', since: '',
|
agentSection: 'Exécutions agent', agentEmpty: 'Aucun agent en cours', running: 'RUNNING', since: '',
|
||||||
projRunning: 'En cours', projPaused: 'En pause', projBlocked: 'Bloqué', projIdle: 'Inactif',
|
projRunning: 'En cours', projPaused: 'En pause', projBlocked: 'Bloqué', projIdle: 'Inactif',
|
||||||
projPendingTip: '{n} en attente de votre revue',
|
projPendingTip: '{n} en attente de votre revue',
|
||||||
|
projAgentsTip: '{n} agents en cours',
|
||||||
|
projBlockedTip: '{n} bloquées',
|
||||||
gAgents: 'Agents globaux', gAgentsDetail: '{p}/{P} projets · {a} agents',
|
gAgents: 'Agents globaux', gAgentsDetail: '{p}/{P} projets · {a} agents',
|
||||||
apActive: 'actifs', apRuns: 'exécutions', apTokens: 'tokens', apWeek: 'cette semaine', apCost: 'coût', apTotal: 'Tous les projets', apPerProj: 'PAR PROJET', apIdle: 'inactif', apMore: '+{n} de plus', apCollapse: 'Réduire',
|
apActive: 'actifs', apRuns: 'exécutions', apTokens: 'tokens', apWeek: 'cette semaine', apCost: 'coût', apTotal: 'Tous les projets', apPerProj: 'PAR PROJET', apIdle: 'inactif', apMore: '+{n} de plus', apCollapse: 'Réduire',
|
||||||
apDetail: 'Détails', apDetailTitle: "Détail d'usage", apByDay: 'Par jour', apByWeek: 'Par semaine', apByMonth: 'Par mois', apColProject: 'Projet', apColTasks: 'Tâches', apColModels: 'Modèles', apEmpty: "Aucune donnée d'usage",
|
apDetail: 'Détails', apDetailTitle: "Détail d'usage", apByDay: 'Par jour', apByWeek: 'Par semaine', apByMonth: 'Par mois', apColProject: 'Projet', apColTasks: 'Tâches', apColModels: 'Modèles', apEmpty: "Aucune donnée d'usage",
|
||||||
|
|||||||
Reference in New Issue
Block a user