TaskUpdate#

An edit to one existing task of a live project. It goes in SchedulingChanges::tasks.update, which Project::apply and Project::preview take. Create it with TaskUpdate::new, then set the fields to change.

Declaration#

#[derive(Clone, Debug)]
pub struct TaskUpdate {
    pub id: Id,
    pub parent: Patch<Id>,
    pub start_date: Patch<DateTime>,
    pub end_date: Patch<DateTime>,
    pub duration: Patch<f64>,
    pub constraint_type: Patch<ConstraintType>,
    pub constraint_date: Patch<DateTime>,
    pub auto_scheduling: Patch<bool>,
    pub unscheduled: Patch<bool>,
    pub progress: Patch<f64>,
    pub calendar_id: Patch<Id>,
    pub priority: Patch<u16>,
    pub leveling_delay: Patch<f64>,
    pub pauses: Patch<Vec<Pause>>,
}

Constructors#

new#

pub fn new(id: impl Into<Id>) -> TaskUpdate

Creates an update for the task with the given id. Accepts anything that converts into an Id.

Returns an update with every field except id at Patch::Missing, so it changes nothing until a field is set.

Fields#

Every field except id is a Patch: Missing leaves the stored value, Value sets it, Null clears it. The On Null column shows what Null leaves behind. For the meaning of each value, see the field of the same name on TaskData.

Field Type On Null Description
id Id required Id of the task to edit.
parent Patch<Id> top level Moves the task under another parent. A value equal to SchedulingConfig::root_id is read as Null.
start_date Patch<DateTime> None New start, for example after a drag.
end_date Patch<DateTime> None New end.
duration Patch<f64> None New working time in the task's duration_unit, for example after a resize.
constraint_type Patch<ConstraintType> None New date constraint.
constraint_date Patch<DateTime> None New constraint date.
auto_scheduling Patch<bool> true false fixes the task.
unscheduled Patch<bool> false true takes the task out of scheduling.
progress Patch<f64> 0.0 New completed share.
calendar_id Patch<Id> None New working calendar.
priority Patch<u16> 500 New leveling priority.
leveling_delay Patch<f64> 0.0 New leveling delay, elapsed time in the task's duration_unit.
pauses Patch<Vec<Pause>> empty Replaces the whole pause list.

Dates after an update#

An update starts from the task's current scheduled start, end and duration. On a plain task (TaskType::Task), the fields set in the update decide which of the three is kept and which is derived again:

Set in the update Kept Derived again
start_date, no end_date start, duration end
end_date only end, start duration
duration, no end_date start, duration end
start_date + end_date, no duration start, end duration
calendar_id, or parent under CalendarMode::TaskInherited, no date field start, duration end
pauses or leveling_delay, no date field start, duration end
  • A leveling_delay update with neither start_date nor end_date also moves the stored dates by the change in delay (elapsed time) and snaps them onto working time.
  • When a task works on several calendars in a project with schedule_from_end, a pauses or leveling_delay update without dates keeps the end and derives the start instead.
  • Under CalendarMode::TaskInherited, a calendar_id or parent update also re-derives the end of each descendant plain task that has no calendar_id of its own. Its start and duration stay.
  • An explicit start on non-working time stays unsnapped when the task has no predecessor.

To write a result entry back as an update, see Mutation.

Errors#

An update is rejected as a single operation, at path tasks.update[i]. Project::apply and Project::preview describe how a rejection is reported.

Message When it occurs
unknown task id no task has id
a validation message the edited task breaks a TaskData rule or a ProjectData rule, for example an unknown calendar_id or parent

Example#

Move a task to a new start and push its finish out by a day:

use plen_core::{
    DateTime, Patch, Project, ProjectData, ProjectOptions, SchedulingChanges, SolveOptions,
    TaskData, TaskUpdate,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let monday = DateTime::from_ymd_hm(2026, 4, 6, 8, 0).ok_or("invalid date")?;
    let wednesday = DateTime::from_ymd_hm(2026, 4, 8, 8, 0).ok_or("invalid date")?;

    let data = ProjectData {
        tasks: vec![TaskData {
            start_date: Some(monday),
            duration: Some(2.0),
            ..TaskData::new("design")
        }],
        ..Default::default()
    };

    let mut project = Project::new(ProjectOptions::default());
    let options = SolveOptions::default();
    project.solve(Some(data), &options)?;

    let mut update = TaskUpdate::new("design");
    update.start_date = Patch::Value(wednesday);
    update.duration = Patch::Value(3.0);

    let mut changes = SchedulingChanges::default();
    changes.tasks.update.push(update);

    let report = project.apply(&changes)?;
    if report.rejected.is_empty() {
        let result = project.solve(None, &options)?;
        println!("{:?}", result.updates);
    }
    Ok(())
}
  • TaskData - the record an update edits
  • ApplyReport - reports whether the update was applied
  • Mutation - a result entry that can be written back as an update
  • Data Updates - shows task updates and which dates they keep