GanttEx.TaskForm (GanttEx v0.1.0)

Copy Markdown View Source

Converts tasks to lightbox form params and validates submitted params.

The lightbox uses plain HTML inputs, so dates travel as "YYYY-MM-DD" (or "YYYY-MM-DDTHH:MM" when the duration unit is smaller than a day) and progress as a percentage.

iex> task = GanttEx.Task.new!(id: 1, text: "Design", start_date: ~D[2025-01-06], duration: 3, progress: 0.4)
iex> GanttEx.TaskForm.params(task, :day)
%{"text" => "Design", "type" => "task", "start_date" => "2025-01-06", "duration" => "3", "progress" => "40", "parent" => "", "constraint_type" => "", "constraint_date" => "", "planned_start" => "", "planned_end" => "", "deadline" => ""}

iex> GanttEx.TaskForm.cast(%{"text" => " Build ", "type" => "task", "start_date" => "2025-01-08", "duration" => "2", "progress" => "25"}, :day)
{:ok, %{text: "Build", type: :task, start_date: ~N[2025-01-08 00:00:00], duration: 2, progress: 0.25}}

iex> GanttEx.TaskForm.cast(%{"text" => "", "start_date" => "nope", "duration" => "-1"}, :day)
{:error, [text: :required, start_date: :invalid_date, duration: :invalid_number]}

Summary

Functions

Validates submitted params.

Returns the HTML input type used for dates with the given duration unit.

Returns the end date to display.

Like display_end/2 for any end date (such as :planned_end).

Formats a datetime for a date input.

Returns the form params for a task.

Converts a displayed (inclusive) end date back to the exclusive end date. The inverse of display_end/2.

Functions

cast(params, unit, store \\ nil)

@spec cast(map(), GanttEx.Dates.unit(), GanttEx.Store.t() | nil) ::
  {:ok, map()} | {:error, keyword(atom())}

Validates submitted params.

Returns {:ok, attrs} with the attributes to apply to the task, or {:error, errors} where errors is a keyword list of field: reason. Reasons are keys of GanttEx.I18n.labels/1 (:required, :invalid_date, :invalid_number, :invalid_progress).

A "parent" param is resolved to a task id when a store is given (an empty value means "top level").

date_input_type(unit)

@spec date_input_type(GanttEx.Dates.unit()) :: String.t()

Returns the HTML input type used for dates with the given duration unit.

iex> GanttEx.TaskForm.date_input_type(:day)
"date"

iex> GanttEx.TaskForm.date_input_type(:hour)
"datetime-local"

display_end(task, unit)

@spec display_end(GanttEx.Task.t(), GanttEx.Dates.unit()) :: NaiveDateTime.t() | nil

Returns the end date to display.

End dates are exclusive internally (a one-day task on January 6th ends on January 7th at midnight), but people expect to read the last day of work. For day-based units, an end date at midnight is shown as the previous day.

iex> task = GanttEx.Task.new!(id: 1, start_date: ~D[2025-01-06], end_date: ~D[2025-01-07])
iex> GanttEx.TaskForm.display_end(task, :day)
~N[2025-01-06 00:00:00]

iex> task = GanttEx.Task.new!(id: 1, start_date: ~N[2025-01-06 09:00:00], end_date: ~N[2025-01-06 17:00:00])
iex> GanttEx.TaskForm.display_end(task, :hour)
~N[2025-01-06 17:00:00]

inclusive_end(finish, start, unit)

@spec inclusive_end(
  NaiveDateTime.t() | nil,
  NaiveDateTime.t() | nil,
  GanttEx.Dates.unit()
) ::
  NaiveDateTime.t() | nil

Like display_end/2 for any end date (such as :planned_end).

iex> GanttEx.TaskForm.inclusive_end(~N[2025-01-08 00:00:00], ~N[2025-01-06 00:00:00], :day)
~N[2025-01-07 00:00:00]

iex> GanttEx.TaskForm.inclusive_end(nil, nil, :day)
nil

input_date(datetime, unit)

@spec input_date(NaiveDateTime.t() | nil, GanttEx.Dates.unit()) :: String.t()

Formats a datetime for a date input.

iex> GanttEx.TaskForm.input_date(~N[2025-01-06 09:30:00], :hour)
"2025-01-06T09:30"

params(task, unit)

@spec params(GanttEx.Task.t(), GanttEx.Dates.unit()) :: %{
  required(String.t()) => String.t()
}

Returns the form params for a task.

parse_end(date, unit)

Converts a displayed (inclusive) end date back to the exclusive end date. The inverse of display_end/2.

iex> GanttEx.TaskForm.parse_end(~N[2025-01-06 00:00:00], :day)
~N[2025-01-07 00:00:00]

iex> GanttEx.TaskForm.parse_end(~N[2025-01-06 17:00:00], :hour)
~N[2025-01-06 17:00:00]