Download app.js from smlflg/CloudCodeUsageAnalysis: direct link, hf CLI and curl.
- Browser
- Download file 9.74 kB
-
https://huggingface.co/smlflg/CloudCodeUsageAnalysis/resolve/main/app.js
- Command line
-
hf download hf://smlflg/CloudCodeUsageAnalysis/app.js
-
curl -L -o app.js https://huggingface.co/smlflg/CloudCodeUsageAnalysis/resolve/main/app.js
9.74 kB
| const formatHours = (value) => `${Number(value).toFixed(1)} h`; | |
| const create = (tag, className, text) => { | |
| const node = document.createElement(tag); | |
| if (className) node.className = className; | |
| if (text !== undefined) node.textContent = text; | |
| return node; | |
| }; | |
| const load = async () => { | |
| const response = await fetch("./data/analysis.json"); | |
| if (!response.ok) throw new Error("analysis.json konnte nicht geladen werden"); | |
| return response.json(); | |
| }; | |
| const renderHero = (data) => { | |
| document.querySelector("#headline").textContent = data.executive_summary.headline; | |
| const panel = document.querySelector("#heroPanel"); | |
| const stats = [ | |
| ["Best Estimate", formatHours(data.work_estimate.best_estimate_hours)], | |
| ["Aktive Projekte", String(data.work_estimate.active_project_count)], | |
| ["Top Empfehlung", data.rankings.top_recommendation.name], | |
| ["Analysefenster", `${data.meta.window_start} bis ${data.meta.window_end}`], | |
| ]; | |
| stats.forEach(([label, value]) => { | |
| const row = create("div", "summary-stat"); | |
| row.append(create("span", "", label)); | |
| row.append(create("strong", "", value)); | |
| panel.append(row); | |
| }); | |
| }; | |
| const renderFindings = (data) => { | |
| const host = document.querySelector("#findingCards"); | |
| data.executive_summary.key_findings.forEach((finding, index) => { | |
| const card = create("article", "card"); | |
| card.append(create("div", "label", `Antwort ${index + 1}`)); | |
| card.append(create("p", "supporting", finding)); | |
| host.append(card); | |
| }); | |
| }; | |
| const renderWork = (data) => { | |
| const host = document.querySelector("#workCards"); | |
| const cards = [ | |
| ["Best Estimate", formatHours(data.work_estimate.best_estimate_hours), "Zentralwert aus Session-Bloecken, Commit-Spans und Artefakt-Bonus."], | |
| ["Untergrenze", formatHours(data.work_estimate.lower_bound_hours), "Konservative Sicht: nur ein Teil der Session-Zeit zaehlt als aktive Build-Zeit."], | |
| ["Obergrenze", formatHours(data.work_estimate.upper_bound_hours), "Erweitert um stille Vor-/Nacharbeit, verworfene Versuche und uncommitted Arbeit."], | |
| ]; | |
| cards.forEach(([label, metric, support]) => { | |
| const card = create("article", "card"); | |
| card.append(create("div", "label", label)); | |
| card.append(create("p", "metric", metric)); | |
| card.append(create("p", "supporting", support)); | |
| host.append(card); | |
| }); | |
| const methodList = document.querySelector("#methodList"); | |
| data.work_estimate.method.forEach((line) => methodList.append(create("li", "", line))); | |
| const uncertaintyList = document.querySelector("#uncertaintyList"); | |
| data.work_estimate.uncertainties.forEach((line) => uncertaintyList.append(create("li", "", line))); | |
| }; | |
| const renderWorkflow = (data) => { | |
| const workflow = data.workflow_patterns; | |
| const narrative = document.querySelector("#workflowNarrative"); | |
| [workflow.startup_pattern, workflow.iteration_pattern, workflow.parallel_vs_serial.evidence].forEach((line) => { | |
| narrative.append(create("p", "", line)); | |
| }); | |
| const total = workflow.prototyping_vs_refinement.prototype_signals + workflow.prototyping_vs_refinement.refinement_signals; | |
| const protoPct = total ? (workflow.prototyping_vs_refinement.prototype_signals / total) * 100 : 0; | |
| const refinePct = 100 - protoPct; | |
| const chart = document.querySelector("#ratioChart"); | |
| [ | |
| ["Prototyping", protoPct, "proto"], | |
| ["Refinement", refinePct, "refine"], | |
| ].forEach(([label, pct, klass]) => { | |
| const row = create("div", "mini-row"); | |
| row.append(create("div", "", label)); | |
| const track = create("div", "track"); | |
| const fill = create("span"); | |
| fill.className = klass; | |
| fill.style.width = `${pct}%`; | |
| track.append(fill); | |
| row.append(track); | |
| row.append(create("div", "muted", `${pct.toFixed(0)}%`)); | |
| chart.append(row); | |
| }); | |
| document.querySelector("#ratioNote").textContent = workflow.prototyping_vs_refinement.interpretation; | |
| const cards = [ | |
| ["Seriell vs. Parallel", workflow.parallel_vs_serial.label], | |
| ["Eval-Loops", workflow.evaluation_loops.interpretation], | |
| ["Bevorzugte Projektarten", workflow.preferred_project_types.join(" • ")], | |
| ["Meta-Systeme", workflow.meta_systems.join(" • ")], | |
| ]; | |
| const host = document.querySelector("#workflowCards"); | |
| cards.forEach(([label, support]) => { | |
| const card = create("article", "card"); | |
| card.append(create("div", "label", label)); | |
| card.append(create("p", "supporting", support)); | |
| host.append(card); | |
| }); | |
| }; | |
| const renderClusters = (data) => { | |
| const grid = document.querySelector("#clusterGrid"); | |
| data.project_clusters.forEach((cluster) => { | |
| const card = create("article", "cluster-card"); | |
| card.append(create("div", "label", `${cluster.count} Projekte`)); | |
| card.append(create("h3", "", cluster.name)); | |
| card.append(create("p", "supporting", cluster.summary)); | |
| const pills = create("div", "pill-row"); | |
| cluster.projects.forEach((project) => { | |
| pills.append(create("span", "pill", `${project.name} · ${project.commit_count}`)); | |
| }); | |
| card.append(pills); | |
| grid.append(card); | |
| }); | |
| const tableHost = document.querySelector("#projectTable"); | |
| const table = create("table"); | |
| table.innerHTML = ` | |
| <thead> | |
| <tr> | |
| <th>Projekt</th> | |
| <th>Cluster</th> | |
| <th>Commits</th> | |
| <th>Sessions</th> | |
| <th>Status</th> | |
| </tr> | |
| </thead> | |
| <tbody></tbody> | |
| `; | |
| const tbody = table.querySelector("tbody"); | |
| data.projects.slice(0, 12).forEach((project) => { | |
| const row = document.createElement("tr"); | |
| row.innerHTML = ` | |
| <td>${project.name}</td> | |
| <td>${project.cluster}</td> | |
| <td>${project.commit_count}</td> | |
| <td>${project.session_count}</td> | |
| <td>${project.status}</td> | |
| `; | |
| tbody.append(row); | |
| }); | |
| tableHost.append(table); | |
| }; | |
| const renderTimeline = (data) => { | |
| const host = document.querySelector("#timeline"); | |
| const grid = create("div", "timeline-grid"); | |
| data.timeline.forEach((day) => { | |
| const cell = create("article", `day-cell level-${day.intensity}`); | |
| const date = new Date(day.date); | |
| const label = date.toLocaleDateString("de-DE", { day: "2-digit", month: "2-digit" }); | |
| const header = create("div", "day-head"); | |
| header.append(create("span", "", label)); | |
| header.append(create("span", "", `${day.projects.length} Projekte`)); | |
| cell.append(header); | |
| const projects = create("div", "day-projects"); | |
| if (day.projects.length === 0) { | |
| projects.append(create("span", "muted", "ruhiger Tag")); | |
| } else { | |
| day.projects.slice(0, 3).forEach((project) => { | |
| projects.append(create("span", "", `${project.name} · ${project.session_count} Session`)); | |
| }); | |
| } | |
| cell.append(projects); | |
| grid.append(cell); | |
| }); | |
| host.append(grid); | |
| }; | |
| const renderRanking = (data) => { | |
| const top = data.rankings.top_recommendation; | |
| const main = document.querySelector("#topRecommendation"); | |
| main.append(create("div", "badge", "Top Empfehlung")); | |
| main.append(create("h3", "", top.name)); | |
| main.append(create("p", "metric", `${top.score.toFixed(2)} / 5`)); | |
| main.append(create("p", "supporting", top.summary)); | |
| const stack = create("div", "mini-stack"); | |
| Object.entries(top.scores).forEach(([label, value]) => { | |
| const row = create("div", "mini-row"); | |
| row.append(create("div", "", label.replace("_", " "))); | |
| const track = create("div", "track"); | |
| const fill = create("span"); | |
| fill.style.width = `${(value / 5) * 100}%`; | |
| track.append(fill); | |
| row.append(track); | |
| row.append(create("div", "muted", value.toFixed(1))); | |
| stack.append(row); | |
| }); | |
| main.append(stack); | |
| const topThree = document.querySelector("#topThree"); | |
| data.rankings.top_three.forEach((project, index) => { | |
| const item = create("div", "rank-item"); | |
| item.innerHTML = `<strong>#${index + 1} ${project.name}</strong><p class="supporting">${project.summary}</p>`; | |
| topThree.append(item); | |
| }); | |
| const rankingTable = document.querySelector("#rankingTable"); | |
| const table = create("table"); | |
| table.innerHTML = ` | |
| <thead> | |
| <tr> | |
| <th>Projekt</th> | |
| <th>Score</th> | |
| <th>Commits</th> | |
| <th>Kernaussage</th> | |
| </tr> | |
| </thead> | |
| <tbody></tbody> | |
| `; | |
| const tbody = table.querySelector("tbody"); | |
| data.rankings.shortlist.forEach((project) => { | |
| const row = document.createElement("tr"); | |
| row.innerHTML = ` | |
| <td>${project.name}</td> | |
| <td>${project.score.toFixed(2)}</td> | |
| <td>${project.commit_count}</td> | |
| <td>${project.summary}</td> | |
| `; | |
| tbody.append(row); | |
| }); | |
| rankingTable.append(table); | |
| }; | |
| const renderEvidence = (data) => { | |
| const host = document.querySelector("#evidenceGrid"); | |
| data.evidence.forEach((entry) => { | |
| const card = create("article", "evidence-card"); | |
| card.append(create("div", "label", entry.project)); | |
| card.append(create("p", "supporting", `${entry.commits} Commits im Fenster · letzter Commit ${entry.last_commit ?? "n/a"}`)); | |
| const pills = create("div", "pill-row"); | |
| Object.entries(entry.artifacts).forEach(([key, value]) => pills.append(create("span", "pill", `${key}: ${value}`))); | |
| card.append(pills); | |
| const list = create("ul", "bullet-list"); | |
| entry.sample_messages.forEach((message) => list.append(create("li", "", message))); | |
| card.append(list); | |
| host.append(card); | |
| }); | |
| }; | |
| load() | |
| .then((data) => { | |
| renderHero(data); | |
| renderFindings(data); | |
| renderWork(data); | |
| renderWorkflow(data); | |
| renderClusters(data); | |
| renderTimeline(data); | |
| renderRanking(data); | |
| renderEvidence(data); | |
| }) | |
| .catch((error) => { | |
| document.body.innerHTML = `<main class="page-shell"><article class="panel"><h1>Ladefehler</h1><p>${error.message}</p></article></main>`; | |
| }); | |