Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 17 additions & 11 deletions lib/modules/entities/entity_data.ex
Original file line number Diff line number Diff line change
Expand Up @@ -820,8 +820,8 @@ defmodule PhoenixKit.Modules.Entities.EntityData do
@doc """
Bulk updates the category of multiple records by UUIDs.

Since category is stored in the JSONB data column, this requires
fetching and updating each record individually.
Uses PostgreSQL jsonb_set to update the category field in the JSONB
data column in a single query.

Returns a tuple with the count of updated records and nil.

Expand All @@ -833,15 +833,21 @@ defmodule PhoenixKit.Modules.Entities.EntityData do
def bulk_update_category(uuids, category) when is_list(uuids) do
now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)

records = from(d in __MODULE__, where: d.uuid in ^uuids) |> repo().all()

Enum.each(records, fn record ->
updated_data = Map.put(record.data || %{}, "category", category)
changeset = changeset(record, %{data: updated_data, date_updated: now})
repo().update(changeset)
end)

{length(records), nil}
from(d in __MODULE__,
where: d.uuid in ^uuids,
update: [
set: [
data:
fragment(
"jsonb_set(COALESCE(?, '{}'::jsonb), '{category}', to_jsonb(?::text))",
d.data,
^category
),
date_updated: ^now
]
]
)
|> repo().update_all([])
end

@doc """
Expand Down
145 changes: 85 additions & 60 deletions lib/modules/entities/web/data_navigator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ defmodule PhoenixKit.Modules.Entities.Web.DataNavigator do
alias PhoenixKit.Modules.Entities.EntityData
alias PhoenixKit.Modules.Entities.Events
alias PhoenixKit.Settings
alias PhoenixKit.Users.Auth.Scope
alias PhoenixKit.Utils.Routes

def mount(params, _session, socket) do
Expand Down Expand Up @@ -363,53 +364,65 @@ defmodule PhoenixKit.Modules.Entities.Web.DataNavigator do
end

def handle_event("bulk_action", %{"action" => "archive"}, socket) do
ids = socket.assigns.selected_ids
if Scope.admin?(socket.assigns.phoenix_kit_current_scope) do
ids = socket.assigns.selected_ids

if ids == [] do
{:noreply, put_flash(socket, :error, gettext("No records selected"))}
else
{count, _} = EntityData.bulk_update_status(ids, "archived")
if ids == [] do
{:noreply, put_flash(socket, :error, gettext("No records selected"))}
else
{count, _} = EntityData.bulk_update_status(ids, "archived")

{:noreply,
socket
|> assign(:selected_ids, [])
|> refresh_data_stats()
|> apply_filters()
|> put_flash(:info, gettext("%{count} records archived", count: count))}
{:noreply,
socket
|> assign(:selected_ids, [])
|> refresh_data_stats()
|> apply_filters()
|> put_flash(:info, gettext("%{count} records archived", count: count))}
end
else
{:noreply, put_flash(socket, :error, gettext("Not authorized"))}
end
end

def handle_event("bulk_action", %{"action" => "restore"}, socket) do
ids = socket.assigns.selected_ids
if Scope.admin?(socket.assigns.phoenix_kit_current_scope) do
ids = socket.assigns.selected_ids

if ids == [] do
{:noreply, put_flash(socket, :error, gettext("No records selected"))}
else
{count, _} = EntityData.bulk_update_status(ids, "published")
if ids == [] do
{:noreply, put_flash(socket, :error, gettext("No records selected"))}
else
{count, _} = EntityData.bulk_update_status(ids, "published")

{:noreply,
socket
|> assign(:selected_ids, [])
|> refresh_data_stats()
|> apply_filters()
|> put_flash(:info, gettext("%{count} records restored", count: count))}
{:noreply,
socket
|> assign(:selected_ids, [])
|> refresh_data_stats()
|> apply_filters()
|> put_flash(:info, gettext("%{count} records restored", count: count))}
end
else
{:noreply, put_flash(socket, :error, gettext("Not authorized"))}
end
end

def handle_event("bulk_action", %{"action" => "delete"}, socket) do
ids = socket.assigns.selected_ids
if Scope.admin?(socket.assigns.phoenix_kit_current_scope) do
ids = socket.assigns.selected_ids

if ids == [] do
{:noreply, put_flash(socket, :error, gettext("No records selected"))}
else
{count, _} = EntityData.bulk_delete(ids)
if ids == [] do
{:noreply, put_flash(socket, :error, gettext("No records selected"))}
else
{count, _} = EntityData.bulk_delete(ids)

{:noreply,
socket
|> assign(:selected_ids, [])
|> refresh_data_stats()
|> apply_filters()
|> put_flash(:info, gettext("%{count} records deleted", count: count))}
{:noreply,
socket
|> assign(:selected_ids, [])
|> refresh_data_stats()
|> apply_filters()
|> put_flash(:info, gettext("%{count} records deleted", count: count))}
end
else
{:noreply, put_flash(socket, :error, gettext("Not authorized"))}
end
end

Expand All @@ -418,36 +431,44 @@ defmodule PhoenixKit.Modules.Entities.Web.DataNavigator do
%{"action" => "change_category", "category" => category},
socket
) do
ids = socket.assigns.selected_ids
if Scope.admin?(socket.assigns.phoenix_kit_current_scope) do
ids = socket.assigns.selected_ids

if ids == [] do
{:noreply, put_flash(socket, :error, gettext("No records selected"))}
else
{count, _} = EntityData.bulk_update_category(ids, category)
if ids == [] do
{:noreply, put_flash(socket, :error, gettext("No records selected"))}
else
{count, _} = EntityData.bulk_update_category(ids, category)

{:noreply,
socket
|> assign(:selected_ids, [])
|> refresh_data_stats()
|> apply_filters()
|> put_flash(:info, gettext("%{count} records updated", count: count))}
{:noreply,
socket
|> assign(:selected_ids, [])
|> refresh_data_stats()
|> apply_filters()
|> put_flash(:info, gettext("%{count} records updated", count: count))}
end
else
{:noreply, put_flash(socket, :error, gettext("Not authorized"))}
end
end

def handle_event("bulk_action", %{"action" => "change_status", "status" => status}, socket) do
ids = socket.assigns.selected_ids
if Scope.admin?(socket.assigns.phoenix_kit_current_scope) do
ids = socket.assigns.selected_ids

if ids == [] do
{:noreply, put_flash(socket, :error, gettext("No records selected"))}
else
{count, _} = EntityData.bulk_update_status(ids, status)
if ids == [] do
{:noreply, put_flash(socket, :error, gettext("No records selected"))}
else
{count, _} = EntityData.bulk_update_status(ids, status)

{:noreply,
socket
|> assign(:selected_ids, [])
|> refresh_data_stats()
|> apply_filters()
|> put_flash(:info, gettext("%{count} records updated", count: count))}
{:noreply,
socket
|> assign(:selected_ids, [])
|> refresh_data_stats()
|> apply_filters()
|> put_flash(:info, gettext("%{count} records updated", count: count))}
end
else
{:noreply, put_flash(socket, :error, gettext("Not authorized"))}
end
end

Expand Down Expand Up @@ -567,17 +588,21 @@ defmodule PhoenixKit.Modules.Entities.Web.DataNavigator do
category = socket.assigns[:selected_category] || "all"
search_term = socket.assigns[:search_term] || ""

# Start with all data and apply filters sequentially
entity_data_records =
# Apply entity and status filters first
pre_category_records =
EntityData.list_all_data()
|> filter_by_entity(entity_id)
|> filter_by_status(status)

# Extract categories BEFORE category filter so dropdown always shows all options
available_categories = EntityData.extract_unique_categories(pre_category_records)

# Then apply remaining filters
entity_data_records =
pre_category_records
|> filter_by_category(category)
|> filter_by_search(search_term)

# Extract available categories from filtered results
available_categories = EntityData.extract_unique_categories(entity_data_records)

socket
|> assign(:entity_data_records, entity_data_records)
|> assign(:available_categories, available_categories)
Expand Down
5 changes: 4 additions & 1 deletion lib/modules/shop/shop.ex
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,10 @@ defmodule PhoenixKit.Modules.Shop do
|> repo().all()
|> Map.new()
rescue
_ -> %{}
e ->
require Logger
Logger.warning("Failed to load product counts by category: #{inspect(e)}")
%{}
end

@doc """
Expand Down
2 changes: 1 addition & 1 deletion lib/modules/shop/web/catalog_product.ex
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ defmodule PhoenixKit.Modules.Shop.Web.CatalogProduct do
:category_icon_mode,
Settings.get_setting_cached("shop_category_icon_mode", "none")
)
|> assign(:admin_edit_url, Routes.path("/admin/shop/products/#{product.id}"))
|> assign(:admin_edit_url, Routes.path("/admin/shop/products/#{product.uuid}/edit"))
|> assign(:admin_edit_label, "Edit Product")

{:ok, socket}
Expand Down
Loading