mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-11-09 21:51:42 +08:00
parent
b5e8cd9b00
commit
a4ba8e926c
2 changed files with 113 additions and 47 deletions
|
|
@ -14,7 +14,7 @@ solely client-side operations.
|
||||||
}
|
}
|
||||||
|
|
||||||
[phx-hook="Dropzone"][data-js-dragging] {
|
[phx-hook="Dropzone"][data-js-dragging] {
|
||||||
@apply bg-red-200 border-red-400;
|
@apply bg-yellow-100 border-yellow-300;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* === Session === */
|
/* === Session === */
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,12 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
renamed_name: nil,
|
renamed_name: nil,
|
||||||
error_message: nil,
|
error_message: nil,
|
||||||
file_systems: Livebook.Settings.file_systems()
|
file_systems: Livebook.Settings.file_systems()
|
||||||
|
)
|
||||||
|
|> allow_upload(:folder,
|
||||||
|
accept: :any,
|
||||||
|
auto_upload: true,
|
||||||
|
max_entries: 1,
|
||||||
|
progress: &handle_progress/3
|
||||||
)}
|
)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -147,41 +153,63 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="grow -m-1 p-1 overflow-y-auto tiny-scrollbar" tabindex="-1">
|
|
||||||
<div
|
|
||||||
class="hidden grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-2 border-b border-dashed border-grey-200 mb-2 pb-2"
|
|
||||||
id="new_dir_section"
|
|
||||||
>
|
|
||||||
<div class="flex space-x-2 items-center p-2 rounded-lg">
|
|
||||||
<span class="block">
|
|
||||||
<.remix_icon icon="folder-add-fill" class="text-xl align-middle text-gray-400" />
|
|
||||||
</span>
|
|
||||||
<span class="flex font-medium text-gray-500">
|
|
||||||
<div
|
|
||||||
phx-window-keydown={js_hide_new_dir_section()}
|
|
||||||
phx-key="escape"
|
|
||||||
phx-target={@myself}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
id="new_dir_input"
|
|
||||||
aria-label="new directory"
|
|
||||||
type="text"
|
|
||||||
spellcheck="false"
|
|
||||||
autocomplete="off"
|
|
||||||
phx-blur={js_hide_new_dir_section()}
|
|
||||||
phx-window-keydown={
|
|
||||||
JS.push("create_dir", target: @myself) |> js_hide_new_dir_section()
|
|
||||||
}
|
|
||||||
phx-key="enter"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<%= if any_highlighted?(@file_infos) do %>
|
<div
|
||||||
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-2 border-b border-dashed border-grey-200 mb-2 pb-2">
|
class="hidden grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-2 border-b border-dashed border-grey-200 mb-2 pb-2"
|
||||||
<%= for file_info <- @file_infos, file_info.highlighted != "" do %>
|
id="new_dir_section"
|
||||||
|
>
|
||||||
|
<div class="flex space-x-2 items-center p-2 rounded-lg">
|
||||||
|
<span class="block">
|
||||||
|
<.remix_icon icon="folder-add-fill" class="text-xl align-middle text-gray-400" />
|
||||||
|
</span>
|
||||||
|
<span class="flex font-medium text-gray-500">
|
||||||
|
<div phx-window-keydown={js_hide_new_dir_section()} phx-key="escape" phx-target={@myself}>
|
||||||
|
<input
|
||||||
|
id="new_dir_input"
|
||||||
|
aria-label="new directory"
|
||||||
|
type="text"
|
||||||
|
spellcheck="false"
|
||||||
|
autocomplete="off"
|
||||||
|
phx-blur={js_hide_new_dir_section()}
|
||||||
|
phx-window-keydown={
|
||||||
|
JS.push("create_dir", target: @myself) |> js_hide_new_dir_section()
|
||||||
|
}
|
||||||
|
phx-key="enter"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form
|
||||||
|
class="h-full"
|
||||||
|
phx-change="file_validate"
|
||||||
|
phx-drop-target={@uploads.folder.ref}
|
||||||
|
phx-target={@myself}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="grow -m-1 p-1 h-full rounded-lg overflow-y-auto tiny-scrollbar"
|
||||||
|
tabindex="-1"
|
||||||
|
phx-hook="Dropzone"
|
||||||
|
id="upload-file-dropzone"
|
||||||
|
>
|
||||||
|
<%= live_file_input(@uploads.folder, class: "hidden", aria_labelledby: "import-from-file") %>
|
||||||
|
|
||||||
|
<%= if any_highlighted?(@file_infos) do %>
|
||||||
|
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-2 border-b border-dashed border-grey-200 mb-2 pb-2">
|
||||||
|
<%= for file_info <- @file_infos, file_info.highlighted != "" do %>
|
||||||
|
<.file
|
||||||
|
file_info={file_info}
|
||||||
|
myself={@myself}
|
||||||
|
renaming_file={@renaming_file}
|
||||||
|
renamed_name={@renamed_name}
|
||||||
|
/>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-2">
|
||||||
|
<%= for file_info <- @file_infos, file_info.highlighted == "" do %>
|
||||||
<.file
|
<.file
|
||||||
file_info={file_info}
|
file_info={file_info}
|
||||||
myself={@myself}
|
myself={@myself}
|
||||||
|
|
@ -189,20 +217,25 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
renamed_name={@renamed_name}
|
renamed_name={@renamed_name}
|
||||||
/>
|
/>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<%= if @uploads.folder.entries != [] do %>
|
||||||
|
<%= for file <- @uploads.folder.entries do %>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span class="font-medium text-gray-400"><%= file.client_name %></span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="icon-button"
|
||||||
|
phx-click="clear-file"
|
||||||
|
phx-target={@myself}
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<.remix_icon icon="close-line" class="text-xl text-gray-300 hover:text-gray-500" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-2">
|
|
||||||
<%= for file_info <- @file_infos, file_info.highlighted == "" do %>
|
|
||||||
<.file
|
|
||||||
file_info={file_info}
|
|
||||||
myself={@myself}
|
|
||||||
renaming_file={@renaming_file}
|
|
||||||
renamed_name={@renamed_name}
|
|
||||||
/>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
@ -295,6 +328,7 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
<.menu id={"file-#{Base.encode16(@file_info.file.path)}"} secondary_click>
|
<.menu id={"file-#{Base.encode16(@file_info.file.path)}"} secondary_click>
|
||||||
<:toggle>
|
<:toggle>
|
||||||
<button
|
<button
|
||||||
|
type="button"
|
||||||
class="w-full flex space-x-2 items-center p-2 rounded-lg hover:bg-gray-100 focus:ring-1 focus:ring-gray-400"
|
class="w-full flex space-x-2 items-center p-2 rounded-lg hover:bg-gray-100 focus:ring-1 focus:ring-gray-400"
|
||||||
data-toggle
|
data-toggle
|
||||||
aria-label={"#{if @file_info.name == "..", do: "parent directory", else: @file_info.name}"}
|
aria-label={"#{if @file_info.name == "..", do: "parent directory", else: @file_info.name}"}
|
||||||
|
|
@ -329,6 +363,7 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
<:content>
|
<:content>
|
||||||
<%= if @file_info.editable do %>
|
<%= if @file_info.editable do %>
|
||||||
<button
|
<button
|
||||||
|
type="button"
|
||||||
class="menu-item text-gray-500"
|
class="menu-item text-gray-500"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
aria-label="rename file"
|
aria-label="rename file"
|
||||||
|
|
@ -340,6 +375,7 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
<span class="font-medium">Rename</span>
|
<span class="font-medium">Rename</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
type="button"
|
||||||
class="menu-item text-red-600"
|
class="menu-item text-red-600"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
aria-label="delete file"
|
aria-label="delete file"
|
||||||
|
|
@ -368,7 +404,32 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
|> JS.hide(to: "#new_dir_section")
|
|> JS.hide(to: "#new_dir_section")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp handle_progress(:folder, entry, socket) when entry.done? do
|
||||||
|
consume_uploaded_entries(socket, :folder, fn %{path: file_path}, entry ->
|
||||||
|
content = File.read!(file_path)
|
||||||
|
|
||||||
|
file_path =
|
||||||
|
FileSystem.File.resolve(
|
||||||
|
socket.assigns.current_dir,
|
||||||
|
entry.client_name
|
||||||
|
)
|
||||||
|
|
||||||
|
FileSystem.File.write(file_path, content)
|
||||||
|
{:ok, :ok}
|
||||||
|
end)
|
||||||
|
|
||||||
|
{:noreply, update_file_infos(socket, true)}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_progress(:folder, _entry, socket) do
|
||||||
|
{:noreply, socket}
|
||||||
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
def handle_event("file_validate", _, socket) do
|
||||||
|
{:noreply, socket}
|
||||||
|
end
|
||||||
|
|
||||||
def handle_event("set_file_system", %{"id" => file_system_id}, socket) do
|
def handle_event("set_file_system", %{"id" => file_system_id}, socket) do
|
||||||
{^file_system_id, file_system} =
|
{^file_system_id, file_system} =
|
||||||
Enum.find(socket.assigns.file_systems, fn {id, _file_system} ->
|
Enum.find(socket.assigns.file_systems, fn {id, _file_system} ->
|
||||||
|
|
@ -482,6 +543,11 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_event("clear-file", %{}, socket) do
|
||||||
|
{socket, _entries} = Phoenix.LiveView.Upload.maybe_cancel_uploads(socket)
|
||||||
|
{:noreply, assign(socket, error: false)}
|
||||||
|
end
|
||||||
|
|
||||||
defp update_file_infos(%{assigns: assigns} = socket, force_reload?) do
|
defp update_file_infos(%{assigns: assigns} = socket, force_reload?) do
|
||||||
current_file_infos = assigns[:file_infos] || []
|
current_file_infos = assigns[:file_infos] || []
|
||||||
{dir, prefix} = dir_and_prefix(assigns.file)
|
{dir, prefix} = dir_and_prefix(assigns.file)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue