defmodule LivebookWeb.SettingsLive do use LivebookWeb, :live_view alias LivebookWeb.{LayoutHelpers, PageHelpers} on_mount LivebookWeb.SidebarHook @impl true def mount(_params, _session, socket) do if connected?(socket) do Livebook.Settings.subscribe() end {:ok, assign(socket, file_systems: Livebook.Settings.file_systems(), env_vars: Livebook.Settings.fetch_env_vars() |> Enum.sort(), env_var: nil, autosave_path_state: %{ file: autosave_dir(), dialog_opened?: false }, update_check_enabled: Livebook.UpdateCheck.enabled?(), page_title: "Livebook - Settings" )} end @impl true def render(assigns) do ~H"""

Here you can change global Livebook configuration. Keep in mind that this configuration gets persisted and will be restored on application launch.

About

<%= if app_name = Livebook.Config.app_service_name() do %> <.labeled_text label="Application"> <%= if app_url = Livebook.Config.app_service_url() do %> <%= app_name %> <% else %> <%= app_name %> <% end %> <% end %> <.labeled_text label="Livebook"> v<%= Application.spec(:livebook, :vsn) %> <.labeled_text label="Elixir"> v<%= System.version() %>
<%= live_redirect to: Routes.live_dashboard_path(@socket, :home), class: "button-base button-outlined-gray" do %> <.remix_icon icon="dashboard-2-line" class="align-middle mr-1" /> Open dashboard <% end %>

Updates

<.switch_checkbox name="update_check_enabled" label="Show banner when a new Livebook version is available" checked={@update_check_enabled} />

Autosave

The directory to keep unsaved notebooks.

<.autosave_path_select state={@autosave_path_state} />

File systems

File systems are used to store notebooks. The local disk filesystem is visible only to the current machine, but alternative file systems are available, such as S3-based storages.

Environment variables

Environment variables store global values which are available inside your notebooks. You can also configure the PATH environment to make system dependencies available to notebooks.

<.live_component module={LivebookWeb.EnvVarsComponent} id="env-vars" env_vars={@env_vars} return_to={Routes.settings_path(@socket, :page)} add_env_var_path={Routes.settings_path(@socket, :add_env_var)} />

The configuration in this section changes only your Livebook experience and is saved in your browser.

Code editor

<.switch_checkbox name="editor_auto_completion" label="Show completion list while typing" checked={false} /> <.switch_checkbox name="editor_auto_signature" label="Show function signature while typing" checked={false} /> <.switch_checkbox name="editor_font_size" label="Increase font size" checked={false} /> <.switch_checkbox name="editor_high_contrast" label="Use high contrast theme" checked={false} /> <.switch_checkbox name="editor_markdown_word_wrap" label="Wrap words in Markdown" checked={false} />
<%= if @live_action == :add_file_system do %> <.modal id="add-file-system-modal" show class="w-full max-w-3xl" patch={Routes.settings_path(@socket, :page)} > <.live_component module={LivebookWeb.SettingsLive.AddFileSystemComponent} id="add-file-system" return_to={Routes.settings_path(@socket, :page)} /> <% end %> <%= if @live_action in [:add_env_var, :edit_env_var] do %> <.modal id="env-var-modal" show class="w-full max-w-3xl" on_close={JS.push("clear_env_var")} patch={Routes.settings_path(@socket, :page)} > <.live_component module={LivebookWeb.EnvVarComponent} id="env-var" env_var={@env_var} headline="Configure your application global environment variables." return_to={Routes.settings_path(@socket, :page)} /> <% end %> """ end defp autosave_path_select(%{state: %{file: nil}} = assigns), do: ~H"" defp autosave_path_select(%{state: %{dialog_opened?: true}} = assigns) do ~H"""
<.live_component module={LivebookWeb.FileSelectComponent} id="autosave-path-component" file={@state.file} extnames={[]} running_files={[]} submit_event={:set_autosave_path} file_system_select_disabled={true} >
""" end defp autosave_path_select(assigns) do ~H"""
""" end @impl true def handle_params(%{"env_var_id" => key}, _url, socket) do env_var = Livebook.Settings.fetch_env_var!(key) {:noreply, assign(socket, env_var: env_var)} end def handle_params(%{"file_system_id" => file_system_id}, _url, socket) do {:noreply, assign(socket, file_system_id: file_system_id)} end def handle_params(_params, _url, socket), do: {:noreply, assign(socket, env_var: nil)} @impl true def handle_event("cancel_autosave_path", %{}, socket) do {:noreply, update( socket, :autosave_path_state, &%{&1 | dialog_opened?: false, file: autosave_dir()} )} end def handle_event("set_autosave_path", %{}, socket) do path = socket.assigns.autosave_path_state.file.path Livebook.Settings.set_autosave_path(path) {:noreply, update( socket, :autosave_path_state, &%{&1 | dialog_opened?: false, file: autosave_dir()} )} end @impl true def handle_event("reset_autosave_path", %{}, socket) do {:noreply, update( socket, :autosave_path_state, &%{&1 | file: default_autosave_dir()} )} end def handle_event("open_autosave_path_select", %{}, socket) do {:noreply, update(socket, :autosave_path_state, &%{&1 | dialog_opened?: true})} end def handle_event("detach_file_system", %{"id" => file_system_id}, socket) do Livebook.Settings.remove_file_system(file_system_id) file_systems = Livebook.Settings.file_systems() {:noreply, assign(socket, file_systems: file_systems)} end def handle_event("save", %{"update_check_enabled" => enabled}, socket) do enabled = enabled == "true" Livebook.UpdateCheck.set_enabled(enabled) {:noreply, assign(socket, :update_check_enabled, enabled)} end def handle_event("save", %{"env_var" => attrs}, socket) do env_var = %Livebook.Settings.EnvVar{} case Livebook.Settings.set_env_var(socket.assigns.env_var || env_var, attrs) do {:ok, _} -> {:noreply, push_patch(socket, to: Routes.settings_path(socket, :page))} {:error, _changeset} -> {:noreply, socket} end end def handle_event("edit_env_var", %{"env_var" => key}, socket) do {:noreply, push_patch(socket, to: Routes.settings_path(socket, :edit_env_var, key))} end def handle_event("delete_env_var", %{"env_var" => key}, socket) do Livebook.Settings.unset_env_var(key) {:noreply, socket} end @impl true def handle_info({:file_systems_updated, file_systems}, socket) do {:noreply, assign(socket, file_systems: file_systems)} end def handle_info({:set_file, file, _info}, socket) do {:noreply, update(socket, :autosave_path_state, &%{&1 | file: file})} end def handle_info(:set_autosave_path, socket) do handle_event("set_autosave_path", %{}, socket) end def handle_info({:env_var_set, env_var}, socket) do idx = Enum.find_index(socket.assigns.env_vars, &(&1.name == env_var.name)) env_vars = if idx, do: List.replace_at(socket.assigns.env_vars, idx, env_var), else: [env_var | socket.assigns.env_vars] {:noreply, assign(socket, env_vars: Enum.sort(env_vars), env_var: nil)} end def handle_info({:env_var_unset, env_var}, socket) do env_vars = Enum.reject(socket.assigns.env_vars, &(&1.name == env_var.name)) {:noreply, assign(socket, env_vars: env_vars, env_var: nil)} end def handle_info(_message, socket), do: {:noreply, socket} defp autosave_dir() do if path = Livebook.Settings.autosave_path() do path |> Livebook.FileSystem.Utils.ensure_dir_path() |> Livebook.FileSystem.File.local() end end defp default_autosave_dir() do Livebook.Settings.default_autosave_path() |> Livebook.FileSystem.Utils.ensure_dir_path() |> Livebook.FileSystem.File.local() end end