@agenticmail/enterprise 0.5.212 → 0.5.213

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -344,91 +344,7 @@ function MetricsBar(props) {
344
344
  );
345
345
  }
346
346
 
347
- // ─── Inline Chain Flowchart (appears below canvas when task expanded)
348
- function ChainFlowInline(props) {
349
- var chain = props.chain;
350
- var taskId = props.taskId;
351
- var onClose = props.onClose;
352
- var onClickTask = props.onClickTask;
353
- if (!chain || chain.length === 0) return null;
354
-
355
- var MINI_W = 180;
356
- var MINI_H = 56;
357
- var MINI_GAP = 40;
358
- var totalW = chain.length * MINI_W + (chain.length - 1) * MINI_GAP + 40;
359
-
360
- return h('div', { style: { borderTop: '1px solid rgba(255,255,255,0.08)', background: 'rgba(0,0,0,0.25)', padding: '12px 16px', flexShrink: 0, overflow: 'auto' } },
361
- h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 } },
362
- h('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } },
363
- h('span', { style: { fontSize: 11, fontWeight: 600, color: 'rgba(255,255,255,0.5)', letterSpacing: '0.06em' } }, 'TASK FLOW'),
364
- h('span', { style: { fontSize: 10, color: 'rgba(255,255,255,0.3)', fontFamily: 'var(--font-mono)' } }, chain[0].chainId ? '#' + chain[0].chainId.slice(0, 8) : ''),
365
- h('span', { style: { fontSize: 10, color: 'rgba(255,255,255,0.3)' } }, chain.length + ' step' + (chain.length > 1 ? 's' : ''))
366
- ),
367
- h('button', { onClick: onClose, style: { background: 'none', border: 'none', color: 'rgba(255,255,255,0.3)', cursor: 'pointer', fontSize: 16, padding: '0 4px' } }, '\u00D7')
368
- ),
369
- h('div', { style: { position: 'relative', height: MINI_H + 20, minWidth: totalW } },
370
- // SVG arrows
371
- h('svg', { width: totalW, height: MINI_H + 20, style: { position: 'absolute', top: 0, left: 0, pointerEvents: 'none' } },
372
- h('defs', null,
373
- h('marker', { id: 'cf-arr', markerWidth: 6, markerHeight: 4, refX: 6, refY: 2, orient: 'auto' },
374
- h('polygon', { points: '0 0, 6 2, 0 4', fill: 'rgba(99,102,241,0.5)' })
375
- )
376
- ),
377
- chain.map(function(ct, i) {
378
- if (i === 0) return null;
379
- var x1 = 20 + (i - 1) * (MINI_W + MINI_GAP) + MINI_W;
380
- var x2 = 20 + i * (MINI_W + MINI_GAP);
381
- var y = 10 + MINI_H / 2;
382
- var dType = ct.delegationType || 'delegation';
383
- var color = DELEGATION_COLORS[dType] || 'rgba(99,102,241,0.5)';
384
- var isActive = chain[i - 1].status === 'in_progress' || ct.status === 'in_progress';
385
- return h(Fragment, { key: 'e' + i },
386
- h('line', { x1: x1, y1: y, x2: x2, y2: y, stroke: color + '88', strokeWidth: 2, markerEnd: 'url(#cf-arr)' }),
387
- isActive && h('line', { x1: x1, y1: y, x2: x2, y2: y, stroke: STATUS_COLORS.in_progress, strokeWidth: 2, strokeDasharray: '4 12', className: 'tp-flow-active', style: { opacity: 0.7 } }),
388
- dType !== 'delegation' && h('text', { x: (x1 + x2) / 2, y: y - 6, fill: color, fontSize: 8, textAnchor: 'middle', fontWeight: 600 }, dType)
389
- );
390
- })
391
- ),
392
- // Task nodes
393
- chain.map(function(ct, i) {
394
- var x = 20 + i * (MINI_W + MINI_GAP);
395
- var sc = STATUS_COLORS[ct.status] || '#6b7394';
396
- var isMe = ct.id === taskId;
397
- var isActive = ct.status === 'in_progress';
398
- return h('div', {
399
- key: ct.id,
400
- onClick: function() { if (onClickTask) onClickTask(ct); },
401
- style: {
402
- position: 'absolute', left: x, top: 10, width: MINI_W, height: MINI_H,
403
- background: isMe ? sc + '15' : 'rgba(255,255,255,0.02)',
404
- border: '1.5px solid ' + (isMe ? sc : 'rgba(255,255,255,0.1)'),
405
- borderLeft: '3px solid ' + sc,
406
- borderRadius: 8, padding: '6px 10px', cursor: 'pointer',
407
- display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: 3,
408
- transition: 'all 0.15s',
409
- },
410
- onMouseEnter: function(e) { e.currentTarget.style.background = 'rgba(255,255,255,0.05)'; },
411
- onMouseLeave: function(e) { e.currentTarget.style.background = isMe ? sc + '15' : 'rgba(255,255,255,0.02)'; },
412
- },
413
- h('div', { style: { display: 'flex', alignItems: 'center', gap: 5 } },
414
- h('div', { style: { width: 16, height: 16, borderRadius: '50%', background: sc + '33', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 7, fontWeight: 700, color: sc, flexShrink: 0 } },
415
- (ct.assignedToName || '?').charAt(0).toUpperCase()
416
- ),
417
- h('span', { style: { fontSize: 10, fontWeight: 600, color: '#fff', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', flex: 1 } }, ct.assignedToName || ct.assignedTo)
418
- ),
419
- h('div', { style: { display: 'flex', alignItems: 'center', gap: 4 } },
420
- tag(sc, ct.status.replace('_', ' ')),
421
- h('span', { style: { fontSize: 8, color: 'rgba(255,255,255,0.3)' } }, timeAgo(ct.createdAt)),
422
- ct.actualDurationMs && h('span', { style: { fontSize: 8, color: 'rgba(255,255,255,0.3)', marginLeft: 'auto' } }, formatDuration(ct.actualDurationMs))
423
- ),
424
- isActive && ct.progress > 0 && h('div', { style: { height: 2, background: 'rgba(255,255,255,0.08)', borderRadius: 1, overflow: 'hidden' } },
425
- h('div', { style: { height: '100%', width: ct.progress + '%', background: sc, borderRadius: 1 } })
426
- )
427
- );
428
- })
429
- )
430
- );
431
- }
347
+ // (ChainFlowInline removed chain flow now renders inline on canvas)
432
348
 
433
349
  // ─── Main Page ───────────────────────────────────────────
434
350
  export function TaskPipelinePage() {
@@ -802,7 +718,123 @@ export function TaskPipelinePage() {
802
718
  h('div', { style: { height: '100%', width: t.progress + '%', background: sc, borderRadius: 1, transition: 'width 0.3s' } })
803
719
  )
804
720
  );
805
- })
721
+ }),
722
+
723
+ // ── Expanded chain flow (rendered ON the canvas below clicked node) ──
724
+ expandedChain && expandedChain.length > 0 && (function() {
725
+ // Find the clicked node position to anchor below it
726
+ var anchor = nodes.find(function(n) { return n.id === expandedTaskId; });
727
+ if (!anchor) return null;
728
+ var flowY = anchor.y + anchor.h + 20;
729
+ var flowX = anchor.x;
730
+ var STEP_W = 120;
731
+ var STEP_H = 44;
732
+ var STEP_GAP = 48;
733
+ var ARROW_W = STEP_GAP;
734
+
735
+ // Build person-centric flow steps: createdBy → assignedTo for each chain task, then final status
736
+ var steps = [];
737
+ expandedChain.forEach(function(ct, i) {
738
+ if (i === 0 && ct.createdBy && ct.createdBy !== 'system') {
739
+ steps.push({ label: ct.createdByName || ct.createdBy, type: 'person', isHuman: ct.createdBy.indexOf('agent') === -1 && ct.createdBy !== 'system', status: null, arrow: ct.delegationType || 'assigned' });
740
+ } else if (i === 0 && ct.createdBy === 'system') {
741
+ steps.push({ label: 'System', type: 'system', isHuman: false, status: null, arrow: 'assigned' });
742
+ }
743
+ steps.push({ label: ct.assignedToName || ct.assignedTo, type: 'agent', isHuman: false, status: ct.status, taskId: ct.id, arrow: i < expandedChain.length - 1 ? (expandedChain[i + 1].delegationType || 'delegation') : null, duration: ct.actualDurationMs, progress: ct.progress });
744
+ });
745
+ // Add final status node
746
+ var lastTask = expandedChain[expandedChain.length - 1];
747
+ var isDone = lastTask.status === 'completed' || lastTask.status === 'failed' || lastTask.status === 'cancelled';
748
+ if (isDone) {
749
+ steps.push({ label: lastTask.status === 'completed' ? 'Completed!' : lastTask.status === 'failed' ? 'Failed' : 'Cancelled', type: 'terminal', isHuman: false, status: lastTask.status, arrow: null });
750
+ }
751
+
752
+ var totalW = steps.length * STEP_W + (steps.length - 1) * STEP_GAP;
753
+
754
+ return h('div', { style: { position: 'absolute', left: flowX, top: flowY, pointerEvents: 'auto' } },
755
+ // Background card
756
+ h('div', { style: { background: 'rgba(10,12,20,0.85)', border: '1px solid rgba(99,102,241,0.2)', borderRadius: 12, padding: '14px 16px 12px', backdropFilter: 'blur(8px)' } },
757
+ // Header
758
+ h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 } },
759
+ h('span', { style: { fontSize: 10, fontWeight: 600, color: 'rgba(255,255,255,0.4)', letterSpacing: '0.06em' } }, 'TASK FLOW'),
760
+ expandedChain[0].chainId && h('span', { style: { fontSize: 9, color: 'rgba(255,255,255,0.2)', fontFamily: 'var(--font-mono)' } }, '#' + expandedChain[0].chainId.slice(0, 8)),
761
+ h('div', { style: { flex: 1 } }),
762
+ h('button', { className: 'tp-node', onClick: function() { setExpandedTaskId(null); }, style: { background: 'none', border: 'none', color: 'rgba(255,255,255,0.3)', cursor: 'pointer', fontSize: 14, padding: '0 2px' } }, '\u00D7')
763
+ ),
764
+ // Flow
765
+ h('div', { style: { position: 'relative', height: STEP_H + 8, minWidth: totalW } },
766
+ // SVG arrows
767
+ h('svg', { width: totalW, height: STEP_H + 8, style: { position: 'absolute', top: 0, left: 0, pointerEvents: 'none' } },
768
+ h('defs', null,
769
+ h('marker', { id: 'fc-arr', markerWidth: 6, markerHeight: 4, refX: 6, refY: 2, orient: 'auto' },
770
+ h('polygon', { points: '0 0, 6 2, 0 4', fill: 'rgba(99,102,241,0.5)' })
771
+ )
772
+ ),
773
+ steps.map(function(step, i) {
774
+ if (i === steps.length - 1 || !step.arrow) return null;
775
+ var x1 = i * (STEP_W + STEP_GAP) + STEP_W;
776
+ var x2 = (i + 1) * (STEP_W + STEP_GAP);
777
+ var y = 4 + STEP_H / 2;
778
+ var arrowColor = DELEGATION_COLORS[step.arrow] || 'rgba(99,102,241,0.5)';
779
+ var nextStep = steps[i + 1];
780
+ var isFlowActive = step.status === 'in_progress' || (nextStep && nextStep.status === 'in_progress');
781
+ return h(Fragment, { key: 'a' + i },
782
+ h('line', { x1: x1, y1: y, x2: x2, y2: y, stroke: arrowColor + '88', strokeWidth: 2, markerEnd: 'url(#fc-arr)' }),
783
+ isFlowActive && h('line', { x1: x1, y1: y, x2: x2, y2: y, stroke: STATUS_COLORS.in_progress, strokeWidth: 2, strokeDasharray: '4 12', className: 'tp-flow-active', style: { opacity: 0.7 } }),
784
+ step.arrow !== 'assigned' && step.arrow !== 'delegation' && h('text', { x: (x1 + x2) / 2, y: y - 6, fill: arrowColor, fontSize: 8, textAnchor: 'middle', fontWeight: 600 }, step.arrow)
785
+ );
786
+ })
787
+ ),
788
+ // Step nodes
789
+ steps.map(function(step, i) {
790
+ var x = i * (STEP_W + STEP_GAP);
791
+ var sc = step.type === 'terminal'
792
+ ? (STATUS_COLORS[step.status] || '#22c55e')
793
+ : step.type === 'person' || step.isHuman
794
+ ? '#f59e0b'
795
+ : step.status ? (STATUS_COLORS[step.status] || '#6366f1') : '#6366f1';
796
+ var isTerminal = step.type === 'terminal';
797
+ var isMe = step.taskId === expandedTaskId;
798
+
799
+ return h('div', {
800
+ key: i,
801
+ className: 'tp-node',
802
+ onClick: function(e) { e.stopPropagation(); if (step.taskId) { var ct = expandedChain.find(function(c) { return c.id === step.taskId; }); if (ct) openTaskDetail(ct); } },
803
+ style: {
804
+ position: 'absolute', left: x, top: 4, width: STEP_W, height: STEP_H,
805
+ background: isTerminal ? sc + '15' : isMe ? 'rgba(255,255,255,0.06)' : 'rgba(255,255,255,0.02)',
806
+ border: '1.5px solid ' + (isTerminal ? sc + '44' : isMe ? sc : 'rgba(255,255,255,0.1)'),
807
+ borderRadius: isTerminal ? 22 : 10,
808
+ display: 'flex', alignItems: 'center', gap: 8, padding: '0 10px',
809
+ cursor: step.taskId ? 'pointer' : 'default',
810
+ },
811
+ },
812
+ // Avatar
813
+ h('div', { style: {
814
+ width: 26, height: 26, borderRadius: '50%', flexShrink: 0,
815
+ background: isTerminal ? sc + '33' : step.isHuman || step.type === 'person' ? 'linear-gradient(135deg, #f59e0b, #f97316)' : step.type === 'system' ? 'rgba(255,255,255,0.1)' : 'linear-gradient(135deg, #6366f1, #8b5cf6)',
816
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
817
+ fontSize: isTerminal ? 12 : 10, fontWeight: 700,
818
+ color: isTerminal ? sc : '#fff',
819
+ border: '2px solid ' + (isTerminal ? sc + '44' : 'transparent'),
820
+ } },
821
+ isTerminal ? (step.status === 'completed' ? '\u2714' : step.status === 'failed' ? '\u2716' : '\u2716') : step.label.charAt(0).toUpperCase()
822
+ ),
823
+ // Info
824
+ h('div', { style: { overflow: 'hidden', flex: 1, minWidth: 0 } },
825
+ h('div', { style: { fontSize: 11, fontWeight: 600, color: isTerminal ? sc : '#fff', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } }, step.label),
826
+ !isTerminal && h('div', { style: { fontSize: 9, color: 'rgba(255,255,255,0.35)', marginTop: 1 } },
827
+ step.type === 'person' || step.isHuman ? 'Human' : step.type === 'system' ? 'System' : 'Agent',
828
+ step.duration ? ' \u00B7 ' + formatDuration(step.duration) : '',
829
+ step.status === 'in_progress' && step.progress > 0 ? ' \u00B7 ' + step.progress + '%' : ''
830
+ )
831
+ )
832
+ );
833
+ })
834
+ )
835
+ )
836
+ );
837
+ })()
806
838
  )
807
839
  ),
808
840
 
@@ -824,14 +856,6 @@ export function TaskPipelinePage() {
824
856
  )
825
857
  ),
826
858
 
827
- // Inline chain flowchart (shown when a task is clicked)
828
- expandedChain && expandedChain.length > 0 && h(ChainFlowInline, {
829
- chain: expandedChain,
830
- taskId: expandedTaskId,
831
- onClose: function() { setExpandedTaskId(null); },
832
- onClickTask: function(t) { openTaskDetail(t); }
833
- }),
834
-
835
859
  // Detail modal (double-click)
836
860
  selectedTask && h(TaskDetail, { task: selectedTask, chain: selectedChain, onClose: function() { setSelectedTask(null); setSelectedChain(null); }, onCancel: cancelTask })
837
861
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/enterprise",
3
- "version": "0.5.212",
3
+ "version": "0.5.213",
4
4
  "description": "AgenticMail Enterprise — cloud-hosted AI agent identity, email, auth & compliance for organizations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -344,91 +344,7 @@ function MetricsBar(props) {
344
344
  );
345
345
  }
346
346
 
347
- // ─── Inline Chain Flowchart (appears below canvas when task expanded)
348
- function ChainFlowInline(props) {
349
- var chain = props.chain;
350
- var taskId = props.taskId;
351
- var onClose = props.onClose;
352
- var onClickTask = props.onClickTask;
353
- if (!chain || chain.length === 0) return null;
354
-
355
- var MINI_W = 180;
356
- var MINI_H = 56;
357
- var MINI_GAP = 40;
358
- var totalW = chain.length * MINI_W + (chain.length - 1) * MINI_GAP + 40;
359
-
360
- return h('div', { style: { borderTop: '1px solid rgba(255,255,255,0.08)', background: 'rgba(0,0,0,0.25)', padding: '12px 16px', flexShrink: 0, overflow: 'auto' } },
361
- h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 } },
362
- h('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } },
363
- h('span', { style: { fontSize: 11, fontWeight: 600, color: 'rgba(255,255,255,0.5)', letterSpacing: '0.06em' } }, 'TASK FLOW'),
364
- h('span', { style: { fontSize: 10, color: 'rgba(255,255,255,0.3)', fontFamily: 'var(--font-mono)' } }, chain[0].chainId ? '#' + chain[0].chainId.slice(0, 8) : ''),
365
- h('span', { style: { fontSize: 10, color: 'rgba(255,255,255,0.3)' } }, chain.length + ' step' + (chain.length > 1 ? 's' : ''))
366
- ),
367
- h('button', { onClick: onClose, style: { background: 'none', border: 'none', color: 'rgba(255,255,255,0.3)', cursor: 'pointer', fontSize: 16, padding: '0 4px' } }, '\u00D7')
368
- ),
369
- h('div', { style: { position: 'relative', height: MINI_H + 20, minWidth: totalW } },
370
- // SVG arrows
371
- h('svg', { width: totalW, height: MINI_H + 20, style: { position: 'absolute', top: 0, left: 0, pointerEvents: 'none' } },
372
- h('defs', null,
373
- h('marker', { id: 'cf-arr', markerWidth: 6, markerHeight: 4, refX: 6, refY: 2, orient: 'auto' },
374
- h('polygon', { points: '0 0, 6 2, 0 4', fill: 'rgba(99,102,241,0.5)' })
375
- )
376
- ),
377
- chain.map(function(ct, i) {
378
- if (i === 0) return null;
379
- var x1 = 20 + (i - 1) * (MINI_W + MINI_GAP) + MINI_W;
380
- var x2 = 20 + i * (MINI_W + MINI_GAP);
381
- var y = 10 + MINI_H / 2;
382
- var dType = ct.delegationType || 'delegation';
383
- var color = DELEGATION_COLORS[dType] || 'rgba(99,102,241,0.5)';
384
- var isActive = chain[i - 1].status === 'in_progress' || ct.status === 'in_progress';
385
- return h(Fragment, { key: 'e' + i },
386
- h('line', { x1: x1, y1: y, x2: x2, y2: y, stroke: color + '88', strokeWidth: 2, markerEnd: 'url(#cf-arr)' }),
387
- isActive && h('line', { x1: x1, y1: y, x2: x2, y2: y, stroke: STATUS_COLORS.in_progress, strokeWidth: 2, strokeDasharray: '4 12', className: 'tp-flow-active', style: { opacity: 0.7 } }),
388
- dType !== 'delegation' && h('text', { x: (x1 + x2) / 2, y: y - 6, fill: color, fontSize: 8, textAnchor: 'middle', fontWeight: 600 }, dType)
389
- );
390
- })
391
- ),
392
- // Task nodes
393
- chain.map(function(ct, i) {
394
- var x = 20 + i * (MINI_W + MINI_GAP);
395
- var sc = STATUS_COLORS[ct.status] || '#6b7394';
396
- var isMe = ct.id === taskId;
397
- var isActive = ct.status === 'in_progress';
398
- return h('div', {
399
- key: ct.id,
400
- onClick: function() { if (onClickTask) onClickTask(ct); },
401
- style: {
402
- position: 'absolute', left: x, top: 10, width: MINI_W, height: MINI_H,
403
- background: isMe ? sc + '15' : 'rgba(255,255,255,0.02)',
404
- border: '1.5px solid ' + (isMe ? sc : 'rgba(255,255,255,0.1)'),
405
- borderLeft: '3px solid ' + sc,
406
- borderRadius: 8, padding: '6px 10px', cursor: 'pointer',
407
- display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: 3,
408
- transition: 'all 0.15s',
409
- },
410
- onMouseEnter: function(e) { e.currentTarget.style.background = 'rgba(255,255,255,0.05)'; },
411
- onMouseLeave: function(e) { e.currentTarget.style.background = isMe ? sc + '15' : 'rgba(255,255,255,0.02)'; },
412
- },
413
- h('div', { style: { display: 'flex', alignItems: 'center', gap: 5 } },
414
- h('div', { style: { width: 16, height: 16, borderRadius: '50%', background: sc + '33', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 7, fontWeight: 700, color: sc, flexShrink: 0 } },
415
- (ct.assignedToName || '?').charAt(0).toUpperCase()
416
- ),
417
- h('span', { style: { fontSize: 10, fontWeight: 600, color: '#fff', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', flex: 1 } }, ct.assignedToName || ct.assignedTo)
418
- ),
419
- h('div', { style: { display: 'flex', alignItems: 'center', gap: 4 } },
420
- tag(sc, ct.status.replace('_', ' ')),
421
- h('span', { style: { fontSize: 8, color: 'rgba(255,255,255,0.3)' } }, timeAgo(ct.createdAt)),
422
- ct.actualDurationMs && h('span', { style: { fontSize: 8, color: 'rgba(255,255,255,0.3)', marginLeft: 'auto' } }, formatDuration(ct.actualDurationMs))
423
- ),
424
- isActive && ct.progress > 0 && h('div', { style: { height: 2, background: 'rgba(255,255,255,0.08)', borderRadius: 1, overflow: 'hidden' } },
425
- h('div', { style: { height: '100%', width: ct.progress + '%', background: sc, borderRadius: 1 } })
426
- )
427
- );
428
- })
429
- )
430
- );
431
- }
347
+ // (ChainFlowInline removed chain flow now renders inline on canvas)
432
348
 
433
349
  // ─── Main Page ───────────────────────────────────────────
434
350
  export function TaskPipelinePage() {
@@ -802,7 +718,123 @@ export function TaskPipelinePage() {
802
718
  h('div', { style: { height: '100%', width: t.progress + '%', background: sc, borderRadius: 1, transition: 'width 0.3s' } })
803
719
  )
804
720
  );
805
- })
721
+ }),
722
+
723
+ // ── Expanded chain flow (rendered ON the canvas below clicked node) ──
724
+ expandedChain && expandedChain.length > 0 && (function() {
725
+ // Find the clicked node position to anchor below it
726
+ var anchor = nodes.find(function(n) { return n.id === expandedTaskId; });
727
+ if (!anchor) return null;
728
+ var flowY = anchor.y + anchor.h + 20;
729
+ var flowX = anchor.x;
730
+ var STEP_W = 120;
731
+ var STEP_H = 44;
732
+ var STEP_GAP = 48;
733
+ var ARROW_W = STEP_GAP;
734
+
735
+ // Build person-centric flow steps: createdBy → assignedTo for each chain task, then final status
736
+ var steps = [];
737
+ expandedChain.forEach(function(ct, i) {
738
+ if (i === 0 && ct.createdBy && ct.createdBy !== 'system') {
739
+ steps.push({ label: ct.createdByName || ct.createdBy, type: 'person', isHuman: ct.createdBy.indexOf('agent') === -1 && ct.createdBy !== 'system', status: null, arrow: ct.delegationType || 'assigned' });
740
+ } else if (i === 0 && ct.createdBy === 'system') {
741
+ steps.push({ label: 'System', type: 'system', isHuman: false, status: null, arrow: 'assigned' });
742
+ }
743
+ steps.push({ label: ct.assignedToName || ct.assignedTo, type: 'agent', isHuman: false, status: ct.status, taskId: ct.id, arrow: i < expandedChain.length - 1 ? (expandedChain[i + 1].delegationType || 'delegation') : null, duration: ct.actualDurationMs, progress: ct.progress });
744
+ });
745
+ // Add final status node
746
+ var lastTask = expandedChain[expandedChain.length - 1];
747
+ var isDone = lastTask.status === 'completed' || lastTask.status === 'failed' || lastTask.status === 'cancelled';
748
+ if (isDone) {
749
+ steps.push({ label: lastTask.status === 'completed' ? 'Completed!' : lastTask.status === 'failed' ? 'Failed' : 'Cancelled', type: 'terminal', isHuman: false, status: lastTask.status, arrow: null });
750
+ }
751
+
752
+ var totalW = steps.length * STEP_W + (steps.length - 1) * STEP_GAP;
753
+
754
+ return h('div', { style: { position: 'absolute', left: flowX, top: flowY, pointerEvents: 'auto' } },
755
+ // Background card
756
+ h('div', { style: { background: 'rgba(10,12,20,0.85)', border: '1px solid rgba(99,102,241,0.2)', borderRadius: 12, padding: '14px 16px 12px', backdropFilter: 'blur(8px)' } },
757
+ // Header
758
+ h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 } },
759
+ h('span', { style: { fontSize: 10, fontWeight: 600, color: 'rgba(255,255,255,0.4)', letterSpacing: '0.06em' } }, 'TASK FLOW'),
760
+ expandedChain[0].chainId && h('span', { style: { fontSize: 9, color: 'rgba(255,255,255,0.2)', fontFamily: 'var(--font-mono)' } }, '#' + expandedChain[0].chainId.slice(0, 8)),
761
+ h('div', { style: { flex: 1 } }),
762
+ h('button', { className: 'tp-node', onClick: function() { setExpandedTaskId(null); }, style: { background: 'none', border: 'none', color: 'rgba(255,255,255,0.3)', cursor: 'pointer', fontSize: 14, padding: '0 2px' } }, '\u00D7')
763
+ ),
764
+ // Flow
765
+ h('div', { style: { position: 'relative', height: STEP_H + 8, minWidth: totalW } },
766
+ // SVG arrows
767
+ h('svg', { width: totalW, height: STEP_H + 8, style: { position: 'absolute', top: 0, left: 0, pointerEvents: 'none' } },
768
+ h('defs', null,
769
+ h('marker', { id: 'fc-arr', markerWidth: 6, markerHeight: 4, refX: 6, refY: 2, orient: 'auto' },
770
+ h('polygon', { points: '0 0, 6 2, 0 4', fill: 'rgba(99,102,241,0.5)' })
771
+ )
772
+ ),
773
+ steps.map(function(step, i) {
774
+ if (i === steps.length - 1 || !step.arrow) return null;
775
+ var x1 = i * (STEP_W + STEP_GAP) + STEP_W;
776
+ var x2 = (i + 1) * (STEP_W + STEP_GAP);
777
+ var y = 4 + STEP_H / 2;
778
+ var arrowColor = DELEGATION_COLORS[step.arrow] || 'rgba(99,102,241,0.5)';
779
+ var nextStep = steps[i + 1];
780
+ var isFlowActive = step.status === 'in_progress' || (nextStep && nextStep.status === 'in_progress');
781
+ return h(Fragment, { key: 'a' + i },
782
+ h('line', { x1: x1, y1: y, x2: x2, y2: y, stroke: arrowColor + '88', strokeWidth: 2, markerEnd: 'url(#fc-arr)' }),
783
+ isFlowActive && h('line', { x1: x1, y1: y, x2: x2, y2: y, stroke: STATUS_COLORS.in_progress, strokeWidth: 2, strokeDasharray: '4 12', className: 'tp-flow-active', style: { opacity: 0.7 } }),
784
+ step.arrow !== 'assigned' && step.arrow !== 'delegation' && h('text', { x: (x1 + x2) / 2, y: y - 6, fill: arrowColor, fontSize: 8, textAnchor: 'middle', fontWeight: 600 }, step.arrow)
785
+ );
786
+ })
787
+ ),
788
+ // Step nodes
789
+ steps.map(function(step, i) {
790
+ var x = i * (STEP_W + STEP_GAP);
791
+ var sc = step.type === 'terminal'
792
+ ? (STATUS_COLORS[step.status] || '#22c55e')
793
+ : step.type === 'person' || step.isHuman
794
+ ? '#f59e0b'
795
+ : step.status ? (STATUS_COLORS[step.status] || '#6366f1') : '#6366f1';
796
+ var isTerminal = step.type === 'terminal';
797
+ var isMe = step.taskId === expandedTaskId;
798
+
799
+ return h('div', {
800
+ key: i,
801
+ className: 'tp-node',
802
+ onClick: function(e) { e.stopPropagation(); if (step.taskId) { var ct = expandedChain.find(function(c) { return c.id === step.taskId; }); if (ct) openTaskDetail(ct); } },
803
+ style: {
804
+ position: 'absolute', left: x, top: 4, width: STEP_W, height: STEP_H,
805
+ background: isTerminal ? sc + '15' : isMe ? 'rgba(255,255,255,0.06)' : 'rgba(255,255,255,0.02)',
806
+ border: '1.5px solid ' + (isTerminal ? sc + '44' : isMe ? sc : 'rgba(255,255,255,0.1)'),
807
+ borderRadius: isTerminal ? 22 : 10,
808
+ display: 'flex', alignItems: 'center', gap: 8, padding: '0 10px',
809
+ cursor: step.taskId ? 'pointer' : 'default',
810
+ },
811
+ },
812
+ // Avatar
813
+ h('div', { style: {
814
+ width: 26, height: 26, borderRadius: '50%', flexShrink: 0,
815
+ background: isTerminal ? sc + '33' : step.isHuman || step.type === 'person' ? 'linear-gradient(135deg, #f59e0b, #f97316)' : step.type === 'system' ? 'rgba(255,255,255,0.1)' : 'linear-gradient(135deg, #6366f1, #8b5cf6)',
816
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
817
+ fontSize: isTerminal ? 12 : 10, fontWeight: 700,
818
+ color: isTerminal ? sc : '#fff',
819
+ border: '2px solid ' + (isTerminal ? sc + '44' : 'transparent'),
820
+ } },
821
+ isTerminal ? (step.status === 'completed' ? '\u2714' : step.status === 'failed' ? '\u2716' : '\u2716') : step.label.charAt(0).toUpperCase()
822
+ ),
823
+ // Info
824
+ h('div', { style: { overflow: 'hidden', flex: 1, minWidth: 0 } },
825
+ h('div', { style: { fontSize: 11, fontWeight: 600, color: isTerminal ? sc : '#fff', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } }, step.label),
826
+ !isTerminal && h('div', { style: { fontSize: 9, color: 'rgba(255,255,255,0.35)', marginTop: 1 } },
827
+ step.type === 'person' || step.isHuman ? 'Human' : step.type === 'system' ? 'System' : 'Agent',
828
+ step.duration ? ' \u00B7 ' + formatDuration(step.duration) : '',
829
+ step.status === 'in_progress' && step.progress > 0 ? ' \u00B7 ' + step.progress + '%' : ''
830
+ )
831
+ )
832
+ );
833
+ })
834
+ )
835
+ )
836
+ );
837
+ })()
806
838
  )
807
839
  ),
808
840
 
@@ -824,14 +856,6 @@ export function TaskPipelinePage() {
824
856
  )
825
857
  ),
826
858
 
827
- // Inline chain flowchart (shown when a task is clicked)
828
- expandedChain && expandedChain.length > 0 && h(ChainFlowInline, {
829
- chain: expandedChain,
830
- taskId: expandedTaskId,
831
- onClose: function() { setExpandedTaskId(null); },
832
- onClickTask: function(t) { openTaskDetail(t); }
833
- }),
834
-
835
859
  // Detail modal (double-click)
836
860
  selectedTask && h(TaskDetail, { task: selectedTask, chain: selectedChain, onClose: function() { setSelectedTask(null); setSelectedChain(null); }, onCancel: cancelTask })
837
861
  );