Skip to content

Commit dce1e04

Browse files
authored
Merge pull request #491 from STAPLE-verse/482-project-summary-export
482 project summary export
2 parents 904e8ac + d3516f2 commit dce1e04

5 files changed

Lines changed: 177 additions & 57 deletions

File tree

summary-viewer/Contributors.html

Lines changed: 133 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,15 @@
308308
// show details cards
309309
function showDetails(type, id, name, detailsSectionId) {
310310
const detailsSection = document.getElementById(detailsSectionId)
311+
if (detailsSectionId === "member-details-section") {
312+
const p = document.getElementById("member-placeholder")
313+
if (p) p.style.display = "none"
314+
}
315+
316+
if (detailsSectionId === "team-details-section") {
317+
const p = document.getElementById("team-placeholder")
318+
if (p) p.style.display = "none"
319+
}
311320

312321
if (!detailsSection) {
313322
console.error(`Details section with ID "${detailsSectionId}" not found.`)
@@ -780,10 +789,18 @@ <h2>${name} Details</h2>
780789
// Count the unique members
781790
const numberOfUniqueMembers = uniqueMemberNames.size
782791
document.getElementById("stat-number-1").textContent = numberOfUniqueMembers
792+
const memberPlaceholder = document.getElementById("member-placeholder")
793+
if (memberPlaceholder) {
794+
memberPlaceholder.style.display = numberOfUniqueMembers > 0 ? "block" : "none"
795+
}
783796

784797
const uniqueTeamNames = new Set(teamsDataArray.map((team) => team.name))
785798
const numberOfUniqueTeams = teamsWithTaskData.size
786799
document.getElementById("stat-number-2").textContent = numberOfUniqueTeams
800+
const teamPlaceholder = document.getElementById("team-placeholder")
801+
if (teamPlaceholder) {
802+
teamPlaceholder.style.display = numberOfUniqueTeams > 0 ? "block" : "none"
803+
}
787804

788805
// Extract all roles from project members
789806
const memberRoles = jsonData.projectMembers.flatMap((member) => member.roles)
@@ -870,7 +887,16 @@ <h2>${name} Details</h2>
870887
}
871888

872889
// Render the donut chart
873-
Plotly.newPlot("roles-donut-chart", roleData, roleLayout)
890+
const hasAnyRoles = roleValues.some((v) => v > 0)
891+
892+
if (hasAnyRoles) {
893+
Plotly.newPlot("roles-donut-chart", roleData, roleLayout)
894+
} else {
895+
const rolesEl = document.getElementById("roles-donut-chart")
896+
if (rolesEl) {
897+
rolesEl.innerHTML = '<p class="empty-note">No roles</p>'
898+
}
899+
}
874900

875901
// Count the total number of rows
876902
const totalTasks = latestTaskLogs.length
@@ -920,7 +946,12 @@ <h2>${name} Details</h2>
920946
}
921947

922948
// Render the chart
923-
Plotly.newPlot("completed-tasks-chart", dataCompletedTasks, layout)
949+
if (totalTasks > 0) {
950+
Plotly.newPlot("completed-tasks-chart", dataCompletedTasks, layout)
951+
} else {
952+
const el = document.getElementById("completed-tasks-chart")
953+
if (el) el.innerHTML = '<p class="empty-note">No tasks yet</p>'
954+
}
924955

925956
// completed form chart
926957
// Count the total number of form tasks
@@ -972,7 +1003,12 @@ <h2>${name} Details</h2>
9721003
}
9731004

9741005
// Render the chart
975-
Plotly.newPlot("completed-forms-chart", dataCompletedForms, layoutForm)
1006+
if (totalForms > 0) {
1007+
Plotly.newPlot("completed-forms-chart", dataCompletedForms, layoutForm)
1008+
} else {
1009+
const el = document.getElementById("completed-forms-chart")
1010+
if (el) el.innerHTML = '<p class="empty-note">No forms</p>'
1011+
}
9761012

9771013
//get roles individuals
9781014
const rolesByIndividual = projectMembersDataFrame.map((individual) => {
@@ -1042,6 +1078,12 @@ <h2>${name} Details</h2>
10421078
100
10431079
).toFixed(1)
10441080

1081+
// Hide progress bar if percentage is NaN
1082+
const showTasksBar = Number.isFinite(Number(tasksPercentComplete))
1083+
const showFormsBar = Number.isFinite(Number(formsPercentComplete))
1084+
const showNoTasksNote = !showTasksBar
1085+
const showNoFormsNote = !showFormsBar
1086+
10451087
// Create the card container
10461088
const card = document.createElement("div")
10471089
card.className = "small-card clickable"
@@ -1051,28 +1093,57 @@ <h2>${name} Details</h2>
10511093
title.textContent = member.name
10521094
card.appendChild(title)
10531095

1054-
// Create a container for the donut chart
1055-
const containerId = `member-role-chart-${member.projectMemberId}`
1056-
const chartDiv = document.createElement("div")
1057-
chartDiv.id = containerId
1058-
card.appendChild(chartDiv)
1096+
// Create a container for the donut chart or an empty note
1097+
const hasRoles = member.roles.length > 0
1098+
1099+
let chartDiv = null
1100+
if (hasRoles) {
1101+
chartDiv = document.createElement("div")
1102+
chartDiv.id = `member-role-chart-${member.projectMemberId}`
1103+
card.appendChild(chartDiv)
1104+
} else {
1105+
const note = document.createElement("p")
1106+
note.className = "empty-note"
1107+
note.textContent = "No roles"
1108+
card.appendChild(note)
1109+
}
10591110

10601111
// Add progress bars for tasks and forms
10611112
const progressBars = `
1062-
<div class="progress-container">
1063-
<div class="progress-bar" style="width: ${tasksPercentComplete}%; background-color: ${themeColors.primary3};" title="Tasks: ${tasksPercentComplete}% Completed"></div>
1064-
</div>
1065-
<div class="progress-container">
1066-
<div class="progress-bar" style="width: ${formsPercentComplete}%; background-color: ${themeColors.primary4};" title="Forms: ${formsPercentComplete}% Submitted"></div>
1067-
</div>
1068-
`
1113+
${
1114+
showTasksBar
1115+
? `
1116+
<div class="progress-container">
1117+
<div class="progress-bar"
1118+
style="width: ${tasksPercentComplete}%; background-color: ${themeColors.primary3};"
1119+
title="Tasks: ${tasksPercentComplete}% Completed"></div>
1120+
</div>`
1121+
: `<p class="empty-note">No tasks</p>`
1122+
}
1123+
${
1124+
showFormsBar
1125+
? `
1126+
<div class="progress-container">
1127+
<div class="progress-bar"
1128+
style="width: ${formsPercentComplete}%; background-color: ${themeColors.primary4};"
1129+
title="Forms: ${formsPercentComplete}% Submitted"></div>
1130+
</div>`
1131+
: `<p class="empty-note">No forms</p>`
1132+
}
1133+
`
10691134
card.innerHTML += progressBars // Append progress bars to the card
10701135

1071-
// Append the card to the members section and render the chart
1136+
// Append the card to the members section and render the chart if appropriate
10721137
const memberRoleChartContainer = document.getElementById("members-section")
10731138
if (memberRoleChartContainer) {
10741139
memberRoleChartContainer.appendChild(card)
1075-
createDonutChart(data, containerId, `${member.name}`)
1140+
if (hasRoles) {
1141+
createDonutChart(
1142+
data,
1143+
`member-role-chart-${member.projectMemberId}`,
1144+
`${member.name}`
1145+
)
1146+
}
10761147
} else {
10771148
console.error("Main container for member charts not found!")
10781149
}
@@ -1157,32 +1228,57 @@ <h2>${name} Details</h2>
11571228
title.textContent = team.teamName
11581229
card.appendChild(title)
11591230

1160-
// Create a container for the donut chart
1161-
const containerId = `team-role-chart-${team.teamId}`
1162-
const chartDiv = document.createElement("div")
1163-
chartDiv.id = containerId
1164-
card.appendChild(chartDiv)
1231+
// Create a container for the donut chart or an empty note
1232+
const hasRoles = team.roles.length > 0
1233+
1234+
let chartDiv = null
1235+
if (hasRoles) {
1236+
chartDiv = document.createElement("div")
1237+
chartDiv.id = `team-role-chart-${team.teamId}`
1238+
card.appendChild(chartDiv)
1239+
} else {
1240+
const note = document.createElement("p")
1241+
note.className = "empty-note"
1242+
note.textContent = "No roles"
1243+
card.appendChild(note)
1244+
}
1245+
1246+
// NaN guards for progress bars
1247+
const showTeamTasksBar = Number.isFinite(Number(team.tasksPercentComplete))
1248+
const showTeamFormsBar = Number.isFinite(Number(team.formsPercentComplete))
11651249

11661250
// Add progress bars for tasks and forms
11671251
const progressBars = `
1168-
<div class="progress-container">
1169-
<div class="progress-bar"
1170-
style="width: ${team.tasksPercentComplete}%; background-color: ${themeColors.primary3};"
1171-
title="Tasks: ${team.tasksPercentComplete}% Completed"></div>
1172-
</div>
1173-
<div class="progress-container">
1174-
<div class="progress-bar"
1175-
style="width: ${team.formsPercentComplete}%; background-color: ${themeColors.primary4};"
1176-
title="Forms: ${team.formsPercentComplete}% Submitted"></div>
1177-
</div>
1178-
`
1252+
${
1253+
showTeamTasksBar
1254+
? `
1255+
<div class="progress-container">
1256+
<div class="progress-bar"
1257+
style="width: ${team.tasksPercentComplete}%; background-color: ${themeColors.primary3};"
1258+
title="Tasks: ${team.tasksPercentComplete}% Completed"></div>
1259+
</div>`
1260+
: `<p class="empty-note">No tasks</p>`
1261+
}
1262+
${
1263+
showTeamFormsBar
1264+
? `
1265+
<div class="progress-container">
1266+
<div class="progress-bar"
1267+
style="width: ${team.formsPercentComplete}%; background-color: ${themeColors.primary4};"
1268+
title="Forms: ${team.formsPercentComplete}% Submitted"></div>
1269+
</div>`
1270+
: `<p class="empty-note">No forms</p>`
1271+
}
1272+
`
11791273
card.innerHTML += progressBars // Append progress bars to the card
11801274

1181-
// Append the card to the teams section and render the chart
1275+
// Append the card to the teams section and render the chart if appropriate
11821276
const teamRoleChartContainer = document.getElementById("teams-section")
11831277
if (teamRoleChartContainer) {
11841278
teamRoleChartContainer.appendChild(card)
1185-
createDonutChart(data, containerId, `${team.teamName}`)
1279+
if (hasRoles) {
1280+
createDonutChart(data, `team-role-chart-${team.teamId}`, `${team.teamName}`)
1281+
}
11861282
} else {
11871283
console.error("Main container for team charts not found!")
11881284
}
@@ -1625,7 +1721,7 @@ <h3>Forms Submitted</h3>
16251721
</p>
16261722
<div id="members-section"></div>
16271723
<div id="member-details-section" class="details-container">
1628-
<p>Select a card to view details about the contributor or team.</p>
1724+
<p id="member-placeholder">Select a card to view details about the contributor.</p>
16291725
</div>
16301726
</div>
16311727
</div>
@@ -1643,7 +1739,7 @@ <h3>Forms Submitted</h3>
16431739
</p>
16441740
<div id="teams-section"></div>
16451741
<div id="team-details-section" class="details-container">
1646-
<p>Select a card to view details about the contributor or team.</p>
1742+
<p id="team-placeholder">Select a card to view details about the team.</p>
16471743
</div>
16481744
</div>
16491745
</div>

summary-viewer/Events.html

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ <h3>Select Time Interval and Color Scheme</h3>
480480
const tickvals = []
481481
const ticktext = []
482482
const allChartData = []
483+
let rowCount = 0
483484

484485
milestoneDataRaw.forEach((m) => {
485486
const milestoneId = String(m.id)
@@ -489,6 +490,7 @@ <h3>Select Time Interval and Color Scheme</h3>
489490
)
490491

491492
milestoneTasks.forEach((t) => {
493+
rowCount += 1
492494
const yLabel = `task-${t.id}`
493495
tickvals.push(yLabel)
494496
ticktext.push("↳ " + t.name)
@@ -509,6 +511,7 @@ <h3>Select Time Interval and Color Scheme</h3>
509511
})
510512
})
511513

514+
rowCount += 1
512515
tickvals.push(milestoneId)
513516
ticktext.push(m.name)
514517

@@ -543,8 +546,9 @@ <h3>Select Time Interval and Color Scheme</h3>
543546
type: "category",
544547
automargin: true,
545548
tickfont: { size: 14 },
549+
tickpadding: 8,
546550
},
547-
height: milestoneDataRaw.length * 40 + 100,
551+
height: Math.min(rowCount * 40 + 120, 2000),
548552
showlegend: false,
549553
margin: { l: 150, r: 30, t: 50, b: 40 },
550554
}
@@ -740,7 +744,9 @@ <h1>Milestone Gantt Chart</h1>
740744
<i class="expand-icon">+</i>
741745
</label>
742746
<div class="collapse-content">
743-
<div id="milestone-gantt-container"></div>
747+
<div class="gantt-scroll-container">
748+
<div id="milestone-gantt-container"></div>
749+
</div>
744750
</div>
745751
</div>
746752
<div class="custom-collapse">

summary-viewer/Form_Data.html

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,6 @@
4747
<link rel="stylesheet" href="./_file/style.ef1f7908.css" />
4848

4949
<script type="module">
50-
// Load Plot and d3 (if needed elsewhere)
51-
const [Plot, d3] = await Promise.all([
52-
import("https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6.17/+esm"),
53-
import("https://cdn.jsdelivr.net/npm/d3@7/+esm"),
54-
])
55-
5650
// Embed the JSON data directly here
5751
const jsonData = __INJECT_JSON__
5852
document.addEventListener("DOMContentLoaded", () => {

summary-viewer/Tasks.html

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,7 @@
241241
// Convert taskLogStatus to a user-friendly format
242242
const formattedStatus = task.taskLogStatus === "COMPLETED" ? "Completed" : "Not Completed"
243243

244-
const formattedTaskStatus =
245-
task.taskStatus === "COMPLETED" ? "Completed" : "Not Completed"
244+
const formattedTaskStatus = task.status === "COMPLETED" ? "Completed" : "Not Completed"
246245

247246
// Return a new object with updated values
248247
return {
@@ -316,8 +315,13 @@
316315
paper_bgcolor: "rgba(0, 0, 0, 0)", // Transparent chart area background
317316
}
318317

319-
// Render the chart
320-
Plotly.newPlot("completed-tasks-chart", dataCompletedTasks, layoutCompletedTasks)
318+
// Render the chart (only if there are tasks)
319+
if (totalTasks > 0) {
320+
Plotly.newPlot("completed-tasks-chart", dataCompletedTasks, layoutCompletedTasks)
321+
} else {
322+
const el = document.getElementById("completed-tasks-chart")
323+
if (el) el.innerHTML = '<p class="empty-note">No tasks created yet</p>'
324+
}
321325

322326
const latestTaskLogs = Array.from(
323327
tasksDataFrame
@@ -385,8 +389,13 @@
385389
paper_bgcolor: "rgba(0, 0, 0, 0)", // Transparent chart area background
386390
}
387391

388-
// Render the chart
389-
Plotly.newPlot("completed-tasklogs-chart", dataCompletedTaskLogs, layout)
392+
// Render the chart (only if there are task logs)
393+
if (totalTaskLogs > 0) {
394+
Plotly.newPlot("completed-tasklogs-chart", dataCompletedTaskLogs, layout)
395+
} else {
396+
const el = document.getElementById("completed-tasklogs-chart")
397+
if (el) el.innerHTML = '<p class="empty-note">No task logs yet</p>'
398+
}
390399

391400
// Step 1: Group logs by taskId and assignedToId
392401
const taskLogMap = tasksDataFrame.reduce((map, log) => {
@@ -431,11 +440,18 @@
431440
})
432441

433442
// Step 3: Calculate average completion time
434-
const averageCompletionTime =
435-
completedCount > 0
436-
? `${(totalCompletionTime / completedCount).toFixed(2)} Days`
437-
: "0 days"
438-
document.getElementById("stat-number-3").textContent = averageCompletionTime
443+
const statNumEl = document.getElementById("stat-number-3")
444+
const statIconEl = document.getElementById("stat-icon-3")
445+
446+
if (completedCount > 0) {
447+
const averageCompletionTime = `${(totalCompletionTime / completedCount).toFixed(2)} Days`
448+
if (statNumEl) statNumEl.textContent = averageCompletionTime
449+
if (statIconEl) statIconEl.style.display = ""
450+
} else {
451+
if (statNumEl)
452+
statNumEl.innerHTML = '<span class="empty-note">No completed tasks yet</span>'
453+
if (statIconEl) statIconEl.style.display = "none"
454+
}
439455

440456
function createTaskDropdownAndDataTable(containerId, dataTableContainerId) {
441457
// Step 1: Get unique task names
@@ -683,7 +699,7 @@ <h4>Task Logs Completed</h4>
683699
<div class="stat-card">
684700
<h4>Average Completion Time</h4>
685701
<p id="stat-number-3">Days</p>
686-
<i class="fas fa-clock" id="stat-number-3" aria-hidden="true"></i>
702+
<i class="fas fa-clock" id="stat-icon-3" aria-hidden="true"></i>
687703
</div>
688704
</div>
689705
</div>

0 commit comments

Comments
 (0)