66 lines
2.3 KiB
TypeScript
66 lines
2.3 KiB
TypeScript
type ParallelShard = {
|
|
id?: string;
|
|
worker_id?: string | null;
|
|
status?: string;
|
|
shard_index?: number | null;
|
|
result?: Record<string, unknown>;
|
|
error?: string | null;
|
|
};
|
|
|
|
interface Props {
|
|
shards: ParallelShard[];
|
|
unit: string;
|
|
}
|
|
|
|
function asCount(value: unknown): number {
|
|
const parsed = Number(value ?? 0);
|
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
|
}
|
|
|
|
function shardProgress(shard: ParallelShard): { processed: number; total: number; percent: number } {
|
|
const result = shard.result ?? {};
|
|
const total = asCount(result.total);
|
|
const outcomes =
|
|
asCount(result.exitosos ?? result.ok) +
|
|
asCount(result.fallidos ?? result.error) +
|
|
asCount(result.existentes);
|
|
const processed = Math.min(total || Number.MAX_SAFE_INTEGER, asCount(result.processed) || outcomes);
|
|
const percent = total > 0 ? Math.min(100, Math.round((processed / total) * 100)) : 0;
|
|
return { processed, total, percent };
|
|
}
|
|
|
|
export function ParallelBotProgress({ shards, unit }: Props) {
|
|
if (shards.length === 0) return null;
|
|
|
|
return (
|
|
<div className="wiz-section" style={{ marginTop: 16, width: "100%", maxWidth: 640 }}>
|
|
<h3 className="wiz-section-title">Avance por bot</h3>
|
|
<div className="wiz-review-grid" style={{ marginTop: 8 }}>
|
|
{shards.map((shard, index) => {
|
|
const progress = shardProgress(shard);
|
|
return (
|
|
<div key={shard.id || String(index)} className="wiz-review-item">
|
|
<div style={{ width: "100%" }}>
|
|
<span className="wiz-review-label">
|
|
Bot {shard.worker_id || `#${(shard.shard_index ?? index) + 1}`}
|
|
</span>
|
|
<span className="wiz-review-value">
|
|
{progress.processed}/{progress.total || "?"} {unit} · {progress.percent}% · {shard.status || "—"}
|
|
</span>
|
|
<div className="wiz-progress-track" style={{ marginTop: 8 }}>
|
|
<div className="wiz-progress-fill" style={{ width: `${progress.percent}%` }} />
|
|
</div>
|
|
{shard.error ? (
|
|
<span className="wiz-hint" style={{ color: "var(--danger, #dc2626)", marginTop: 6 }}>
|
|
{shard.error}
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|