defmodule DaProductAppWeb.SbomComponentLive do use DaProductAppWeb, :live_view import Logger alias DaProductApp.Users alias DaProductAppWeb.Router.Helpers, as: Routes alias DaProductApp.SBOM alias DaProductApp.SBOM.Component # on_mount DaProductAppWeb.Live.SetCurrentPage # def mount(_params, _session, socket) do # components = SBOM.list_components() # Fetch existing components # {:ok, assign(socket, components: components, form: to_form(Component.changeset(%Component{}, %{})))} # end @impl true def mount(_params, session, socket) do components = SBOM.list_components() # Fetch existing components changeset = build_changeset() current_user = session["user_token"] |> Users.get_user_by_session_token() || nil socket = socket |> assign(:current_user, current_user) |> assign(:show_sidebar, true) # Enable sidebar for dashboard |> assign(:page_title, "SBOM Component") # Set the page title {:ok, assign(socket, modal: false, slide_over: false, slide_over: "organization", group_size: "md", pagination_page: 1, total_pages: 10, form: to_form(Component.changeset(%Component{}, %{})), form2: to_form(Component.changeset(%Component{}, %{})), show_childbom_spdx: false, show_checksum_details: false, components: components, active_tab: :live )} end @impl true def handle_event("toggle_childbom", _params, socket) do new_value = !socket.assigns.show_childbom_spdx {:noreply, assign(socket, show_childbom_spdx: new_value)} end def handle_event("toggle_checksum_type", %{"value" => "File"}, socket) do {:noreply, assign(socket, show_checksum_details: true)} end def handle_event("toggle_checksum_type", _params, socket) do {:noreply, assign(socket, show_checksum_details: false)} end @impl true def handle_event("validate", %{"object" => object_params}, socket) do changeset = object_params |> build_changeset() |> Map.put(:action, :validate) {:noreply, assign_form(socket, changeset)} end def handle_event("submit", %{"component" => component_params}, socket) do Logger.debug("Received component params: #{inspect(component_params)}") # Ensure required integer fields are set correctly component_params = component_params |> Map.put("user_id", 1) |> Map.put("application_id", 1) |> Map.put("organization_id", 1) # Check if required fields are actually present required_fields = ["component_name", "version", "supplier_type", "supplier_name", "relationship", "checksum_type", "checksum_algorithm", "checksum_value"] missing_fields = Enum.filter(required_fields, fn field -> Map.get(component_params, field, "") |> String.trim() == "" end) if missing_fields != [] do Logger.error("Missing required fields: #{inspect(missing_fields)}") {:noreply, put_flash(socket, :error, "Missing required fields: #{Enum.join(missing_fields, ", ")}")} else case DaProductApp.SBOM.create_component(component_params) do {:ok, _component} -> socket = socket |> put_flash(:info, "Component created successfully") |> push_patch(to: "/sbomcomponent") {:noreply, socket} {:error, changeset} -> Logger.error("Failed to insert component: #{inspect(changeset.errors)}") {:noreply, assign(socket, :form, to_form(changeset))} end end end @impl true def handle_params(params, _url, socket) do Logger.debug("Component: #{inspect(params)}") slide_over = params["origin"] || nil slidefor = params["slidefor"] || nil socket = load_data(socket) {:noreply, assign(socket, slide_over: slide_over, slidefor: slidefor)} end defp load_data(socket) do components = DaProductApp.SBOM.list_components() assign(socket, components: components) end @impl true #def handle_event("submit", %{"object" => object_params}, socket) do #def handle_event("submit", %{"component" => component_params}, socket) do # Logger.debug("Component: #{inspect(component_params)}", []) # Correct usage # changeset = build_changeset(object_params) # case SBOM.create_component(component_params) do # {:ok, _component} -> # socket = # socket # |> put_flash(:success, "Component successfully created") # |> assign(:components, SBOM.list_components()) # Refresh the list # {:noreply, socket} # {:error, changeset} -> # {:noreply, assign(socket, form: to_form(changeset))} # end # case validate_changeset(changeset) do # {:ok, _object} -> # socket = # socket # |> put_flash(:success, "Object successfully created") # |> assign_form(build_changeset()) # # {:noreply, socket} # # {:error, changeset} -> # socket = # socket # |> put_flash(:error, inspect(changeset.errors)) # {:noreply, assign_form(socket, changeset)} # end # end defp assign_form(socket, changeset) do assign(socket, form: to_form(changeset, as: :object)) end defp build_changeset(params \\ %{}) do data = %{} types = %{ text: :string, select: :string, checkbox_group: {:array, :string}, radio_group: :string, textarea: :string, checkbox: :boolean, color: :string, date: :date, datetime: :naive_datetime, email: :string, file: :string, hidden: :string, month: :string, number: :integer, password: :string, radio: :string, range: :integer, search: :string, tel: :string, time: :time, url: :string, week: :string, switch: :boolean } {data, types} |> Ecto.Changeset.cast(params, Map.keys(types)) |> Ecto.Changeset.validate_required([:text]) |> Ecto.Changeset.validate_acceptance(:checkbox) |> Ecto.Changeset.validate_length(:text, min: 3, max: 50) end defp validate_changeset(changeset) do Ecto.Changeset.apply_action(changeset, :validate) end @impl true def handle_event("delete_component", %{"id" => id}, socket) do SBOM.delete_component(id) {:noreply, assign(socket, components: SBOM.list_components())} end @impl true def handle_params(params, _uri, socket) do case socket.assigns.live_action do :index -> {:noreply, assign(socket, modal: false, slide_over: false)} :modal -> {:noreply, assign(socket, modal: params["size"])} :slide_over -> {:noreply, assign(socket, slide_over: params["origin"])} :pagination -> {:noreply, assign(socket, pagination_page: String.to_integer(params["page"]))} end end @impl true def render(assigns) do ~H"""
ACME-INFUSION-1.0-SBOM-DRAFT
Application Name
| Component Name | Version | Supplier | Action |
|---|---|---|---|
| <%= component.component_name %> | <%= component.version %> | <%= component.supplier_name %> | <.icon_button tooltip="Clock" size="xs" phx-click="delete_component" color="danger"> <.icon name="hero-x-circle" class="w-5 h-5" /> |