From 7453bf62fc1255c258bcfb0b3862357be9a6181c Mon Sep 17 00:00:00 2001 From: Rogerio Pontual Date: Mon, 3 Feb 2025 10:53:48 +0100 Subject: [PATCH 1/2] Add main and dropdown buttons component on the UI --- .../live/job_live/cron_run_component.ex | 132 ++++++++++++++++++ lib/lightning_web/live/workflow_live/edit.ex | 13 +- 2 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 lib/lightning_web/live/job_live/cron_run_component.ex 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..8f33e22dde --- /dev/null +++ b/lib/lightning_web/live/job_live/cron_run_component.ex @@ -0,0 +1,132 @@ +defmodule LightningWeb.JobLive.CronRunButton do + @moduledoc """ + Displays and manages cron runs in a form. + """ + use LightningWeb, :live_component + + alias Lightning.Run + + require Run + + @impl true + def render(assigns) do + ~H""" +
+
+ <.button + id={@id} + phx-hook="DefaultRunViaCtrlEnter" + type="button" + phx-click={@selected_option} + 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 %> + +
+
+ <.dropdown_action {assigns} /> +
+
+ """ + end + + @impl true + def update( + assigns, + socket + ) do + follow_run = Map.get(assigns, :follow_run) + snapshot_version_tag = "latest" + disabled = processing(follow_run) or snapshot_version_tag != "latest" + selected_option = Map.get(assigns, :selected_option, "clear_and_run") + + {:ok, + socket + |> assign(assigns) + |> assign( + disabled: disabled, + follow_run: follow_run, + selected_option: selected_option + )} + end + + @impl true + def handle_event("clear_and_run", _params, socket) do + {:noreply, assign(socket, selected_option: "clear_and_run")} + end + + def handle_event("run_last_state", _params, socket) do + {:noreply, assign(socket, selected_option: "run_last_state")} + end + + def handle_event("run_custom_state", _params, socket) do + {:noreply, assign(socket, selected_option: "run_custom_state")} + end + + defp cron_trigger_bt_classes(_assigns) do + ["relative inline-flex rounded-r-none"] + end + + def button_text(selected) do + case selected do + "clear_and_run" -> "Clear state and run" + "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 + + defp dropdown_action(assigns) do + ~H""" + <.button + type="button" + class="h-full rounded-l-none pr-1 pl-1 focus:ring-inset" + id="option-menu-button" + aria-expanded="true" + aria-haspopup="true" + disabled={@disabled} + phx-click={show_dropdown("dropdown-bt")} + > + Open options + <.icon name="hero-chevron-down" class="w-4 h-4" /> + +
+ +
+ """ + end +end diff --git a/lib/lightning_web/live/workflow_live/edit.ex b/lib/lightning_web/live/workflow_live/edit.ex index e77b39e9c3..6c722a90d6 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,12 @@ defmodule LightningWeb.WorkflowLive.Edit do label="Enabled" />
+
+ <.live_component + id="cron-run-button" + module={LightningWeb.JobLive.CronRunButton} + /> +
@@ -1114,6 +1120,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, @@ -2156,6 +2163,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) From b260b2ba91dbd0e3af47433f375296640d9a010b Mon Sep 17 00:00:00 2001 From: Rogerio Pontual Date: Mon, 3 Feb 2025 15:56:50 +0100 Subject: [PATCH 2/2] Hide the other options and leave default as Run now --- .../live/job_live/cron_run_component.ex | 102 ++++------- lib/lightning_web/live/workflow_live/edit.ex | 166 ++++++++++-------- 2 files changed, 131 insertions(+), 137 deletions(-) diff --git a/lib/lightning_web/live/job_live/cron_run_component.ex b/lib/lightning_web/live/job_live/cron_run_component.ex index 8f33e22dde..445d8bf33e 100644 --- a/lib/lightning_web/live/job_live/cron_run_component.ex +++ b/lib/lightning_web/live/job_live/cron_run_component.ex @@ -4,7 +4,11 @@ defmodule LightningWeb.JobLive.CronRunButton do """ use LightningWeb, :live_component + import Ecto.Query + + alias Lightning.Repo alias Lightning.Run + alias Lightning.WorkOrder require Run @@ -15,9 +19,9 @@ defmodule LightningWeb.JobLive.CronRunButton do
<.button id={@id} - phx-hook="DefaultRunViaCtrlEnter" - type="button" + phx-target={@myself} phx-click={@selected_option} + phx-hook="DefaultRunViaCtrlEnter" class={cron_trigger_bt_classes(assigns)} disabled={@disabled} > @@ -31,53 +35,69 @@ defmodule LightningWeb.JobLive.CronRunButton do <% end %>
-
- <.dropdown_action {assigns} /> -
""" end @impl true def update( - assigns, + %{follow_run: follow_run} = assigns, socket ) do - follow_run = Map.get(assigns, :follow_run) snapshot_version_tag = "latest" disabled = processing(follow_run) or snapshot_version_tag != "latest" - selected_option = Map.get(assigns, :selected_option, "clear_and_run") {:ok, socket |> assign(assigns) |> assign( disabled: disabled, - follow_run: follow_run, - selected_option: selected_option + follow_run: nil, + selected_option: "clear_and_run" )} end @impl true def handle_event("clear_and_run", _params, socket) do - {:noreply, assign(socket, selected_option: "clear_and_run")} - end + cron_trigger = + Enum.find(socket.assigns.workflow.triggers, &(&1.type == :cron)) - def handle_event("run_last_state", _params, socket) do - {:noreply, assign(socket, selected_option: "run_last_state")} - end + 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}} + ) - def handle_event("run_custom_state", _params, socket) do - {:noreply, assign(socket, selected_option: "run_custom_state")} + {: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 rounded-r-none"] + ["relative inline-flex"] end def button_text(selected) do case selected do - "clear_and_run" -> "Clear state and run" + "clear_and_run" -> "Run now" "run_last_state" -> "Run with last state" "run_custom_state" -> "Run with custom state" end @@ -85,48 +105,4 @@ defmodule LightningWeb.JobLive.CronRunButton do defp processing(%{state: state}), do: state not in Run.final_states() defp processing(_run), do: false - - defp dropdown_action(assigns) do - ~H""" - <.button - type="button" - class="h-full rounded-l-none pr-1 pl-1 focus:ring-inset" - id="option-menu-button" - aria-expanded="true" - aria-haspopup="true" - disabled={@disabled} - phx-click={show_dropdown("dropdown-bt")} - > - Open options - <.icon name="hero-chevron-down" class="w-4 h-4" /> - -
- -
- """ - end end diff --git a/lib/lightning_web/live/workflow_live/edit.ex b/lib/lightning_web/live/workflow_live/edit.ex index 6c722a90d6..4b4e3474d8 100644 --- a/lib/lightning_web/live/workflow_live/edit.ex +++ b/lib/lightning_web/live/workflow_live/edit.ex @@ -566,6 +566,9 @@ defmodule LightningWeb.WorkflowLive.Edit do <.live_component id="cron-run-button" module={LightningWeb.JobLive.CronRunButton} + workflow={@workflow} + follow_run={@follow_run} + snapshot_version_tag={@snapshot_version_tag} /> @@ -1670,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 @@ -1800,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 @@ -2637,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