Load all task dates#

Get the start, end and duration of every scheduled task from one solve, for example to fill your UI when a project first opens.

By default, updates in a ScheduleResult is sparse: it lists only the tasks that moved. Set includeUnchanged: true in the solve options and the same solve also reports the tasks that didn't move. You don't need a separate call.

Steps#

  1. Serialize the solve options with includeUnchanged set to true:

    const options = JSON.stringify({ includeUnchanged: true });
    
  2. Pass the options to the call that loads the data. Use solve with a data string for a long-lived JsonProject, or schedule for a one-shot job:

    const text = project.solve(JSON.stringify(data), options);
    // or, without a handle: schedule(JSON.stringify(data), options)
    const response = JSON.parse(text);
    
  3. Check ok, then read every entry of result.updates. Each entry has start_date, end_date and duration set.

The full example below schedules three tasks. review doesn't move, but it's still reported:

const { JsonProject } = require("./pkg-node/plen_wasm.js");

function unwrap(text) {
  const response = JSON.parse(text);
  if (!response.ok) {
    const { kind, code, message, path } = response.error;
    throw new Error(`${kind} ${code ?? ""}: ${message} (at ${path})`);
  }
  return response.result;
}

const data = {
  // 24/7 time keeps the example dates easy to check.
  config: { use_calendars: false },
  tasks: [
    { id: "design", start_date: "2026-01-01 00:00", duration: 2 },
    { id: "build", start_date: "2026-01-01 00:00", duration: 1 },
    { id: "review", start_date: "2026-01-05 00:00", duration: 1 },
  ],
  links: [{ id: "design-build", source: "design", target: "build", type: "fs" }],
};

const options = JSON.stringify({ includeUnchanged: true });

const project = new JsonProject("{}");
try {
  const result = unwrap(project.solve(JSON.stringify(data), options));
  for (const u of result.updates) {
    console.log(`${u.id} ${u.start_date}..${u.end_date} ${u.duration}`);
  }
} finally {
  project.free();
}

Each entry of updates looks like this:

{ "duration": 2, "end_date": "2026-01-03 00:00", "id": "design", "kind": "task", "start_date": "2026-01-01 00:00" }

Get the full list from an already solved project#

To reload every date later, call solve without data and with the same options. On a solved project with no pending edits, the call doesn't replan or change the accepted state, and baselineId stays the same:

const allDates = unwrap(project.solve(undefined, options));

Switch back to sparse results for the edits that follow. "{}" returns only what changed:

const next = unwrap(project.solve(undefined, "{}"));

The result cache uses the whole options object as its key. An includeUnchanged call never gets a cached sparse result, and a sparse call never gets a cached full one.

What is and isn't reported#

  • The result includes every scheduled task: leaf tasks, summaries and milestones. Check each entry's kind ("task", "summary" or "milestone") to tell them apart.
  • Tasks with unscheduled: true are never reported.
  • leveling_delay and pauses never appear, because a solve doesn't change them.
  • baselineId follows real changes only. Asking for unchanged tasks doesn't create a new baseline.
  • With subtree, the result holds every task in the subtree, including the subtree tasks' ancestors. Tasks outside the subtree appear only when a sparse subtree solve would report them too, because they changed or were edited.
  • On a project with a dependency cycle, nothing is scheduled. The result still lists every scheduled task, in model order, with its dates and duration as stored. subtree is ignored, and no entry has a reason, even with reasons: true.
  • preview and level always return sparse updates. PreviewOptions has no includeUnchanged field.

Result#

Run the example with node. It prints one line per task, including review, which didn't move:

design 2026-01-01 00:00..2026-01-03 00:00 2
build 2026-01-03 00:00..2026-01-04 00:00 1
review 2026-01-05 00:00..2026-01-06 00:00 1

Without includeUnchanged, the same solve reports only build.

See Reading results for how to write the dates back into your model.