Packages
phoenix_kit
1.7.49
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/modules/storage/web/bucket_form.ex
defmodule PhoenixKitWeb.Live.Modules.Storage.BucketForm do
@moduledoc """
Bucket form LiveView for storage bucket management.
Provides form interface for creating and editing storage buckets.
"""
use PhoenixKitWeb, :live_view
use Gettext, backend: PhoenixKitWeb.Gettext
alias PhoenixKit.Modules.Storage
alias PhoenixKit.Settings
alias PhoenixKit.Utils.Routes
def mount(params, session, socket) do
bucket_id = params["id"]
mode = if bucket_id, do: :edit, else: :new
# Get current path for navigation
current_path = get_current_path(socket, session)
# Get project title from settings
project_title = Settings.get_project_title()
bucket = load_bucket_data(mode, bucket_id)
changeset =
case mode do
:new ->
Storage.change_bucket(%Storage.Bucket{}, %{})
:edit ->
Storage.change_bucket(bucket, %{
name: bucket.name,
provider: bucket.provider,
region: bucket.region,
endpoint: bucket.endpoint,
bucket_name: bucket.bucket_name,
access_key_id: bucket.access_key_id,
secret_access_key: bucket.secret_access_key,
cdn_url: bucket.cdn_url,
enabled: bucket.enabled,
priority: bucket.priority,
max_size_mb: bucket.max_size_mb
})
end
socket =
socket
|> assign(:mode, mode)
|> assign(:bucket_id, bucket_id)
|> assign(:page_title, page_title(mode))
|> assign(:project_title, project_title)
|> assign(:form_action, page_title(mode))
|> assign(:current_path, current_path)
|> assign(:bucket, bucket)
|> assign(:changeset, changeset)
|> assign(:current_provider, get_current_provider(changeset, bucket))
|> assign(:pending_bucket_params, nil)
|> assign(:show_create_path_modal, false)
{:ok, socket}
end
def handle_event("validate", %{"bucket" => bucket_params}, socket) do
changeset =
case socket.assigns.mode do
:new ->
Storage.change_bucket(%Storage.Bucket{}, bucket_params)
:edit ->
bucket = Storage.get_bucket(socket.assigns.bucket_id)
Storage.change_bucket(bucket, bucket_params)
end
# Update current provider if it changed
current_provider = get_current_provider(changeset, socket.assigns.bucket)
socket =
socket
|> assign(:changeset, changeset)
|> assign(:current_provider, current_provider)
{:noreply, socket}
end
def handle_event("save", %{"bucket" => bucket_params}, socket) do
provider = Map.get(bucket_params, "provider")
endpoint = Map.get(bucket_params, "endpoint")
cond do
provider != "local" ->
# Not a local bucket, proceed with save
save_bucket(socket, bucket_params)
is_nil(endpoint) ->
# No endpoint provided, will be handled by changeset validation
save_bucket(socket, bucket_params)
true ->
# Local bucket with endpoint - validate path first
handle_local_bucket_save(socket, bucket_params, endpoint)
end
end
def handle_event("confirm_create_path", %{"path" => expanded_path}, socket) do
# User confirmed, create the directory and save
case Storage.create_directory(expanded_path) do
{:ok, _} ->
# Directory created, proceed with save
bucket_params = socket.assigns.pending_bucket_params
flash_socket =
socket
|> put_flash(:info, "Storage path created: #{expanded_path}")
socket =
flash_socket
|> assign(:pending_bucket_params, nil)
|> assign(:show_create_path_modal, false)
|> assign(:missing_path, nil)
case socket.assigns.mode do
:new -> create_bucket(socket, bucket_params)
:edit -> update_bucket(socket, bucket_params)
end
{:error, reason} ->
# Failed to create, redirect back with error
socket =
socket
|> put_flash(
:error,
"Storage path could not be created: #{inspect(reason)}. Please create it manually."
)
|> assign(:show_create_path_modal, false)
|> push_navigate(
to: socket.assigns.current_path || Routes.path("/admin/settings/media")
)
{:noreply, socket}
end
end
def handle_event("cancel_create_path", _params, socket) do
# User cancelled, close modal
socket =
socket
|> assign(:pending_bucket_params, nil)
|> assign(:show_create_path_modal, false)
|> assign(:missing_path, nil)
{:noreply, socket}
end
defp handle_local_bucket_save(socket, bucket_params, endpoint) do
case Storage.validate_and_normalize_path(endpoint) do
{:ok, _relative_path} ->
# Path exists, proceed with save
save_bucket(socket, bucket_params)
{:error, :does_not_exist, expanded_path} ->
# Path doesn't exist, show confirmation modal
{:noreply, show_path_creation_modal(socket, bucket_params, expanded_path)}
{:error, :invalid_path} ->
# Invalid path format, redirect back with error
socket =
socket
|> put_flash(
:error,
"Invalid storage path format. Please check the path and try again."
)
|> push_navigate(
to: socket.assigns.current_path || Routes.path("/admin/settings/media")
)
{:noreply, socket}
end
end
defp save_bucket(socket, bucket_params) do
case socket.assigns.mode do
:new -> create_bucket(socket, bucket_params)
:edit -> update_bucket(socket, bucket_params)
end
end
defp show_path_creation_modal(socket, bucket_params, expanded_path) do
socket
|> assign(:pending_bucket_params, bucket_params)
|> assign(:show_create_path_modal, true)
|> assign(:missing_path, expanded_path)
end
defp create_bucket(socket, bucket_params) do
case Storage.create_bucket(bucket_params) do
{:ok, _bucket} ->
socket =
socket
|> put_flash(:info, "Bucket created successfully")
|> push_navigate(to: Routes.path("/admin/settings/media"))
{:noreply, socket}
{:error, changeset} ->
socket =
socket
|> assign(:changeset, changeset)
|> put_flash(:error, "Failed to create bucket")
{:noreply, socket}
end
end
defp update_bucket(socket, bucket_params) do
bucket = Storage.get_bucket(socket.assigns.bucket_id)
case Storage.update_bucket(bucket, bucket_params) do
{:ok, _bucket} ->
socket =
socket
|> put_flash(:info, "Bucket updated successfully")
|> push_navigate(to: Routes.path("/admin/settings/media"))
{:noreply, socket}
{:error, changeset} ->
socket =
socket
|> assign(:changeset, changeset)
|> put_flash(:error, "Failed to update bucket")
{:noreply, socket}
end
end
defp load_bucket_data(:new, _bucket_id), do: nil
defp load_bucket_data(:edit, bucket_id) do
Storage.get_bucket(bucket_id)
end
defp page_title(:new), do: "Add Storage Bucket"
defp page_title(:edit), do: "Edit Storage Bucket"
# Helper function to get current path for navigation
defp get_current_path(_socket, _session) do
# For Bucket form page
Routes.path("/admin/settings/media")
end
# Helper function for input validation styling
defp input_class(changeset, field) do
if Keyword.has_key?(changeset.errors, field) do
"input-error"
else
""
end
end
# Helper function to get currently selected provider from changeset
defp get_current_provider(changeset, bucket) do
case changeset do
%Ecto.Changeset{changes: %{provider: provider}} -> provider
%Ecto.Changeset{} -> if bucket, do: bucket.provider, else: nil
end
end
end