GanttEx.Task (GanttEx v0.1.0)

Copy Markdown View Source

A task (row) of the Gantt chart.

Tasks mirror the DHTMLX Gantt data model:

  • :id - unique identifier (integer, string or atom). Required.
  • :text - the task name.
  • :start_date, :end_date - NaiveDateTime boundaries (end is exclusive).
  • :duration - integer amount of the chart's duration unit (:day by default).
  • :progress - completion between 0.0 and 1.0.
  • :parent - id of the parent task, nil for root tasks.
  • :type - :task, :project (summary task whose dates are computed from its children) or :milestone (zero-duration event).
  • :open - whether the children are expanded initially.
  • :readonly - disables editing for this task.
  • :color, :text_color, :progress_color - optional CSS colors.
  • :calendar_id - the working-time calendar of the task (see GanttEx.Calendar).
  • :constraint_type, :constraint_date - scheduling constraint used by auto-scheduling (see GanttEx.Scheduler and constraint_types/0).
  • :planned_start, :planned_end - the baseline (the original plan).
  • :deadline - the date the task must be finished by.
  • :render - :split draws the children of the task on its own row.
  • :rollup - also show the task on the rows of its ancestor projects.
  • :resources - resource assignments (see GanttEx.Resource.cast_assignments/1).
  • :has_children - the task has children that are not loaded yet (dynamic loading: expanding it sends a :branch_requested event).
  • :meta - any additional fields (for custom grid columns, templates, ...).

Only one or two of :start_date, :end_date and :duration are needed: the missing one is computed by GanttEx.Store (see GanttEx.Store.new/3).

Building tasks

new/1 accepts maps (atom or string keys), keyword lists and structs, such as Ecto schemas. Unknown fields are kept in :meta, and :parent_id is accepted as an alias of :parent:

iex> {:ok, task} = GanttEx.Task.new(%{"id" => 1, "text" => "Design", "start_date" => "2025-01-06", "duration" => 3, "owner" => "Ana"})
iex> {task.id, task.text, task.start_date, task.duration, task.meta}
{1, "Design", ~N[2025-01-06 00:00:00], 3, %{"owner" => "Ana"}}

iex> {:ok, task} = GanttEx.Task.new(id: 2, parent_id: 1, type: "milestone", start_date: ~D[2025-01-10])
iex> {task.parent, task.type}
{1, :milestone}

iex> GanttEx.Task.new(%{text: "No id"})
{:error, {:missing, :id}}

iex> GanttEx.Task.new(%{id: 1, progress: 50})
{:error, {:invalid, :progress}}

Summary

Types

A scheduling constraint: as soon/late as possible, start/finish no earlier/later than a date, or must start/finish on a date.

Casting errors returned by new/1 and change/2.

A task or link identifier.

t()

The kind of task.

Functions

Casts a constraint type (DHTMLX codes such as "snet" or atoms).

Casts a task type from an atom or string.

Applies attrs on top of an existing task, casting only the given fields.

Returns the supported constraint types.

Returns true for milestones.

Builds a task from a map, keyword list or struct. See the module docs.

Like new/1 but raises ArgumentError on invalid attributes.

Returns true for project (summary) tasks.

Converts the task into a plain map, handy to persist it.

Returns the supported task types.

Types

constraint()

@type constraint() :: :asap | :alap | :snet | :snlt | :fnet | :fnlt | :mso | :mfo

A scheduling constraint: as soon/late as possible, start/finish no earlier/later than a date, or must start/finish on a date.

error()

@type error() :: {:missing, atom()} | {:invalid, atom()}

Casting errors returned by new/1 and change/2.

id()

@type id() :: integer() | String.t() | atom()

A task or link identifier.

t()

@type t() :: %GanttEx.Task{
  calendar_id: term(),
  color: String.t() | nil,
  constraint_date: NaiveDateTime.t() | nil,
  constraint_type: constraint() | nil,
  deadline: NaiveDateTime.t() | nil,
  duration: non_neg_integer() | nil,
  end_date: NaiveDateTime.t() | nil,
  has_children: boolean(),
  id: id(),
  meta: map(),
  open: boolean(),
  parent: id() | nil,
  planned_end: NaiveDateTime.t() | nil,
  planned_start: NaiveDateTime.t() | nil,
  progress: float(),
  progress_color: String.t() | nil,
  readonly: boolean(),
  render: :split | nil,
  resources: [GanttEx.Resource.assignment()],
  rollup: boolean(),
  start_date: NaiveDateTime.t() | nil,
  text: String.t(),
  text_color: String.t() | nil,
  type: type()
}

type()

@type type() :: :task | :project | :milestone

The kind of task.

Functions

cast_constraint(value)

@spec cast_constraint(term()) :: {:ok, constraint() | nil} | :error

Casts a constraint type (DHTMLX codes such as "snet" or atoms).

iex> GanttEx.Task.cast_constraint("mso")
{:ok, :mso}

iex> GanttEx.Task.cast_constraint("")
{:ok, nil}

cast_type(type)

@spec cast_type(term()) :: {:ok, type()} | :error

Casts a task type from an atom or string.

iex> GanttEx.Task.cast_type("project")
{:ok, :project}

iex> GanttEx.Task.cast_type(nil)
{:ok, :task}

iex> GanttEx.Task.cast_type("epic")
:error

change(task, attrs)

@spec change(t(), map() | keyword()) :: {:ok, t()} | {:error, error()}

Applies attrs on top of an existing task, casting only the given fields.

The :id cannot be changed. Unknown fields are merged into :meta.

iex> task = GanttEx.Task.new!(id: 1, text: "Draft", start_date: ~D[2025-01-01])
iex> {:ok, task} = GanttEx.Task.change(task, %{"text" => "Final", "progress" => "0.25"})
iex> {task.text, task.progress}
{"Final", 0.25}

constraint_types()

@spec constraint_types() :: [constraint()]

Returns the supported constraint types.

iex> GanttEx.Task.constraint_types()
[:asap, :alap, :snet, :snlt, :fnet, :fnlt, :mso, :mfo]

milestone?(task)

@spec milestone?(t()) :: boolean()

Returns true for milestones.

iex> GanttEx.Task.milestone?(GanttEx.Task.new!(id: 1, type: :milestone))
true

new(task)

@spec new(map() | keyword() | struct()) :: {:ok, t()} | {:error, error()}

Builds a task from a map, keyword list or struct. See the module docs.

new!(attrs)

@spec new!(map() | keyword() | struct()) :: t()

Like new/1 but raises ArgumentError on invalid attributes.

iex> GanttEx.Task.new!(id: 1, text: "Kickoff", start_date: ~D[2025-01-01]).text
"Kickoff"

project?(task)

@spec project?(t()) :: boolean()

Returns true for project (summary) tasks.

iex> GanttEx.Task.project?(GanttEx.Task.new!(id: 1))
false

to_map(task, opts \\ [])

@spec to_map(t(), keyword()) :: map()

Converts the task into a plain map, handy to persist it.

:meta fields are merged at the top level unless meta: false is given.

iex> task = GanttEx.Task.new!(id: 1, text: "A", start_date: ~D[2025-01-01], duration: 2, priority: :high)
iex> GanttEx.Task.to_map(task) |> Map.take([:id, :text, :duration, :priority])
%{id: 1, text: "A", duration: 2, priority: :high}

types()

@spec types() :: [type()]

Returns the supported task types.

iex> GanttEx.Task.types()
[:task, :project, :milestone]