Created
December 16, 2020 18:02
-
-
Save brbcoding/f32a69566ed0e3db7cc99167f9c1f8a5 to your computer and use it in GitHub Desktop.
Taskmaster.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let config = input.config({ | |
title: 'Taskmaster v0.2', | |
description: "Create and link tasks to projects based on a project template and task template", | |
items: [ | |
input.config.table('projectTemplatesTable', { | |
label: 'What table do you store your project templates in?' | |
}), | |
input.config.table('taskTemplatesTable', { | |
label: 'What table dox you store your task templates in?' | |
}), | |
input.config.table('projectsTable', { | |
label: 'What table do you store your projects in?' | |
}), | |
input.config.table('tasksTable', { | |
label: 'What table do you store your tasks in?' | |
}), | |
] | |
}) | |
let projectTemplatesTable = config.projectTemplatesTable | |
let taskTemplatesTable = config.taskTemplatesTable | |
let projectsTable = config.projectsTable | |
let tasksTable = config.tasksTable | |
// TODO: add settings for any hardcoded fields | |
let project = await input.recordAsync("Select a project", projectsTable) | |
const projectTasks = project.getCellValue("Tasks") | |
// TODO: if the project already has tasks | |
// prompt the user to make sure they want to continue | |
let projectTemplate = project.getCellValue('Request Type') | |
if(!projectTemplate) { | |
projectTemplate = await input.recordAsync("Select a template to use when creating tasks for this project", projectTemplatesTable) | |
await projectsTable.updateRecordAsync(project.id, { "Request Type": [{ id: projectTemplate.id }]}) | |
const projects = await projectsTable.selectRecordsAsync() | |
project = projects.getRecord(project.id) | |
} | |
let projectApproval = project.getCellValue('Approval') | |
const deadlineRequested = project.getCellValueAsString('Deadline or Open') | |
const deadline = project.getCellValueAsString("Deadline") | |
// if there is a deadline requested, and the project timeline hasn't been approved | |
if(!projectApproval && deadlineRequested === "Deadline") { | |
const acceptDeadline = await input.buttonsAsync(`The requester has a deadline for this project: ${deadline}. Do you want to accept?`, ['Yes', 'No']) | |
const approvalStatus = acceptDeadline === "Yes" ? "Approved: Accept Deadline" : "Approved: Timeline Pending" | |
// if no approval status is selected, force the user to select one. | |
await projectsTable.updateRecordAsync(project.id, { "Approval": { "name": approvalStatus }}) | |
const projects = await projectsTable.selectRecordsAsync() | |
project = projects.getRecord(project.id) | |
} | |
// check if the project has a deadline, and if it's been accepted | |
output.markdown(`Creating tasks...`) | |
// 2. duplicate all records, replacing linked project with selected project | |
const templateTableRecords = await taskTemplatesTable.selectRecordsAsync() | |
// Request Type == Project Template | |
// TODO: make this less stringy | |
const templateRecords = (templateTableRecords.records || []).filter(record => record.getCellValueAsString('Request Type') === project.getCellValueAsString('Request Type')) | |
const tasksFieldsNames = [...tasksTable.fields.map(field => field.name), "Use Project Driver", "Start"] | |
const newRecords = templateRecords.map(record => { | |
const recordFields = taskTemplatesTable.fields.reduce((field, fieldCurr) => { | |
let fieldVal = null | |
if(fieldCurr.isComputed || fieldCurr.name === "Request Type" || (tasksFieldsNames.indexOf(fieldCurr.name) === -1)) { | |
return { ...field } | |
} else if(fieldCurr.name === "Use Project Driver") { | |
let useProjectDriver = record.getCellValue("Use Project Driver") | |
let projectDriver = project.getCellValue("Driver") | |
if(useProjectDriver === true && projectDriver && projectDriver.length > 0) { | |
fieldVal = [{ id: projectDriver[0].id }] | |
return { ...field, "Task Driver": fieldVal } | |
} else { | |
return { ...field } | |
} | |
} else if (fieldCurr.name === "Start") { | |
fieldVal = project.getCellValue("Start") | |
} else if(fieldCurr.type === "singleSelect") { | |
fieldVal = { name: record.getCellValueAsString(fieldCurr.name) } | |
} else if(fieldCurr.type === "multipleRecordLinks") { | |
} else if (fieldCurr.type === "singleCollaborator") { | |
let collaborator = record.getCellValue(fieldCurr.name) | |
if(collaborator) { | |
fieldVal = [{ id: collaborator.id }] | |
} | |
} else { | |
fieldVal = record.getCellValue(fieldCurr.name) | |
} | |
return { ...field, [fieldCurr.name]: fieldVal } | |
}, { "Project": [{id : project.id }] }) | |
return { | |
fields: recordFields | |
} | |
}) | |
const insertedRecords = await tasksTable.createRecordsAsync(newRecords) | |
// required post-insert updates | |
// - dependencies | |
// - start / end times? | |
let tasks = await tasksTable.selectRecordsAsync() | |
let newTasks = insertedRecords.map(recordId => tasks.getRecord(recordId)) | |
// start date of the second task should be the end date of the first task | |
// const firstTask = await tasks.getRecord(insertedRecords[0]) | |
// const firstTaskStart = firstTask.getCellValueAsString("Start") | |
// let start = new Date(firstTaskStart) | |
// TODO: setup start/end times based on the deadline | |
// we could probably backtrack by using `reverse` | |
// check if the project has a requested deadline | |
// and if we have accepted the deadline | |
// of Approval = Accepted: Deadline | |
// setup dependencies | |
let taskDependencies = [] | |
templateRecords.forEach(record => { | |
const dependencies = record.getCellValue("Dependency") | |
// lookup indexes from taskDependencies | |
taskDependencies.push({ | |
id: record.id, | |
dependentIndices: !dependencies ? null : dependencies.map(dependency => templateRecords.findIndex(d => d.id === dependency.id)) | |
}) | |
}) | |
let postInsertUpdates = newTasks.map((record, idx) => { | |
const dependentIds = taskDependencies[idx].dependentIndices | |
if(dependentIds && dependentIds.length) { | |
// TODO: check to make sure it has a dependency | |
// const previousRecordDuration = tasks.getRecord(previousRecordId).getCellValue("Duration (Days)") | |
// start = addDays(start, previousRecordDuration) | |
// check if the template that created this has a dependency | |
const update = { | |
id: record.id, | |
fields: { | |
// "Start": start, | |
"Dependency": dependentIds.map(id => { | |
return { id: insertedRecords[id] } | |
}) | |
} | |
} | |
return update | |
} | |
}) | |
// TODO: combine this and the dependency setup | |
// let projectApproval = project.getCellValueAsString('Approval') | |
// const deadlineRequested = project.getCellValueAsString('Deadline or Open') | |
// const deadline = project.getCellValueAsString("Deadline") | |
// Approved: Accept Deadline | |
let dateUpdates = [] | |
if(project.getCellValueAsString('Approval') === "Approved: Accept Deadline") { | |
let end = project.getCellValue('Deadline') | |
let start = tasks.getRecord(insertedRecords[insertedRecords.length - 1]).getCellValue("Duration (Days)") | |
dateUpdates = insertedRecords.reverse().map((record, idx) => { | |
end = idx === 0 ? end : start | |
const recordDuration = tasks.getRecord(record).getCellValue("Duration (Days)") | |
start = subtractDays(new Date(end), recordDuration) | |
const update = { | |
id: record, | |
fields: { | |
"Start": start, | |
"End": end, | |
} | |
} | |
return update | |
}) | |
} | |
output.markdown("๐ Updating Dependencies...") | |
while(postInsertUpdates.length) { | |
const update = postInsertUpdates.shift() | |
if(update) await tasksTable.updateRecordAsync(update.id, update.fields) | |
} | |
output.markdown("๐ Scheduling Tasks...") | |
while(dateUpdates.length) { | |
const update = dateUpdates.shift() | |
if(update) await tasksTable.updateRecordAsync(update.id, update.fields) | |
} | |
// get the duration of the final task | |
// add it to start | |
// use it as the project end date | |
// tasks = await tasksTable.selectRecordsAsync() | |
// const lastRecordDuration = tasks.getRecord(insertedRecords[insertedRecords.length - 1]).getCellValue("Duration (Days)") | |
// start = addDays(start, lastRecordDuration) | |
// output.markdown(start.toString()) | |
// await projectsTable.updateRecordAsync(project.id, { "End": start }) | |
output.markdown("Created tasks!") | |
function addDays(start, days) { | |
var date = new Date(start) | |
date.setDate(date.getDate() + days) | |
return date | |
} | |
function subtractDays(start, days) { | |
var date = new Date(start) | |
date.setDate(date.getDate() - days) | |
return date | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment