Inputs

ContributorTag: INPUT[text:ContributorTag] Start Date: INPUT[datePicker:startDate] End Date: INPUT[datePicker:endDate] Profile:: Jonny Stryder Optional GoalTags: Optional INPUT[inlineListSuggester(optionQuery("Efforts/Goal Board/GoalTags")):GoalTags] (Only affects Time Sheet)

BUTTON[new-goal-tag] BUTTON[refresh-tables]

[[GoalTag Buttons]]

Tasks Completed
const contributorTag = dv.current().ContributorTag;
 
const startDate = dv.date(dv.current().startDate);
const endDate = dv.date(dv.current().endDate);
 
dv.taskList(dv.pages().file.tasks
  .where(t => t.text.includes(contributorTag))
  .where(t => t.completed && t.completion >= startDate && t.completion <= endDate)
  ,false)
Tasks In Progress
const contributorTag = dv.current().ContributorTag;
 
dv.taskList(dv.pages().file.tasks
  .where(t => t.text.includes(contributorTag))
  .where(t => !t.completed)
  .where(t => !t.text.includes("#Blocked"))
  ,false)
Tasks Blocked
const contributorTag = dv.current().ContributorTag;
 
const endDate = dv.date(dv.current().endDate);
 
dv.taskList(dv.pages().file.tasks
  .where(t => t.text.includes(contributorTag))
  .where(t => !t.completed)
  .where(t => t.text.includes("#Blocked"))
  ,false)

INPUT[textArea(placeholder('Please explain the blocked tasks, if any')):blockedReasons]

Time Sheet

const contributorTag = dv.current().ContributorTag;
const goalTagsList = dv.current().GoalTags
  .map(gt => {
    const fileName = gt.path.split('/').pop().replace('.md', '');
    return '#' + fileName.replace(/\s+/g, '-');
  });
const startDate = dv.date(dv.current().startDate);
const endDate = dv.date(dv.current().endDate);
 
function extractMinutes(text, tag) {
  const regex = new RegExp(`${tag}\\/(?:timed|spent)\\/(\\d+)minutes`);
  const match = text.match(regex);
  return match ? parseInt(match[1]) : 0;
}
 
let tableData = goalTagsList.map(goalTag => {
  const tasks = dv.pages().file.tasks
    .where(t => t.text.includes(contributorTag))
    .where(t => t.completed && t.completion >= startDate && t.completion <= endDate)
    .where(t => t.text.includes(goalTag));
  
  let tasksCompleted = 0;
  let minutesWorked = 0;
  
  tasks.forEach(task => {
    tasksCompleted++;
    minutesWorked += extractMinutes(task.text, contributorTag);
  });
  
  return {
    goalTag: goalTag,
    tasksCompleted: tasksCompleted,
    minutesWorked: minutesWorked
  };
});
 
dv.table(["GoalTags", "Tasks Completed", "PP Earned", "Minutes Worked"], 
  tableData.map(row => [
    row.goalTag,
    row.tasksCompleted,
    "NA",
    row.minutesWorked
  ])
);
  • Legand

    • Timing convention
      • Nminutes means the contributor logged N working minutes to complete this task
      • Contributor means the timing has not been logged
    • Priority Points (pp), Icons, and Levels
      • highest priority = 🔺 = 100pp
      • high priority = ⏫ = 25pp
      • medium priority = 🔼 = 5pp
      • default priority = (none) = 3pp
      • low priority = 🔽 = 2pp
      • lowest priority = ⏬ = 1pp
    • PP Earned = Tasks Done x PP