Tasks
A Task is an element of a Scenario, and is anything that needs to get done in order for the project to move toward completion. Each task has attributes such as start and end dates, a completion percentage, and resource assignments.
Instance Properties
As with most scriptable objects, instances of the Task class have properties that define their abilities and usage.
NOTE: In the properties list shown below r/o indicates a property whose value is “read-only” or can only be read, not changed by the script.
NOTE: In OmniPlan 4.x, tasks now support manual scheduling. Tasks which are set to be scheduled manually will use the start and end dates you provide; OmniPlan will not attempt to automatically reschedule them. (Manual task scheduling replaces the “locked” task date functionality offered by previous OmniPlan versions.)
absoluteEndLimit (Date r/o) • Latest that this task could end without effecting the overall start or end of the project.
absoluteStartLimit (Date r/o) • Earliest that this task could start without effecting the overall start or end of the project.
assignments (Array of Assignment r/o) • Resources assigned to this task.
assignmentsCost (Number r/o) • The cost of assigned resources to this task (per use and per hour costs).
currentEndLimit (Date r/o) • Latest that this task could end without effecting any other connected task.
currentStartLimit (Date r/o) • Earliest that this task could start without effecting any other connected task.
dependents (Array of Dependency) • Dependencies where this task is the prerequisite task.
duration (Duration) • Duration of the task.
effort (Number) • Total effort needed to complete this task in person-seconds.
effortDone (Number) • Effort already accomplished upon this task in person-seconds.
effortRemaining (Number) • Effort remaining until completion of this task in person-seconds.
endDate (Date r/o) • Scheduled end date.
endNoEarlierThanDate (Date or null) • Constraint that this task must end no earlier than the given date, if any.
endNoLaterThanDate (Date or null) • Constraint that this task must end no later than the given date, if any.
expectedEffortEstimate (Number) • Three-point estimation expected effort estimate in person-seconds.
freeSlack (Number r/o) • Free slack (or float) is how much time a task can be delayed before any other connected task is effected.
manualEndDate (Date or null) • (OmniPlan 4.x) Manual end date of this task, if any. Tasks which are set to be scheduled manually will use the start and end dates you provide; OmniPlan will not attempt to automatically reschedule them.
manualStartDate (Date or null) • (OmniPlan 4.x) Manual start date of this task, if any. Tasks which are set to be scheduled manually will use the start and end dates you provide; OmniPlan will not attempt to automatically reschedule them.
lockedEndDate (Date or null) • (Dropped in OmniPlan 4.x) Locked end date of this task, if any.
lockedStartDate (Date or null) • (Dropped in OmniPlan 4.x) Locked start date of this task, if any.
maxEffortEstimate (Number) • Three-point estimation maximum effort estimate in person-seconds.
minEffortEstimate (Number) • Three-point estimation minimum effort estimate in person-seconds.
note (String) • The note for this task.
prerequisites (Array of Dependency r/o) • Dependencies where this task is the dependent task.
priority (Number) • Priority of this task during resource leveling. The higher the priority, the sooner leveling will attempt to schedule the task.
resourceAssignmentType (ResourceAssignmentType) • How this task should react when resources are assigned to it.
resourceLeveledDate (Date or null r/o) • The date that resource leveling has determined that this task ought to be scheduled at. May be missing if resource leveling isn’t needed to place this task. (E.g. if the task is already locked or otherwise already scheduled at an appropriate date.)
resourceLevelingDelay (Number r/o) • The amount of time that resource leveling needs to delay this task beyond when it could otherwise be scheduled.
startDate (Date r/o) • Scheduled start date.
startNoEarlierThanDate (Date or null) • Constraint that this task must start no earlier than the given date, if any.
startNoLaterThanDate (Date or null) • Constraint that this task must start no later than the given date, if any.
staticCost (Number) • The built-in cost of performing this task.
subtasks (Array of Task r/o) • Child tasks contained within this task group, or split chunks of this task, if it is split.
title (String) • Title of this task.
totalCost (Number r/o) • The sum of static and assignment costs.
totalSlack (Number r/o) • Total slack (or float) is how much time a task can be delayed before effecting the overall start or end of the project.
type (TaskType) • Type of this task.
uniqueID (String r/o) • The unique identifier for the task. Used in creating URL links to tasks in OmniPlan: omniplan:///task/<uniqueID>
Working with Properties
A function that returns references to tasks whose title contain, begins with, or ends with the provided string:
Locating Tasks by Title
function tasksMatchedByTitle(searchIndex, searchString){
var searchString = searchString.toUpperCase()
var allTasks = actual.rootTask.descendents()
var matches = allTasks.filter(task => {
var title = task.title.toUpperCase()
switch(searchIndex){
case 0:
return title === searchString
case 1:
return title.startsWith(searchString)
case 1:
return title.includes(searchString)
case 3:
return title.endsWith(searchString)
}
})
return matches
}
tasksWhoseTitleMatches(1, "City")
To generate a reference to an existing task, use the taskNamed() function of the Scenario class, which searches the entire hierarchy of tasks, to return the first matching task. In the following example, a reference to a task is generated and if the task does not exist, one will be created and the reference to the new task stored.
Reference Task by Title
var taskName = "Build Porch"
var task = actual.taskNamed(taskName)
if(!task){
task = actual.rootTask.addSubtask()
task.title = taskName
}
A function for selecting specified tasks in the project:
Select Tasks
function selectTasks(taskReferenceArray){
var identifiers = taskReferenceArray.map(task => task.uniqueID)
var IDstr = identifiers.join(",")
URL.fromString(`omniplan:///task/${IDstr}`).open()
}
A plug-in to open the first URL in the note of the selected task.
Open Note Link
/*{
"type": "action",
"targets": ["omniplan"],
"author": "Otto Automator",
"identifier": "com.omni-automation.op.open-note-url",
"version": "1.0",
"description": "Open the first URL in the note of the selected task.",
"label": "Open Note Link",
"shortLabel": "Open Note Link",
"paletteLabel": "Open Note Link"
}*/
(() => {
var action = new PlugIn.Action(function(selection, sender){
try {
var task = document.windows[0].selection.tasks[0]
var note = task.note
if (note.includes("://")) {
var urlStr = note.match(/[^<\s][^\s]+\/\/[^\s>]+/)[0]
var url = URL.fromString(urlStr)
if(url){
url.open()
} else {
console.error("ERROR: \"" + urlStr + "\" is not a valid URL.")
}
}
}
catch(err){console.error(err)}
});
action.validate = function(selection, sender){
return (selection.tasks.length === 1)
};
return action;
})();
Instance Functions
The following functions can be performed on instances of the Task class.
customValue(forKey:String) → (String or null) • (OmniPlan 4.x) Access to custom data values.
setCustomValue(forKey:String, to:String) → (OmniPlan 4.x) Change custom data values.
descendents() → (Array of Task) • Returns an array of all tasks which are descended from this one. Sometimes used with the rootTask object to generate a list of all tasks.
clearResourceLeveledDate() • Remove the effects of resource leveling from this task.
addPrerequisite(to:Task) → (Dependency) • Create a new dependency where the passed in task is the prerequisite and this task is the dependent.
addDependent(to:Task) → (Dependency) • Create a new dependency where the passed in task is the dependent and this task is the prerequisite.
addAssignment(to:Resource) → (Assignment) • Create a new assignment to the given resource.
addSubtask() → (Task) • Create a new subtask, and making this task into a group. When used with the rootTask object, a new task is created at the top-level.
split(at:Date, resumingAt:Date) → (Boolean) • Divide this task into multiple split chunks, with the same name, overall effort, and assignments, but with any duration after the split date moved to begin at the resume date.
remove() • Delete this task and remove it from the project, along with any associated dependencies and assignments.
User Data Examples
Getting and setting custom data for tasks:
Set/Get Task Custom Data Object
var task = actual.taskNamed("Add Rebar")
if (task){
task.setCustomValue("PO","A635479")
task.customValue("PO")
//--> "A635479"
}
Identifying tasks using a specified custom tag:
Tasks Using Specified Custom Tag
function tasksUsingCustomTag(tagName){
var allTasks = actual.rootTask.descendents()
var matches = allTasks.filter(task => {
return task.customValue(tagName).length > 0
})
return matches
}
tasksUsingCustomTag("SKU")
The previous function combined with the previous function for selecting tasks in the application interface:
Select Tasks Using Specified Custom Tag
function tasksUsingCustomTag(tagName){
var allTasks = actual.rootTask.descendents()
var matches = allTasks.filter(task => {
return task.customValue(tagName).length > 0
})
return matches
}
function selectTasks(taskReferenceArray){
var identifiers = taskReferenceArray.map(task => task.uniqueID)
var IDstr = identifiers.join(",")
URL.fromString(`omniplan:///task/${IDstr}`).open()
}
var taskReferenceArray = tasksUsingCustomTag("SKU")
if(taskReferenceArray.length > 0){selectTasks(taskReferenceArray)}
Here's a function that returns an object reference to all tasks whose custom tag has the provided value. In this example, the custom tag is “UUID”:
NOTE: The result of this function is an array. No matches produces an empty array.
Find Tasks by Value of Custom Tag
function matchTasksByCustomTag(tagName, tagValue){
var allTasks = actual.rootTask.descendents()
var matches = allTasks.filter(task => {
return task.customValue(tagName) === tagValue
})
return matches
}
var tasks = matchTasksByCustomTag('UUID', "88279F64-86CE-4BF7-A5D3-5910E0D7534C")
Tasks whose custom tag value begins with a specified value:
Find Tasks Whose Custom Tag Value Begins With Value
function tasksWhereCustomTagValueBeginsWithValue(tagName, tagValue){
var allTasks = actual.rootTask.descendents()
var matches = allTasks.filter(task => {
return task.customValue(tagName).startsWith(tagValue)
})
return matches
}
var tasks = tasksWhereCustomTagValueBeginsWithValue('SKU', "OZ346")
Tasks whose custom tag value ends with a specified value:
Find Tasks Whose Custom Tag Value Ends With Value
function tasksWhereCustomTagValueEndsWithValue(tagName, tagValue){
var allTasks = actual.rootTask.descendents()
var matches = allTasks.filter(task => {
return task.customValue(tagName).endsWith(tagValue)
})
return matches
}
var tasks = tasksWhereCustomTagValueEndsWithValue('SKU', "1234")
Tasks whose custom tag value includes a specified value:
Find Tasks Whose Custom Tag Value Includes Value
function tasksWhereCustomTagValueIncludesValue(tagName, tagValue){
var allTasks = actual.rootTask.descendents()
var matches = allTasks.filter(task => {
return task.customValue(tagName).includes(tagValue)
})
return matches
}
var tasks = tasksWhereCustomTagValueEndsWithValue('SKU', "000X")
Task Types (TaskType class)
Here are the various properties of the TaskType class that are used as values for the type property of the Task class:
all → (Array of TaskType r/o) • An array of all items of this enumeration. Often used when creating action forms.
group → (TaskType r/o) • A container for other tasks.
hammock → (TaskType r/o) • A task whose length is determined by its dependencies rather than from a fixed effort or duration.
milestone → (TaskType r/o) • A milestone. Has zero duration.
task → (TaskType r/o) • A standard task. (created by default if no type is specified)
Set Task Type
var task = actual.rootTask.addSubtask()
task.title = "GROUP TASK"
task.type = TaskType.group
var child = task.addSubtask()
child.title = "CHILD TASK"
URL.fromString(`omniplan:///task/${task.uniqueID}`).open()
Removing Tasks
Using the remove() instance function of the Task class, scripts can delete tasks from a project or task container.
Remove All Tasks
actual.rootTask.descendents().forEach(task => task.remove())
Creating Tasks
Tasks are created by calling the addSubtask() method on an instance of the Task class. The result will be a reference to the newly created task, which will be added to the specified task as a subtask.
To create a task at the top-level of the scenario, apply the method to the value of the rootTask property of the Project class.
Create Top-Level Tasks
var taskTitles = ["rake leaves","mow lawn","clean gutters","trim hedges"]
var createdTasks = taskTitles.map(title => {
var task = actual.rootTask.addSubtask()
task.title = title
return task
})
By default in OmniPlan, multiple tasks may share the same title. If you want tasks to have unique names, you must add checks to ensure there is no existing task with a specific name.
In the first script example, the taskNamed() function of the Scenario class is used to check for an existing task with the targeted name, in order to ensure that no duplicate tasks are created and that all tasks have a unique title.
Create Unique Top-Level Tasks
var createdTasks = new Array()
var taskTitles = ["rake leaves","mow lawn","clean gutters","trim hedges"]
taskTitles.forEach(title => {
if(!actual.taskNamed(title)){
var task = actual.rootTask.addSubtask()
var task.title = title
createdTasks.push(task)
}
})
console.log(createdTasks)
NOTE: The taskNamed() function is case sensitive, so “mow lawn” will not match “Mow Lawn” or other variations containing capitalized letters. To ignore character case when comparing a task name for uniqueness, another approach must be used:
Create Unique Top-Level Tasks (Case Insensitive)
var allTasks = actual.rootTask.descendents()
var allTaskTitles = allTasks.map(task => task.title.toUpperCase())
var taskTitles = ["Rake Leaves","Mow Lawn","Clean Gutters","Trim Hedges"]
taskTitles.forEach(aTitle => {
if(!allTaskTitles.includes(aTitle.toUpperCase())){
var task = actual.rootTask.addSubtask()
task.title = aTitle
allTaskTitles.push(aTitle)
}
})
A script for creating a basic top-level task group:
Create Task Group
var groupTitle = "Exterior Maintenance"
var taskTitles = ["Rake Leaves","Mow Grass","Clean Gutters","Trim Hedges"]
var groupTask = actual.rootTask.addSubtask()
groupTask.title = groupTitle
groupTask.type = TaskType.group
taskTitles.forEach(aTitle => {
groupTask.addSubtask().title = aTitle
})
Milestones
Milestones are the anchor points in your project that mark important shifts in focus or unlocking a new phase of the project. Clarifying these will help break a dauntingly large project down into more manageable sections, and help dictate the tasks leading up to and following the milestone.
A Milestone is a Task with no duration. Milestones are used to mark specific points within the project. In the following script example, a milestone marking the project end is created 90 days from the current date.
Section End Milestone
var targetDate = new Date(new Date().setHours(0,0,0,0))
targetDate = new Date(eDate.setDate(eDate.getDate() + 90))
var task = actual.rootTask.addSubtask()
task.title = "Section End"
task.type = TaskType.milestone
task.manualStartDate = targetDate