diff --git a/lib/lightning_web/live/job_live/cron_run_component.ex b/lib/lightning_web/live/job_live/cron_run_component.ex new file mode 100644 index 0000000000..445d8bf33e --- /dev/null +++ b/lib/lightning_web/live/job_live/cron_run_component.ex @@ -0,0 +1,108 @@ +defmodule LightningWeb.JobLive.CronRunButton do + @moduledoc """ + Displays and manages cron runs in a form. + """ + use LightningWeb, :live_component + + import Ecto.Query + + alias Lightning.Repo + alias Lightning.Run + alias Lightning.WorkOrder + + require Run + + @impl true + def render(assigns) do + ~H""" +
+
+ <.button + id={@id} + phx-target={@myself} + phx-click={@selected_option} + phx-hook="DefaultRunViaCtrlEnter" + class={cron_trigger_bt_classes(assigns)} + disabled={@disabled} + > + <%= if processing(@follow_run) do %> + <.icon name="hero-arrow-path" class="w-4 h-4 animate-spin mr-1" /> + Processing + <% else %> + <.icon name="hero-play-mini" class="w-4 h-4 mr-1" /> <%= button_text( + @selected_option + ) %> + <% end %> + +
+
+ """ + end + + @impl true + def update( + %{follow_run: follow_run} = assigns, + socket + ) do + snapshot_version_tag = "latest" + disabled = processing(follow_run) or snapshot_version_tag != "latest" + + {:ok, + socket + |> assign(assigns) + |> assign( + disabled: disabled, + follow_run: nil, + selected_option: "clear_and_run" + )} + end + + @impl true + def handle_event("clear_and_run", _params, socket) do + cron_trigger = + Enum.find(socket.assigns.workflow.triggers, &(&1.type == :cron)) + + dataclip_id = + Repo.one( + from(wo in WorkOrder, + where: wo.trigger_id == ^cron_trigger.id, + select: wo.dataclip_id, + limit: 1, + order_by: [desc: :inserted_at] + ) + ) + + send( + self(), + {__MODULE__, "cron_trigger_manual_run", %{dataclip_id: dataclip_id}} + ) + + {:noreply, socket} + end + + # @impl true + # def handle_info( + # %RunUpdated{run: run}, + # %{assigns: %{follow_run: %{id: follow_run_id}}} = socket + # ) + # when run.id === follow_run_id do + # {:noreply, + # socket + # |> assign(follow_run: run)} + # end + + defp cron_trigger_bt_classes(_assigns) do + ["relative inline-flex"] + end + + def button_text(selected) do + case selected do + "clear_and_run" -> "Run now" + "run_last_state" -> "Run with last state" + "run_custom_state" -> "Run with custom state" + end + end + + defp processing(%{state: state}), do: state not in Run.final_states() + defp processing(_run), do: false +end diff --git a/lib/lightning_web/live/workflow_live/edit.ex b/lib/lightning_web/live/workflow_live/edit.ex index e77b39e9c3..4b4e3474d8 100644 --- a/lib/lightning_web/live/workflow_live/edit.ex +++ b/lib/lightning_web/live/workflow_live/edit.ex @@ -550,7 +550,7 @@ defmodule LightningWeb.WorkflowLive.Edit do /> <:footer>
-
+
<.input type="toggle" field={tf[:enabled]} @@ -562,6 +562,15 @@ defmodule LightningWeb.WorkflowLive.Edit do label="Enabled" />
+
+ <.live_component + id="cron-run-button" + module={LightningWeb.JobLive.CronRunButton} + workflow={@workflow} + follow_run={@follow_run} + snapshot_version_tag={@snapshot_version_tag} + /> +
@@ -1114,6 +1123,7 @@ defmodule LightningWeb.WorkflowLive.Edit do selected_job: nil, selected_run: nil, selected_trigger: nil, + show_cron_run_button: false, selection_mode: nil, query_params: %{ "s" => nil, @@ -1663,80 +1673,7 @@ defmodule LightningWeb.WorkflowLive.Edit do # The manual_run_submit event is for create a new work order from a dataclip and # a job. def handle_event("manual_run_submit", params, socket) do - %{ - project: project, - selected_job: selected_job, - current_user: current_user, - workflow_params: workflow_params, - has_presence_edit_priority: has_presence_edit_priority, - workflow: workflow, - manual_run_form: form - } = socket.assigns - - manual_params = Map.get(params, "manual", %{}) - - params = - case form do - nil -> manual_params - %{params: form_params} -> Map.merge(form_params, manual_params) - end - - socket = socket |> apply_params(workflow_params, :workflow) - - workflow_or_changeset = - if has_presence_edit_priority do - socket.assigns.changeset - else - get_workflow_by_id(workflow.id) - end - - with :ok <- check_user_can_manual_run_workflow(socket) do - case Helpers.run_workflow( - workflow_or_changeset, - params, - project: project, - selected_job: selected_job, - created_by: current_user - ) do - {:ok, %{workorder: workorder, workflow: workflow}} -> - %{runs: [run]} = workorder - - Runs.subscribe(run) - - snapshot = snapshot_by_version(workflow.id, workflow.lock_version) - - {:noreply, - socket - |> assign_workflow(workflow, snapshot) - |> follow_run(run) - |> push_event("push-hash", %{"hash" => "log"})} - - {:error, %Ecto.Changeset{data: %WorkOrders.Manual{}} = changeset} -> - {:noreply, - socket - |> assign_manual_run_form(changeset)} - - {:error, %Ecto.Changeset{data: %Workflow{}} = changeset} -> - { - :noreply, - socket - |> assign_changeset(changeset) - |> mark_validated() - |> put_flash(:error, "Workflow could not be saved") - } - - {:error, %{text: message}} -> - {:noreply, put_flash(socket, :error, message)} - - {:error, :workflow_deleted} -> - {:noreply, - put_flash( - socket, - :error, - "Oops! You cannot modify a deleted workflow" - )} - end - end + handle_manual_run_submit(socket, params) end def handle_event("toggle_workflow_state", %{"workflow_state" => state}, socket) do @@ -1793,6 +1730,15 @@ defmodule LightningWeb.WorkflowLive.Edit do end end + def handle_info( + {LightningWeb.JobLive.CronRunButton, "cron_trigger_manual_run", + dataclip_id}, + socket + ) do + params = %{"manual" => %{"dataclip_id" => dataclip_id}} + handle_manual_run_submit(socket, params) + end + def handle_info({"form_changed", %{"workflow" => params}}, socket) do {:noreply, handle_new_params(socket, params, :workflow)} end @@ -2156,6 +2102,10 @@ defmodule LightningWeb.WorkflowLive.Edit do WorkflowParams.apply_form_params(socket.assigns.workflow_params, params) socket + |> assign( + :show_cron_run_button, + get_in(params, ["triggers", "0", "type"]) == "cron" + ) |> apply_params(next_params, type) |> mark_validated() |> push_patches_applied(initial_params) @@ -2626,4 +2576,83 @@ defmodule LightningWeb.WorkflowLive.Edit do end defp loaded?(%Workflow{} = workflow), do: workflow.__meta__.state == :loaded + + defp handle_manual_run_submit(socket, params) do + IO.inspect(params) + + %{ + project: project, + selected_job: selected_job, + current_user: current_user, + workflow_params: workflow_params, + has_presence_edit_priority: has_presence_edit_priority, + workflow: workflow, + manual_run_form: form + } = socket.assigns + + manual_params = Map.get(params, "manual", %{}) + + params = + case form do + nil -> manual_params + %{params: form_params} -> Map.merge(form_params, manual_params) + end + + socket = socket |> apply_params(workflow_params, :workflow) + + workflow_or_changeset = + if has_presence_edit_priority do + socket.assigns.changeset + else + get_workflow_by_id(workflow.id) + end + + with :ok <- check_user_can_manual_run_workflow(socket) do + case Helpers.run_workflow( + workflow_or_changeset, + params, + project: project, + selected_job: selected_job, + created_by: current_user + ) do + {:ok, %{workorder: workorder, workflow: workflow}} -> + %{runs: [run]} = workorder + + Runs.subscribe(run) + + snapshot = snapshot_by_version(workflow.id, workflow.lock_version) + + {:noreply, + socket + |> assign_workflow(workflow, snapshot) + |> follow_run(run) + |> push_event("push-hash", %{"hash" => "log"})} + + {:error, %Ecto.Changeset{data: %WorkOrders.Manual{}} = changeset} -> + {:noreply, + socket + |> assign_manual_run_form(changeset)} + + {:error, %Ecto.Changeset{data: %Workflow{}} = changeset} -> + { + :noreply, + socket + |> assign_changeset(changeset) + |> mark_validated() + |> put_flash(:error, "Workflow could not be saved") + } + + {:error, %{text: message}} -> + {:noreply, put_flash(socket, :error, message)} + + {:error, :workflow_deleted} -> + {:noreply, + put_flash( + socket, + :error, + "Oops! You cannot modify a deleted workflow" + )} + end + end + end end