init commit
This commit is contained in:
8
lib/diffuser_web/channels/request_channel.ex
Normal file
8
lib/diffuser_web/channels/request_channel.ex
Normal file
@@ -0,0 +1,8 @@
|
||||
defmodule DiffuserWeb.RequestChannel do
|
||||
use Phoenix.Channel
|
||||
|
||||
def join("request:" <> room_id, _message, socket) do
|
||||
IO.inspect(room_id)
|
||||
{:ok, socket}
|
||||
end
|
||||
end
|
46
lib/diffuser_web/channels/request_socket.ex
Normal file
46
lib/diffuser_web/channels/request_socket.ex
Normal file
@@ -0,0 +1,46 @@
|
||||
defmodule DiffuserWeb.RequestSocket do
|
||||
use Phoenix.Socket
|
||||
|
||||
# A Socket handler
|
||||
#
|
||||
# It's possible to control the websocket connection and
|
||||
# assign values that can be accessed by your channel topics.
|
||||
|
||||
channel "request:*", DiffuserWeb.RequestChannel
|
||||
#
|
||||
# To create a channel file, use the mix task:
|
||||
#
|
||||
# mix phx.gen.channel Room
|
||||
#
|
||||
# See the [`Channels guide`](https://hexdocs.pm/phoenix/channels.html)
|
||||
# for further details.
|
||||
|
||||
# Socket params are passed from the client and can
|
||||
# be used to verify and authenticate a user. After
|
||||
# verification, you can put default assigns into
|
||||
# the socket that will be set for all channels, ie
|
||||
#
|
||||
# {:ok, assign(socket, :user_id, verified_user_id)}
|
||||
#
|
||||
# To deny connection, return `:error`.
|
||||
#
|
||||
# See `Phoenix.Token` documentation for examples in
|
||||
# performing token verification on connect.
|
||||
@impl true
|
||||
def connect(_params, socket, _connect_info) do
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
# Socket id's are topics that allow you to identify all sockets for a given user:
|
||||
#
|
||||
# def id(socket), do: "user_socket:#{socket.assigns.user_id}"
|
||||
#
|
||||
# Would allow you to broadcast a "disconnect" event and terminate
|
||||
# all active sockets and channels for a given user:
|
||||
#
|
||||
# Elixir.DiffuserWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{})
|
||||
#
|
||||
# Returning `nil` makes this socket anonymous.
|
||||
@impl true
|
||||
def id(_socket), do: nil
|
||||
end
|
7
lib/diffuser_web/controllers/page_controller.ex
Normal file
7
lib/diffuser_web/controllers/page_controller.ex
Normal file
@@ -0,0 +1,7 @@
|
||||
defmodule DiffuserWeb.PageController do
|
||||
use DiffuserWeb, :controller
|
||||
|
||||
def index(conn, _params) do
|
||||
render(conn, "index.html")
|
||||
end
|
||||
end
|
56
lib/diffuser_web/endpoint.ex
Normal file
56
lib/diffuser_web/endpoint.ex
Normal file
@@ -0,0 +1,56 @@
|
||||
defmodule DiffuserWeb.Endpoint do
|
||||
use Phoenix.Endpoint, otp_app: :diffuser
|
||||
|
||||
# The session will be stored in the cookie and signed,
|
||||
# this means its contents can be read but not tampered with.
|
||||
# Set :encryption_salt if you would also like to encrypt it.
|
||||
@session_options [
|
||||
store: :cookie,
|
||||
key: "_diffuser_key",
|
||||
signing_salt: "NZfusVTj"
|
||||
]
|
||||
|
||||
socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]]
|
||||
|
||||
socket "/socket", DiffuserWeb.RequestSocket,
|
||||
websocket: true,
|
||||
longpoll: false
|
||||
|
||||
# Serve at "/" the static files from "priv/static" directory.
|
||||
#
|
||||
# You should set gzip to true if you are running phx.digest
|
||||
# when deploying your static files in production.
|
||||
plug Plug.Static,
|
||||
at: "/",
|
||||
from: :diffuser,
|
||||
gzip: false,
|
||||
only: ~w(assets fonts images favicon.ico robots.txt)
|
||||
|
||||
plug Plug.Static, at: "/uploads", from: Path.expand('./uploads'), gzip: false
|
||||
|
||||
# Code reloading can be explicitly enabled under the
|
||||
# :code_reloader configuration of your endpoint.
|
||||
if code_reloading? do
|
||||
socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
|
||||
plug Phoenix.LiveReloader
|
||||
plug Phoenix.CodeReloader
|
||||
plug Phoenix.Ecto.CheckRepoStatus, otp_app: :diffuser
|
||||
end
|
||||
|
||||
plug Phoenix.LiveDashboard.RequestLogger,
|
||||
param_key: "request_logger",
|
||||
cookie_key: "request_logger"
|
||||
|
||||
plug Plug.RequestId
|
||||
plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]
|
||||
|
||||
plug Plug.Parsers,
|
||||
parsers: [:urlencoded, :multipart, :json],
|
||||
pass: ["*/*"],
|
||||
json_decoder: Phoenix.json_library()
|
||||
|
||||
plug Plug.MethodOverride
|
||||
plug Plug.Head
|
||||
plug Plug.Session, @session_options
|
||||
plug DiffuserWeb.Router
|
||||
end
|
24
lib/diffuser_web/gettext.ex
Normal file
24
lib/diffuser_web/gettext.ex
Normal file
@@ -0,0 +1,24 @@
|
||||
defmodule DiffuserWeb.Gettext do
|
||||
@moduledoc """
|
||||
A module providing Internationalization with a gettext-based API.
|
||||
|
||||
By using [Gettext](https://hexdocs.pm/gettext),
|
||||
your module gains a set of macros for translations, for example:
|
||||
|
||||
import DiffuserWeb.Gettext
|
||||
|
||||
# Simple translation
|
||||
gettext("Here is the string to translate")
|
||||
|
||||
# Plural translation
|
||||
ngettext("Here is the string to translate",
|
||||
"Here are the strings to translate",
|
||||
3)
|
||||
|
||||
# Domain-based translation
|
||||
dgettext("errors", "Here is the error message to translate")
|
||||
|
||||
See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
|
||||
"""
|
||||
use Gettext, otp_app: :diffuser
|
||||
end
|
60
lib/diffuser_web/live/live_helpers.ex
Normal file
60
lib/diffuser_web/live/live_helpers.ex
Normal file
@@ -0,0 +1,60 @@
|
||||
defmodule DiffuserWeb.LiveHelpers do
|
||||
import Phoenix.LiveView
|
||||
import Phoenix.LiveView.Helpers
|
||||
|
||||
alias Phoenix.LiveView.JS
|
||||
|
||||
@doc """
|
||||
Renders a live component inside a modal.
|
||||
|
||||
The rendered modal receives a `:return_to` option to properly update
|
||||
the URL when the modal is closed.
|
||||
|
||||
## Examples
|
||||
|
||||
<.modal return_to={Routes.prompt_request_index_path(@socket, :index)}>
|
||||
<.live_component
|
||||
module={DiffuserWeb.PromptRequestLive.FormComponent}
|
||||
id={@prompt_request.id || :new}
|
||||
title={@page_title}
|
||||
action={@live_action}
|
||||
return_to={Routes.prompt_request_index_path(@socket, :index)}
|
||||
prompt_request: @prompt_request
|
||||
/>
|
||||
</.modal>
|
||||
"""
|
||||
def modal(assigns) do
|
||||
assigns = assign_new(assigns, :return_to, fn -> nil end)
|
||||
|
||||
~H"""
|
||||
<div id="modal" class="phx-modal fade-in" phx-remove={hide_modal()}>
|
||||
<div
|
||||
id="modal-content"
|
||||
class="phx-modal-content fade-in-scale"
|
||||
phx-click-away={JS.dispatch("click", to: "#close")}
|
||||
phx-window-keydown={JS.dispatch("click", to: "#close")}
|
||||
phx-key="escape"
|
||||
>
|
||||
<%= if @return_to do %>
|
||||
<%= live_patch "✖",
|
||||
to: @return_to,
|
||||
id: "close",
|
||||
class: "phx-modal-close",
|
||||
phx_click: hide_modal()
|
||||
%>
|
||||
<% else %>
|
||||
<a id="close" href="#" class="phx-modal-close" phx-click={hide_modal()}>✖</a>
|
||||
<% end %>
|
||||
|
||||
<%= render_slot(@inner_block) %>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
defp hide_modal(js \\ %JS{}) do
|
||||
js
|
||||
|> JS.hide(to: "#modal", transition: "fade-out")
|
||||
|> JS.hide(to: "#modal-content", transition: "fade-out-scale")
|
||||
end
|
||||
end
|
57
lib/diffuser_web/live/prompt_request_live/form_component.ex
Normal file
57
lib/diffuser_web/live/prompt_request_live/form_component.ex
Normal file
@@ -0,0 +1,57 @@
|
||||
defmodule DiffuserWeb.PromptRequestLive.FormComponent do
|
||||
use DiffuserWeb, :live_component
|
||||
|
||||
alias Diffuser.Generator
|
||||
alias Diffuser.Generator.PromptRequest
|
||||
|
||||
@impl true
|
||||
def update(%{prompt_request: prompt_request} = assigns, socket) do
|
||||
changeset = Generator.change_prompt_request(prompt_request)
|
||||
|
||||
{:ok,
|
||||
socket
|
||||
|> assign(assigns)
|
||||
|> assign(:changeset, changeset)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("validate", %{"prompt_request" => prompt_request_params}, socket) do
|
||||
changeset =
|
||||
socket.assigns.prompt_request
|
||||
|> Generator.change_prompt_request(prompt_request_params)
|
||||
|> Map.put(:action, :validate)
|
||||
|
||||
{:noreply, assign(socket, :changeset, changeset)}
|
||||
end
|
||||
|
||||
def handle_event("save", %{"prompt_request" => prompt_request_params}, socket) do
|
||||
save_prompt_request(socket, socket.assigns.action, prompt_request_params)
|
||||
end
|
||||
|
||||
defp save_prompt_request(socket, :edit, prompt_request_params) do
|
||||
case Generator.update_prompt_request(socket.assigns.prompt_request, prompt_request_params) do
|
||||
{:ok, %PromptRequest{} = prompt_request} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:info, "Prompt request updated successfully")
|
||||
|> push_redirect(to: Routes.prompt_request_show_path(socket, :show, prompt_request))}
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
{:noreply, assign(socket, :changeset, changeset)}
|
||||
end
|
||||
end
|
||||
|
||||
defp save_prompt_request(socket, :new, prompt_request_params) do
|
||||
with {:ok, prompt_request} <- Generator.create_prompt_request(prompt_request_params),
|
||||
{:ok, _pid} <-
|
||||
Diffuser.Generator.PromptRequestSupervisor.start_prompt_request(prompt_request) do
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:info, "Prompt request created successfully")
|
||||
|> push_redirect(to: Routes.prompt_request_show_path(socket, :show, prompt_request))}
|
||||
else
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
{:noreply, assign(socket, changeset: changeset)}
|
||||
end
|
||||
end
|
||||
end
|
@@ -0,0 +1,20 @@
|
||||
<div>
|
||||
<h2><%= @title %></h2>
|
||||
|
||||
<.form
|
||||
let={f}
|
||||
for={@changeset}
|
||||
id="prompt_request-form"
|
||||
phx-target={@myself}
|
||||
phx-change="validate"
|
||||
phx-submit="save">
|
||||
|
||||
<%= label f, :prompt %>
|
||||
<%= text_input f, :prompt %>
|
||||
<%= error_tag f, :prompt %>
|
||||
|
||||
<div>
|
||||
<%= submit "Save", phx_disable_with: "Saving..." %>
|
||||
</div>
|
||||
</.form>
|
||||
</div>
|
46
lib/diffuser_web/live/prompt_request_live/index.ex
Normal file
46
lib/diffuser_web/live/prompt_request_live/index.ex
Normal file
@@ -0,0 +1,46 @@
|
||||
defmodule DiffuserWeb.PromptRequestLive.Index do
|
||||
use DiffuserWeb, :live_view
|
||||
|
||||
alias Diffuser.Generator
|
||||
alias Diffuser.Generator.PromptRequest
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, assign(socket, :prompt_requests, list_prompt_requests())}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_params(params, _url, socket) do
|
||||
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
|
||||
end
|
||||
|
||||
defp apply_action(socket, :edit, %{"id" => id}) do
|
||||
socket
|
||||
|> assign(:page_title, "Edit Prompt request")
|
||||
|> assign(:prompt_request, Generator.get_prompt_request!(id))
|
||||
end
|
||||
|
||||
defp apply_action(socket, :new, _params) do
|
||||
socket
|
||||
|> assign(:page_title, "New Prompt request")
|
||||
|> assign(:prompt_request, %PromptRequest{})
|
||||
end
|
||||
|
||||
defp apply_action(socket, :index, _params) do
|
||||
socket
|
||||
|> assign(:page_title, "Listing Prompt requests")
|
||||
|> assign(:prompt_request, nil)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("delete", %{"id" => id}, socket) do
|
||||
prompt_request = Generator.get_prompt_request!(id)
|
||||
{:ok, _} = Generator.delete_prompt_request(prompt_request)
|
||||
|
||||
{:noreply, assign(socket, :prompt_requests, list_prompt_requests())}
|
||||
end
|
||||
|
||||
defp list_prompt_requests do
|
||||
Generator.list_prompt_requests()
|
||||
end
|
||||
end
|
38
lib/diffuser_web/live/prompt_request_live/index.html.heex
Normal file
38
lib/diffuser_web/live/prompt_request_live/index.html.heex
Normal file
@@ -0,0 +1,38 @@
|
||||
<h1>Listing Prompt requests</h1>
|
||||
|
||||
<%= if @live_action in [:new, :edit] do %>
|
||||
<.modal return_to={Routes.prompt_request_index_path(@socket, :index)}>
|
||||
<.live_component
|
||||
module={DiffuserWeb.PromptRequestLive.FormComponent}
|
||||
id={@prompt_request.id || :new}
|
||||
title={@page_title}
|
||||
action={@live_action}
|
||||
prompt_request={@prompt_request}}
|
||||
/>
|
||||
</.modal>
|
||||
<% end %>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Prompt</th>
|
||||
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="prompt_requests">
|
||||
<%= for prompt_request <- @prompt_requests do %>
|
||||
<tr id={"prompt_request-#{prompt_request.id}"}>
|
||||
<td><%= prompt_request.prompt %></td>
|
||||
|
||||
<td>
|
||||
<span><%= live_redirect "Show", to: Routes.prompt_request_show_path(@socket, :show, prompt_request) %></span>
|
||||
<span><%= live_patch "Edit", to: Routes.prompt_request_index_path(@socket, :edit, prompt_request) %></span>
|
||||
<span><%= link "Delete", to: "#", phx_click: "delete", phx_value_id: prompt_request.id, data: [confirm: "Are you sure?"] %></span>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<span><%= live_patch "New Prompt request", to: Routes.prompt_request_index_path(@socket, :new) %></span>
|
43
lib/diffuser_web/live/prompt_request_live/show.ex
Normal file
43
lib/diffuser_web/live/prompt_request_live/show.ex
Normal file
@@ -0,0 +1,43 @@
|
||||
defmodule DiffuserWeb.PromptRequestLive.Show do
|
||||
use DiffuserWeb, :live_view
|
||||
import Ecto.Query
|
||||
|
||||
alias Diffuser.Generator
|
||||
alias Diffuser.Generator.{Image, PromptRequest}
|
||||
alias Diffuser.Repo
|
||||
alias Phoenix.Socket.Broadcast
|
||||
alias DiffuserWeb.Endpoint
|
||||
|
||||
@impl true
|
||||
def mount(%{"id" => id}, _session, socket) do
|
||||
Endpoint.subscribe("request:#{id}")
|
||||
|
||||
{:ok, socket |> assign(:prompt_request, Generator.get_prompt_request!(id))}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_params(%{"id" => id}, _, socket) do
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:page_title, page_title(socket.assigns.live_action))
|
||||
|> assign(:prompt_request, Generator.get_prompt_request!(id))}
|
||||
end
|
||||
|
||||
defp page_title(:show), do: "Show Prompt request"
|
||||
defp page_title(:edit), do: "Edit Prompt request"
|
||||
|
||||
@impl true
|
||||
def handle_info(
|
||||
%Broadcast{
|
||||
topic: _,
|
||||
event: "request",
|
||||
payload: %{prompt_request: %PromptRequest{} = prompt_request}
|
||||
},
|
||||
socket
|
||||
),
|
||||
do:
|
||||
{:noreply,
|
||||
assign(socket, %{
|
||||
prompt_request: prompt_request
|
||||
})}
|
||||
end
|
38
lib/diffuser_web/live/prompt_request_live/show.html.heex
Normal file
38
lib/diffuser_web/live/prompt_request_live/show.html.heex
Normal file
@@ -0,0 +1,38 @@
|
||||
<h1>Show Prompt request</h1>
|
||||
|
||||
<%= if @live_action in [:edit] do %>
|
||||
<.modal return_to={Routes.prompt_request_show_path(@socket, :show, @prompt_request)}>
|
||||
<.live_component
|
||||
module={DiffuserWeb.PromptRequestLive.FormComponent}
|
||||
id={@prompt_request.id}
|
||||
title={@page_title}
|
||||
action={@live_action}
|
||||
prompt_request={@prompt_request}
|
||||
return_to={Routes.prompt_request_show_path(@socket, :show, @prompt_request)}
|
||||
/>
|
||||
</.modal>
|
||||
<% end %>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<strong>Prompt:</strong>
|
||||
<%= @prompt_request.prompt %>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Status:</strong>
|
||||
<%= @prompt_request.status %>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Images:</strong>
|
||||
<%= if @prompt_request.images do %>
|
||||
<%= for result <- @prompt_request.images do %>
|
||||
<img src={"#{Diffuser.Uploaders.Image.url({result.image, result})}"} />
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<span><%= live_patch "Edit", to: Routes.prompt_request_show_path(@socket, :edit, @prompt_request), class: "button" %></span> |
|
||||
<span><%= live_redirect "Back", to: Routes.prompt_request_index_path(@socket, :index) %></span>
|
63
lib/diffuser_web/router.ex
Normal file
63
lib/diffuser_web/router.ex
Normal file
@@ -0,0 +1,63 @@
|
||||
defmodule DiffuserWeb.Router do
|
||||
use DiffuserWeb, :router
|
||||
|
||||
pipeline :browser do
|
||||
plug :accepts, ["html"]
|
||||
plug :fetch_session
|
||||
plug :fetch_live_flash
|
||||
plug :put_root_layout, {DiffuserWeb.LayoutView, :root}
|
||||
plug :protect_from_forgery
|
||||
plug :put_secure_browser_headers
|
||||
end
|
||||
|
||||
pipeline :api do
|
||||
plug :accepts, ["json"]
|
||||
end
|
||||
|
||||
scope "/", DiffuserWeb do
|
||||
pipe_through :browser
|
||||
|
||||
get "/", PageController, :index
|
||||
|
||||
live "/prompt_requests", PromptRequestLive.Index, :index
|
||||
live "/prompt_requests/new", PromptRequestLive.Index, :new
|
||||
live "/prompt_requests/:id/edit", PromptRequestLive.Index, :edit
|
||||
|
||||
live "/prompt_requests/:id", PromptRequestLive.Show, :show
|
||||
live "/prompt_requests/:id/show/edit", PromptRequestLive.Show, :edit
|
||||
end
|
||||
|
||||
# Other scopes may use custom stacks.
|
||||
# scope "/api", DiffuserWeb do
|
||||
# pipe_through :api
|
||||
# end
|
||||
|
||||
# Enables LiveDashboard only for development
|
||||
#
|
||||
# If you want to use the LiveDashboard in production, you should put
|
||||
# it behind authentication and allow only admins to access it.
|
||||
# If your application does not have an admins-only section yet,
|
||||
# you can use Plug.BasicAuth to set up some basic authentication
|
||||
# as long as you are also using SSL (which you should anyway).
|
||||
if Mix.env() in [:dev, :test] do
|
||||
import Phoenix.LiveDashboard.Router
|
||||
|
||||
scope "/" do
|
||||
pipe_through :browser
|
||||
|
||||
live_dashboard "/dashboard", metrics: DiffuserWeb.Telemetry
|
||||
end
|
||||
end
|
||||
|
||||
# Enables the Swoosh mailbox preview in development.
|
||||
#
|
||||
# Note that preview only shows emails that were sent by the same
|
||||
# node running the Phoenix server.
|
||||
if Mix.env() == :dev do
|
||||
scope "/dev" do
|
||||
pipe_through :browser
|
||||
|
||||
forward "/mailbox", Plug.Swoosh.MailboxPreview
|
||||
end
|
||||
end
|
||||
end
|
71
lib/diffuser_web/telemetry.ex
Normal file
71
lib/diffuser_web/telemetry.ex
Normal file
@@ -0,0 +1,71 @@
|
||||
defmodule DiffuserWeb.Telemetry do
|
||||
use Supervisor
|
||||
import Telemetry.Metrics
|
||||
|
||||
def start_link(arg) do
|
||||
Supervisor.start_link(__MODULE__, arg, name: __MODULE__)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(_arg) do
|
||||
children = [
|
||||
# Telemetry poller will execute the given period measurements
|
||||
# every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics
|
||||
{:telemetry_poller, measurements: periodic_measurements(), period: 10_000}
|
||||
# Add reporters as children of your supervision tree.
|
||||
# {Telemetry.Metrics.ConsoleReporter, metrics: metrics()}
|
||||
]
|
||||
|
||||
Supervisor.init(children, strategy: :one_for_one)
|
||||
end
|
||||
|
||||
def metrics do
|
||||
[
|
||||
# Phoenix Metrics
|
||||
summary("phoenix.endpoint.stop.duration",
|
||||
unit: {:native, :millisecond}
|
||||
),
|
||||
summary("phoenix.router_dispatch.stop.duration",
|
||||
tags: [:route],
|
||||
unit: {:native, :millisecond}
|
||||
),
|
||||
|
||||
# Database Metrics
|
||||
summary("diffuser.repo.query.total_time",
|
||||
unit: {:native, :millisecond},
|
||||
description: "The sum of the other measurements"
|
||||
),
|
||||
summary("diffuser.repo.query.decode_time",
|
||||
unit: {:native, :millisecond},
|
||||
description: "The time spent decoding the data received from the database"
|
||||
),
|
||||
summary("diffuser.repo.query.query_time",
|
||||
unit: {:native, :millisecond},
|
||||
description: "The time spent executing the query"
|
||||
),
|
||||
summary("diffuser.repo.query.queue_time",
|
||||
unit: {:native, :millisecond},
|
||||
description: "The time spent waiting for a database connection"
|
||||
),
|
||||
summary("diffuser.repo.query.idle_time",
|
||||
unit: {:native, :millisecond},
|
||||
description:
|
||||
"The time the connection spent waiting before being checked out for the query"
|
||||
),
|
||||
|
||||
# VM Metrics
|
||||
summary("vm.memory.total", unit: {:byte, :kilobyte}),
|
||||
summary("vm.total_run_queue_lengths.total"),
|
||||
summary("vm.total_run_queue_lengths.cpu"),
|
||||
summary("vm.total_run_queue_lengths.io")
|
||||
]
|
||||
end
|
||||
|
||||
defp periodic_measurements do
|
||||
[
|
||||
# A module, function and arguments to be invoked periodically.
|
||||
# This function must call :telemetry.execute/3 and a metric must be added above.
|
||||
# {DiffuserWeb, :count_users, []}
|
||||
]
|
||||
end
|
||||
end
|
5
lib/diffuser_web/templates/layout/app.html.heex
Normal file
5
lib/diffuser_web/templates/layout/app.html.heex
Normal file
@@ -0,0 +1,5 @@
|
||||
<main class="container">
|
||||
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
|
||||
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
|
||||
<%= @inner_content %>
|
||||
</main>
|
11
lib/diffuser_web/templates/layout/live.html.heex
Normal file
11
lib/diffuser_web/templates/layout/live.html.heex
Normal file
@@ -0,0 +1,11 @@
|
||||
<main class="container">
|
||||
<p class="alert alert-info" role="alert"
|
||||
phx-click="lv:clear-flash"
|
||||
phx-value-key="info"><%= live_flash(@flash, :info) %></p>
|
||||
|
||||
<p class="alert alert-danger" role="alert"
|
||||
phx-click="lv:clear-flash"
|
||||
phx-value-key="error"><%= live_flash(@flash, :error) %></p>
|
||||
|
||||
<%= @inner_content %>
|
||||
</main>
|
30
lib/diffuser_web/templates/layout/root.html.heex
Normal file
30
lib/diffuser_web/templates/layout/root.html.heex
Normal file
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta name="csrf-token" content={csrf_token_value()}>
|
||||
<%= live_title_tag assigns[:page_title] || "Diffuser", suffix: " · Phoenix Framework" %>
|
||||
<link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/app.css")}/>
|
||||
<script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<section class="container">
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="https://hexdocs.pm/phoenix/overview.html">Get Started</a></li>
|
||||
<%= if function_exported?(Routes, :live_dashboard_path, 2) do %>
|
||||
<li><%= link "LiveDashboard", to: Routes.live_dashboard_path(@conn, :home) %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</nav>
|
||||
<a href="https://phoenixframework.org/" class="phx-logo">
|
||||
<img src={Routes.static_path(@conn, "/images/phoenix.png")} alt="Phoenix Framework Logo"/>
|
||||
</a>
|
||||
</section>
|
||||
</header>
|
||||
<%= @inner_content %>
|
||||
</body>
|
||||
</html>
|
41
lib/diffuser_web/templates/page/index.html.heex
Normal file
41
lib/diffuser_web/templates/page/index.html.heex
Normal file
@@ -0,0 +1,41 @@
|
||||
<section class="phx-hero">
|
||||
<h1><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h1>
|
||||
<p>Peace of mind from prototype to production</p>
|
||||
</section>
|
||||
|
||||
<section class="row">
|
||||
<article class="column">
|
||||
<h2>Resources</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://hexdocs.pm/phoenix/overview.html">Guides & Docs</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/phoenixframework/phoenix">Source</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/phoenixframework/phoenix/blob/v1.6/CHANGELOG.md">v1.6 Changelog</a>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
<article class="column">
|
||||
<h2>Help</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://elixirforum.com/c/phoenix-forum">Forum</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://web.libera.chat/#elixir">#elixir on Libera Chat (IRC)</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://twitter.com/elixirphoenix">Twitter @elixirphoenix</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://elixir-slackin.herokuapp.com/">Elixir on Slack</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://discord.gg/elixir">Elixir on Discord</a>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
60
lib/diffuser_web/uploaders/image.ex
Normal file
60
lib/diffuser_web/uploaders/image.ex
Normal file
@@ -0,0 +1,60 @@
|
||||
defmodule Diffuser.Uploaders.Image do
|
||||
use Waffle.Definition
|
||||
use Waffle.Ecto.Definition
|
||||
|
||||
# Include ecto support (requires package waffle_ecto installed):
|
||||
# use Waffle.Ecto.Definition
|
||||
|
||||
@versions [:original]
|
||||
|
||||
# To add a thumbnail version:
|
||||
# @versions [:original, :thumb]
|
||||
|
||||
# Override the bucket on a per definition basis:
|
||||
# def bucket do
|
||||
# :custom_bucket_name
|
||||
# end
|
||||
|
||||
# def bucket({_file, scope}) do
|
||||
# scope.bucket || bucket()
|
||||
# end
|
||||
|
||||
# Whitelist file extensions:
|
||||
# def validate({file, _}) do
|
||||
# file_extension = file.file_name |> Path.extname() |> String.downcase()
|
||||
#
|
||||
# case Enum.member?(~w(.jpg .jpeg .gif .png), file_extension) do
|
||||
# true -> :ok
|
||||
# false -> {:error, "invalid file type"}
|
||||
# end
|
||||
# end
|
||||
|
||||
# Define a thumbnail transformation:
|
||||
# def transform(:thumb, _) do
|
||||
# {:convert, "-strip -thumbnail 250x250^ -gravity center -extent 250x250 -format png", :png}
|
||||
# end
|
||||
|
||||
# Override the persisted filenames:
|
||||
# def filename(version, _) do
|
||||
# version
|
||||
# end
|
||||
|
||||
# Override the storage directory:
|
||||
# def storage_dir(version, {file, scope}) do
|
||||
# "uploads/user/avatars/#{scope.id}"
|
||||
# end
|
||||
|
||||
# Provide a default URL if there hasn't been a file uploaded
|
||||
# def default_url(version, scope) do
|
||||
# "/images/avatars/default_#{version}.png"
|
||||
# end
|
||||
|
||||
# Specify custom headers for s3 objects
|
||||
# Available options are [:cache_control, :content_disposition,
|
||||
# :content_encoding, :content_length, :content_type,
|
||||
# :expect, :expires, :storage_class, :website_redirect_location]
|
||||
#
|
||||
# def s3_object_headers(version, {file, scope}) do
|
||||
# [content_type: MIME.from_path(file.file_name)]
|
||||
# end
|
||||
end
|
47
lib/diffuser_web/views/error_helpers.ex
Normal file
47
lib/diffuser_web/views/error_helpers.ex
Normal file
@@ -0,0 +1,47 @@
|
||||
defmodule DiffuserWeb.ErrorHelpers do
|
||||
@moduledoc """
|
||||
Conveniences for translating and building error messages.
|
||||
"""
|
||||
|
||||
use Phoenix.HTML
|
||||
|
||||
@doc """
|
||||
Generates tag for inlined form input errors.
|
||||
"""
|
||||
def error_tag(form, field) do
|
||||
Enum.map(Keyword.get_values(form.errors, field), fn error ->
|
||||
content_tag(:span, translate_error(error),
|
||||
class: "invalid-feedback",
|
||||
phx_feedback_for: input_name(form, field)
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Translates an error message using gettext.
|
||||
"""
|
||||
def translate_error({msg, opts}) do
|
||||
# When using gettext, we typically pass the strings we want
|
||||
# to translate as a static argument:
|
||||
#
|
||||
# # Translate "is invalid" in the "errors" domain
|
||||
# dgettext("errors", "is invalid")
|
||||
#
|
||||
# # Translate the number of files with plural rules
|
||||
# dngettext("errors", "1 file", "%{count} files", count)
|
||||
#
|
||||
# Because the error messages we show in our forms and APIs
|
||||
# are defined inside Ecto, we need to translate them dynamically.
|
||||
# This requires us to call the Gettext module passing our gettext
|
||||
# backend as first argument.
|
||||
#
|
||||
# Note we use the "errors" domain, which means translations
|
||||
# should be written to the errors.po file. The :count option is
|
||||
# set by Ecto and indicates we should also apply plural rules.
|
||||
if count = opts[:count] do
|
||||
Gettext.dngettext(DiffuserWeb.Gettext, "errors", msg, msg, count, opts)
|
||||
else
|
||||
Gettext.dgettext(DiffuserWeb.Gettext, "errors", msg, opts)
|
||||
end
|
||||
end
|
||||
end
|
16
lib/diffuser_web/views/error_view.ex
Normal file
16
lib/diffuser_web/views/error_view.ex
Normal file
@@ -0,0 +1,16 @@
|
||||
defmodule DiffuserWeb.ErrorView do
|
||||
use DiffuserWeb, :view
|
||||
|
||||
# If you want to customize a particular status code
|
||||
# for a certain format, you may uncomment below.
|
||||
# def render("500.html", _assigns) do
|
||||
# "Internal Server Error"
|
||||
# end
|
||||
|
||||
# By default, Phoenix returns the status message from
|
||||
# the template name. For example, "404.html" becomes
|
||||
# "Not Found".
|
||||
def template_not_found(template, _assigns) do
|
||||
Phoenix.Controller.status_message_from_template(template)
|
||||
end
|
||||
end
|
7
lib/diffuser_web/views/layout_view.ex
Normal file
7
lib/diffuser_web/views/layout_view.ex
Normal file
@@ -0,0 +1,7 @@
|
||||
defmodule DiffuserWeb.LayoutView do
|
||||
use DiffuserWeb, :view
|
||||
|
||||
# Phoenix LiveDashboard is available only in development by default,
|
||||
# so we instruct Elixir to not warn if the dashboard route is missing.
|
||||
@compile {:no_warn_undefined, {Routes, :live_dashboard_path, 2}}
|
||||
end
|
3
lib/diffuser_web/views/page_view.ex
Normal file
3
lib/diffuser_web/views/page_view.ex
Normal file
@@ -0,0 +1,3 @@
|
||||
defmodule DiffuserWeb.PageView do
|
||||
use DiffuserWeb, :view
|
||||
end
|
Reference in New Issue
Block a user