diff --git a/core/assets/css/app.css b/core/assets/css/app.css
index 25a2f807d..946e624c7 100644
--- a/core/assets/css/app.css
+++ b/core/assets/css/app.css
@@ -222,17 +222,17 @@ trix-editor,
trix-editor h1,
.wysiwig h1 {
- @apply text-title2 font-title2 mb-8;
+ @apply text-title3 font-title3 mb-8;
}
trix-editor h2,
.wysiwig h2 {
- @apply text-title3 font-title3 mb-8;
+ @apply text-title4 font-title4 mb-8;
}
trix-editor h3,
.wysiwig h3 {
- @apply text-title4 font-title4 mb-8;
+ @apply text-title5 font-title5 mb-8;
}
trix-editor strong,
diff --git a/core/assets/js/feldspar_app.js b/core/assets/js/feldspar_app.js
index 8cf14c428..2b8a2962e 100644
--- a/core/assets/js/feldspar_app.js
+++ b/core/assets/js/feldspar_app.js
@@ -25,6 +25,6 @@ export const FeldsparApp = {
},
handleMessage(e) {
- this.pushEvent("app_event", e.data);
+ this.pushEvent("feldspar_event", e.data);
},
};
diff --git a/core/config/dev.exs b/core/config/dev.exs
index e1526ab02..33c6e92ed 100644
--- a/core/config/dev.exs
+++ b/core/config/dev.exs
@@ -85,14 +85,6 @@ config :core,
config :core, :s3, bucket: "eylixir"
-config :core,
- :data_donation_storage_backend,
- fake: Systems.Storage.FakeBackend,
- s3: Systems.Storage.AWS.Backend,
- azure: Systems.Storage.Azure.Backend,
- centerdata: Systems.Storage.Centerdata.Backend,
- yoda: Systems.Storage.YodaBackend
-
# For Minio (local S3)
config :ex_aws,
access_key_id: "my_access_key",
diff --git a/core/config/runtime.exs b/core/config/runtime.exs
index b681f1ea8..801f34963 100644
--- a/core/config/runtime.exs
+++ b/core/config/runtime.exs
@@ -26,15 +26,6 @@ if config_env() == :prod do
port: String.to_integer(System.get_env("HTTP_PORT", "8000"))
]
- # Port
-
- config :core,
- :data_donation_storage_backend,
- s3: Systems.Storage.AWS.Backend,
- azure: Systems.Storage.Azure.Backend,
- centerdata: Systems.Storage.Centerdata.Backend,
- yoda: Systems.Storage.YodaBackend
-
# MAILGUN
if mailgun_api_key = System.get_env("MAILGUN_API_KEY") do
diff --git a/core/frameworks/fabric.ex b/core/frameworks/fabric.ex
index cfb66aee2..4ae221877 100644
--- a/core/frameworks/fabric.ex
+++ b/core/frameworks/fabric.ex
@@ -1,29 +1,129 @@
defmodule Fabric do
- alias Fabric.LiveView
- alias Fabric.LiveComponent
+ @type assigns :: map()
+ @type composition_id :: atom()
+ @type composition :: child() | element()
+ @type child :: %{module: module(), params: map()}
+ @type element :: map() | binary() | number()
+
+ @callback compose(id :: composition_id(), a :: assigns()) :: composition() | nil
+
+ defmacro __using__(_opts) do
+ quote do
+ @behaviour Fabric
+
+ import Fabric
+ import Fabric.Html
+
+ require Logger
+
+ def compose_element(%Phoenix.LiveView.Socket{assigns: assigns} = socket, element_id)
+ when is_atom(element_id) do
+ %Phoenix.LiveView.Socket{socket | assigns: compose_element(assigns, element_id)}
+ end
+
+ def compose_element(%{} = assigns, element_id) when is_atom(element_id) do
+ element = compose(element_id, assigns)
+ Phoenix.Component.assign(assigns, element_id, element)
+ end
+
+ def compose_child(context, child_id, opts \\ [])
+
+ def compose_child(%Phoenix.LiveView.Socket{assigns: assigns} = socket, child_id, opts)
+ when is_atom(child_id) do
+ %Phoenix.LiveView.Socket{socket | assigns: compose_child(assigns, child_id)}
+ end
+
+ def compose_child(%{fabric: fabric} = assigns, child_id, only: update)
+ when is_atom(child_id) do
+ if exists?(fabric, child_id) do
+ compose_child(assigns, child_id)
+ else
+ assigns
+ end
+ end
+
+ def compose_child(%{fabric: fabric} = assigns, child_id, _opts) when is_atom(child_id) do
+ fabric =
+ if child = prepare_child(fabric, child_id, compose(child_id, assigns)) do
+ add_child(fabric, child)
+ else
+ remove_child(fabric, child_id)
+ end
+
+ Phoenix.Component.assign(assigns, fabric: fabric)
+ end
+
+ def compose(_id, _assigns) do
+ Logger.error("compose/2 not implemented")
+ nil
+ end
+
+ defoverridable compose: 2
+
+ def element(_id, _assigns) do
+ Logger.error("element/2 not implemented")
+ nil
+ end
+
+ defoverridable element: 2
+ end
+ end
+
+ # Prepare
+
+ def prepare_child(context, child_id, %{module: module, params: params}) do
+ prepare_child(context, child_id, module, params)
+ end
+
+ def prepare_child(_context, _child_id, _), do: nil
def prepare_child(
- %Phoenix.LiveView.Socket{assigns: %{fabric: fabric}},
+ %Phoenix.LiveView.Socket{assigns: assigns},
child_id,
module,
params
) do
+ prepare_child(assigns, child_id, module, params)
+ end
+
+ def prepare_child(%{fabric: fabric}, child_id, module, params) do
prepare_child(fabric, child_id, module, params)
end
def prepare_child(%Fabric.Model{self: self}, child_id, module, params) do
- child_ref = %LiveComponent.RefModel{id: child_id, module: module}
- child_fabric = %Fabric.Model{parent: self, self: child_ref, children: []}
+ child_ref = %Fabric.LiveComponent.RefModel{id: child_id, module: module}
+ child_fabric = %Fabric.Model{parent: self, self: child_ref, children: nil}
params = Map.put(params, :fabric, child_fabric)
- %LiveComponent.Model{ref: child_ref, params: params}
+ %Fabric.LiveComponent.Model{ref: child_ref, params: params}
+ end
+
+ def install_children(%Phoenix.LiveView.Socket{assigns: %{fabric: fabric}} = socket, children)
+ when is_list(children) do
+ Phoenix.Component.assign(socket, fabric: install_children(fabric, children))
+ end
+
+ def install_children(%{fabric: fabric} = assigns, children) when is_list(children) do
+ Phoenix.Component.assign(assigns, fabric: install_children(fabric, children))
+ end
+
+ def install_children(%Fabric.Model{} = fabric, children) when is_list(children) do
+ %Fabric.Model{fabric | children: children}
end
def get_child(%Phoenix.LiveView.Socket{assigns: %{fabric: fabric}}, child_id) do
get_child(fabric, child_id)
end
+ def get_child(%{fabric: fabric}, child_id) do
+ get_child(fabric, child_id)
+ end
+
def get_child(%Fabric.Model{children: children}, child_id) do
- Enum.find(children, &(&1.ref.id == child_id))
+ Enum.find(List.wrap(children), &(&1.ref.id == child_id))
+ end
+
+ def exists?(context, child_id) do
+ get_child(context, child_id) != nil
end
def new_fabric(%Phoenix.LiveView.Socket{} = socket) do
@@ -32,56 +132,93 @@ defmodule Fabric do
end
def new_fabric() do
- %Fabric.Model{parent: nil, children: []}
+ %Fabric.Model{parent: nil, children: nil}
+ end
+
+ def show_child(
+ %Phoenix.LiveView.Socket{assigns: assigns} = socket,
+ %Fabric.LiveComponent.Model{} = child
+ ) do
+ %Phoenix.LiveView.Socket{socket | assigns: show_child(assigns, child)}
end
- def show_child(%Phoenix.LiveView.Socket{} = socket, %LiveComponent.Model{} = child) do
- socket |> add_child(child)
+ def show_child(%{fabric: fabric} = assigns, %Fabric.LiveComponent.Model{} = child) do
+ Phoenix.Component.assign(assigns, fabric: add_child(fabric, child))
end
def replace_child(
- %Phoenix.LiveView.Socket{} = socket,
- %LiveComponent.Model{ref: %{id: id}} = child
+ %Phoenix.LiveView.Socket{assigns: assigns} = socket,
+ %Fabric.LiveComponent.Model{} = child
) do
- socket
- |> remove_child(id)
- |> add_child(child)
+ %Phoenix.LiveView.Socket{socket | assigns: replace_child(assigns, child)}
end
- def hide_child(%Phoenix.LiveView.Socket{} = socket, child_id) do
- socket |> remove_child(child_id)
+ def replace_child(
+ %{fabric: fabric} = assigns,
+ %Fabric.LiveComponent.Model{ref: %{id: id}} = child
+ ) do
+ Phoenix.Component.assign(assigns,
+ fabric:
+ fabric
+ |> remove_child(id)
+ |> add_child(child)
+ )
end
- def show_popup(%Phoenix.LiveView.Socket{} = socket, %LiveComponent.Model{} = child) do
- socket
- |> add_child(child)
- |> send_event(:root, "show_popup", child)
+ def hide_child(%Phoenix.LiveView.Socket{assigns: assigns} = socket, child_id) do
+ %Phoenix.LiveView.Socket{socket | assigns: hide_child(assigns, child_id)}
end
- def hide_popup(%Phoenix.LiveView.Socket{} = socket, child_id) do
- socket
- |> remove_child(child_id)
- |> send_event(:root, "hide_popup")
+ def hide_child(%{fabric: fabric} = assigns, child_id) do
+ Phoenix.Component.assign(assigns, fabric: remove_child(fabric, child_id))
end
- def add_child(%Phoenix.LiveView.Socket{assigns: %{fabric: fabric}} = socket, child) do
- fabric = add_child(fabric, child)
- Phoenix.Component.assign(socket, :fabric, fabric)
+ def show_popup(
+ %Phoenix.LiveView.Socket{assigns: assigns} = socket,
+ %Fabric.LiveComponent.Model{} = child
+ ) do
+ %Phoenix.LiveView.Socket{socket | assigns: show_popup(assigns, child)}
end
- def add_child(%Fabric.Model{children: children} = fabric, %LiveComponent.Model{} = child) do
- %Fabric.Model{fabric | children: children ++ [child]}
+ def show_popup(%{fabric: fabric} = assigns, %Fabric.LiveComponent.Model{} = child) do
+ send_event(fabric, :root, "show_popup", child)
+ Phoenix.Component.assign(assigns, fabric: add_child(fabric, child))
end
- def remove_child(%Phoenix.LiveView.Socket{assigns: %{fabric: fabric}} = socket, child_id) do
- fabric = remove_child(fabric, child_id)
- Phoenix.Component.assign(socket, :fabric, fabric)
+ def hide_popup(%Phoenix.LiveView.Socket{assigns: assigns} = socket, child_id) do
+ %Phoenix.LiveView.Socket{socket | assigns: hide_popup(assigns, child_id)}
+ end
+
+ def hide_popup(%{fabric: fabric} = assigns, child_id) do
+ send_event(fabric, :root, "hide_popup")
+ Phoenix.Component.assign(assigns, fabric: remove_child(fabric, child_id))
+ end
+
+ def add_child(%Fabric.Model{children: children} = fabric, %Fabric.LiveComponent.Model{} = child) do
+ %Fabric.Model{fabric | children: List.wrap(children) ++ List.wrap(child)}
end
+ def remove_child(%Fabric.Model{} = fabric, nil), do: fabric
+
def remove_child(%Fabric.Model{children: children} = fabric, child_id) do
- %Fabric.Model{fabric | children: Enum.filter(children, &(&1.ref.id != child_id))}
+ %Fabric.Model{fabric | children: Enum.filter(List.wrap(children), &(&1.ref.id != child_id))}
+ end
+
+ # Flow
+ def show_next(%Phoenix.LiveView.Socket{assigns: %{fabric: fabric}} = socket) do
+ Phoenix.Component.assign(socket, fabric: show_next(fabric))
+ end
+
+ def show_next(%Fabric.Model{children: children} = fabric) do
+ %Fabric.Model{fabric | children: List.wrap(children) |> List.delete_at(0)}
end
+ def get_current_child(%Fabric.Model{children: children}) do
+ List.wrap(children) |> List.first()
+ end
+
+ # Events
+
def send_event(_, _, _, payload \\ %{})
def send_event(
@@ -111,17 +248,25 @@ defmodule Fabric do
send_event(self, %{name: name, payload: payload})
end
+ def send_event(%Fabric.Model{children: [%{ref: ref} | _]}, :flow, name, payload) do
+ send_event(ref, %{name: name, payload: payload})
+ end
+
+ def send_event(%Fabric.Model{}, :flow, name, _payload) do
+ raise "Sending event '#{name}' to empty flow"
+ end
+
def send_event(%Fabric.Model{} = fabric, child_id, name, payload) do
if child = get_child(fabric, child_id) do
send_event(child.ref, %{name: name, payload: payload})
end
end
- def send_event(%LiveComponent.RefModel{id: id, module: module}, event) do
+ def send_event(%Fabric.LiveComponent.RefModel{id: id, module: module}, event) do
Phoenix.LiveView.send_update(module, %{id: id, fabric_event: event})
end
- def send_event(%LiveView.RefModel{pid: pid}, event) do
+ def send_event(%Fabric.LiveView.RefModel{pid: pid}, event) do
send_event(pid, event)
end
diff --git a/core/frameworks/fabric/html.ex b/core/frameworks/fabric/html.ex
index b2f04f6a5..f1da296e4 100644
--- a/core/frameworks/fabric/html.ex
+++ b/core/frameworks/fabric/html.ex
@@ -10,9 +10,41 @@ defmodule Fabric.Html do
~H"""
<%= if child = Fabric.get_child(@fabric, @id) do %>
<%= render_slot(@header) %>
- <.live_component {Map.from_struct(child.ref)} {child.params}/>
+ <.live_child {Map.from_struct(child)} />
<%= render_slot(@footer) %>
<% end %>
"""
end
+
+ attr(:fabric, :map, required: true)
+
+ def flow(assigns) do
+ ~H"""
+ <%= if child = Fabric.get_current_child(@fabric) do %>
+ <.live_child {Map.from_struct(child)} />
+ <% end %>
+ """
+ end
+
+ attr(:fabric, :map, required: true)
+ attr(:gap, :string, default: "gap-4")
+
+ def stack(assigns) do
+ ~H"""
+
+ <%= for child <- @fabric.children do %>
+ <.live_child {Map.from_struct(child)} />
+ <% end %>
+
+ """
+ end
+
+ attr(:ref, :map, required: true)
+ attr(:params, :map, required: true)
+
+ def live_child(assigns) do
+ ~H"""
+ <.live_component {Map.from_struct(@ref)} {@params}/>
+ """
+ end
end
diff --git a/core/frameworks/fabric/live_component.ex b/core/frameworks/fabric/live_component.ex
index b0f22da5c..f64370867 100644
--- a/core/frameworks/fabric/live_component.ex
+++ b/core/frameworks/fabric/live_component.ex
@@ -13,19 +13,29 @@ defmodule Fabric.LiveComponent do
defmacro __using__(_opts) do
quote do
- import Fabric
- import Fabric.Html
+ use Fabric
+ use Phoenix.LiveComponent
+ @impl true
def update(%{fabric_event: %{name: name, payload: payload}}, socket) do
- {:noreply, socket} = __MODULE__.handle_event(name, payload, socket)
+ {:noreply, socket} = handle_event(name, payload, socket)
{:ok, socket}
end
+ @impl true
def update(%{id: _id, fabric: fabric} = params, socket) do
params = Map.drop(params, [:fabric])
socket = assign(socket, fabric: fabric)
update(params, socket)
end
+
+ @impl true
+ def handle_event(_name, _payload, socket) do
+ Logger.error("handle_event/3 not implemented")
+ {:noreply, socket}
+ end
+
+ defoverridable handle_event: 3
end
end
end
diff --git a/core/frameworks/fabric/live_view.ex b/core/frameworks/fabric/live_view.ex
index 79e376979..e2a77a233 100644
--- a/core/frameworks/fabric/live_view.ex
+++ b/core/frameworks/fabric/live_view.ex
@@ -4,16 +4,37 @@ defmodule Fabric.LiveView do
defstruct [:pid]
end
- defmacro __using__(_opts) do
+ defmacro __using__(layout) do
quote do
- import Fabric
- import Fabric.Html
+ use Phoenix.LiveView, layout: {unquote(layout), :live}
+ unquote(helpers())
+ end
+ end
+
+ defmacro __using__() do
+ quote do
+ use Phoenix.LiveView
+ unquote(helpers())
+ end
+ end
+
+ def helpers() do
+ quote do
+ use Fabric
@before_compile Fabric.LiveView
+ @impl true
def handle_info(%{fabric_event: %{name: name, payload: payload}}, socket) do
- __MODULE__.handle_event(name, payload, socket)
+ handle_event(name, payload, socket)
end
+
+ @impl true
+ def handle_event(_name, _payload, _socket) do
+ raise "handle_event/3 not implemented"
+ end
+
+ defoverridable handle_event: 3
end
end
@@ -26,7 +47,7 @@ defmodule Fabric.LiveView do
"""
def mount(params, session, socket) do
self = %Fabric.LiveView.RefModel{pid: self()}
- fabric = %Fabric.Model{parent: nil, self: self, children: []}
+ fabric = %Fabric.Model{parent: nil, self: self, children: nil}
socket = Phoenix.Component.assign(socket, :fabric, fabric)
super(params, session, socket)
end
diff --git a/core/frameworks/fabric/model.ex b/core/frameworks/fabric/model.ex
index 44202f992..6e7db1b0a 100644
--- a/core/frameworks/fabric/model.ex
+++ b/core/frameworks/fabric/model.ex
@@ -5,11 +5,15 @@ defmodule Fabric.Model do
@type ref :: LiveView.RefModel.t() | LiveComponent.RefModel.t()
@type ref_optional :: ref | nil
@type model :: LiveComponent.Model.t()
+ @type model_id :: atom()
+ @type model_id_optional :: model_id() | nil
+ @type model_list :: [model()]
+ @type model_list_optional :: model_list() | nil
@type t :: %__MODULE__{
parent: ref_optional(),
- self: ref,
- children: [model()]
+ self: ref(),
+ children: model_list_optional()
}
defstruct [:parent, :self, :children]
diff --git a/core/lib/core_web.ex b/core/lib/core_web.ex
index 0fa0f969c..fc3868475 100644
--- a/core/lib/core_web.ex
+++ b/core/lib/core_web.ex
@@ -101,14 +101,60 @@ defmodule CoreWeb do
end
end
+ def live_view_fabric do
+ quote do
+ unquote(component_helpers())
+
+ import Phoenix.Controller,
+ only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1]
+
+ use CoreWeb.LiveLocale
+ use CoreWeb.LiveUri
+ import Core.Authorization, only: [can_access?: 2]
+ use Frameworks.GreenLight.Live, Core.Authorization
+ alias CoreWeb.Router.Helpers, as: Routes
+
+ use CoreWeb.LiveAssignHelper
+ import Core.FeatureFlags
+
+ use Frameworks.Pixel.Flash
+
+ import CoreWeb.UrlResolver, only: [url_resolver: 1]
+
+ import CoreWeb.UI.Popup
+ import CoreWeb.UI.Empty
+ alias CoreWeb.UI.Margin
+
+ alias CoreWeb.UI.Area
+
+ # Routes generation with the ~p sigil
+ unquote(verified_routes())
+ end
+ end
+
def live_component do
quote do
unquote(component_helpers())
use Phoenix.LiveComponent
+ unquote(live_component_helpers())
+ unquote(verified_routes())
+ end
+ end
+
+ def live_component_fabric do
+ quote do
+ unquote(component_helpers())
+ unquote(live_component_helpers())
+ unquote(verified_routes())
+ end
+ end
+
+ def live_component_helpers do
+ quote do
def update_target(%{id: id, type: type}, message) when is_map(message) do
- send_update(type, message |> Map.put(:id, id))
+ Phoenix.LiveView.send_update(type, message |> Map.put(:id, id))
end
def update_target(pid, message) when is_pid(pid) do
@@ -124,9 +170,6 @@ defmodule CoreWeb do
Map.put(socket, :assigns, assigns)
end
-
- # Routes generation with the ~p sigil
- unquote(verified_routes())
end
end
diff --git a/core/lib/core_web/live_form.ex b/core/lib/core_web/live_form.ex
index 5250fff1c..2793913c4 100644
--- a/core/lib/core_web/live_form.ex
+++ b/core/lib/core_web/live_form.ex
@@ -1,9 +1,22 @@
defmodule CoreWeb.LiveForm do
+ defmacro __using__(:fabric) do
+ quote do
+ use CoreWeb, :live_component_fabric
+ unquote(flash_helpers())
+ unquote(form_helpers())
+ end
+ end
+
defmacro __using__(_opts) do
quote do
use CoreWeb, :live_component
- import Frameworks.Pixel.Form
+ unquote(flash_helpers())
+ unquote(form_helpers())
+ end
+ end
+ def flash_helpers() do
+ quote do
def hide_flash(socket) do
Frameworks.Pixel.Flash.push_hide()
socket
@@ -29,6 +42,12 @@ defmodule CoreWeb.LiveForm do
Frameworks.Pixel.Flash.push_info(message)
socket
end
+ end
+ end
+
+ def form_helpers() do
+ quote do
+ import Frameworks.Pixel.Form
def save(socket, changeset) do
socket
diff --git a/core/priv/gettext/en/LC_MESSAGES/eyra-consent.po b/core/priv/gettext/en/LC_MESSAGES/eyra-consent.po
index 95f6a6712..514c23985 100644
--- a/core/priv/gettext/en/LC_MESSAGES/eyra-consent.po
+++ b/core/priv/gettext/en/LC_MESSAGES/eyra-consent.po
@@ -18,3 +18,7 @@ msgstr "Someone made changes to the consent text. Please refresh the page to con
#, elixir-autogen, elixir-format
msgid "default.consent.text"
msgstr "Write here your custom consent terms and conditions..
"
+
+#, elixir-autogen, elixir-format
+msgid "onboarding.consent.checkbox"
+msgstr "I have read and agree with the above terms"
diff --git a/core/priv/gettext/eyra-consent.pot b/core/priv/gettext/eyra-consent.pot
index 191c27999..3c1fbcac2 100644
--- a/core/priv/gettext/eyra-consent.pot
+++ b/core/priv/gettext/eyra-consent.pot
@@ -18,3 +18,7 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "default.consent.text"
msgstr ""
+
+#, elixir-autogen, elixir-format
+msgid "onboarding.consent.checkbox"
+msgstr ""
diff --git a/core/priv/gettext/nl/LC_MESSAGES/eyra-consent.po b/core/priv/gettext/nl/LC_MESSAGES/eyra-consent.po
index 1c43d4e89..37ca4e1e4 100644
--- a/core/priv/gettext/nl/LC_MESSAGES/eyra-consent.po
+++ b/core/priv/gettext/nl/LC_MESSAGES/eyra-consent.po
@@ -18,3 +18,7 @@ msgstr "Iemand heeft de consent tekst is aangepast. Ververs de pagina om verder
#, elixir-autogen, elixir-format
msgid "default.consent.text"
msgstr "Beschrijf hier de consent voorwaarden
"
+
+#, elixir-autogen, elixir-format
+msgid "onboarding.consent.checkbox"
+msgstr "Ik heb de bovenstaande voorwaarden gelezen en ga ermee akkoord"
diff --git a/core/systems/alliance/content_page.ex b/core/systems/alliance/content_page.ex
index 9337e10b3..1e887c857 100644
--- a/core/systems/alliance/content_page.ex
+++ b/core/systems/alliance/content_page.ex
@@ -1,4 +1,5 @@
defmodule Systems.Alliance.ContentPage do
+ use CoreWeb, :live_view
use Systems.Content.Page
alias Systems.{
diff --git a/core/systems/assignment/connection_view.ex b/core/systems/assignment/connection_view.ex
index 9a317a821..db9528f24 100644
--- a/core/systems/assignment/connection_view.ex
+++ b/core/systems/assignment/connection_view.ex
@@ -1,5 +1,5 @@
defmodule Systems.Assignment.ConnectionView do
- use CoreWeb, :live_component
+ use CoreWeb, :live_component_fabric
use Fabric.LiveComponent
alias Frameworks.Pixel.Panel
diff --git a/core/systems/assignment/connector_popup_panel.ex b/core/systems/assignment/connector_popup_panel.ex
index dea885588..e769b825f 100644
--- a/core/systems/assignment/connector_popup_panel.ex
+++ b/core/systems/assignment/connector_popup_panel.ex
@@ -1,5 +1,5 @@
defmodule Systems.Assignment.ConnectorPopupPanel do
- use CoreWeb, :live_component
+ use CoreWeb, :live_component_fabric
use Fabric.LiveComponent
import CoreWeb.UI.Dialog
diff --git a/core/systems/assignment/connector_popup_storage.ex b/core/systems/assignment/connector_popup_storage.ex
index 925641c67..62909c467 100644
--- a/core/systems/assignment/connector_popup_storage.ex
+++ b/core/systems/assignment/connector_popup_storage.ex
@@ -1,5 +1,5 @@
defmodule Systems.Assignment.ConnectorPopupStorage do
- use CoreWeb, :live_component
+ use CoreWeb, :live_component_fabric
use Fabric.LiveComponent
import CoreWeb.UI.Dialog
diff --git a/core/systems/assignment/connector_view.ex b/core/systems/assignment/connector_view.ex
index 5ff02d90f..2a984b7dc 100644
--- a/core/systems/assignment/connector_view.ex
+++ b/core/systems/assignment/connector_view.ex
@@ -1,5 +1,5 @@
defmodule Systems.Assignment.ConnectorView do
- use CoreWeb, :live_component
+ use CoreWeb, :live_component_fabric
use Fabric.LiveComponent
alias Systems.{
diff --git a/core/systems/assignment/content_page.ex b/core/systems/assignment/content_page.ex
index 1e4807770..eb5c77dd7 100644
--- a/core/systems/assignment/content_page.ex
+++ b/core/systems/assignment/content_page.ex
@@ -1,6 +1,7 @@
defmodule Systems.Assignment.ContentPage do
+ use CoreWeb, :live_view_fabric
+ use Fabric.LiveView, CoreWeb.Layouts
use Systems.Content.Page
- use Fabric.LiveView
alias Systems.{
Assignment,
diff --git a/core/systems/assignment/crew_page.ex b/core/systems/assignment/crew_page.ex
index af3b88345..3d30ef6c2 100644
--- a/core/systems/assignment/crew_page.ex
+++ b/core/systems/assignment/crew_page.ex
@@ -1,24 +1,20 @@
defmodule Systems.Assignment.CrewPage do
- use CoreWeb, :live_view
+ use CoreWeb, :live_view_fabric
+ use Fabric.LiveView, CoreWeb.Layouts
+
use Systems.Observatory.Public
use CoreWeb.LiveRemoteIp
use CoreWeb.Layouts.Stripped.Component, :projects
require Logger
- alias Frameworks.Concept
+
+ alias CoreWeb.UI.Timestamp
alias Systems.{
Assignment,
- Project,
- Workflow,
- Crew,
Storage
}
- import Assignment.StartView
- import Project.ToolRefView
- import Workflow.ItemViews, only: [work_list: 1]
-
@impl true
def get_authorization_context(%{"id" => id}, _session, _socket) do
%{crew: crew} = Assignment.Public.get!(String.to_integer(id), [:crew])
@@ -26,7 +22,7 @@ defmodule Systems.Assignment.CrewPage do
end
@impl true
- def mount(%{"id" => id} = _params, _session, socket) do
+ def mount(%{"id" => id}, session, socket) do
model = Assignment.Public.get!(id, Assignment.Model.preload_graph(:down))
{
@@ -34,16 +30,11 @@ defmodule Systems.Assignment.CrewPage do
socket
|> assign(
id: id,
- model: model,
- tool_ref_view: nil
+ model: model
)
+ |> update_panel_info(session)
|> observe_view_model()
- |> update_onboarding()
- |> update_selected_item_id()
- |> update_selected_item()
- |> update_start_view()
- |> update_work_list()
- |> update_menus()
+ |> update_flow()
}
end
@@ -51,255 +42,64 @@ defmodule Systems.Assignment.CrewPage do
def handle_view_model_updated(socket) do
socket
- |> update_onboarding()
- |> update_selected_item_id()
- |> update_selected_item()
- |> update_start_view()
- |> update_work_list()
+ |> update_flow()
|> update_menus()
end
- defp update_onboarding(%{assigns: %{vm: %{onboarding: onboarding}}} = socket) do
- socket |> assign(onboarding: onboarding)
- end
-
- defp update_selected_item_id(%{assigns: %{selected_item_id: selected_item_id}} = socket)
- when not is_nil(selected_item_id) do
- socket
- end
-
- defp update_selected_item_id(%{assigns: %{vm: %{items: []}}} = socket) do
- socket |> assign(selected_item_id: nil)
- end
-
- defp update_selected_item_id(%{assigns: %{vm: %{items: [{%{id: id}, _}]}}} = socket) do
- socket |> assign(selected_item_id: id)
- end
-
- defp update_selected_item_id(%{assigns: %{vm: %{items: items}}} = socket) do
- {%{id: selected_item_id}, _} =
- Enum.find(items, List.first(items), fn {_, %{status: status}} -> status == :pending end)
-
- socket |> assign(selected_item_id: selected_item_id)
- end
-
- defp update_selected_item(
- %{assigns: %{selected_item_id: selected_item_id, vm: %{items: items}}} = socket
- ) do
- selected_item = Enum.find(items, fn {%{id: id}, _} -> id == selected_item_id end)
-
- socket |> assign(selected_item: selected_item)
- end
-
- defp update_start_view(
- %{
- assigns: %{
- selected_item:
- {%{title: title, description: description, group: group}, _task} = selected_item
- }
- } = socket
- ) do
- button = %{
- action: start_action(selected_item),
- face: %{type: :primary, label: "Start"}
- }
-
- start_view = %{
- title: title,
- description: description,
- icon: group,
- button: button
- }
-
- socket |> assign(start_view: start_view)
- end
-
- defp update_start_view(socket) do
- socket |> assign(start_view: nil)
- end
-
- defp start_action({%{tool_ref: tool_ref}, _task} = item) do
- Project.ToolRefModel.tool(tool_ref)
- |> Concept.ToolModel.launcher()
- |> start_action(item)
- end
-
- defp start_action(%{function: _, props: _}, {%{id: id}, _}) do
- %{type: :send, event: "start", item: id}
- end
-
- defp start_action(%{url: url}, _) do
- %{type: :http_get, to: url, target: "_blank"}
+ defp update_panel_info(socket, %{"panel_info" => panel_info}) do
+ assign(socket, panel_info: panel_info)
end
- defp start_action(_, {%{id: id}, _}) do
- %{type: :send, event: "start", item: id}
+ defp update_panel_info(socket, _) do
+ assign(socket, panel_info: nil)
end
- defp update_work_list(
- %{assigns: %{vm: %{items: items}, selected_item: {%{id: selected_item_id}, _}}} = socket
- ) do
- work_list = %{
- items: Enum.map(items, &map_item/1),
- selected_item_id: selected_item_id
- }
-
- socket |> assign(work_list: work_list, show_left_column: Enum.count(items) > 1)
- end
-
- defp update_work_list(socket) do
- socket |> assign(work_list: nil, show_left_column: false)
- end
-
- defp map_item({%{id: id, title: title, group: group}, task}) do
- %{id: id, title: title, icon: group, status: task_status(task)}
+ defp update_flow(%{assigns: %{vm: %{flow: flow}}} = socket) do
+ socket |> install_children(flow)
end
- defp task_status(%{status: status}), do: status
- defp task_status(_), do: :pending
-
@impl true
- def handle_info(
- {:store_participant_data, _data},
- %{assigns: %{model: %{storage_endpoint: nil}}} = socket
- ) do
- raise "Unable to store participant data: no storage endpoint configurated"
- {:noreply, socket}
+ def handle_event("continue", _payload, socket) do
+ {:noreply, socket |> show_next()}
end
@impl true
- def handle_info(
- {:store_participant_data, data},
- %{assigns: %{model: %{storage_endpoint: endpoint}, remote_ip: remote_ip}} = socket
- ) do
- Storage.Public.store(endpoint, data, remote_ip)
- {:noreply, socket}
- end
-
- @impl true
- def handle_info(
- {:complete_task, _},
- %{assigns: %{vm: %{items: items}, selected_item: {%{id: selected_item_id}, _}}} = socket
- ) do
- {_, task} = Enum.find(items, fn {%{id: id}, _} -> id == selected_item_id end)
-
- Crew.Public.activate_task(task)
-
- {:noreply, socket}
- end
-
- @impl true
- def handle_info({:onboarding_continue, _}, %{assigns: %{onboarding: onboarding}} = socket) do
- {_, onboarding} = List.pop_at(onboarding, 0)
-
+ def handle_event("feldspar_event", event, socket) do
{
:noreply,
- socket |> assign(onboarding: onboarding)
+ socket |> send_event(:flow, "feldspar_event", event)
}
end
@impl true
- def handle_event(
- "work_item_selected",
- %{"item" => item_id},
- socket
- ) do
- item_id = String.to_integer(item_id)
-
- {
- :noreply,
- socket
- |> assign(
- selected_item_id: item_id,
- tool_ref_view: nil
- )
- |> update_selected_item()
- |> update_start_view()
- |> update_work_list()
- }
+ def handle_event("store", %{key: key, data: data}, socket) do
+ {:noreply, socket |> store(key, data)}
end
- @impl true
- def handle_event("start", %{"item" => item_id}, %{assigns: %{vm: %{items: items}}} = socket) do
- item_id = String.to_integer(item_id)
- {%{tool_ref: tool_ref}, task} = Enum.find(items, fn {%{id: id}, _} -> id == item_id end)
-
- tool_ref_view = %{
- tool_ref: tool_ref,
- task: task
- }
-
- Crew.Public.lock_task(task)
-
- {
- :noreply,
- socket |> assign(tool_ref_view: tool_ref_view, start_view: nil)
- }
- end
-
- @impl true
- def handle_event("app_event", event, socket) do
- {
- :noreply,
- socket |> handle_app_event(event)
+ def store(
+ %{assigns: %{panel_info: panel_info, model: assignment, remote_ip: remote_ip}} = socket,
+ key,
+ data
+ ) do
+ meta_data = %{
+ remote_ip: remote_ip,
+ timestamp: Timestamp.now() |> DateTime.to_unix(),
+ key: key
}
- end
- defp handle_app_event(%{assigns: %{selected_item: {_, task}}} = socket, %{
- "__type__" => "CommandSystemExit",
- "code" => code,
- "info" => _info
- }) do
- if code == 0 do
- Crew.Public.activate_task(task)
- socket
- else
- Frameworks.Pixel.Flash.put_error(socket, "Application stopped")
- end
- end
+ assignment
+ |> Storage.Private.storage_info()
+ |> Storage.Public.store(panel_info, data, meta_data)
- defp handle_app_event(socket, %{
- "__type__" => "CommandSystemDonate",
- "json_string" => _json_string
- }) do
- socket |> Frameworks.Pixel.Flash.put_info("Donation received")
- end
-
- defp handle_app_event(socket, %{"__type__" => type}) do
- socket |> Frameworks.Pixel.Flash.put_error("Unsupported event " <> type)
- end
-
- defp handle_app_event(socket, _) do
- socket |> Frameworks.Pixel.Flash.put_error("Unsupported event")
+ socket
end
@impl true
def render(assigns) do
~H"""
- <.stripped menus={@menus} footer?={false}>
- <%= if view = List.first(@onboarding) do %>
- <.live_component {view} />
- <% else %>
-
- <%= if @work_list && @show_left_column do %>
-
- <.work_list {@work_list} />
-
-
-
- <% end %>
-
- <%= if @tool_ref_view do %>
- <.tool_ref_view {@tool_ref_view}/>
- <% else %>
- <%= if @start_view do %>
- <.start_view {@start_view} />
- <% end %>
- <% end %>
-
-
- <% end %>
-
+ <.stripped menus={@menus} footer?={false}>
+ <.flow fabric={@fabric} />
+
"""
end
end
diff --git a/core/systems/assignment/crew_page_builder.ex b/core/systems/assignment/crew_page_builder.ex
index b7aff0b4f..1fe0e65ed 100644
--- a/core/systems/assignment/crew_page_builder.ex
+++ b/core/systems/assignment/crew_page_builder.ex
@@ -8,61 +8,68 @@ defmodule Systems.Assignment.CrewPageBuilder do
def view_model(assignment, assigns) do
%{
- onboarding: onboarding(assignment, assigns),
- items: items(assignment, assigns)
+ flow: flow(assignment, assigns)
}
end
- defp onboarding(%{status: status} = assignment, assigns) do
+ defp flow(%{status: status} = assignment, assigns) do
if is_tester?(assignment, assigns) or status == :online do
- onboarding(assignment, assigns, current_onboarding(assigns))
+ flow(assignment, assigns, current_flow(assigns))
else
[]
end
end
- defp onboarding(assignment, assigns, nil), do: full_onboarding(assignment, assigns)
+ defp flow(assignment, assigns, nil), do: full_flow(assignment, assigns)
- defp onboarding(assignment, assigns, current_onboarding) do
- full_onboarding(assignment, assigns)
- |> Enum.filter(fn %{id: id} ->
- Enum.find(current_onboarding, &(&1.id == id)) != nil
+ defp flow(assignment, assigns, current_flow) do
+ full_flow(assignment, assigns)
+ |> Enum.filter(fn %{ref: %{id: id}} ->
+ Enum.find(current_flow, &(&1.ref.id == id)) != nil
end)
end
- defp full_onboarding(assignment, assigns) do
- [consent_view(assignment, assigns)]
+ defp full_flow(assignment, assigns) do
+ [
+ consent_view(assignment, assigns),
+ work_view(assignment, assigns)
+ ]
end
- defp current_onboarding(%{onboarding: onboarding}), do: onboarding
- defp current_onboarding(_), do: nil
+ defp current_flow(%{fabric: %{children: children}}), do: children
- defp consent_view(%{consent_agreement: consent_agreement}, %{current_user: user}) do
+ defp consent_view(%{consent_agreement: consent_agreement}, %{current_user: user, fabric: fabric}) do
revision = Consent.Public.latest_revision(consent_agreement)
- %{
- id: :onboarding_consent_view,
- module: Assignment.OnboardingConsentView,
+ Fabric.prepare_child(fabric, :onboarding_view, Assignment.OnboardingConsentView, %{
revision: revision,
user: user
- }
+ })
+ end
+
+ defp work_view(assignment, %{fabric: fabric} = assigns) do
+ work_items = work_items(assignment, assigns)
+
+ Fabric.prepare_child(fabric, :work_view, Assignment.CrewWorkView, %{
+ work_items: work_items
+ })
end
- defp items(%{status: status, crew: crew} = assignment, %{current_user: user} = assigns) do
+ defp work_items(%{status: status, crew: crew} = assignment, %{current_user: user} = assigns) do
if is_tester?(assignment, assigns) or status == :online do
member = Crew.Public.get_member(crew, user)
- items(assignment, member)
+ work_items(assignment, member)
else
[]
end
end
- defp items(%{workflow: workflow} = assignment, %{} = member) do
+ defp work_items(%{workflow: workflow} = assignment, %{} = member) do
ordered_items = Workflow.Model.ordered_items(workflow)
Enum.map(ordered_items, &{&1, get_or_create_task(&1, assignment, member)})
end
- defp items(_assignment, nil), do: []
+ defp work_items(_assignment, nil), do: []
defp is_tester?(%{crew: crew}, %{current_user: user}) do
Core.Authorization.user_has_role?(user, crew, :tester)
diff --git a/core/systems/assignment/crew_work_view.ex b/core/systems/assignment/crew_work_view.ex
new file mode 100644
index 000000000..b4f624464
--- /dev/null
+++ b/core/systems/assignment/crew_work_view.ex
@@ -0,0 +1,218 @@
+defmodule Systems.Assignment.CrewWorkView do
+ use CoreWeb, :live_component_fabric
+ use Fabric.LiveComponent
+
+ alias Systems.{
+ Assignment,
+ Crew,
+ Workflow,
+ Project
+ }
+
+ def update(%{work_items: work_items}, %{assigns: %{id: _id}} = socket) do
+ {
+ :ok,
+ socket
+ |> assign(work_items: work_items)
+ |> compose_child(:start_view)
+ |> compose_child(:work_list_view)
+ |> compose_child(:tool_ref_view, only: :update)
+ }
+ end
+
+ def update(%{id: id, work_items: work_items}, socket) do
+ {
+ :ok,
+ socket
+ |> assign(
+ id: id,
+ work_items: work_items
+ )
+ |> update_selected_item_id()
+ |> update_selected_item()
+ |> compose_child(:start_view)
+ |> compose_child(:work_list_view)
+ }
+ end
+
+ defp update_selected_item_id(%{assigns: %{selected_item_id: selected_item_id}} = socket)
+ when not is_nil(selected_item_id) do
+ socket
+ end
+
+ defp update_selected_item_id(%{assigns: %{work_items: []}} = socket) do
+ socket |> assign(selected_item_id: nil)
+ end
+
+ defp update_selected_item_id(%{assigns: %{work_items: [{%{id: id}, _}]}} = socket) do
+ socket |> assign(selected_item_id: id)
+ end
+
+ defp update_selected_item_id(%{assigns: %{work_items: work_items}} = socket) do
+ {%{id: selected_item_id}, _} =
+ Enum.find(work_items, List.first(work_items), fn {_, %{status: status}} ->
+ status == :pending
+ end)
+
+ socket |> assign(selected_item_id: selected_item_id)
+ end
+
+ defp update_selected_item(
+ %{assigns: %{selected_item_id: selected_item_id, work_items: work_items}} = socket
+ ) do
+ selected_item = Enum.find(work_items, fn {%{id: id}, _} -> id == selected_item_id end)
+
+ socket |> assign(selected_item: selected_item)
+ end
+
+ @impl true
+ def compose(:start_view, %{selected_item: selected_item}) when not is_nil(selected_item) do
+ %{module: Assignment.StartView, params: %{work_item: selected_item}}
+ end
+
+ @impl true
+ def compose(:start_view, _assigns), do: nil
+
+ @impl true
+ def compose(:work_list_view, %{
+ work_items: [_one, _two | _] = work_items,
+ selected_item_id: selected_item_id
+ })
+ when not is_nil(selected_item_id) do
+ work_list = %{
+ items: Enum.map(work_items, &map_item/1),
+ selected_item_id: selected_item_id
+ }
+
+ %{module: Workflow.WorkListView, params: %{work_list: work_list}}
+ end
+
+ @impl true
+ def compose(:work_list_view, _assigns), do: nil
+
+ @impl true
+ def compose(:tool_ref_view, %{selected_item: {%{tool_ref: tool_ref}, task}}) do
+ %{module: Project.ToolRefView, params: %{tool_ref: tool_ref, task: task}}
+ end
+
+ @impl true
+ def compose(:tool_ref_view, _assigns), do: nil
+
+ defp map_item({%{id: id, title: title, group: group}, task}) do
+ %{id: id, title: title, icon: group, status: task_status(task)}
+ end
+
+ defp task_status(%{status: status}), do: status
+ defp task_status(_), do: :pending
+
+ defp lock_task(socket, task) do
+ Crew.Public.lock_task(task)
+ socket
+ end
+
+ @impl true
+ def handle_event(
+ "complete_task",
+ _,
+ %{assigns: %{work_items: work_items, selected_item: {%{id: selected_item_id}, _}}} =
+ socket
+ ) do
+ {_, task} = Enum.find(work_items, fn {%{id: id}, _} -> id == selected_item_id end)
+
+ Crew.Public.activate_task(task)
+
+ {:noreply, socket}
+ end
+
+ @impl true
+ def handle_event(
+ "work_item_selected",
+ %{"item" => item_id},
+ socket
+ ) do
+ item_id = String.to_integer(item_id)
+
+ {
+ :noreply,
+ socket
+ |> assign(
+ selected_item_id: item_id,
+ tool_ref_view: nil
+ )
+ |> update_selected_item()
+ |> compose_child(:start_view)
+ |> compose_child(:work_list_view)
+ }
+ end
+
+ @impl true
+ def handle_event("start", _, %{assigns: %{selected_item: {_, task}}} = socket) do
+ {
+ :noreply,
+ socket
+ |> compose_child(:tool_ref_view)
+ |> lock_task(task)
+ }
+ end
+
+ @impl true
+ def handle_event("feldspar_event", event, socket) do
+ {
+ :noreply,
+ socket |> handle_feldspar_event(event)
+ }
+ end
+
+ defp handle_feldspar_event(%{assigns: %{selected_item: {_, task}}} = socket, %{
+ "__type__" => "CommandSystemExit",
+ "code" => code,
+ "info" => _info
+ }) do
+ if code == 0 do
+ Crew.Public.activate_task(task)
+ socket
+ else
+ Frameworks.Pixel.Flash.put_info(socket, "Application stopped")
+ end
+ end
+
+ defp handle_feldspar_event(socket, %{
+ "__type__" => "CommandSystemDonate",
+ "key" => key,
+ "json_string" => json_string
+ }) do
+ socket
+ |> send_event(:parent, "store", %{key: key, data: json_string})
+ |> Frameworks.Pixel.Flash.put_info("Donated")
+ end
+
+ defp handle_feldspar_event(socket, %{"__type__" => type}) do
+ socket |> Frameworks.Pixel.Flash.put_error("Unsupported event " <> type)
+ end
+
+ defp handle_feldspar_event(socket, _) do
+ socket |> Frameworks.Pixel.Flash.put_error("Unsupported event")
+ end
+
+ @impl true
+ def render(assigns) do
+ ~H"""
+
+ <%= if exists?(@fabric, :tool_ref_view) do %>
+ <.child id={:tool_ref_view} fabric={@fabric} />
+ <% else %>
+ <%= if exists?(@fabric, :work_list_view) do %>
+
+ <.child id={:work_list_view} fabric={@fabric} />
+
+
+
+ <% end %>
+
+ <.child id={:start_view} fabric={@fabric} />
+
+ <% end %>
+
+ """
+ end
+end
diff --git a/core/systems/assignment/external_panel_controller.ex b/core/systems/assignment/external_panel_controller.ex
index 62ed3feee..cc0c57e36 100644
--- a/core/systems/assignment/external_panel_controller.ex
+++ b/core/systems/assignment/external_panel_controller.ex
@@ -1,57 +1,47 @@
defmodule Systems.Assignment.ExternalPanelController do
use CoreWeb, :controller
- @supported_locales ~w(nl en)
- @centerdata_callback_url "https://quest.centerdata.nl/eyra/dd.php"
-
- def create(conn, %{"id" => id, "panel" => panel} = params) do
- []
- |> add_locale(params)
- |> add_panel_info(String.to_existing_atom(panel), params)
- |> start_assignment(conn, id)
+ def create(conn, %{"id" => _id, "panel" => _panel} = params) do
+ conn
+ |> add_panel_info(params)
+ |> redirect(to: path(params))
end
- defp add_panel_info(opts, panel, params) do
+ defp add_panel_info(conn, params) do
panel_info = %{
- callback_url: get_callback_url(panel),
- participant: get_participant(panel, params),
- language: get_language(panel, params),
+ participant: get_participant(params),
query_string: params
}
- Keyword.put(opts, :panel_info, panel_info)
+ conn |> put_session(:panel_info, panel_info)
end
- defp add_locale(opts, %{"locale" => locale}), do: add_locale(opts, locale)
- defp add_locale(opts, %{"lang" => locale}), do: add_locale(opts, locale)
+ defp path(%{"id" => id} = params) do
+ query_string = query_string(params)
+ "/assignment/#{id}#{query_string}"
+ end
- defp add_locale(opts, locale) when is_binary(locale) do
- if is_supported?(locale) do
- Keyword.put(opts, :locale, locale)
+ defp query_string(params) do
+ if locale = get_locale(params) do
+ "?locale=#{locale}"
else
- opts
+ ""
end
end
- defp add_locale(opts, _), do: opts
-
- defp is_supported?(locale) when is_binary(locale) do
- locale in @supported_locales
- end
-
- defp start_assignment(_opts, conn, id) do
- path = ~p"/assignment/#{id}"
- redirect(conn, to: path)
- end
+ # @supported_locales ~w(nl en)
+ # defp is_supported?(locale) when is_binary(locale) do
+ # locale in @supported_locales
+ # end
# Param Mappings
- defp get_participant(:liss, %{"respondent" => respondent}), do: respondent
- defp get_participant(_, %{"participant" => participant}), do: participant
-
- defp get_language(:liss, %{"lang" => lang}), do: lang
- defp get_language(_, %{"language" => language}), do: language
+ defp get_participant(%{"respondent" => respondent}), do: respondent
+ defp get_participant(%{"participant" => participant}), do: participant
+ defp get_participant(_), do: nil
- defp get_callback_url(:liss), do: @centerdata_callback_url
- defp get_callback_url(_), do: nil
+ defp get_locale(%{"lang" => lang}), do: lang
+ defp get_locale(%{"language" => language}), do: language
+ defp get_locale(%{"locale" => locale}), do: locale
+ defp get_locale(_), do: nil
end
diff --git a/core/systems/assignment/onboarding_consent_view.ex b/core/systems/assignment/onboarding_consent_view.ex
index f4dbaeb00..963c4bece 100644
--- a/core/systems/assignment/onboarding_consent_view.ex
+++ b/core/systems/assignment/onboarding_consent_view.ex
@@ -1,20 +1,11 @@
defmodule Systems.Assignment.OnboardingConsentView do
- use CoreWeb.LiveForm
+ use CoreWeb.LiveForm, :fabric
+ use Fabric.LiveComponent
alias Systems.{
Consent
}
- @impl true
- def update(%{consent_clickwrap_view: :continue}, %{assigns: %{id: id}} = socket) do
- send(self(), {:onboarding_continue, id})
-
- {
- :ok,
- socket
- }
- end
-
@impl true
def update(%{id: id, revision: revision, user: user}, socket) do
{
@@ -29,18 +20,19 @@ defmodule Systems.Assignment.OnboardingConsentView do
}
end
- defp update_clickwrap_view(
- %{assigns: %{revision: revision, user: user, myself: myself}} = socket
- ) do
- clickwrap_view = %{
- id: :consent_clickwrap_view,
- module: Consent.ClickWrapView,
- revision: revision,
- user: user,
- target: myself
- }
+ defp update_clickwrap_view(%{assigns: %{revision: revision, user: user}} = socket) do
+ child =
+ prepare_child(socket, :clickwrap_view, Consent.ClickWrapView, %{
+ revision: revision,
+ user: user
+ })
- assign(socket, clickwrap_view: clickwrap_view)
+ show_child(socket, child)
+ end
+
+ @impl true
+ def handle_event("continue", _payload, socket) do
+ {:noreply, socket |> send_event(:parent, "continue")}
end
@impl true
@@ -50,7 +42,7 @@ defmodule Systems.Assignment.OnboardingConsentView do
<%= dgettext("eyra-assignment", "onboarding.consent.title") %>
- <.live_component {@clickwrap_view} />
+ <.child id={:clickwrap_view} fabric={@fabric} />
"""
diff --git a/core/systems/assignment/settings_view.ex b/core/systems/assignment/settings_view.ex
index 3881fd5ae..0f9db4009 100644
--- a/core/systems/assignment/settings_view.ex
+++ b/core/systems/assignment/settings_view.ex
@@ -1,5 +1,5 @@
defmodule Systems.Assignment.SettingsView do
- use CoreWeb, :live_component
+ use CoreWeb, :live_component_fabric
use Fabric.LiveComponent
alias Systems.{
diff --git a/core/systems/assignment/start_view.ex b/core/systems/assignment/start_view.ex
index 564369e85..449c58bcd 100644
--- a/core/systems/assignment/start_view.ex
+++ b/core/systems/assignment/start_view.ex
@@ -1,17 +1,71 @@
defmodule Systems.Assignment.StartView do
- use CoreWeb, :html
+ use CoreWeb, :live_component_fabric
+ use Fabric.LiveComponent
alias Frameworks.Pixel.Align
alias Frameworks.Pixel.Button
alias Frameworks.Pixel.Text
+ alias Frameworks.Concept
- attr(:id, :any, required: true)
- attr(:title, :string, required: true)
- attr(:icon, :string, required: true)
- attr(:description, :string, required: true)
- attr(:button, :map, required: true)
+ alias Systems.Project
- def start_view(assigns) do
+ def update(%{id: id, work_item: work_item}, socket) do
+ {
+ :ok,
+ socket
+ |> assign(
+ id: id,
+ work_item: work_item
+ )
+ |> compose_element(:title)
+ |> compose_element(:description)
+ |> compose_element(:icon)
+ |> compose_element(:button)
+ }
+ end
+
+ @impl true
+ def compose(:button, %{work_item: work_item}) do
+ %{
+ action: start_action(work_item),
+ face: %{type: :primary, label: "Start"}
+ }
+ end
+
+ @impl true
+ def compose(:title, %{work_item: {%{title: title}, _}}), do: title
+
+ @impl true
+ def compose(:description, %{work_item: {%{description: description}, _}}), do: description
+
+ @impl true
+ def compose(:icon, %{work_item: {%{group: group}, _}}), do: group
+
+ defp start_action({%{tool_ref: tool_ref}, _task} = item) do
+ Project.ToolRefModel.tool(tool_ref)
+ |> Concept.ToolModel.launcher()
+ |> start_action(item)
+ end
+
+ defp start_action(%{function: _, props: _}, _) do
+ %{type: :send, event: "start"}
+ end
+
+ defp start_action(%{url: url}, _) do
+ %{type: :http_get, to: url, target: "_blank"}
+ end
+
+ defp start_action(_, _) do
+ %{type: :send, event: "start"}
+ end
+
+ @impl true
+ def handle_event("start", _, socket) do
+ {:noreply, socket |> send_event(:parent, "start")}
+ end
+
+ @impl true
+ def render(assigns) do
~H"""
diff --git a/core/systems/benchmark/content_page.ex b/core/systems/benchmark/content_page.ex
index 27dbd907c..82109eb07 100644
--- a/core/systems/benchmark/content_page.ex
+++ b/core/systems/benchmark/content_page.ex
@@ -1,4 +1,5 @@
defmodule Systems.Benchmark.ContentPage do
+ use CoreWeb, :live_view
use Systems.Content.Page
alias Systems.{
diff --git a/core/systems/consent/clickwrap_view.ex b/core/systems/consent/clickwrap_view.ex
index 73000ffef..7b1ae070f 100644
--- a/core/systems/consent/clickwrap_view.ex
+++ b/core/systems/consent/clickwrap_view.ex
@@ -2,14 +2,15 @@ defmodule Systems.Consent.ClickWrapView do
# Clickwrap agreements are a type of electronic signature that involves a user
# clicking a simple button to accept the agreement.
- use CoreWeb.LiveForm
+ use CoreWeb.LiveForm, :fabric
+ use Fabric.LiveComponent
alias Systems.{
Consent
}
@impl true
- def update(%{id: id, revision: revision, user: user, target: target}, socket) do
+ def update(%{id: id, revision: revision, user: user}, socket) do
signature = Consent.Public.get_signature(revision, user)
selected? = signature != nil
@@ -20,12 +21,12 @@ defmodule Systems.Consent.ClickWrapView do
id: id,
revision: revision,
user: user,
- target: target,
signature: signature,
selected?: selected?
)
|> update_form()
|> update_continue_button()
+ |> update_checkbox()
}
end
@@ -47,6 +48,15 @@ defmodule Systems.Consent.ClickWrapView do
assign(socket, continue_button: continue_button)
end
+ defp update_checkbox(socket) do
+ checkbox = %{
+ field: :signature_check,
+ label_text: dgettext("eyra-consent", "onboarding.consent.checkbox")
+ }
+
+ assign(socket, checkbox: checkbox)
+ end
+
@impl true
def handle_event(
"toggle",
@@ -78,9 +88,8 @@ defmodule Systems.Consent.ClickWrapView do
|> handle_continue()
end
- def handle_continue(%{assigns: %{id: id, signature: %{id: _}, target: target}} = socket) do
- send_update(target, %{id => :continue})
- socket
+ def handle_continue(%{assigns: %{signature: %{id: _}}} = socket) do
+ socket |> send_event(:parent, "continue")
end
@impl true
@@ -92,11 +101,7 @@ defmodule Systems.Consent.ClickWrapView do
<.spacing value="M" />
<.form id={@id} :let={form} for={@form} phx-target={@myself} >
- <.checkbox
- form={form}
- field={:signature_check}
- label_text="I have read and agree with the above terms."
- />
+ <.checkbox {@checkbox} form={form} />
<.wrap>
diff --git a/core/systems/content/page.ex b/core/systems/content/page.ex
index 929f26183..3db6591f6 100644
--- a/core/systems/content/page.ex
+++ b/core/systems/content/page.ex
@@ -81,9 +81,8 @@ defmodule Systems.Content.Page do
def tabbar_size({:unknown, _}), do: :unknown
def tabbar_size(bp), do: Breakpoint.value(bp, :narrow, sm: %{30 => :wide})
- defmacro __using__(_opts) do
+ defmacro __using__(_) do
quote do
- use CoreWeb, :live_view
use CoreWeb.Layouts.Workspace.Component, :projects
use CoreWeb.UI.Responsive.Viewport
use Systems.Observatory.Public
@@ -91,7 +90,7 @@ defmodule Systems.Content.Page do
alias Frameworks.Pixel.Flash
import CoreWeb.Gettext
- import Systems.Content.Page
+ import Systems.Content.Page, except: [helpers: 0]
defp initialize(socket, id, model, tabbar_id, initial_tab, locale) do
socket
diff --git a/core/systems/document/content_page.ex b/core/systems/document/content_page.ex
index 6e93263f3..be3ee36dd 100644
--- a/core/systems/document/content_page.ex
+++ b/core/systems/document/content_page.ex
@@ -1,4 +1,5 @@
defmodule Systems.Document.ContentPage do
+ use CoreWeb, :live_view
use Systems.Content.Page
alias Systems.{
diff --git a/core/systems/email/form.ex b/core/systems/email/form.ex
index a06cee217..b81b64b89 100644
--- a/core/systems/email/form.ex
+++ b/core/systems/email/form.ex
@@ -1,6 +1,5 @@
defmodule Systems.Email.Form do
use CoreWeb, :live_component
- import Phoenix.LiveView
alias Core.Accounts
alias CoreWeb.UI.Timestamp
@@ -105,15 +104,6 @@ defmodule Systems.Email.Form do
|> Enum.map(&username(&1))
end
- # data(subject, :string)
- # data(message, :string)
- # data(model, :map)
- # data(changeset, :any)
- # data(validate?, :boolean)
-
- attr(:users, :list)
- attr(:from_user, :map)
-
@impl true
def render(assigns) do
~H"""
diff --git a/core/systems/feldspar/app_page.ex b/core/systems/feldspar/app_page.ex
index 8fd9479cf..41e8afce0 100644
--- a/core/systems/feldspar/app_page.ex
+++ b/core/systems/feldspar/app_page.ex
@@ -27,7 +27,7 @@ defmodule Systems.Feldspar.AppPage do
end
@impl true
- def handle_event("app_event", %{"__type__" => type, "json_string" => event}, socket) do
+ def handle_event("feldspar_event", %{"__type__" => type, "json_string" => event}, socket) do
{
:noreply,
socket |> handle(type, event)
@@ -35,7 +35,7 @@ defmodule Systems.Feldspar.AppPage do
end
@impl true
- def handle_event("app_event", event, socket) do
+ def handle_event("feldspar_event", event, socket) do
{
:noreply,
socket |> handle(nil, inspect(event))
@@ -43,7 +43,12 @@ defmodule Systems.Feldspar.AppPage do
end
defp handle(socket, "CommandSystemDonate", event) do
- send(self(), {:store_participant_data, event})
+ Frameworks.Pixel.Flash.put_error(socket, "Unsupported CommandSystemDonate " <> event)
+ socket
+ end
+
+ defp handle(socket, "CommandSystemExit", event) do
+ Frameworks.Pixel.Flash.put_error(socket, "Unsupported CommandSystemExit " <> event)
socket
end
diff --git a/core/systems/feldspar/content_page.ex b/core/systems/feldspar/content_page.ex
index 4a08b71b2..9f0056a3d 100644
--- a/core/systems/feldspar/content_page.ex
+++ b/core/systems/feldspar/content_page.ex
@@ -1,4 +1,5 @@
defmodule Systems.Feldspar.ContentPage do
+ use CoreWeb, :live_view
use Systems.Content.Page
alias Systems.{
diff --git a/core/systems/lab/content_page.ex b/core/systems/lab/content_page.ex
index 5df5829e2..2023d9cef 100644
--- a/core/systems/lab/content_page.ex
+++ b/core/systems/lab/content_page.ex
@@ -1,4 +1,5 @@
defmodule Systems.Lab.ContentPage do
+ use CoreWeb, :live_view
use Systems.Content.Page
alias Systems.{
diff --git a/core/systems/project/tool_ref_view.ex b/core/systems/project/tool_ref_view.ex
index 724461531..bd8aa66c6 100644
--- a/core/systems/project/tool_ref_view.ex
+++ b/core/systems/project/tool_ref_view.ex
@@ -1,5 +1,6 @@
defmodule Systems.Project.ToolRefView do
- use CoreWeb, :html
+ use CoreWeb, :live_component_fabric
+ use Fabric.LiveComponent
alias Frameworks.Concept
@@ -7,22 +8,30 @@ defmodule Systems.Project.ToolRefView do
Project
}
- defp get_tool(tool_ref), do: Project.ToolRefModel.tool(tool_ref)
- defp get_work(tool), do: Concept.ToolModel.launcher(tool)
-
- attr(:tool_ref, :map, required: true)
- attr(:task, :map, required: true)
+ def update(%{id: id, tool_ref: tool_ref, task: task}, socket) do
+ {
+ :ok,
+ socket
+ |> assign(
+ id: id,
+ tool_ref: tool_ref,
+ task: task
+ )
+ |> compose_element(:launcher)
+ }
+ end
- def tool_ref_view(%{tool_ref: tool_ref} = assigns) do
- assigns =
- tool_ref
- |> get_tool()
- |> get_work()
- |> then(&assign(assigns, :work, &1))
+ @impl true
+ def compose(:launcher, %{tool_ref: tool_ref}) do
+ Project.ToolRefModel.tool(tool_ref)
+ |> Concept.ToolModel.launcher()
+ end
+ @impl true
+ def render(assigns) do
~H"""
- <.function_component function={@work.function} props={@work.props} />
+ <.function_component {@launcher} />
"""
end
diff --git a/core/systems/storage/_private.ex b/core/systems/storage/_private.ex
index 87917fd55..977c1dd60 100644
--- a/core/systems/storage/_private.ex
+++ b/core/systems/storage/_private.ex
@@ -3,6 +3,8 @@ defmodule Systems.Storage.Private do
Storage
}
+ @centerdata_callback_url "https://quest.centerdata.nl/eyra/dd.php"
+
def allowed_service_ids() do
Keyword.get(config(), :services, [])
end
@@ -13,6 +15,30 @@ defmodule Systems.Storage.Private do
def build_special(:aws), do: %Storage.AWS.EndpointModel{}
def build_special(:azure), do: %Storage.Azure.EndpointModel{}
- def build_special(:centerdata), do: %Storage.Centerdata.EndpointModel{}
def build_special(:yoda), do: %Storage.Yoda.EndpointModel{}
+
+ def backend_info(%Storage.AWS.EndpointModel{}), do: {:aws, Storage.AWS.Backend}
+ def backend_info(%Storage.Azure.EndpointModel{}), do: {:azure, Storage.Azure.Backend}
+ def backend_info(%Storage.Yoda.EndpointModel{}), do: {:yoda, Storage.Yoda.Backend}
+
+ def storage_info(%{storage_endpoint: %{} = storage_endpoint, external_panel: external_panel}) do
+ if endpoint = Storage.EndpointModel.special(storage_endpoint) do
+ {key, backend} = backend_info(endpoint)
+ %{key: key, backend: backend, endpoint: endpoint}
+ else
+ storage_info(external_panel)
+ end
+ end
+
+ def storage_info(%{external_panel: external_panel}) do
+ storage_info(external_panel)
+ end
+
+ def storage_info(:liss) do
+ endpoint = %Storage.Centerdata.EndpointModel{url: @centerdata_callback_url}
+ backend = Storage.Centerdata.Backend
+ %{key: :centerdata, endpoint: endpoint, backend: backend}
+ end
+
+ def storage_info(_), do: nil
end
diff --git a/core/systems/storage/_public.ex b/core/systems/storage/_public.ex
index dcfde7334..8c076a66e 100644
--- a/core/systems/storage/_public.ex
+++ b/core/systems/storage/_public.ex
@@ -4,18 +4,21 @@ defmodule Systems.Storage.Public do
Storage
}
- def store(%Storage.EndpointModel{} = endpoint, data, remote_ip) do
- storage = %{
- key: Storage.EndpointModel.special_field_id(endpoint),
- endpoint: Storage.EndpointModel.special(endpoint)
- }
-
+ def store(
+ %{key: key, backend: backend, endpoint: endpoint},
+ panel_info,
+ data,
+ %{remote_ip: remote_ip} = meta_data
+ ) do
packet_size = String.length(data)
- with :granted <- Rate.Public.request_permission(storage.key, remote_ip, packet_size) do
+ with :granted <- Rate.Public.request_permission(key, remote_ip, packet_size) do
%{
- storage: storage,
- data: data
+ backend: backend,
+ endpoint: endpoint,
+ panel_info: panel_info,
+ data: data,
+ meta_data: meta_data
}
|> Storage.Delivery.new()
|> Oban.insert()
diff --git a/core/systems/storage/aws/backend.ex b/core/systems/storage/aws/backend.ex
index 51ebeffb5..60bb76c00 100644
--- a/core/systems/storage/aws/backend.ex
+++ b/core/systems/storage/aws/backend.ex
@@ -4,26 +4,21 @@ defmodule Systems.Storage.AWS.Backend do
alias ExAws.S3
def store(
- state,
- %{storage_info: %{key: key}} = _vm,
- data
+ %{"s3_bucket_name" => bucket} = _endpoint,
+ panel_info,
+ data,
+ meta_data
) do
[data]
- |> S3.upload(bucket(), path(key, state))
+ |> S3.upload(bucket, path(panel_info, meta_data))
|> ExAws.request()
end
- defp bucket do
- :core
- |> Application.fetch_env!(:aws)
- |> Keyword.fetch!(:bucket)
+ defp path(%{"participant" => participant}, %{"key" => key, "timestamp" => timestamp}) do
+ "#{participant}/#{key}/#{timestamp}.json"
end
- defp path(key, %{"participant" => participant, "timestamp" => timestamp} = _state) do
- "#{key}/#{participant}/#{timestamp}.json"
- end
-
- defp path(key, %{"participant" => participant} = _state) do
+ defp path(%{"participant" => participant}, %{"key" => key}) do
"#{key}/#{participant}.json"
end
end
diff --git a/core/systems/storage/aws/endpoint_model.ex b/core/systems/storage/aws/endpoint_model.ex
index c6be57792..c8b202df5 100644
--- a/core/systems/storage/aws/endpoint_model.ex
+++ b/core/systems/storage/aws/endpoint_model.ex
@@ -4,6 +4,10 @@ defmodule Systems.Storage.AWS.EndpointModel do
import Ecto.Changeset
+ @fields ~w(access_key_id secret_access_key s3_bucket_name region_code)a
+ @required_fields @fields
+
+ @derive {Jason.Encoder, only: @fields}
schema "storage_endpoints_aws" do
field(:access_key_id, :string)
field(:secret_access_key, :string)
@@ -13,9 +17,6 @@ defmodule Systems.Storage.AWS.EndpointModel do
timestamps()
end
- @fields ~w(access_key_id secret_access_key s3_bucket_name region_code)a
- @required_fields @fields
-
def changeset(model, params) do
model
|> cast(params, @fields)
diff --git a/core/systems/storage/azure/backend.ex b/core/systems/storage/azure/backend.ex
index c1a065757..10c70fe05 100644
--- a/core/systems/storage/azure/backend.ex
+++ b/core/systems/storage/azure/backend.ex
@@ -4,20 +4,19 @@ defmodule Systems.Storage.Azure.Backend do
require Logger
def store(
- %{"participant" => participant, "key" => donation_key},
- %{"storage_info" => %{"key" => root_key}},
- data
+ endpoint,
+ panel_info,
+ data,
+ meta_data
) do
- path = path(root_key, participant, donation_key)
+ path = path(panel_info, meta_data)
headers = [
{"Content-Type", "text/plain"},
{"x-ms-blob-type", "BlockBlob"}
]
- config = config()
-
- case url(config, path) do
+ case url(endpoint, path) do
{:ok, url} ->
HTTPoison.put(url, data, headers)
|> case do
@@ -37,27 +36,27 @@ defmodule Systems.Storage.Azure.Backend do
end
end
- def path(root_key, participant, donation_key) do
- "#{root_key}/#{participant}/#{donation_key}.json"
+ defp path(%{"participant" => participant}, %{"key" => key, "timestamp" => timestamp}) do
+ "#{participant}/#{key}/#{timestamp}.json"
+ end
+
+ defp path(%{"participant" => participant}, %{"key" => key}) do
+ "#{key}/#{participant}.json"
end
defp url(
- config,
+ %{
+ "storage_account_name" => storage_account_name,
+ "container" => container,
+ "sas_token" => sas_token
+ },
path
) do
- storage_account_name = Keyword.get(config, :storage_account_name)
- container = Keyword.get(config, :container)
- sas_token = Keyword.get(config, :sas_token)
-
- if storage_account_name && container && sas_token do
- {:ok,
- "https://#{storage_account_name}.blob.core.windows.net/#{container}/#{path}#{sas_token}"}
- else
- {:error, "Unable to deliver donation: invalid Azure config"}
- end
+ {:ok,
+ "https://#{storage_account_name}.blob.core.windows.net/#{container}/#{path}#{sas_token}"}
end
- defp config() do
- Application.get_env(:core, :azure_storage_backend)
+ defp url(_, _) do
+ {:error, "Unable to deliver donation: invalid Azure config"}
end
end
diff --git a/core/systems/storage/azure/endpoint_model.ex b/core/systems/storage/azure/endpoint_model.ex
index 384e1dfa8..5c32a7d5e 100644
--- a/core/systems/storage/azure/endpoint_model.ex
+++ b/core/systems/storage/azure/endpoint_model.ex
@@ -4,6 +4,10 @@ defmodule Systems.Storage.Azure.EndpointModel do
import Ecto.Changeset
+ @fields ~w(account_name container sas_token)a
+ @required_fields @fields
+
+ @derive {Jason.Encoder, only: @fields}
schema "storage_endpoints_azure" do
field(:account_name, :string)
field(:container, :string)
@@ -12,9 +16,6 @@ defmodule Systems.Storage.Azure.EndpointModel do
timestamps()
end
- @fields ~w(account_name container sas_token)a
- @required_fields @fields
-
def changeset(model, params) do
model
|> cast(params, @fields)
diff --git a/core/systems/storage/backend.ex b/core/systems/storage/backend.ex
index 6ca300cc7..24c3a8beb 100644
--- a/core/systems/storage/backend.ex
+++ b/core/systems/storage/backend.ex
@@ -1,7 +1,8 @@
defmodule Systems.Storage.Backend do
@callback store(
- session :: map(),
- vm :: map(),
- data :: binary()
+ endpoint :: map(),
+ panel_info :: map(),
+ data :: binary(),
+ meta_data :: map()
) :: any()
end
diff --git a/core/systems/storage/centerdata/backend.ex b/core/systems/storage/centerdata/backend.ex
index d3315da72..867c57442 100644
--- a/core/systems/storage/centerdata/backend.ex
+++ b/core/systems/storage/centerdata/backend.ex
@@ -4,18 +4,29 @@ defmodule Systems.Storage.Centerdata.Backend do
require Logger
def store(
+ %{"url" => url} = _endpoint,
%{
- "url" => url,
- "varname1" => varname1,
- "page" => page,
- "respondent" => respondent,
- "token" => token
- } = _session,
- %{storage_info: %{quest: quest}} = _vm,
- data
+ "query_string" => %{
+ "quest" => quest,
+ "varname1" => varname1,
+ "respondent" => respondent,
+ "token" => token,
+ "page" => page
+ }
+ } = _panel_info,
+ data,
+ _meta_data
) do
body =
- "{\"#{varname1}\": \"#{data}\", \"button_next\": \"Next\", \"page\": \"#{page}\", \"_respondent\": \"#{respondent}\", \"token\": \"#{token}\", \"quest\": \"#{quest}}\""
+ %{
+ "#{varname1}" => Jason.decode!(data),
+ button_next: "Next",
+ page: page,
+ _respondent: respondent,
+ token: token,
+ quest: quest
+ }
+ |> Jason.encode!()
post(url, body)
end
diff --git a/core/systems/storage/centerdata/endpoint_model.ex b/core/systems/storage/centerdata/endpoint_model.ex
index 47f4ad874..5fb7faada 100644
--- a/core/systems/storage/centerdata/endpoint_model.ex
+++ b/core/systems/storage/centerdata/endpoint_model.ex
@@ -4,15 +4,16 @@ defmodule Systems.Storage.Centerdata.EndpointModel do
import Ecto.Changeset
+ @fields ~w(url)a
+ @required_fields @fields
+
+ @derive {Jason.Encoder, only: @fields}
schema "storage_endpoints_centerdata" do
field(:url, :string)
timestamps()
end
- @fields ~w(url)a
- @required_fields @fields
-
def changeset(model, params) do
model
|> cast(params, @fields)
diff --git a/core/systems/storage/delivery.ex b/core/systems/storage/delivery.ex
index 49970cf48..f63658fd6 100644
--- a/core/systems/storage/delivery.ex
+++ b/core/systems/storage/delivery.ex
@@ -26,28 +26,12 @@ defmodule Systems.Storage.Delivery do
end
defp deliver(%{
- "storage_key" => storage_key,
- "state" => state,
- "vm" => vm,
- "data" => data
+ "backend" => backend,
+ "endpoint" => endpoint,
+ "panel_info" => panel_info,
+ "data" => data,
+ "meta_data" => meta_data
}) do
- storage = storage(storage_key)
- storage.store(state, vm, data)
- end
-
- defp config() do
- Application.fetch_env!(:core, :data_donation_storage_backend)
- end
-
- defp storage(storage_key) do
- config = config()
-
- case Keyword.get(config, String.to_existing_atom(storage_key)) do
- nil ->
- raise DeliveryError, "Could not deliver donated data, invalid config for #{storage_key}"
-
- value ->
- value
- end
+ String.to_existing_atom(backend).store(endpoint, panel_info, data, meta_data)
end
end
diff --git a/core/systems/storage/endpoint_form.ex b/core/systems/storage/endpoint_form.ex
index 8cd8b35d0..7ae59a8bd 100644
--- a/core/systems/storage/endpoint_form.ex
+++ b/core/systems/storage/endpoint_form.ex
@@ -1,5 +1,5 @@
defmodule Systems.Storage.EndpointForm do
- use CoreWeb.LiveForm
+ use CoreWeb.LiveForm, :fabric
use Fabric.LiveComponent
alias Frameworks.Concept
diff --git a/core/systems/storage/endpoint_form_helper.ex b/core/systems/storage/endpoint_form_helper.ex
index 9606cb8d7..fc88da0a1 100644
--- a/core/systems/storage/endpoint_form_helper.ex
+++ b/core/systems/storage/endpoint_form_helper.ex
@@ -1,7 +1,7 @@
defmodule Systems.Storage.EndpointForm.Helper do
defmacro __using__(model) do
quote do
- use CoreWeb.LiveForm
+ use CoreWeb.LiveForm, :fabric
use Fabric.LiveComponent
alias unquote(model), as: Model
diff --git a/core/systems/storage/fake_backend.ex b/core/systems/storage/fake_backend.ex
index bff1109fc..e6774f0ae 100644
--- a/core/systems/storage/fake_backend.ex
+++ b/core/systems/storage/fake_backend.ex
@@ -1,7 +1,7 @@
defmodule Systems.Storage.FakeBackend do
@behaviour Systems.Storage.Backend
- def store(_state, _vm, data) do
+ def store(_endpoint, _panel_info, data, _meta_data) do
IO.puts("fake store: #{data}")
:ok
end
diff --git a/core/systems/storage/yoda/backend.ex b/core/systems/storage/yoda/backend.ex
index abdbe669d..4df7a7a45 100644
--- a/core/systems/storage/yoda/backend.ex
+++ b/core/systems/storage/yoda/backend.ex
@@ -1,2 +1,14 @@
defmodule Systems.Storage.Yoda.Backend do
+ @behaviour Systems.Storage.Backend
+
+ require Logger
+
+ def store(
+ _endpoint,
+ _panel_info,
+ _data,
+ _meta_data
+ ) do
+ Logger.warn("Yoda backend not implemented yet")
+ end
end
diff --git a/core/systems/storage/yoda/endpoint_model.ex b/core/systems/storage/yoda/endpoint_model.ex
index 2f7e300fc..84c9f3303 100644
--- a/core/systems/storage/yoda/endpoint_model.ex
+++ b/core/systems/storage/yoda/endpoint_model.ex
@@ -4,6 +4,10 @@ defmodule Systems.Storage.Yoda.EndpointModel do
import Ecto.Changeset
+ @fields ~w(url user password)a
+ @required_fields @fields
+
+ @derive {Jason.Encoder, only: @fields}
schema "storage_endpoints_yoda" do
field(:url, :string)
field(:user, :string)
@@ -12,9 +16,6 @@ defmodule Systems.Storage.Yoda.EndpointModel do
timestamps()
end
- @fields ~w(url user password)a
- @required_fields @fields
-
def changeset(endpoint, params) do
endpoint
|> cast(params, @fields)
diff --git a/core/systems/workflow/item_views.ex b/core/systems/workflow/item_views.ex
index e30eab368..b7b2e0d83 100644
--- a/core/systems/workflow/item_views.ex
+++ b/core/systems/workflow/item_views.ex
@@ -7,12 +7,9 @@ defmodule Systems.Workflow.ItemViews do
import CoreWeb.UI.StepIndicator
alias Systems.{
- Workflow,
- Project
+ Workflow
}
- import Project.ToolRefView
-
attr(:title, :string, required: true)
attr(:description, :string, required: true)
attr(:items, :list, required: true)
@@ -55,19 +52,6 @@ defmodule Systems.Workflow.ItemViews do
"""
end
- attr(:items, :list, required: true)
- attr(:selected_item_id, :integer, required: true)
-
- def work_list(assigns) do
- ~H"""
-
- <%= for {item, index} <- Enum.with_index(@items) do %>
- <.work_item {item} index={index} selected?={item.id == @selected_item_id} />
- <% end %>
-
- """
- end
-
attr(:id, :any, required: true)
attr(:title, :map, required: true)
attr(:icon, :string, required: true)
@@ -107,17 +91,6 @@ defmodule Systems.Workflow.ItemViews do
"""
end
- attr(:item, :map, required: true)
- attr(:task, :map, required: true)
-
- def launcher(%{item: %{tool_ref: tool_ref}} = assigns) when not is_nil(tool_ref) do
- ~H"""
-
- <.tool_ref_view tool_ref={@item.tool_ref} task={@task} />
-
- """
- end
-
defp relative_position(0, _count), do: :top
defp relative_position(position, count) when position == count - 1, do: :bottom
defp relative_position(_position, _count), do: :middle
diff --git a/core/systems/workflow/work_list_view.ex b/core/systems/workflow/work_list_view.ex
new file mode 100644
index 000000000..a4b2cad05
--- /dev/null
+++ b/core/systems/workflow/work_list_view.ex
@@ -0,0 +1,30 @@
+defmodule Systems.Workflow.WorkListView do
+ use CoreWeb, :live_component_fabric
+ use Fabric.LiveComponent
+
+ import Systems.Workflow.ItemViews, only: [work_item: 1]
+
+ @impl true
+ def update(%{id: id, items: items, selected_item_id: selected_item_id}, socket) do
+ {
+ :ok,
+ socket
+ |> assign(
+ id: id,
+ items: items,
+ selected_item_id: selected_item_id
+ )
+ }
+ end
+
+ @impl true
+ def render(assigns) do
+ ~H"""
+
+ <%= for {item, index} <- Enum.with_index(@items) do %>
+ <.work_item {item} index={index} selected?={item.id == @selected_item_id} />
+ <% end %>
+
+ """
+ end
+end
diff --git a/core/test/frameworks/fabric/factories.ex b/core/test/frameworks/fabric/factories.ex
index 8cb0690f7..26804ea66 100644
--- a/core/test/frameworks/fabric/factories.ex
+++ b/core/test/frameworks/fabric/factories.ex
@@ -4,11 +4,11 @@ defmodule Fabric.Factories do
end
def create_fabric(%Fabric.LiveView.RefModel{} = self) do
- %Fabric.Model{parent: nil, self: self, children: []}
+ %Fabric.Model{parent: nil, self: self, children: nil}
end
def create_fabric(%Fabric.LiveComponent.RefModel{} = self) do
- %Fabric.Model{parent: nil, self: self, children: []}
+ %Fabric.Model{parent: nil, self: self, children: nil}
end
def create_child(id, module \\ Fabric.LiveComponentMock, params \\ %{}) do
diff --git a/core/test/frameworks/fabric/live_component_mock.ex b/core/test/frameworks/fabric/live_component_mock.ex
index 928ce5900..b4b429cf6 100644
--- a/core/test/frameworks/fabric/live_component_mock.ex
+++ b/core/test/frameworks/fabric/live_component_mock.ex
@@ -1,5 +1,4 @@
defmodule Fabric.LiveComponentMock do
- use Phoenix.LiveComponent
use Fabric.LiveComponent
@impl true
diff --git a/core/test/frameworks/fabric/live_view_mock.ex b/core/test/frameworks/fabric/live_view_mock.ex
index d01b49e69..e085af4dd 100644
--- a/core/test/frameworks/fabric/live_view_mock.ex
+++ b/core/test/frameworks/fabric/live_view_mock.ex
@@ -1,6 +1,5 @@
defmodule Fabric.LiveViewMock do
- use Phoenix.LiveView
- use Fabric.LiveView
+ use Fabric.LiveView, Fabric.TestLayouts
@impl true
def mount(:not_mounted_at_router, _session, socket) do
diff --git a/core/test/frameworks/fabric/test.ex b/core/test/frameworks/fabric/test.exs
similarity index 86%
rename from core/test/frameworks/fabric/test.ex
rename to core/test/frameworks/fabric/test.exs
index 49adc62e2..4b9a7e2f7 100644
--- a/core/test/frameworks/fabric/test.ex
+++ b/core/test/frameworks/fabric/test.exs
@@ -12,7 +12,7 @@ defmodule Fabric.Test do
assert %Phoenix.LiveView.Socket{
assigns: %{
__changed__: %{fabric: true},
- fabric: %Fabric.Model{parent: nil, self: nil, children: []}
+ fabric: %Fabric.Model{parent: nil, self: nil, children: nil}
}
} = socket
end
@@ -21,13 +21,13 @@ defmodule Fabric.Test do
describe "new_fabric/0" do
test "default" do
fabric = Fabric.new_fabric()
- assert %Fabric.Model{parent: nil, self: nil, children: []} = fabric
+ assert %Fabric.Model{parent: nil, self: nil, children: nil} = fabric
end
end
describe "prepare_child/4" do
test "socket" do
- fabric = %Fabric.Model{parent: nil, children: []}
+ fabric = %Fabric.Model{parent: nil, children: nil}
child =
%Phoenix.LiveView.Socket{}
@@ -43,14 +43,14 @@ defmodule Fabric.Test do
id: :child,
module: Fabric.LiveComponentMock
},
- children: []
+ children: nil
}
}
} = child
end
test "fabric" do
- fabric = %Fabric.Model{parent: nil, children: []}
+ fabric = %Fabric.Model{parent: nil, children: nil}
child = Fabric.prepare_child(fabric, :child, Fabric.LiveComponentMock, %{})
@@ -63,7 +63,7 @@ defmodule Fabric.Test do
id: :child,
module: Fabric.LiveComponentMock
},
- children: []
+ children: nil
}
}
} = child
@@ -89,7 +89,7 @@ defmodule Fabric.Test do
id: :child,
module: Fabric.LiveComponentMock
},
- children: []
+ children: nil
}
}
} = child
@@ -109,7 +109,7 @@ defmodule Fabric.Test do
id: :child,
module: Fabric.LiveComponentMock
},
- children: []
+ children: nil
}
}
} = child
@@ -119,7 +119,7 @@ defmodule Fabric.Test do
describe "show_child/2" do
test "socket" do
child = create_child(:child)
- fabric = %Fabric.Model{parent: nil, children: []}
+ fabric = %Fabric.Model{parent: nil, children: nil}
socket =
%Phoenix.LiveView.Socket{}
@@ -144,7 +144,7 @@ defmodule Fabric.Test do
id: :child,
module: Fabric.LiveComponentMock
},
- children: []
+ children: nil
}
}
}
@@ -158,37 +158,31 @@ defmodule Fabric.Test do
describe "add_child/2" do
test "socket" do
child = create_child(:child)
- fabric = %Fabric.Model{parent: nil, children: []}
- socket =
- %Phoenix.LiveView.Socket{}
- |> Phoenix.Component.assign(:fabric, fabric)
+ fabric =
+ %Fabric.Model{parent: nil, children: nil}
|> Fabric.add_child(child)
- assert %Phoenix.LiveView.Socket{
- assigns: %{
- fabric: %Fabric.Model{
- children: [
- %Fabric.LiveComponent.Model{
- ref: %Fabric.LiveComponent.RefModel{
+ assert %Fabric.Model{
+ children: [
+ %Fabric.LiveComponent.Model{
+ ref: %Fabric.LiveComponent.RefModel{
+ id: :child,
+ module: Fabric.LiveComponentMock
+ },
+ params: %{
+ fabric: %Fabric.Model{
+ parent: nil,
+ self: %Fabric.LiveComponent.RefModel{
id: :child,
module: Fabric.LiveComponentMock
},
- params: %{
- fabric: %Fabric.Model{
- parent: nil,
- self: %Fabric.LiveComponent.RefModel{
- id: :child,
- module: Fabric.LiveComponentMock
- },
- children: []
- }
- }
+ children: nil
}
- ]
+ }
}
- }
- } = socket
+ ]
+ } = fabric
end
end
@@ -223,7 +217,7 @@ defmodule Fabric.Test do
id: :child,
module: Fabric.LiveComponentMock
},
- children: []
+ children: nil
}
}
}
@@ -261,22 +255,15 @@ defmodule Fabric.Test do
test "socket" do
child = create_child(:child, Fabric.LiveComponentMock)
- fabric = %Fabric.Model{parent: nil, children: [child]}
-
- socket =
- %Phoenix.LiveView.Socket{}
- |> Phoenix.Component.assign(:fabric, fabric)
+ fabric =
+ %Fabric.Model{parent: nil, children: [child]}
|> Fabric.remove_child(:child)
- assert %Phoenix.LiveView.Socket{
- assigns: %{
- fabric: %Fabric.Model{
- parent: nil,
- self: nil,
- children: []
- }
- }
- } = socket
+ assert %Fabric.Model{
+ parent: nil,
+ self: nil,
+ children: []
+ } = fabric
end
end
@@ -295,7 +282,7 @@ defmodule Fabric.Test do
fabric: %Fabric.Model{
parent: nil,
self: %Fabric.LiveComponent.RefModel{id: :child, module: Fabric.LiveComponentMock},
- children: []
+ children: nil
}
},
ref: %Fabric.LiveComponent.RefModel{id: :child, module: Fabric.LiveComponentMock}
@@ -323,7 +310,7 @@ defmodule Fabric.Test do
id: :child,
module: Fabric.LiveComponentMock
},
- children: []
+ children: nil
}
}
}
diff --git a/core/test/frameworks/fabric/test_layouts.ex b/core/test/frameworks/fabric/test_layouts.ex
new file mode 100644
index 000000000..ef4165da3
--- /dev/null
+++ b/core/test/frameworks/fabric/test_layouts.ex
@@ -0,0 +1,5 @@
+defmodule Fabric.TestLayouts do
+ use Phoenix.Component
+
+ embed_templates("test_layouts/*")
+end
diff --git a/core/test/frameworks/fabric/test_layouts/live.html.leex b/core/test/frameworks/fabric/test_layouts/live.html.leex
new file mode 100644
index 000000000..965815270
--- /dev/null
+++ b/core/test/frameworks/fabric/test_layouts/live.html.leex
@@ -0,0 +1,3 @@
+
+ <%= @inner_content %>
+
diff --git a/core/test/frameworks/fabric/test_layouts/root.html.leex b/core/test/frameworks/fabric/test_layouts/root.html.leex
new file mode 100644
index 000000000..9b29fc027
--- /dev/null
+++ b/core/test/frameworks/fabric/test_layouts/root.html.leex
@@ -0,0 +1,9 @@
+
+
+
+ Fabric
+
+
+ <%= @inner_content %>
+
+
diff --git a/core/test/systems/feldspar/app_page_test.exs b/core/test/systems/feldspar/app_page_test.exs
index 550e13f4c..57aea79f4 100644
--- a/core/test/systems/feldspar/app_page_test.exs
+++ b/core/test/systems/feldspar/app_page_test.exs
@@ -14,7 +14,7 @@ defmodule Systems.Feldspar.AppPageTest do
test "can receive random app_event data", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/feldspar/apps/test")
- assert render_hook(view, :app_event, %{unexpected_key: "some data"}) =~
+ assert render_hook(view, :feldspar_event, %{unexpected_key: "some data"}) =~
"Unsupported "
end
end
diff --git a/core/test/test_helper.exs b/core/test/test_helper.exs
index 33c77e5a6..a2462e732 100644
--- a/core/test/test_helper.exs
+++ b/core/test/test_helper.exs
@@ -27,11 +27,3 @@ Mox.defmock(BankingClient.MockClient, for: BankingClient.API)
Application.put_env(:core, BankingClient, client: BankingClient.MockClient)
Mox.defmock(Systems.Storage.MockBackend, for: Systems.Storage.Backend)
-
-Application.put_env(
- :core,
- :data_donation_storage_backend,
- s3: Systems.Storage.MockBackend,
- centerdata: Systems.Storage.MockBackend,
- yoda: Systems.Storage.MockBackend
-)