Allow importing a livebook via file upload #645 (#665)

This commit is contained in:
Jakub Perżyło 2021-11-01 13:59:39 +01:00 committed by GitHub
parent 2694007c0e
commit fbef386aa8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 118 additions and 0 deletions

View file

@ -24,6 +24,7 @@ import Timer from "./timer";
import MarkdownRenderer from "./markdown_renderer";
import Highlight from "./highlight";
import ClipCopy from "./clip_copy";
import DragAndDrop from "./darg_and_drop";
import morphdomCallbacks from "./morphdom_callbacks";
import { loadUserData } from "./lib/user";
@ -41,6 +42,7 @@ const hooks = {
MarkdownRenderer,
Highlight,
ClipCopy,
DragAndDrop,
};
const csrfToken = document

View file

@ -0,0 +1,25 @@
const DragAndDrop = {
mounted() {
const dropZone = this.el.querySelector("[data-dropzone]");
["dragenter", "dragover"].forEach((eventName) => {
dropZone.addEventListener(eventName, highlight, false);
});
["dragleave", "drop"].forEach((eventName) => {
dropZone.addEventListener(eventName, unhighlight, false);
});
function highlight(e) {
dropZone.classList.add("bg-red-200");
dropZone.classList.add("border-red-400");
}
function unhighlight(e) {
dropZone.classList.remove("bg-red-200");
dropZone.classList.remove("border-red-400");
}
},
};
export default DragAndDrop;

View file

@ -14,6 +14,11 @@ config :logger, :console,
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
# Add mime type to upload notebooks with `Phoenix.LiveView.Upload`
config :mime, :types, %{
"text/plain" => ["livemd"]
}
# Sets the default authentication mode to token
config :livebook, :authentication_mode, :token

View file

@ -23,6 +23,13 @@ defmodule LivebookWeb.HomeLive.ImportComponent do
From clipboard
</span>
<% end %>
<%= live_patch to: Routes.home_path(@socket, :import, "file_upload"),
class: "tab #{if(@tab == "file_upload", do: "active")}" do %>
<.remix_icon icon="file-upload-line" class="align-middle" />
<span class="font-medium">
File upload
</span>
<% end %>
<div class="flex-grow tab">
</div>
</div>
@ -35,4 +42,5 @@ defmodule LivebookWeb.HomeLive.ImportComponent do
defp component_for_tab("url"), do: LivebookWeb.HomeLive.ImportUrlComponent
defp component_for_tab("content"), do: LivebookWeb.HomeLive.ImportContentComponent
defp component_for_tab("file_upload"), do: LivebookWeb.HomeLive.ImportFileUploadComponent
end

View file

@ -0,0 +1,78 @@
defmodule LivebookWeb.HomeLive.ImportFileUploadComponent do
use LivebookWeb, :live_component
@impl true
def mount(socket) do
{:ok,
socket
|> assign(:error, false)
|> allow_upload(:notebook, accept: ~w(.livemd), max_entries: 1)}
end
@impl true
def render(assigns) do
~H"""
<div class="flex-col space-y-5">
<p class="text-gray-700">
Drag and drop a <code>.livemd</code> file below to import it.
</p>
<form id="upload-file-form"
phx-submit="save"
phx-change="validate"
phx-drop-target={@uploads.notebook.ref}
phx-target={@myself}
phx-hook="DragAndDrop"
class="flex flex-col items-start"
>
<%= live_file_input @uploads.notebook, class: "hidden" %>
<div data-dropzone class="flex flex-col justify-center items-center w-full rounded-xl border-2 border-dashed border-gray-400 h-48">
<%= if @uploads.notebook.entries == [] do %>
<span name="placeholder" class="font-medium text-gray-400">Drop your notebook here</span>
<% else %>
<%= for file <- @uploads.notebook.entries do %>
<div class="flex items-center">
<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>
<%= if @error do %>
<div class="text-red-500 text-sm py-2">
You can only upload files with .livemd extension.
</div>
<% end %>
<button type="submit" class="mt-5 button button-blue" disabled={@uploads.notebook.entries == [] || @error}>
Import
</button>
</form>
</div>
"""
end
@impl Phoenix.LiveComponent
def handle_event("clear-file", _params, socket) do
{socket, _entries} = Phoenix.LiveView.Upload.maybe_cancel_uploads(socket)
{:noreply, assign(socket, error: false)}
end
@impl Phoenix.LiveComponent
def handle_event("validate", _params, socket) do
has_error? = Enum.any?(socket.assigns.uploads.notebook.entries, &(not &1.valid?))
{:noreply, assign(socket, error: has_error?)}
end
@impl Phoenix.LiveComponent
def handle_event("save", _params, socket) do
consume_uploaded_entries(socket, :notebook, fn %{path: path}, _entry ->
content = File.read!(path)
send(self(), {:import_content, content, []})
end)
{:noreply, socket}
end
end