lib/step_flow/view/workflow_view.ex

defmodule StepFlow.WorkflowView do
  use StepFlow, :view
  alias StepFlow.{ArtifactView, JobView, WorkflowStatusView, WorkflowView}
  require Logger

  def render("index.json", %{workflows: %{data: workflows, total: total}}) do
    %{
      data: render_many(workflows, WorkflowView, "workflow_full.json"),
      total: total
    }
  end

  def render("show.json", %{workflow: workflow, mode: mode}) do
    %{data: render_one(workflow, WorkflowView, "workflow_#{mode}.json")}
  end

  def render("created.json", %{workflow: workflow}) do
    %{data: render_one(workflow, WorkflowView, "workflow_created.json")}
  end

  def render("workflow_full.json", %{workflow: workflow}) do
    result = %{
      schema_version: workflow.schema_version,
      id: workflow.id,
      identifier: workflow.identifier,
      is_live: workflow.is_live,
      deleted: workflow.deleted,
      version_major: workflow.version_major,
      version_minor: workflow.version_minor,
      version_micro: workflow.version_micro,
      tags: workflow.tags,
      reference: workflow.reference,
      steps: workflow.steps,
      parameters: workflow.parameters,
      created_at: workflow.inserted_at,
      user_uuid: workflow.user_uuid,
      notification_hooks: workflow.notification_hooks,
      parent_id: workflow.parent_id
    }

    result =
      if is_list(workflow.artifacts) do
        artifacts = render_many(workflow.artifacts, ArtifactView, "artifact.json")
        Map.put(result, :artifacts, artifacts)
      else
        result
      end

    result =
      if is_list(workflow.jobs) do
        jobs = render_many(workflow.jobs, JobView, "job.json")
        Map.put(result, :jobs, jobs)
      else
        result
      end

    result =
      if is_list(workflow.status) do
        last_status =
          workflow.status
          |> Enum.sort_by(fn s -> {s.inserted_at, s.id} end)
          |> List.last()

        state = render_one(last_status, WorkflowStatusView, "state.json")
        Map.put(result, :status, state)
      else
        result
      end

    result
  end

  def render("workflow_simple.json", %{workflow: workflow}) do
    result = %{
      schema_version: workflow.schema_version,
      id: workflow.id,
      identifier: workflow.identifier,
      is_live: workflow.is_live,
      version_major: workflow.version_major,
      version_minor: workflow.version_minor,
      version_micro: workflow.version_micro,
      created_at: workflow.inserted_at,
      user_uuid: workflow.user_uuid,
      notification_hooks: workflow.notification_hooks,
      parent_id: workflow.parent_id
    }

    if is_list(workflow.status) do
      last_status =
        workflow.status
        |> Enum.sort_by(fn s -> {s.inserted_at, s.id} end)
        |> List.last()

      state = render_one(last_status, WorkflowStatusView, "state.json")
      Map.put(result, :status, state)
    else
      result
    end
  end

  def render("workflow_created.json", %{workflow: workflow}) do
    %{
      id: workflow.id,
      identifier: workflow.identifier,
      version_major: workflow.version_major,
      version_minor: workflow.version_minor,
      version_micro: workflow.version_micro,
      tags: workflow.tags
    }
  end

  def render("statistics.json", %{workflows_status: []}) do
    %{
      data: %{
        processing: 0,
        error: 0,
        completed: 0,
        pending: 0,
        bins: []
      }
    }
  end

  def render("statistics.json", %{
        workflows_status: workflows_status,
        time_interval: time_interval,
        end_date: end_date
      }) do
    %{
      data: %{
        processing:
          workflows_status
          |> Enum.filter(fn s -> s.state == :processing end)
          |> length(),
        error:
          workflows_status
          |> Enum.filter(fn s -> s.state == :error end)
          |> length(),
        completed:
          workflows_status
          |> Enum.filter(fn s -> s.state == :completed end)
          |> length(),
        pending:
          workflows_status
          |> Enum.filter(fn s -> s.state == :pending end)
          |> length(),
        bins:
          workflows_status
          |> Enum.group_by(fn s ->
            NaiveDateTime.diff(end_date, s.inserted_at, :second)
            |> Kernel.div(time_interval)
          end)
          |> Enum.map(fn {bin, group} ->
            %{
              bin: bin,
              start_date:
                NaiveDateTime.add(end_date, -(bin + 1) * time_interval, :second)
                |> NaiveDateTime.to_string(),
              end_date:
                NaiveDateTime.add(end_date, -bin * time_interval, :second)
                |> NaiveDateTime.to_string(),
              processing:
                group
                |> Enum.filter(fn s -> s.state == :processing end)
                |> length(),
              error:
                group
                |> Enum.filter(fn s -> s.state == :error end)
                |> length(),
              completed:
                group
                |> Enum.filter(fn s -> s.state == :completed end)
                |> length(),
              pending:
                group
                |> Enum.filter(fn s -> s.state == :pending end)
                |> length()
            }
          end)
      }
    }
  end
end