Current section

Files

Jump to
livebook lib livebook_web live settings_live add_file_system_component.ex
Raw

lib/livebook_web/live/settings_live/add_file_system_component.ex

defmodule LivebookWeb.SettingsLive.AddFileSystemComponent do
use LivebookWeb, :live_component
alias Livebook.FileSystem
@impl true
def mount(socket) do
{:ok, assign(socket, data: empty_data(), error_message: nil)}
end
@impl true
def render(assigns) do
~H"""
<div class="p-6 pb-4 max-w-4xl flex flex-col space-y-3">
<h3 class="text-2xl font-semibold text-gray-800">
Add file system
</h3>
<div class="w-full flex-col space-y-5">
<p class="text-gray-700">
Configure an AWS S3 bucket as a drop in replacement of the regular
file system. Many storage services offer an S3-compatible API, so
you can use those as well. One such service is
<a class="link" href="https://www.storj.io" rel="noreferrer noopener">Storj</a>
and they offer free storage.
</p>
<p class="text-gray-700">
Note that any other user of your Livebook could theoretically extract
the credentials, so make sure to properly limit their access to this
specific bucket.
</p>
<%= if @error_message do %>
<div class="error-box">
<%= @error_message %>
</div>
<% end %>
<.form let={f} for={:data}
phx-target={@myself}
phx-submit="add"
phx-change="validate"
autocomplete="off"
spellcheck="false">
<div class="flex flex-col space-y-4">
<div>
<div class="input-label">Bucket URL</div>
<%= text_input f, :bucket_url, value: @data["bucket_url"], class: "input", placeholder: "https://s3.[region].amazonaws.com/[bucket]" %>
</div>
<div>
<div class="input-label">Access Key ID</div>
<.with_password_toggle id="access-key">
<%= text_input f, :access_key_id, value: @data["access_key_id"], class: "input", type: "password" %>
</.with_password_toggle>
</div>
<div>
<div class="input-label">Secret Access Key</div>
<.with_password_toggle id="secret-access-key">
<%= text_input f, :secret_access_key, value: @data["secret_access_key"], class: "input", type: "password" %>
</.with_password_toggle>
</div>
</div>
<div class="mt-5 flex justify-end space-x-2">
<%= live_patch "Cancel", to: @return_to, class: "button button-outlined-gray" %>
<button class="button button-blue"
type="submit"
disabled={not data_valid?(@data)}>
Add
</button>
</div>
</.form>
</div>
</div>
"""
end
@impl true
def handle_event("validate", %{"data" => data}, socket) do
{:noreply, assign(socket, :data, data)}
end
def handle_event("add", %{"data" => data}, socket) do
file_system = data_to_file_system(data)
default_dir = FileSystem.File.new(file_system)
case FileSystem.File.list(default_dir) do
{:ok, _} ->
file_systems = Livebook.Config.append_file_system(file_system)
send(self(), {:file_systems_updated, file_systems})
{:noreply, push_patch(socket, to: socket.assigns.return_to)}
{:error, message} ->
{:noreply, assign(socket, error_message: "Connection test failed: " <> message)}
end
end
defp empty_data() do
%{"bucket_url" => "", "access_key_id" => "", "secret_access_key" => ""}
end
defp data_valid?(data) do
Livebook.Utils.valid_url?(data["bucket_url"]) and data["access_key_id"] != "" and
data["secret_access_key"] != ""
end
defp data_to_file_system(data) do
FileSystem.S3.new(data["bucket_url"], data["access_key_id"], data["secret_access_key"])
end
end