[Canonical page](<https://docs.dhtmlx.com/planning-engine/rust/api/project-preview/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Project::preview

Applies hypothetical changes to a copy of the solved baseline of a [`Project`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md>) and schedules the copy. The project isn't modified. Use it to show what an edit would do before committing it with [`apply`](<https://docs.dhtmlx.com/planning-engine/rust/api/project-apply.md>).

## Signature

```rust
pub fn preview(
    &self,
    changes: &SchedulingChanges,
    options: &PreviewOptions,
) -> Result<ScheduleResult, Error>
```

Takes `&self`. Synchronous and CPU-only.

## Parameters

| Name | Type | Description |
|---|---|---|
| `changes` | `&`[`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/scheduling-changes.md>) | The edits to try |
| `options` | `&`[`PreviewOptions`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/preview-options.md>) | Subtree, analytics, reasons, baseline check and an optional load profile |

## Behavior

- `updates` are relative to the baseline. An empty change set gives empty `updates`.
- The result's `baseline_id` is the baseline the preview read, so it's accepted by a following `preview`.
- The change set isn't partially accepted: one rejected operation fails the whole call.
- `options.baseline_id` and `changes.baseline_id` are checked separately. `None` skips a check.

## Returns

A [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/schedule-result.md>) for the previewed state.

## Errors

| Error | When |
|---|---|
| [`Error::Project(ProjectError::NoBaseline)`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/project-error.md>) | The project is unsolved, including after `apply` |
| `Error::Project(ProjectError::StaleBaseline)` | `options.baseline_id` or `changes.baseline_id` doesn't name the current baseline |
| [`Error::Input`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/error.md>) | An operation in `changes` is rejected (the error reports the first one), or the `profile` query is invalid |

:::note
A start date that falls on non-working time is kept unsnapped when the task has no predecessor. The end is computed forward from it on the working calendar.
:::

## Example

Preview a drag of task `b` and check that the project keeps its dates.

```rust
use plen_core::{
    DateTime, Patch, PreviewOptions, Project, ProjectData, SchedulingChanges, SolveOptions,
    TaskData, TaskUpdate,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let day = |d| DateTime::from_ymd_hm(2026, 1, d, 0, 0).ok_or("invalid date");

    let mut task = TaskData::new("b");
    task.start_date = Some(day(1)?);
    task.duration = Some(1.0);
    let mut data = ProjectData {
        tasks: vec![task],
        ..Default::default()
    };
    data.config.use_calendars = false;

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

    let mut moved = TaskUpdate::new("b");
    moved.start_date = Patch::Value(day(5)?);
    let mut drag = SchedulingChanges::default();
    drag.tasks.update.push(moved);

    let options = PreviewOptions {
        baseline_id: solved.baseline_id.clone(),
        ..Default::default()
    };
    let preview = project.preview(&drag, &options)?;
    for update in &preview.updates {
        if let (Some(start), Some(end)) = (update.start_date, update.end_date) {
            println!("task {}: {start} .. {end}", update.id); // task b: 2026-01-05 00:00 .. 2026-01-06 00:00
        }
    }

    // The project is unchanged: an empty preview reports no updates.
    let unchanged = project.preview(&SchedulingChanges::default(), &PreviewOptions::default())?;
    assert!(unchanged.updates.is_empty());
    Ok(())
}
```

## Related

- [`Project`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#preview>) - the type and its other methods
- [`PreviewOptions`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/preview-options.md>) - subtree, analytics, reasons, baseline check and load profile
- [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/scheduling-changes.md>) - the change set
- [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/schedule-result.md>) - the returned result
- [Previewing Changes](<https://docs.dhtmlx.com/planning-engine/rust/live-projects/previewing-changes.md>) - previews, baseline tokens, load previews and clones
