From 7065ce3979b055114828ed129bff6e6641408a30 Mon Sep 17 00:00:00 2001
From: stuartc Registry process to query and maintain a list of adaptors available for
writing jobs. Currently it queries NPM for all modules in the Usage Caching By default the results are cached to disk, and will be reused every start. In order to disable or configure caching pass see: The process uses Caching By default the results are cached to disk, and will be reused every start. In order to disable or configure caching pass see: The process uses Timeouts There is a 'general' timeout of 30s, this is used for GenServer calls like
Destructures an NPM style package name into module name and version. Example Destructures an NPM style package name into module name and version. Example Queries the AI assistant with the given content. Returns Example Queries the AI assistant with the given content. Returns Example Perform a DELETE request. See Perform a DELETE request. See Perform a DELETE request. See Perform a DELETE request. See Perform a GET request. See Perform a GET request. See Perform a GET request. See Perform a GET request. See Perform a HEAD request. See Perform a HEAD request. See Perform a HEAD request. See Perform a HEAD request. See Perform a OPTIONS request. See Perform a OPTIONS request. See Perform a OPTIONS request. See Perform a OPTIONS request. See Perform a PATCH request. See Perform a PATCH request. See Perform a PATCH request. See Perform a PATCH request. See Perform a POST request. See Perform a POST request. See Perform a POST request. See Perform a POST request. See Perform a PUT request. See Perform a PUT request. See Perform a PUT request. See Perform a PUT request. See Perform a TRACE request. See Perform a TRACE request. See Perform a TRACE request. See Perform a TRACE request. See The OpenFn CLI returns JSON formatted log lines, which are decoded and added
-to a There are two kinds of output: These are usually for general logging, and debugging. The above is the equivalent of the output of a commandapply_user_email(user, password, attrs)
Examples
-
+iex> apply_user_email(user, "valid password", %{email: ...})
-{:ok, %User{}}role: :superuser
-iex> apply_user_email(user, "invalid password", %{email: ...})
-{:error, %Ecto.Changeset{}}
iex> apply_user_email(user, "valid password", %{email: ...})
+{:ok, %User{}}role: :superuser
+iex> apply_user_email(user, "invalid password", %{email: ...})
+{:error, %Ecto.Changeset{}}
change_scheduled_deletion(user, attrs \\ %{
Examples
-
+iex> change_scheduled_deletion(user)
-%Ecto.Changeset{data: %User{}}
iex> change_scheduled_deletion(user)
+%Ecto.Changeset{data: %User{}}
change_superuser_registration(attrs \\ %{})
Examples
-
+iex> change_superuser_registration(user)
-%Ecto.Changeset{data: %User{}}
iex> change_superuser_registration(user)
+%Ecto.Changeset{data: %User{}}
change_user_email(user, attrs \\ %{})
Examples
-
+iex> change_user_email(user)
-%Ecto.Changeset{data: %User{}}
iex> change_user_email(user)
+%Ecto.Changeset{data: %User{}}
change_user_password(user, attrs \\ %{})
Examples
-
+iex> change_user_password(user)
-%Ecto.Changeset{data: %User{}}
iex> change_user_password(user)
+%Ecto.Changeset{data: %User{}}
change_user_registration(attrs \\ %{})
Examples
-
+iex> change_user_registration(user)
-%Ecto.Changeset{data: %User{}}
iex> change_user_registration(user)
+%Ecto.Changeset{data: %User{}}
delete_token(token)
Examples
-iex> delete_token(token)
-{:ok, %UserToken{}}
+
+iex> delete_token(token)
+{:error, %Ecto.Changeset{}}iex> delete_token(token)
+{:ok, %UserToken{}}
-iex> delete_token(token)
-{:error, %Ecto.Changeset{}}
delete_user(user)
Examples
-iex> delete_user(user)
-{:ok, %User{}}
+
+iex> delete_user(user)
+{:error, %Ecto.Changeset{}}iex> delete_user(user)
+{:ok, %User{}}
-iex> delete_user(user)
-{:error, %Ecto.Changeset{}}
deliver_user_confirmation_instructions(user
Examples
-
iex> deliver_user_confirmation_instructions(user)
-{:ok, %{to: ..., body: ...}}
+
+iex> deliver_user_confirmation_instructions(confirmed_user)
+{:error, :already_confirmed}iex> deliver_user_confirmation_instructions(user)
+{:ok, %{to: ..., body: ...}}
-iex> deliver_user_confirmation_instructions(confirmed_user)
-{:error, :already_confirmed}
deliver_user_reset_password_instructions(us
Examples
-
+iex> deliver_user_reset_password_instructions(user, &Routes.user_reset_password_url(conn, :edit, &1))
-{:ok, %{to: ..., body: ...}}
iex> deliver_user_reset_password_instructions(user, &Routes.user_reset_password_url(conn, :edit, &1))
+{:ok, %{to: ..., body: ...}}
get_preference(user, key)
Examples
-iex> get_preference(user, "editor.orientation")
+
iex> get_preference(user, "editor.orientation")
"vertical"
-iex> get_preference(user, "notifications.enabled")
+iex> get_preference(user, "notifications.enabled")
true
get_token!(id)
Examples
-iex> get_token!(123)
-%UserToken{}
+
@@ -1565,10 +1565,10 @@ iex> get_token!(123)
+%UserToken{}
-iex> get_token!(456)
+iex> get_token!(456)
** (Ecto.NoResultsError)
get_user!(id)
Examples
-iex> get_user!(123)
-%User{}
+
@@ -1641,10 +1641,10 @@ iex> get_user!(123)
+%User{}
-iex> get_user!(456)
+iex> get_user!(456)
** (Ecto.NoResultsError)
get_user_by_email(email)
Examples
-iex> get_user_by_email("foo@example.com")
-%User{}
+
@@ -1673,10 +1673,10 @@ iex> get_user_by_email("foo@example.com")
+%User{}
-iex> get_user_by_email("unknown@example.com")
+iex> get_user_by_email("unknown@example.com")
nil
get_user_by_email_and_password(email, passw
Examples
-
iex> get_user_by_email_and_password("foo@example.com", "correct_password")
-%User{}
+
@@ -1705,10 +1705,10 @@ iex> get_user_by_email_and_password("foo@example.com", "correct_password")
+%User{}
-iex> get_user_by_email_and_password("foo@example.com", "invalid_password")
+iex> get_user_by_email_and_password("foo@example.com", "invalid_password")
nil
get_user_by_reset_password_token(token)
Examples
-iex> get_user_by_reset_password_token("validtoken")
-%User{}
+
@@ -1905,8 +1905,8 @@ iex> get_user_by_reset_password_token("validtoken")
+%User{}
-iex> get_user_by_reset_password_token("invalidtoken")
+iex> get_user_by_reset_password_token("invalidtoken")
nil
list_users()
Examples
-
+iex> list_users()
-[%User{}, ...]
iex> list_users()
+[%User{}, ...]
register_superuser(attrs)
Examples
-iex> register_superuser(%{field: value})
-{:ok, %User{}}
+
+iex> register_superuser(%{field: bad_value})
+{:error, %Ecto.Changeset{}}iex> register_superuser(%{field: value})
+{:ok, %User{}}
-iex> register_superuser(%{field: bad_value})
-{:error, %Ecto.Changeset{}}
register_user(attrs)
Examples
-iex> register_user(%{field: value})
-{:ok, %User{}}
+
+iex> register_user(%{field: bad_value})
+{:error, %Ecto.Changeset{}}iex> register_user(%{field: value})
+{:ok, %User{}}
-iex> register_user(%{field: bad_value})
-{:error, %Ecto.Changeset{}}
request_email_update(user, new_email)
Examples
-iex> request_email_update(user, new_email)
+
iex> request_email_update(user, new_email)
:ok
reset_user_password(user, attrs)
Examples
-iex> reset_user_password(user, %{password: "new long password", password_confirmation: "new long password"})
-{:ok, %User{}}
+
+iex> reset_user_password(user, %{password: "valid", password_confirmation: "not the same"})
+{:error, %Ecto.Changeset{}}iex> reset_user_password(user, %{password: "new long password", password_confirmation: "new long password"})
+{:ok, %User{}}
-iex> reset_user_password(user, %{password: "valid", password_confirmation: "not the same"})
-{:error, %Ecto.Changeset{}}
update_user_password(user, password, attrs)
Examples
-
iex> update_user_password(user, "valid password", %{password: ...})
-{:ok, %User{}}
+
+iex> update_user_password(user, "invalid password", %{password: ...})
+{:error, %Ecto.Changeset{}}iex> update_user_password(user, "valid password", %{password: ...})
+{:ok, %User{}}
-iex> update_user_password(user, "invalid password", %{password: ...})
-{:error, %Ecto.Changeset{}}
update_user_preference(user, key, value)
Examples
-
iex> update_user_preference(user, "editor.orientation", "vertical")
-{:ok, %User{}}
+
+iex> update_user_preference(user, "notifications.enabled", true)
+{:ok, %User{}}iex> update_user_preference(user, "editor.orientation", "vertical")
+{:ok, %User{}}
-iex> update_user_preference(user, "notifications.enabled", true)
-{:ok, %User{}}
update_user_preferences(user, preferences)<
Examples
-
+iex> update_user_preferences(%User{}, %{"editor.orientaion" => "vertical"})
iex> update_user_preferences(%User{}, %{"editor.orientaion" => "vertical"})
validate_change_user_email(user, params \\
Examples
-
+iex> validate_change_user_email(user, %{"email" => "new@example.com", "current_password" => "secret"})
-%Ecto.Changeset{...}
iex> validate_change_user_email(user, %{"email" => "new@example.com", "current_password" => "secret"})
+%Ecto.Changeset{...}
request(request)
Examples
-request = %HTTPoison.Request{
+
+request(request)request = %HTTPoison.Request{
method: :post,
url: "https://my.website.com",
body: "{\"foo\": 3}",
- headers: [{"Accept", "application/json"}]
-}
+ headers: [{"Accept", "application/json"}]
+}
-request(request)
request(method, url, body \\ "",
Examples
-
+request(:post, "https://my.website.com", "{\"foo\": 3}", [{"Accept", "application/json"}])
request(:post, "https://my.website.com", "{\"foo\": 3}", [{"Accept", "application/json"}])
@openfn
organization and
filters out modules that are known not to be adaptors.# Starting the process
-AdaptorRegistry.start_link()
+AdaptorRegistry.start_link()
# Getting a list of all adaptors
-Lightning.AdaptorRegistry.AdaptorRegistry.all()
start_link/1
.:continue
to return before the adaptors have been queried.
+start_link/1
.:continue
to return before the adaptors have been queried.
This does mean that the first call to the process will be delayed until
the handle_continue/2
has finished.all/1
and also internally when the modules are being queried. NPM can
@@ -432,10 +432,10 @@ resolve_package_name(package_name)
-
+iex> resolve_package_name("@openfn/language-salesforce@1.2.3")
-{ "@openfn/language-salesforce", "1.2.3" }
-iex> resolve_package_name("@openfn/language-salesforce")
-{ "@openfn/language-salesforce", nil }
iex> resolve_package_name("@openfn/language-salesforce@1.2.3")
+{ "@openfn/language-salesforce", "1.2.3" }
+iex> resolve_package_name("@openfn/language-salesforce")
+{ "@openfn/language-salesforce", nil }
query(session, content)
-{:ok, session}
if the query was successful, otherwise :error
.
+iex> AiAssistant.query(session, "fn()")
-{:ok, session}
{:ok, session}
if the query was successful, otherwise :error
.iex> AiAssistant.query(session, "fn()")
+{:ok, session}
delete(client, url, opts)
-request/1
or request/2
for options definition.
+delete("/users")
-delete("/users", query: [scope: "admin"])
-delete(client, "/users")
-delete(client, "/users", query: [scope: "admin"])
-delete(client, "/users", body: %{name: "Jon"})
request/1
or request/2
for options definition.delete("/users")
+delete("/users", query: [scope: "admin"])
+delete(client, "/users")
+delete(client, "/users", query: [scope: "admin"])
+delete(client, "/users", body: %{name: "Jon"})
delete!(client, url, opts)
-request!/1
or request!/2
for options definition.
+delete!("/users")
-delete!("/users", query: [scope: "admin"])
-delete!(client, "/users")
-delete!(client, "/users", query: [scope: "admin"])
-delete!(client, "/users", body: %{name: "Jon"})
request!/1
or request!/2
for options definition.delete!("/users")
+delete!("/users", query: [scope: "admin"])
+delete!(client, "/users")
+delete!(client, "/users", query: [scope: "admin"])
+delete!(client, "/users", body: %{name: "Jon"})
get(client, url, opts)
-request/1
or request/2
for options definition.
+get("/users")
-get("/users", query: [scope: "admin"])
-get(client, "/users")
-get(client, "/users", query: [scope: "admin"])
-get(client, "/users", body: %{name: "Jon"})
request/1
or request/2
for options definition.get("/users")
+get("/users", query: [scope: "admin"])
+get(client, "/users")
+get(client, "/users", query: [scope: "admin"])
+get(client, "/users", body: %{name: "Jon"})
get!(client, url, opts)
-request!/1
or request!/2
for options definition.
+get!("/users")
-get!("/users", query: [scope: "admin"])
-get!(client, "/users")
-get!(client, "/users", query: [scope: "admin"])
-get!(client, "/users", body: %{name: "Jon"})
request!/1
or request!/2
for options definition.get!("/users")
+get!("/users", query: [scope: "admin"])
+get!(client, "/users")
+get!(client, "/users", query: [scope: "admin"])
+get!(client, "/users", body: %{name: "Jon"})
head(client, url, opts)
-request/1
or request/2
for options definition.
+head("/users")
-head("/users", query: [scope: "admin"])
-head(client, "/users")
-head(client, "/users", query: [scope: "admin"])
-head(client, "/users", body: %{name: "Jon"})
request/1
or request/2
for options definition.head("/users")
+head("/users", query: [scope: "admin"])
+head(client, "/users")
+head(client, "/users", query: [scope: "admin"])
+head(client, "/users", body: %{name: "Jon"})
head!(client, url, opts)
-request!/1
or request!/2
for options definition.
+head!("/users")
-head!("/users", query: [scope: "admin"])
-head!(client, "/users")
-head!(client, "/users", query: [scope: "admin"])
-head!(client, "/users", body: %{name: "Jon"})
request!/1
or request!/2
for options definition.head!("/users")
+head!("/users", query: [scope: "admin"])
+head!(client, "/users")
+head!(client, "/users", query: [scope: "admin"])
+head!(client, "/users", body: %{name: "Jon"})
options(client, url, opts)
-request/1
or request/2
for options definition.
+options("/users")
-options("/users", query: [scope: "admin"])
-options(client, "/users")
-options(client, "/users", query: [scope: "admin"])
-options(client, "/users", body: %{name: "Jon"})
request/1
or request/2
for options definition.options("/users")
+options("/users", query: [scope: "admin"])
+options(client, "/users")
+options(client, "/users", query: [scope: "admin"])
+options(client, "/users", body: %{name: "Jon"})
options!(client, url, opts)
-request!/1
or request!/2
for options definition.
+options!("/users")
-options!("/users", query: [scope: "admin"])
-options!(client, "/users")
-options!(client, "/users", query: [scope: "admin"])
-options!(client, "/users", body: %{name: "Jon"})
request!/1
or request!/2
for options definition.options!("/users")
+options!("/users", query: [scope: "admin"])
+options!(client, "/users")
+options!(client, "/users", query: [scope: "admin"])
+options!(client, "/users", body: %{name: "Jon"})
patch(client, url, body, opts)
-request/1
or request/2
for options definition.
+patch("/users", %{name: "Jon"})
-patch("/users", %{name: "Jon"}, query: [scope: "admin"])
-patch(client, "/users", %{name: "Jon"})
-patch(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request/1
or request/2
for options definition.patch("/users", %{name: "Jon"})
+patch("/users", %{name: "Jon"}, query: [scope: "admin"])
+patch(client, "/users", %{name: "Jon"})
+patch(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
patch!(client, url, body, opts)
-request!/1
or request!/2
for options definition.
+patch!("/users", %{name: "Jon"})
-patch!("/users", %{name: "Jon"}, query: [scope: "admin"])
-patch!(client, "/users", %{name: "Jon"})
-patch!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request!/1
or request!/2
for options definition.patch!("/users", %{name: "Jon"})
+patch!("/users", %{name: "Jon"}, query: [scope: "admin"])
+patch!(client, "/users", %{name: "Jon"})
+patch!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
post(client, url, body, opts)
-request/1
or request/2
for options definition.
+post("/users", %{name: "Jon"})
-post("/users", %{name: "Jon"}, query: [scope: "admin"])
-post(client, "/users", %{name: "Jon"})
-post(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request/1
or request/2
for options definition.post("/users", %{name: "Jon"})
+post("/users", %{name: "Jon"}, query: [scope: "admin"])
+post(client, "/users", %{name: "Jon"})
+post(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
post!(client, url, body, opts)
-request!/1
or request!/2
for options definition.
+post!("/users", %{name: "Jon"})
-post!("/users", %{name: "Jon"}, query: [scope: "admin"])
-post!(client, "/users", %{name: "Jon"})
-post!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request!/1
or request!/2
for options definition.post!("/users", %{name: "Jon"})
+post!("/users", %{name: "Jon"}, query: [scope: "admin"])
+post!(client, "/users", %{name: "Jon"})
+post!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
put(client, url, body, opts)
-request/1
or request/2
for options definition.
+put("/users", %{name: "Jon"})
-put("/users", %{name: "Jon"}, query: [scope: "admin"])
-put(client, "/users", %{name: "Jon"})
-put(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request/1
or request/2
for options definition.put("/users", %{name: "Jon"})
+put("/users", %{name: "Jon"}, query: [scope: "admin"])
+put(client, "/users", %{name: "Jon"})
+put(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
put!(client, url, body, opts)
-request!/1
or request!/2
for options definition.
+put!("/users", %{name: "Jon"})
-put!("/users", %{name: "Jon"}, query: [scope: "admin"])
-put!(client, "/users", %{name: "Jon"})
-put!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request!/1
or request!/2
for options definition.put!("/users", %{name: "Jon"})
+put!("/users", %{name: "Jon"}, query: [scope: "admin"])
+put!(client, "/users", %{name: "Jon"})
+put!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request(client \\ %Tesla.Client{}, options)
Examples
-
ExampleApi.request(method: :get, url: "/users/path")
+
+ExampleApi.get("/users/1")
+ExampleApi.post(client, "/users", %{name: "Jon"})ExampleApi.request(method: :get, url: "/users/path")
# use shortcut methods
-ExampleApi.get("/users/1")
-ExampleApi.post(client, "/users", %{name: "Jon"})
trace(client, url, opts)
-request/1
or request/2
for options definition.
+trace("/users")
-trace("/users", query: [scope: "admin"])
-trace(client, "/users")
-trace(client, "/users", query: [scope: "admin"])
-trace(client, "/users", body: %{name: "Jon"})
request/1
or request/2
for options definition.trace("/users")
+trace("/users", query: [scope: "admin"])
+trace(client, "/users")
+trace(client, "/users", query: [scope: "admin"])
+trace(client, "/users", body: %{name: "Jon"})
trace!(client, url, opts)
-request!/1
or request!/2
for options definition.
+trace!("/users")
-trace!("/users", query: [scope: "admin"])
-trace!(client, "/users")
-trace!(client, "/users", query: [scope: "admin"])
-trace!(client, "/users", body: %{name: "Jon"})
request!/1
or request!/2
for options definition.trace!("/users")
+trace!("/users", query: [scope: "admin"])
+trace!(client, "/users")
+trace!(client, "/users", query: [scope: "admin"])
+trace!(client, "/users", body: %{name: "Jon"})
request(request)
Examples
-request = %HTTPoison.Request{
+
+request(request)request = %HTTPoison.Request{
method: :post,
url: "https://my.website.com",
body: "{\"foo\": 3}",
- headers: [{"Accept", "application/json"}]
-}
+ headers: [{"Accept", "application/json"}]
+}
-request(request)
request(method, url, body \\ "",
Examples
-
+request(:post, "https://my.website.com", "{\"foo\": 3}", [{"Accept", "application/json"}])
request(:post, "https://my.website.com", "{\"foo\": 3}", [{"Accept", "application/json"}])
do_in(envs, list)
Examples
-do_in(:dev) do
- IO.puts("This will only be printed in the dev environment")
-end
+
+do_in([:dev, :test]) do
+ IO.puts("This will only be printed in the dev and test environments")
+enddo_in(:dev) do
+ IO.puts("This will only be printed in the dev environment")
+end
-do_in([:dev, :test]) do
- IO.puts("This will only be printed in the dev and test environments")
-end
Logs
Result
struct.{"level":"<<level>>","name":"<<module>>","message":"..."],"time":<<timestamp>>}
{"message":["<<message|filepath|output>>"]}
Result
struct.
There are two kinds of output:
{"level":"<<level>>","name":"<<module>>","message":"..."],"time":<<timestamp>>}
These are usually for general logging, and debugging.
{"message":["<<message|filepath|output>>"]}
The above is the equivalent of the output of a command
diff --git a/Lightning.Config.Bootstrap.html b/Lightning.Config.Bootstrap.html index 6ee139d151..7ab44a4ab3 100644 --- a/Lightning.Config.Bootstrap.html +++ b/Lightning.Config.Bootstrap.html @@ -143,8 +143,8 @@config/runtime.exs
) file.Sourcing envs
Internally this module uses
Dotenvy.source/1
to source environment variables from the.env
,.env.<config_env>
, and.env.<config_env>.override
files. It also sources the system environment variables.Calling
configure/0
without callingsource_envs/0
orDotenvy.source/2
-first will result in no environment variables being loaded.
Usage:
Lightning.Config.Bootstrap.source_envs()
-Lightning.Config.Bootstrap.configure()
+first will result in no environment variables being loaded.Usage:
Lightning.Config.Bootstrap.source_envs()
+Lightning.Config.Bootstrap.configure()
diff --git a/Lightning.Credentials.html b/Lightning.Credentials.html
index 5336e05427..4d727a63ce 100644
--- a/Lightning.Credentials.html
+++ b/Lightning.Credentials.html
@@ -406,8 +406,8 @@ iex> change_credential(credential)
-%Ecto.Changeset{data: %Credential{}}
+iex> change_credential(credential)
+%Ecto.Changeset{data: %Credential{}}
iex> create_credential(%{field: value})
-{:ok, %Credential{}}
+iex> create_credential(%{field: value})
+{:ok, %Credential{}}
-iex> create_credential(%{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> create_credential(%{field: bad_value})
+{:error, %Ecto.Changeset{}}
iex> delete_credential(credential)
-{:ok, %Credential{}}
+iex> delete_credential(credential)
+{:ok, %Credential{}}
-iex> delete_credential(credential)
-{:error, %Ecto.Changeset{}}
+iex> delete_credential(credential)
+{:error, %Ecto.Changeset{}}
iex> get_credential!(123)
-%Credential{}
+iex> get_credential!(123)
+%Credential{}
-iex> get_credential!(456)
+iex> get_credential!(456)
** (Ecto.NoResultsError)
iex> has_activity_in_projects?(%Credential{id: some_id})
+iex> has_activity_in_projects?(%Credential{id: some_id})
true
-iex> has_activity_in_projects?(%Credential{id: another_id})
+iex> has_activity_in_projects?(%Credential{id: another_id})
false
@@ -659,11 +659,11 @@ invalid_projects_for_user(credential_id, us
Examples
-iex> can_credential_be_shared_to_user(credential_id, user_id)
-[]
+iex> can_credential_be_shared_to_user(credential_id, user_id)
+[]
-iex> can_credential_be_shared_to_user(credential_id, user_id)
-["52ea8758-6ce5-43d7-912f-6a1e1f11dc55"]
+iex> can_credential_be_shared_to_user(credential_id, user_id)
+["52ea8758-6ce5-43d7-912f-6a1e1f11dc55"]
@@ -703,9 +703,9 @@ list_credentials(project)
Examples
- When given a Project:
iex> list_credentials(%Project{id: 1})
-[%Credential{project_id: 1}, %Credential{project_id: 1}]
When given a User:
iex> list_credentials(%User{id: 123})
-[%Credential{user_id: 123}, %Credential{user_id: 123}]
+ When given a Project:
iex> list_credentials(%Project{id: 1})
+[%Credential{project_id: 1}, %Credential{project_id: 1}]
When given a User:
iex> list_credentials(%User{id: 123})
+[%Credential{user_id: 123}, %Credential{user_id: 123}]
@@ -816,11 +816,11 @@ schedule_credential_deletion(credential)
Examples
-iex> schedule_credential_deletion(%Credential{id: some_id})
-{:ok, %Credential{}}
+iex> schedule_credential_deletion(%Credential{id: some_id})
+{:ok, %Credential{}}
-iex> schedule_credential_deletion(%Credential{})
-{:error, %Ecto.Changeset{}}
+iex> schedule_credential_deletion(%Credential{})
+{:error, %Ecto.Changeset{}}
@@ -877,11 +877,11 @@ update_credential(credential, attrs)
Examples
-iex> update_credential(credential, %{field: new_value})
-{:ok, %Credential{}}
+iex> update_credential(credential, %{field: new_value})
+{:ok, %Credential{}}
-iex> update_credential(credential, %{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> update_credential(credential, %{field: bad_value})
+{:error, %Ecto.Changeset{}}
diff --git a/Lightning.Invocation.html b/Lightning.Invocation.html
index 3008be28d6..64f5857db2 100644
--- a/Lightning.Invocation.html
+++ b/Lightning.Invocation.html
@@ -519,8 +519,8 @@ change_dataclip(dataclip, attrs \\ %{})
Examples
-iex> change_dataclip(dataclip)
-%Ecto.Changeset{data: %Dataclip{}}
+iex> change_dataclip(dataclip)
+%Ecto.Changeset{data: %Dataclip{}}
@@ -550,8 +550,8 @@ change_step(step, attrs \\ %{})
Examples
-iex> change_step(step)
-%Ecto.Changeset{data: %Step{}}
+iex> change_step(step)
+%Ecto.Changeset{data: %Step{}}
@@ -611,11 +611,11 @@ create_dataclip(attrs \\ %{})
Examples
-iex> create_dataclip(%{field: value})
-{:ok, %Dataclip{}}
+iex> create_dataclip(%{field: value})
+{:ok, %Dataclip{}}
-iex> create_dataclip(%{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> create_dataclip(%{field: bad_value})
+{:error, %Ecto.Changeset{}}
@@ -643,11 +643,11 @@ delete_dataclip(dataclip)
Examples
-iex> delete_dataclip(dataclip)
-{:ok, %Dataclip{}}
+iex> delete_dataclip(dataclip)
+{:ok, %Dataclip{}}
-iex> delete_dataclip(dataclip)
-{:error, %Ecto.Changeset{}}
+iex> delete_dataclip(dataclip)
+{:error, %Ecto.Changeset{}}
@@ -682,14 +682,14 @@ get_dataclip(step)
Examples
-iex> get_dataclip("27b73932-16c7-4a72-86a3-85d805ccff98")
-%Dataclip{}
+iex> get_dataclip("27b73932-16c7-4a72-86a3-85d805ccff98")
+%Dataclip{}
-iex> get_dataclip("27b73932-16c7-4a72-86a3-85d805ccff98")
+iex> get_dataclip("27b73932-16c7-4a72-86a3-85d805ccff98")
nil
-iex> get_dataclip(%Step{id: "a uuid"})
-%Dataclip{}
+iex> get_dataclip(%Step{id: "a uuid"})
+%Dataclip{}
@@ -723,10 +723,10 @@ get_dataclip!(id)
Examples
-iex> get_dataclip!(123)
-%Dataclip{}
+iex> get_dataclip!(123)
+%Dataclip{}
-iex> get_dataclip!(456)
+iex> get_dataclip!(456)
** (Ecto.NoResultsError)
@@ -924,10 +924,10 @@ get_step!(id)
Examples
-iex> get_step!(123)
-%Step{}
+iex> get_step!(123)
+%Step{}
-iex> get_step!(456)
+iex> get_step!(456)
** (Ecto.NoResultsError)
@@ -1056,8 +1056,8 @@ list_dataclips()
Examples
-iex> list_dataclips()
-[%Dataclip{}, ...]
+iex> list_dataclips()
+[%Dataclip{}, ...]
@@ -1166,8 +1166,8 @@ list_steps()
Examples
-iex> list_steps()
-[%Step{}, ...]
+iex> list_steps()
+[%Step{}, ...]
@@ -1294,7 +1294,7 @@ search_workorders(project)
Example:
-search_workorders(%Project{id: 1}, %SearchParams{status: ["completed"]})
+search_workorders(%Project{id: 1}, %SearchParams{status: ["completed"]})
@@ -1400,11 +1400,11 @@ update_dataclip(dataclip, attrs)
Examples
-iex> update_dataclip(dataclip, %{field: new_value})
-{:ok, %Dataclip{}}
+iex> update_dataclip(dataclip, %{field: new_value})
+{:ok, %Dataclip{}}
-iex> update_dataclip(dataclip, %{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> update_dataclip(dataclip, %{field: bad_value})
+{:error, %Ecto.Changeset{}}
diff --git a/Lightning.Jobs.html b/Lightning.Jobs.html
index cb37e17669..ddfbdc0082 100644
--- a/Lightning.Jobs.html
+++ b/Lightning.Jobs.html
@@ -306,8 +306,8 @@ change_job(job, attrs \\ %{})
Examples
-iex> change_job(job)
-%Ecto.Changeset{data: %Job{}}
+iex> change_job(job)
+%Ecto.Changeset{data: %Job{}}
@@ -337,11 +337,11 @@ create_job(attrs \\ %{})
Examples
-iex> create_job(%{field: value})
-{:ok, %Job{}}
+iex> create_job(%{field: value})
+{:ok, %Job{}}
-iex> create_job(%{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> create_job(%{field: bad_value})
+{:error, %Ecto.Changeset{}}
@@ -405,10 +405,10 @@ get_job!(id)
Examples
-iex> get_job!(123)
-%Job{}
+iex> get_job!(123)
+%Job{}
-iex> get_job!(456)
+iex> get_job!(456)
** (Ecto.NoResultsError)
@@ -620,11 +620,11 @@ update_job(job, attrs)
Examples
-iex> update_job(job, %{field: new_value})
-{:ok, %Job{}}
+iex> update_job(job, %{field: new_value})
+{:ok, %Job{}}
-iex> update_job(job, %{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> update_job(job, %{field: bad_value})
+{:error, %Ecto.Changeset{}}
diff --git a/Lightning.KafkaTriggers.MessageRecovery.html b/Lightning.KafkaTriggers.MessageRecovery.html
index d93f427595..068f0e89bf 100644
--- a/Lightning.KafkaTriggers.MessageRecovery.html
+++ b/Lightning.KafkaTriggers.MessageRecovery.html
@@ -152,7 +152,7 @@
an error during reprocessing. These files can be reprocessed if you think the
error was transient.
Usage:
alias Lightning.KafkaTriggers.MessageRecovery
case MessageRecovery.recover_messages(Lightning.Config.kafka_alternate_storage_file_path) do
:ok -> # Success code
-{:error, error_count} -> # Failure code
end
+{:error, error_count} -> # Failure code
end
diff --git a/Lightning.OauthClients.html b/Lightning.OauthClients.html
index a88ba51d86..5762494409 100644
--- a/Lightning.OauthClients.html
+++ b/Lightning.OauthClients.html
@@ -267,8 +267,8 @@ change_client(client, attrs \\ %{})
Examples
-iex> change_client(%OauthClient{}, %{name: "New Client"})
-%Ecto.Changeset{...}
+iex> change_client(%OauthClient{}, %{name: "New Client"})
+%Ecto.Changeset{...}
@@ -353,11 +353,11 @@ delete_client(client)
Examples
-iex> delete_client(client)
-{:ok, %OauthClient{}}
+iex> delete_client(client)
+{:ok, %OauthClient{}}
-iex> delete_client(client)
-{:error, %Ecto.Changeset{}}
+iex> delete_client(client)
+{:error, %Ecto.Changeset{}}
@@ -403,10 +403,10 @@ get_client!(id)
Examples
-iex> get_client!(123)
-%OauthClient{}
+iex> get_client!(123)
+%OauthClient{}
-iex> get_client!(456)
+iex> get_client!(456)
** (Ecto.NoResultsError)
@@ -447,9 +447,9 @@ list_clients(project)
Examples
- When given a Project:
iex> list_clients(%Project{id: 1})
-[%OauthClient{project_id: 1}, %OauthClient{project_id: 1}]
When given a User:
iex> list_clients(%User{id: 123})
-[%OauthClient{user_id: 123}, %OauthClient{user_id: 123}]
+ When given a Project:
iex> list_clients(%Project{id: 1})
+[%OauthClient{project_id: 1}, %OauthClient{project_id: 1}]
When given a User:
iex> list_clients(%User{id: 123})
+[%OauthClient{user_id: 123}, %OauthClient{user_id: 123}]
@@ -489,11 +489,11 @@ update_client(client, attrs)
Examples
-iex> update_client(client, %{field: new_value})
-{:ok, %OauthClient{}}
+iex> update_client(client, %{field: new_value})
+{:ok, %OauthClient{}}
-iex> update_client(client, %{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> update_client(client, %{field: bad_value})
+{:error, %Ecto.Changeset{}}
diff --git a/Lightning.Policies.Permissions.html b/Lightning.Policies.Permissions.html
index ef4589516c..7a7d010af0 100644
--- a/Lightning.Policies.Permissions.html
+++ b/Lightning.Policies.Permissions.html
@@ -138,13 +138,13 @@
This module defines a unique interface managing authorizations in Lightning.
Users in Lightning have instance-wide and project-wide roles which determine their level of access to resources in the application. Fo rmore details see the documentation.
These authorizations policies are all implemented under the lib/lightning/policies
folder. In that folder you can find 3 files:
- The
users.ex
file has all the policies for the instances wide access levels - The
project_users.ex
file has all the policies for the project wide access levels - The
permissions.ex
file defines the Lightning.Policies.Permissions.can/4
interface. Which is a wrapper around the Bodyguard.permit/4
function.
-We use that interface to be able to harmonize the use of policies accross the entire app.
All the policies are tested in the test/lightning/policies
folder. And the test are written in a way that allows the reader to quickly who can do what in the app.
We have two variants of the Lightning.Policies.Permissions.can/4
interface:
Lightning.Policies.Permissions.can(policy, action, actor, resource)
returns :ok
if the actor can perform the action on the resource and {:error, :unauthorized}
otherwise.Lightning.Policies.Permissions.can?(policy, action, actor, resource)
returns true
if the actor can perform the action on the resource and false
otherwise.
Here is an example of how we the Lightning.Policies.Permissions.can/4
interface to check if the a user can edit a job or not
can_edit_workflow = Lightning.Policies.ProjectUsers |> Lightning.Policies.Permissions.can?(:edit_workflow, socket.assigns.current_user, socket.assigns.project)
+We use that interface to be able to harmonize the use of policies accross the entire app.All the policies are tested in the test/lightning/policies
folder. And the test are written in a way that allows the reader to quickly who can do what in the app.
We have two variants of the Lightning.Policies.Permissions.can/4
interface:
Lightning.Policies.Permissions.can(policy, action, actor, resource)
returns :ok
if the actor can perform the action on the resource and {:error, :unauthorized}
otherwise.Lightning.Policies.Permissions.can?(policy, action, actor, resource)
returns true
if the actor can perform the action on the resource and false
otherwise.
Here is an example of how we the Lightning.Policies.Permissions.can/4
interface to check if the a user can edit a job or not
can_edit_workflow = Lightning.Policies.ProjectUsers |> Lightning.Policies.Permissions.can?(:edit_workflow, socket.assigns.current_user, socket.assigns.project)
-if can_edit_workflow do
+if can_edit_workflow do
# allow user to edit the workflow
-else
+else
# quick user out
-end
+end
@@ -220,11 +220,11 @@ can(policy, action, user, params \\ [])
Examples
-iex> can(Lightning.Policies.Users, :create_workflow, user, project)
+iex> can(Lightning.Policies.Users, :create_workflow, user, project)
:ok
-iex> can(Lightning.Policies.Users, :create_project, user, %{})
-{:error, :unauthorized}
+iex> can(Lightning.Policies.Users, :create_project, user, %{})
+{:error, :unauthorized}
@@ -254,10 +254,10 @@ can?(policy, action, user, params \\ [])
Examples
-iex> can(Lightning.Policies.Users, :create_workflow, user, project)
+iex> can(Lightning.Policies.Users, :create_workflow, user, project)
true
-iex> can(Lightning.Policies.Users, :create_project, user, %{})
+iex> can(Lightning.Policies.Users, :create_project, user, %{})
false
diff --git a/Lightning.Projects.html b/Lightning.Projects.html
index fccd7ce5bf..f374a35943 100644
--- a/Lightning.Projects.html
+++ b/Lightning.Projects.html
@@ -670,8 +670,8 @@ change_project(project, attrs \\ %{})
Examples
-iex> change_project(project)
-%Ecto.Changeset{data: %Project{}}
+iex> change_project(project)
+%Ecto.Changeset{data: %Project{}}
@@ -703,11 +703,11 @@ create_project(attrs \\ %{}, schedule_email
Examples
-iex> create_project(%{field: value})
-{:ok, %Project{}}
+iex> create_project(%{field: value})
+{:ok, %Project{}}
-iex> create_project(%{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> create_project(%{field: bad_value})
+{:error, %Ecto.Changeset{}}
@@ -736,11 +736,11 @@ delete_project(project)
Examples
-iex> delete_project(project)
-{:ok, %Project{}}
+iex> delete_project(project)
+{:ok, %Project{}}
-iex> delete_project(project)
-{:error, %Ecto.Changeset{}}
+iex> delete_project(project)
+{:error, %Ecto.Changeset{}}
@@ -805,8 +805,8 @@ export_project(atom, project_id, snapshot_i
Examples
-iex> export_project(:yaml, project_id)
-{:ok, string}
+iex> export_project(:yaml, project_id)
+{:ok, string}
@@ -878,10 +878,10 @@ get_project!(id)
Examples
-iex> get_project!(123)
-%Project{}
+iex> get_project!(123)
+%Project{}
-iex> get_project!(456)
+iex> get_project!(456)
** (Ecto.NoResultsError)
@@ -976,10 +976,10 @@ get_project_user!(id)
Examples
-iex> get_project_user!(123)
-%ProjectUser{}
+iex> get_project_user!(123)
+%ProjectUser{}
-iex> get_project_user!(456)
+iex> get_project_user!(456)
** (Ecto.NoResultsError)
@@ -1009,16 +1009,16 @@ get_project_user_role(user, project)
Examples
-iex> get_project_user_role(user, project)
+iex> get_project_user_role(user, project)
:admin
-iex> get_project_user_role(user, project)
+iex> get_project_user_role(user, project)
:viewer
-iex> get_project_user_role(user, project)
+iex> get_project_user_role(user, project)
:editor
-iex> get_project_user_role(user, project)
+iex> get_project_user_role(user, project)
:owner
@@ -1069,10 +1069,10 @@ get_project_with_users!(id)
Examples
-iex> get_project!(123)
-%Project{}
+iex> get_project!(123)
+%Project{}
-iex> get_project!(456)
+iex> get_project!(456)
** (Ecto.NoResultsError)
@@ -1274,8 +1274,8 @@ list_projects()
Examples
-iex> list_projects()
-[%Project{}, ...]
+iex> list_projects()
+[%Project{}, ...]
@@ -1755,11 +1755,11 @@ update_project(project, attrs)
Examples
-iex> update_project(project, %{field: new_value})
-{:ok, %Project{}}
+iex> update_project(project, %{field: new_value})
+{:ok, %Project{}}
-iex> update_project(project, %{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> update_project(project, %{field: bad_value})
+{:error, %Ecto.Changeset{}}
@@ -1787,11 +1787,11 @@ update_project_user(project_user, attrs)
Examples
-iex> update_project_user(project_user, %{field: new_value})
-{:ok, %ProjectUser{}}
+iex> update_project_user(project_user, %{field: new_value})
+{:ok, %ProjectUser{}}
-iex> update_project_user(projectUser, %{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> update_project_user(projectUser, %{field: bad_value})
+{:error, %Ecto.Changeset{}}
@@ -1872,8 +1872,8 @@ validate_for_deletion(project, attrs)
Examples
-iex> validate_for_deletion(project)
-%Ecto.Changeset{data: %Project{}}
+iex> validate_for_deletion(project)
+%Ecto.Changeset{data: %Project{}}
diff --git a/Lightning.PromEx.html b/Lightning.PromEx.html
index 08108b40f1..c6a8b5b95c 100644
--- a/Lightning.PromEx.html
+++ b/Lightning.PromEx.html
@@ -142,24 +142,24 @@
more details regarding configuring PromEx:config :lightning, Lightning.PromEx,
disabled: false,
manual_metrics_start_delay: :no_delay,
- drop_metrics_groups: [],
+ drop_metrics_groups: [],
grafana: :disabled,
metrics_server: :disabled
Add this module to your application supervision tree. It should be one of the first
things that is started so that no Telemetry events are missed. For example, if PromEx
is started after your Repo module, you will miss Ecto's init events and the dashboards
-will be missing some data points:
def start(_type, _args) do
- children = [
+will be missing some data points:def start(_type, _args) do
+ children = [
Lightning.PromEx,
...
- ]
+ ]
...
-end
Update your endpoint.ex
file to expose your metrics (or configure a standalone
+
end
Update your endpoint.ex
file to expose your metrics (or configure a standalone
server using the :metrics_server
config options). Be sure to put this plug before
your Plug.Telemetry
entry so that you can avoid having calls to your /metrics
endpoint create their own metrics and logs which can pollute your logs/metrics given
-that Prometheus will scrape at a regular interval and that can get noisy:
defmodule LightningWeb.Endpoint do
+that Prometheus will scrape at a regular interval and that can get noisy:defmodule LightningWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :lightning
...
@@ -167,7 +167,7 @@
plug PromEx.Plug, prom_ex_module: Lightning.PromEx
...
-end
Update the list of plugins in the plugins/0
function return list to reflect your
+
end
Update the list of plugins in the plugins/0
function return list to reflect your
application's dependencies. Also update the list of dashboards that are to be uploaded
to Grafana in the dashboards/0
function.
diff --git a/Lightning.Repo.html b/Lightning.Repo.html
index f10369baed..7ab3dc6952 100644
--- a/Lightning.Repo.html
+++ b/Lightning.Repo.html
@@ -1738,13 +1738,13 @@ transact(fun, opts \\ [])
A small wrapper around Repo.transaction/2
.
Commits the transaction if the lambda returns :ok
or {:ok, result}
,
rolling it back if the lambda returns :error
or {:error, reason}
. In both
-cases, the function returns the result of the lambda.
Example:
Repo.transact(fn ->
- with {:ok, user} <- Accounts.create_user(params),
- {:ok, _log} <- Logs.log_action(:user_registered, user),
- {:ok, _job} <- Mailer.enqueue_email_confirmation(user) do
- {:ok, user}
- end
-end)
From blog post found here
+cases, the function returns the result of the lambda.Example:
Repo.transact(fn ->
+ with {:ok, user} <- Accounts.create_user(params),
+ {:ok, _log} <- Logs.log_action(:user_registered, user),
+ {:ok, _job} <- Mailer.enqueue_email_confirmation(user) do
+ {:ok, user}
+ end
+end)
From blog post found here
diff --git a/Lightning.Runs.Query.html b/Lightning.Runs.Query.html
index 4c2ddb547d..b08e1792eb 100644
--- a/Lightning.Runs.Query.html
+++ b/Lightning.Runs.Query.html
@@ -241,7 +241,7 @@ eligible_for_claim()
This query does not currently take into account the priority of the run.
To allow for prioritization, the query should be updated to order by
-priority.
eligible_for_claim() |> prepend_order_by([:priority])
+priority.eligible_for_claim() |> prepend_order_by([:priority])
diff --git a/Lightning.Runs.html b/Lightning.Runs.html
index fa8a775586..387a5bc5d0 100644
--- a/Lightning.Runs.html
+++ b/Lightning.Runs.html
@@ -477,7 +477,7 @@ get(id, opts \\ [])
-Get a run by id.
Optionally preload associations by passing a list of atoms to :include
.
Lightning.Runs.get(id, include: [:workflow])
+Get a run by id.
Optionally preload associations by passing a list of atoms to :include
.
Lightning.Runs.get(id, include: [:workflow])
diff --git a/Lightning.Runtime.LogAgent.html b/Lightning.Runtime.LogAgent.html
index 1d9cb302b5..50690c789b 100644
--- a/Lightning.Runtime.LogAgent.html
+++ b/Lightning.Runtime.LogAgent.html
@@ -138,9 +138,9 @@
Agent facility to consume STDOUT/STDERR byte by byte.
Since it works on a byte by byte basis, you will need to perform line-splitting
-yourself.
Usage:
{:ok, log} = LogAgent.start_link()
-"foo" = LogAgent.process_chunk(log, {:stdout, "foo"})
-"foobar" = LogAgent.process_chunk(log, {:stdout, "bar"})
+yourself.Usage:
{:ok, log} = LogAgent.start_link()
+"foo" = LogAgent.process_chunk(log, {:stdout, "foo"})
+"foobar" = LogAgent.process_chunk(log, {:stdout, "bar"})
diff --git a/Lightning.Runtime.RuntimeManager.html b/Lightning.Runtime.RuntimeManager.html
index 9957ff9525..e413e8e210 100644
--- a/Lightning.Runtime.RuntimeManager.html
+++ b/Lightning.Runtime.RuntimeManager.html
@@ -146,8 +146,8 @@
Sample:
config :lightining, Elixir.Lightning.Runtime.RuntimeManager,
version: "0.1.0",
start: true,
args: ~w(js/app.js --bundle --target=es2016 --outdir=../priv/static/assets),
-cd: Path.expand("../assets", __DIR__),
-env: %{}
Options:
:version
- the expected runtime version
:start
- flag to start the runtime manager. If false
the GenServer
+
cd: Path.expand("../assets", __DIR__),
+env: %{}
Options:
:version
- the expected runtime version
:start
- flag to start the runtime manager. If false
the GenServer
won't be started
:path
- the path to find the runtime executable at. By
default, it is automatically downloaded and placed inside
the _build
directory of your current app
Overriding the :path
is not recommended, as we will automatically
diff --git a/Lightning.Scrubber.html b/Lightning.Scrubber.html
index 85885e1704..8e3761629e 100644
--- a/Lightning.Scrubber.html
+++ b/Lightning.Scrubber.html
@@ -137,11 +137,11 @@
-Process used to scrub strings of sensitive information.
Can be started via start_link/1
.
{:ok, scrubber} =
- Lightning.Scrubber.start_link(
+Process used to scrub strings of sensitive information.
Can be started via start_link/1
.
{:ok, scrubber} =
+ Lightning.Scrubber.start_link(
samples:
- Lightning.Credentials.sensitive_values_for(credential)
- )
Takes an optional :name
key, in case you need to name the process.
+ Lightning.Credentials.sensitive_values_for(credential)
+ )
Takes an optional :name
key, in case you need to name the process.
diff --git a/Lightning.Storage.GCS.html b/Lightning.Storage.GCS.html
index 48492be44f..8db65d3272 100644
--- a/Lightning.Storage.GCS.html
+++ b/Lightning.Storage.GCS.html
@@ -150,10 +150,10 @@
Example Usage
# Store a file in GCS
-Lightning.Storage.GCS.store("/path/to/source", "destination/path")
+Lightning.Storage.GCS.store("/path/to/source", "destination/path")
# Get a signed URL for the stored file
-{:ok, url} = Lightning.Storage.GCS.get_url("destination/path")
+
{:ok, url} = Lightning.Storage.GCS.get_url("destination/path")
diff --git a/Lightning.Storage.Local.html b/Lightning.Storage.Local.html
index c49e7a7d62..62ac5f070c 100644
--- a/Lightning.Storage.Local.html
+++ b/Lightning.Storage.Local.html
@@ -156,11 +156,11 @@ # Store a file
-{:ok, filename} =
- Lightning.Storage.Local.store("/path/to/source", "destination/path")
+{:ok, filename} =
+ Lightning.Storage.Local.store("/path/to/source", "destination/path")
# Get the URL for the stored file
-{:ok, url} = Lightning.Storage.Local.get_url("destination/path")
+{:ok, url} = Lightning.Storage.Local.get_url("destination/path")
diff --git a/Lightning.Storage.ProjectFileDefinition.html b/Lightning.Storage.ProjectFileDefinition.html
index 573a097468..4f3d3b0d62 100644
--- a/Lightning.Storage.ProjectFileDefinition.html
+++ b/Lightning.Storage.ProjectFileDefinition.html
@@ -138,13 +138,13 @@ This module provides functionality for managing the storage and retrieval of project files.
It handles operations related to storing project files, generating URLs for accessing these files, and constructing storage paths for exported files. It serves as an abstraction layer over the underlying storage mechanism provided by the Lightning.Storage
module.
## Functions
store/2
: Stores a file from a given source path into the storage system based on the file's path.get_url/1
: Retrieves the URL for accessing a stored file.storage_path_for_exports/2
: Constructs a storage path for exported files, defaulting to a .zip
extension.## Example Usage
# Store a file
- Lightning.Storage.ProjectFileDefinition.store("/path/to/source", project_file)
+ Lightning.Storage.ProjectFileDefinition.store("/path/to/source", project_file)
# Get a URL for the stored file
- url = Lightning.Storage.ProjectFileDefinition.get_url(project_file)
+ url = Lightning.Storage.ProjectFileDefinition.get_url(project_file)
# Get the storage path for an exported file
- path = Lightning.Storage.ProjectFileDefinition.storage_path_for_exports(project_file)
+ path = Lightning.Storage.ProjectFileDefinition.storage_path_for_exports(project_file)
A TaskWorker with concurrency limits.
A simple concurrency limiter that wraps Task.Supervisor
, which already does
have the ability to specify max_children
; it throws an error when
that limit is exceeded.
To use it, start it like any other process; ideally in your supervision tree.
...,
- {Lightning.TaskWorker, name: :cli_task_worker, max_tasks: 4}
Options
:max_tasks
Defaults to the number of system schedulers available to the vm.Options
:max_tasks
Defaults to the number of system schedulers available to the vm.Validate that only one of the fields is set at a time.
Example:
changeset
-|> validate_exclusive(
- [:source_job_id, :source_trigger_id],
+|> validate_exclusive(
+ [:source_job_id, :source_trigger_id],
"source_job_id and source_trigger_id are mutually exclusive"
-)
+)
Perform a DELETE request.
See request/1
or request/2
for options definition.
delete("/users")
-delete("/users", query: [scope: "admin"])
-delete(client, "/users")
-delete(client, "/users", query: [scope: "admin"])
-delete(client, "/users", body: %{name: "Jon"})
+Perform a DELETE request.
See request/1
or request/2
for options definition.
delete("/users")
+delete("/users", query: [scope: "admin"])
+delete(client, "/users")
+delete(client, "/users", query: [scope: "admin"])
+delete(client, "/users", body: %{name: "Jon"})
Perform a DELETE request.
See request!/1
or request!/2
for options definition.
delete!("/users")
-delete!("/users", query: [scope: "admin"])
-delete!(client, "/users")
-delete!(client, "/users", query: [scope: "admin"])
-delete!(client, "/users", body: %{name: "Jon"})
+Perform a DELETE request.
See request!/1
or request!/2
for options definition.
delete!("/users")
+delete!("/users", query: [scope: "admin"])
+delete!(client, "/users")
+delete!(client, "/users", query: [scope: "admin"])
+delete!(client, "/users", body: %{name: "Jon"})
Perform a GET request.
See request/1
or request/2
for options definition.
get("/users")
-get("/users", query: [scope: "admin"])
-get(client, "/users")
-get(client, "/users", query: [scope: "admin"])
-get(client, "/users", body: %{name: "Jon"})
+Perform a GET request.
See request/1
or request/2
for options definition.
get("/users")
+get("/users", query: [scope: "admin"])
+get(client, "/users")
+get(client, "/users", query: [scope: "admin"])
+get(client, "/users", body: %{name: "Jon"})
Perform a GET request.
See request!/1
or request!/2
for options definition.
get!("/users")
-get!("/users", query: [scope: "admin"])
-get!(client, "/users")
-get!(client, "/users", query: [scope: "admin"])
-get!(client, "/users", body: %{name: "Jon"})
+Perform a GET request.
See request!/1
or request!/2
for options definition.
get!("/users")
+get!("/users", query: [scope: "admin"])
+get!(client, "/users")
+get!(client, "/users", query: [scope: "admin"])
+get!(client, "/users", body: %{name: "Jon"})
Perform a HEAD request.
See request/1
or request/2
for options definition.
head("/users")
-head("/users", query: [scope: "admin"])
-head(client, "/users")
-head(client, "/users", query: [scope: "admin"])
-head(client, "/users", body: %{name: "Jon"})
+Perform a HEAD request.
See request/1
or request/2
for options definition.
head("/users")
+head("/users", query: [scope: "admin"])
+head(client, "/users")
+head(client, "/users", query: [scope: "admin"])
+head(client, "/users", body: %{name: "Jon"})
Perform a HEAD request.
See request!/1
or request!/2
for options definition.
head!("/users")
-head!("/users", query: [scope: "admin"])
-head!(client, "/users")
-head!(client, "/users", query: [scope: "admin"])
-head!(client, "/users", body: %{name: "Jon"})
+Perform a HEAD request.
See request!/1
or request!/2
for options definition.
head!("/users")
+head!("/users", query: [scope: "admin"])
+head!(client, "/users")
+head!(client, "/users", query: [scope: "admin"])
+head!(client, "/users", body: %{name: "Jon"})
Perform a OPTIONS request.
See request/1
or request/2
for options definition.
options("/users")
-options("/users", query: [scope: "admin"])
-options(client, "/users")
-options(client, "/users", query: [scope: "admin"])
-options(client, "/users", body: %{name: "Jon"})
+Perform a OPTIONS request.
See request/1
or request/2
for options definition.
options("/users")
+options("/users", query: [scope: "admin"])
+options(client, "/users")
+options(client, "/users", query: [scope: "admin"])
+options(client, "/users", body: %{name: "Jon"})
Perform a OPTIONS request.
See request!/1
or request!/2
for options definition.
options!("/users")
-options!("/users", query: [scope: "admin"])
-options!(client, "/users")
-options!(client, "/users", query: [scope: "admin"])
-options!(client, "/users", body: %{name: "Jon"})
+Perform a OPTIONS request.
See request!/1
or request!/2
for options definition.
options!("/users")
+options!("/users", query: [scope: "admin"])
+options!(client, "/users")
+options!(client, "/users", query: [scope: "admin"])
+options!(client, "/users", body: %{name: "Jon"})
Perform a PATCH request.
See request/1
or request/2
for options definition.
patch("/users", %{name: "Jon"})
-patch("/users", %{name: "Jon"}, query: [scope: "admin"])
-patch(client, "/users", %{name: "Jon"})
-patch(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
+Perform a PATCH request.
See request/1
or request/2
for options definition.
patch("/users", %{name: "Jon"})
+patch("/users", %{name: "Jon"}, query: [scope: "admin"])
+patch(client, "/users", %{name: "Jon"})
+patch(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Perform a PATCH request.
See request!/1
or request!/2
for options definition.
patch!("/users", %{name: "Jon"})
-patch!("/users", %{name: "Jon"}, query: [scope: "admin"])
-patch!(client, "/users", %{name: "Jon"})
-patch!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
+Perform a PATCH request.
See request!/1
or request!/2
for options definition.
patch!("/users", %{name: "Jon"})
+patch!("/users", %{name: "Jon"}, query: [scope: "admin"])
+patch!(client, "/users", %{name: "Jon"})
+patch!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Perform a POST request.
See request/1
or request/2
for options definition.
post("/users", %{name: "Jon"})
-post("/users", %{name: "Jon"}, query: [scope: "admin"])
-post(client, "/users", %{name: "Jon"})
-post(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
+Perform a POST request.
See request/1
or request/2
for options definition.
post("/users", %{name: "Jon"})
+post("/users", %{name: "Jon"}, query: [scope: "admin"])
+post(client, "/users", %{name: "Jon"})
+post(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Perform a POST request.
See request!/1
or request!/2
for options definition.
post!("/users", %{name: "Jon"})
-post!("/users", %{name: "Jon"}, query: [scope: "admin"])
-post!(client, "/users", %{name: "Jon"})
-post!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
+Perform a POST request.
See request!/1
or request!/2
for options definition.
post!("/users", %{name: "Jon"})
+post!("/users", %{name: "Jon"}, query: [scope: "admin"])
+post!(client, "/users", %{name: "Jon"})
+post!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Perform a PUT request.
See request/1
or request/2
for options definition.
put("/users", %{name: "Jon"})
-put("/users", %{name: "Jon"}, query: [scope: "admin"])
-put(client, "/users", %{name: "Jon"})
-put(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
+Perform a PUT request.
See request/1
or request/2
for options definition.
put("/users", %{name: "Jon"})
+put("/users", %{name: "Jon"}, query: [scope: "admin"])
+put(client, "/users", %{name: "Jon"})
+put(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Perform a PUT request.
See request!/1
or request!/2
for options definition.
put!("/users", %{name: "Jon"})
-put!("/users", %{name: "Jon"}, query: [scope: "admin"])
-put!(client, "/users", %{name: "Jon"})
-put!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
+Perform a PUT request.
See request!/1
or request!/2
for options definition.
put!("/users", %{name: "Jon"})
+put!("/users", %{name: "Jon"}, query: [scope: "admin"])
+put!(client, "/users", %{name: "Jon"})
+put!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
ExampleApi.request(method: :get, url: "/users/path")
+ExampleApi.request(method: :get, url: "/users/path")
# use shortcut methods
-ExampleApi.get("/users/1")
-ExampleApi.post(client, "/users", %{name: "Jon"})
+ExampleApi.get("/users/1")
+ExampleApi.post(client, "/users", %{name: "Jon"})
Perform a TRACE request.
See request/1
or request/2
for options definition.
trace("/users")
-trace("/users", query: [scope: "admin"])
-trace(client, "/users")
-trace(client, "/users", query: [scope: "admin"])
-trace(client, "/users", body: %{name: "Jon"})
+Perform a TRACE request.
See request/1
or request/2
for options definition.
trace("/users")
+trace("/users", query: [scope: "admin"])
+trace(client, "/users")
+trace(client, "/users", query: [scope: "admin"])
+trace(client, "/users", body: %{name: "Jon"})
Perform a TRACE request.
See request!/1
or request!/2
for options definition.
trace!("/users")
-trace!("/users", query: [scope: "admin"])
-trace!(client, "/users")
-trace!(client, "/users", query: [scope: "admin"])
-trace!(client, "/users", body: %{name: "Jon"})
+Perform a TRACE request.
See request!/1
or request!/2
for options definition.
trace!("/users")
+trace!("/users", query: [scope: "admin"])
+trace!(client, "/users")
+trace!(client, "/users", query: [scope: "admin"])
+trace!(client, "/users", body: %{name: "Jon"})
Creating a WebhookAuthMethod
without an associated trigger:
iex> create_auth_method(%{valid_attributes}, actor: %User{})
-{:ok, %WebhookAuthMethod{}}
+Creating a WebhookAuthMethod
without an associated trigger:
iex> create_auth_method(%{valid_attributes}, actor: %User{})
+{:ok, %WebhookAuthMethod{}}
-iex> create_auth_method(%{invalid_attributes}, actor: %User{})
-{:error, %Ecto.Changeset{}}
Creating a WebhookAuthMethod
with an associated trigger:
iex> create_auth_method(%Trigger{}, %{valid_attributes}, actor: %User{})
-{:ok, %WebhookAuthMethod{}}
+iex> create_auth_method(%{invalid_attributes}, actor: %User{})
+{:error, %Ecto.Changeset{}}
Creating a WebhookAuthMethod
with an associated trigger:
iex> create_auth_method(%Trigger{}, %{valid_attributes}, actor: %User{})
+{:ok, %WebhookAuthMethod{}}
-iex> create_auth_method(%Trigger{}, %{invalid_attributes}, actor: %User{})
-{:error, %Ecto.Changeset{}}
+
iex> create_auth_method(%Trigger{}, %{invalid_attributes}, actor: %User{})
+{:error, %Ecto.Changeset{}}
Creating a changeset for an API type auth method:
iex> Lightning.Workflows.create_changeset(%WebhookAuthMethod{auth_type: :api}, %{})
-%WebhookAuthMethod{api_key: some_new_api_key}
Creating a changeset for a non-API type auth method:
iex> Lightning.Workflows.create_changeset(%WebhookAuthMethod{auth_type: :other}, %{})
-%WebhookAuthMethod{}
Creating a changeset for an API type auth method:
iex> Lightning.Workflows.create_changeset(%WebhookAuthMethod{auth_type: :api}, %{})
+%WebhookAuthMethod{api_key: some_new_api_key}
Creating a changeset for a non-API type auth method:
iex> Lightning.Workflows.create_changeset(%WebhookAuthMethod{auth_type: :other}, %{})
+%WebhookAuthMethod{}
Successful deletion:
iex> delete_auth_method(%WebhookAuthMethod{id: "some_id"})
-{:ok, %WebhookAuthMethod{}}
Deletion fails due to the item not existing or other conflict:
iex> delete_auth_method(%WebhookAuthMethod{id: "non_existing_id"})
-{:error, reason}
Successful deletion:
iex> delete_auth_method(%WebhookAuthMethod{id: "some_id"})
+{:ok, %WebhookAuthMethod{}}
Deletion fails due to the item not existing or other conflict:
iex> delete_auth_method(%WebhookAuthMethod{id: "non_existing_id"})
+{:error, reason}
When a matching WebhookAuthMethod
is found:
iex> Lightning.Workflows.find_by_api_key("existing_api_key", %Project{id: "existing_project_id"})
-%WebhookAuthMethod{}
When there is no matching WebhookAuthMethod
:
iex> Lightning.Workflows.find_by_api_key("non_existing_api_key", %Project{id: "existing_project_id"})
+When a matching WebhookAuthMethod
is found:
iex> Lightning.Workflows.find_by_api_key("existing_api_key", %Project{id: "existing_project_id"})
+%WebhookAuthMethod{}
When there is no matching WebhookAuthMethod
:
iex> Lightning.Workflows.find_by_api_key("non_existing_api_key", %Project{id: "existing_project_id"})
nil
When a WebhookAuthMethod
with the given ID exists:
iex> Lightning.Workflows.find_by_id!("existing_id")
-%WebhookAuthMethod{}
When there is no WebhookAuthMethod
with the given ID:
iex> Lightning.Workflows.find_by_id!("non_existing_id")
+When a WebhookAuthMethod
with the given ID exists:
iex> Lightning.Workflows.find_by_id!("existing_id")
+%WebhookAuthMethod{}
When there is no WebhookAuthMethod
with the given ID:
iex> Lightning.Workflows.find_by_id!("non_existing_id")
** (Ecto.NoResultsError)
@@ -652,8 +652,8 @@ find_by_username_and_password(username, pas
Examples
-When a matching WebhookAuthMethod
is found and the password is valid:
iex> Lightning.Workflows.find_by_username_and_password("existing_username", "valid_password", %Project{id: "existing_project_id"})
-%WebhookAuthMethod{}
When the username is found but the password is invalid or no matching record is found:
iex> Lightning.Workflows.find_by_username_and_password("existing_username", "invalid_password", %Project{id: "existing_project_id"})
+When a matching WebhookAuthMethod
is found and the password is valid:
iex> Lightning.Workflows.find_by_username_and_password("existing_username", "valid_password", %Project{id: "existing_project_id"})
+%WebhookAuthMethod{}
When the username is found but the password is invalid or no matching record is found:
iex> Lightning.Workflows.find_by_username_and_password("existing_username", "invalid_password", %Project{id: "existing_project_id"})
nil
@@ -702,9 +702,9 @@ list_for_project(project)
Examples
-When the project exists and has associated auth methods:
iex> list_for_project(%Project{id: "existing_project_id"})
-[%WebhookAuthMethod{}, ...]
When the project does not exist or has no associated auth methods:
iex> list_for_project(%Project{id: "non_existing_project_id"})
-[]
+When the project exists and has associated auth methods:
iex> list_for_project(%Project{id: "existing_project_id"})
+[%WebhookAuthMethod{}, ...]
When the project does not exist or has no associated auth methods:
iex> list_for_project(%Project{id: "non_existing_project_id"})
+[]
@@ -752,9 +752,9 @@ list_for_trigger(trigger)
Examples
-When the Trigger
has associated WebhookAuthMethod
s not scheduled for deletion:
iex> Lightning.Workflows.list_for_trigger(%Trigger{id: "existing_trigger_id"})
-[%WebhookAuthMethod{}, ...]
When the Trigger
has no associated WebhookAuthMethod
s or they are all scheduled for deletion:
iex> Lightning.Workflows.list_for_trigger(%Trigger{id: "trigger_without_methods"})
-[]
+When the Trigger
has associated WebhookAuthMethod
s not scheduled for deletion:
iex> Lightning.Workflows.list_for_trigger(%Trigger{id: "existing_trigger_id"})
+[%WebhookAuthMethod{}, ...]
When the Trigger
has no associated WebhookAuthMethod
s or they are all scheduled for deletion:
iex> Lightning.Workflows.list_for_trigger(%Trigger{id: "trigger_without_methods"})
+[]
@@ -807,10 +807,10 @@ perform(job)
Example
-%Oban.Job{
-args: %{"type" => "purge_deleted"}
-}
-|> MyModule.perform()
+%Oban.Job{
+args: %{"type" => "purge_deleted"}
+}
+|> MyModule.perform()
# => {:ok, %{disassociated_count: 2, deleted_count: 2}}
@@ -864,9 +864,9 @@ schedule_for_deletion(webhook_auth_method,
Examples
-When a webhook auth method is successfully scheduled for deletion:
iex> Lightning.Workflows.schedule_for_deletion(%WebhookAuthMethod{id: some_id})
-{:ok, %WebhookAuthMethod{scheduled_deletion: deletion_date}}
When scheduling for deletion fails due to validation errors:
iex> Lightning.Workflows.schedule_for_deletion(%WebhookAuthMethod{})
-{:error, %Ecto.Changeset{}}
+When a webhook auth method is successfully scheduled for deletion:
iex> Lightning.Workflows.schedule_for_deletion(%WebhookAuthMethod{id: some_id})
+{:ok, %WebhookAuthMethod{scheduled_deletion: deletion_date}}
When scheduling for deletion fails due to validation errors:
iex> Lightning.Workflows.schedule_for_deletion(%WebhookAuthMethod{})
+{:error, %Ecto.Changeset{}}
@@ -916,9 +916,9 @@ update_auth_method(webhook_auth_method, att
Examples
-Successful update:
iex> update_auth_method(webhook_auth_method, %{field: new_value}, actor: %User{})
-{:ok, %WebhookAuthMethod{}}
Update fails due to invalid data:
iex> update_auth_method(webhook_auth_method, %{field: bad_value}, actor: %User{})
-{:error, %Ecto.Changeset{}}
+Successful update:
iex> update_auth_method(webhook_auth_method, %{field: new_value}, actor: %User{})
+{:ok, %WebhookAuthMethod{}}
Update fails due to invalid data:
iex> update_auth_method(webhook_auth_method, %{field: bad_value}, actor: %User{})
+{:error, %Ecto.Changeset{}}
@@ -974,9 +974,9 @@ update_trigger_auth_methods(trigger, auth_m
Examples
-Successful association update:
iex> update_trigger_auth_methods(trigger, [webhook_auth_method], actor: %User{})
-{:ok, %Trigger{}}
Update fails due to an invalid changeset:
iex> update_trigger_auth_methods(trigger, [invalid_webhook_auth_method], actor: %User{})
-{:error, %Ecto.Changeset{}}
+Successful association update:
iex> update_trigger_auth_methods(trigger, [webhook_auth_method], actor: %User{})
+{:ok, %Trigger{}}
Update fails due to an invalid changeset:
iex> update_trigger_auth_methods(trigger, [invalid_webhook_auth_method], actor: %User{})
+{:error, %Ecto.Changeset{}}
diff --git a/Lightning.WorkOrders.ExportWorker.html b/Lightning.WorkOrders.ExportWorker.html
index 69bf95a11c..f230657dbc 100644
--- a/Lightning.WorkOrders.ExportWorker.html
+++ b/Lightning.WorkOrders.ExportWorker.html
@@ -138,7 +138,7 @@
This module handles the export of work orders for a given project. The export process is performed asynchronously using the Oban background job system.
## Responsibilities
- Enqueueing Export Jobs: The
enqueue_export/2
function creates and enqueues an Oban job for exporting work orders based on the given project and search parameters. - Processing Exports: The
perform/1
function is the main entry point for executing the export job. It retrieves the project, processes work orders, and handles the export process. - Export Logic: The export logic involves querying work orders, extracting relevant entities, processing logs and dataclips asynchronously, and writing the final export data to files.
- Error Handling: The module includes comprehensive error handling and logging to ensure that issues during the export process are recorded and can be diagnosed.
- Zip File Creation: After processing, the exported files are compressed into a zip file for easy download or further use.
## Usage
- To enqueue an export job, call
enqueue_export/2
with the project and search parameters. - The export process is triggered by Oban and runs in the
history_exports
queue, limited to a single attempt per job.
## Example
# Enqueue an export job
- Lightning.WorkOrders.ExportWorker.enqueue_export(project, search_params)
+ Lightning.WorkOrders.ExportWorker.enqueue_export(project, search_params)
# The job will run in the background and log the status of the export process.
This module is designed to handle potentially large datasets efficiently by using streaming, async processing, and error recovery mechanisms.
diff --git a/Lightning.WorkOrders.html b/Lightning.WorkOrders.html
index 9b942f46fc..0a54108afa 100644
--- a/Lightning.WorkOrders.html
+++ b/Lightning.WorkOrders.html
@@ -451,7 +451,7 @@ create_for(target, multi \\ Multi.new(), op
-
Create a new Work Order.
For a webhook
create_for(trigger, workflow: workflow, dataclip: dataclip)
For a user
create_for(job, workflow: workflow, dataclip: dataclip, user: user)
+Create a new Work Order.
For a webhook
create_for(trigger, workflow: workflow, dataclip: dataclip)
For a user
create_for(job, workflow: workflow, dataclip: dataclip, user: user)
@@ -503,7 +503,7 @@ get(id, opts \\ [])
-Get a Work Order by id.
Optionally preload associations by passing a list of atoms to :include
.
Lightning.WorkOrders.get(id, include: [:runs])
+Get a Work Order by id.
Optionally preload associations by passing a list of atoms to :include
.
Lightning.WorkOrders.get(id, include: [:runs])
diff --git a/Lightning.Workflows.Job.html b/Lightning.Workflows.Job.html
index 49abe996e4..6022c6d522 100644
--- a/Lightning.Workflows.Job.html
+++ b/Lightning.Workflows.Job.html
@@ -356,17 +356,17 @@ put_workflow(changeset, workflow)
Attaches a workflow to a job, this is useful when you have an unpersisted
Workflow changeset - and want it to be created at the same time as a Job.
Example:
workflow =
- Ecto.Changeset.cast(
- %Lightning.Workflows.Workflow{},
- %{ "project_id" => attrs[:project_id], "id" => Ecto.UUID.generate() },
- [:project_id, :id]
- )
+ Ecto.Changeset.cast(
+ %Lightning.Workflows.Workflow{},
+ %{ "project_id" => attrs[:project_id], "id" => Ecto.UUID.generate() },
+ [:project_id, :id]
+ )
job =
- %Job{}
- |> Ecto.Changeset.change()
- |> Job.put_workflow(workflow)
- |> Job.changeset(attrs)
+
%Job{}
+ |> Ecto.Changeset.change()
+ |> Job.put_workflow(workflow)
+ |> Job.changeset(attrs)
diff --git a/Lightning.Workflows.Presence.html b/Lightning.Workflows.Presence.html
index f5c7fc72ad..82526d7628 100644
--- a/Lightning.Workflows.Presence.html
+++ b/Lightning.Workflows.Presence.html
@@ -352,27 +352,27 @@ build_presences_summary(presences, params)<
Examples
-iex> presences = [
-...> %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
-...> %{user: %{id: 2}, joined_at: ~N[2024-07-03 12:05:00], active_sessions: 1},
-...> %{user: %{id: 3}, joined_at: ~N[2024-07-03 12:10:00], active_sessions: 1}
-...> ]
-iex> params = %{
-...> current_user_presence: %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
-...> current_user: %{id: 1},
-...> view_only_users_ids: [2]
-...> }
-iex> build_presences_summary(presences, params)
-%{
- presences: [
- %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
- %{user: %{id: 2}, joined_at: ~N[2024-07-03 12:05:00], active_sessions: 1},
- %{user: %{id: 3}, joined_at: ~N[2024-07-03 12:10:00], active_sessions: 1}
- ],
- prior_user_presence: %{user: %{id: 3}, joined_at: ~N[2024-07-03 12:10:00], active_sessions: 1},
- current_user_presence: %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
+iex> presences = [
+...> %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
+...> %{user: %{id: 2}, joined_at: ~N[2024-07-03 12:05:00], active_sessions: 1},
+...> %{user: %{id: 3}, joined_at: ~N[2024-07-03 12:10:00], active_sessions: 1}
+...> ]
+iex> params = %{
+...> current_user_presence: %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
+...> current_user: %{id: 1},
+...> view_only_users_ids: [2]
+...> }
+iex> build_presences_summary(presences, params)
+%{
+ presences: [
+ %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
+ %{user: %{id: 2}, joined_at: ~N[2024-07-03 12:05:00], active_sessions: 1},
+ %{user: %{id: 3}, joined_at: ~N[2024-07-03 12:10:00], active_sessions: 1}
+ ],
+ prior_user_presence: %{user: %{id: 3}, joined_at: ~N[2024-07-03 12:10:00], active_sessions: 1},
+ current_user_presence: %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
has_presence_edit_priority: true
-}
+}
@@ -516,8 +516,8 @@ list_presences(topic)
Examples
-iex> Lightning.Workflows.Presence.list_presences("workflow:canvas")
-[%Lightning.Workflows.Presence{user: %User{id: 1}, ...}, ...]
+iex> Lightning.Workflows.Presence.list_presences("workflow:canvas")
+[%Lightning.Workflows.Presence{user: %User{id: 1}, ...}, ...]
@@ -553,12 +553,12 @@ new_user_presence(user, joined_at, active_s
Examples
-iex> Lightning.Workflows.Presence.new_user_presence(%User{id: 1}, 1625597762000000)
-%Lightning.Workflows.Presence{
- user: %User{id: 1},
+iex> Lightning.Workflows.Presence.new_user_presence(%User{id: 1}, 1625597762000000)
+%Lightning.Workflows.Presence{
+ user: %User{id: 1},
joined_at: 1625597762000000,
active_sessions: 0
-}
+}
@@ -636,7 +636,7 @@ track_user_presence(user, topic, pid)
Examples
-iex> Lightning.Workflows.Presence.track_user_presence(%User{id: 1}, "room:lobby", self())
+iex> Lightning.Workflows.Presence.track_user_presence(%User{id: 1}, "room:lobby", self())
:ok
diff --git a/Lightning.Workflows.html b/Lightning.Workflows.html
index 62a4c3b2e3..2a0ec2d90f 100644
--- a/Lightning.Workflows.html
+++ b/Lightning.Workflows.html
@@ -444,8 +444,8 @@ change_workflow(workflow, attrs \\ %{})
Examples
-iex> change_workflow(workflow)
-%Ecto.Changeset{data: %Workflow{}}
+iex> change_workflow(workflow)
+%Ecto.Changeset{data: %Workflow{}}
@@ -507,12 +507,12 @@ get_edge_by_trigger(trigger)
Examples
-trigger = %Trigger{id: 1, ...}
-Lightning.Workflows.get_edge_by_trigger(trigger)
+trigger = %Trigger{id: 1, ...}
+Lightning.Workflows.get_edge_by_trigger(trigger)
# => %Edge{source_trigger: %Trigger{}, target_job: %Job{}, ...}
-non_existent_trigger = %Trigger{id: 999, ...}
-Lightning.Workflows.get_edge_by_trigger(non_existent_trigger)
+non_existent_trigger = %Trigger{id: 999, ...}
+Lightning.Workflows.get_edge_by_trigger(non_existent_trigger)
# => nil
@@ -582,10 +582,10 @@ get_trigger_by_webhook(path)
Examples
-Lightning.Workflows.get_trigger_by_webhook("some_path_or_id")
+Lightning.Workflows.get_trigger_by_webhook("some_path_or_id")
# => %Trigger{id: 1, custom_path: "some_path_or_id", ...}
-Lightning.Workflows.get_trigger_by_webhook("non_existent_path_or_id")
+Lightning.Workflows.get_trigger_by_webhook("non_existent_path_or_id")
# => nil
@@ -660,10 +660,10 @@ get_workflow!(id)
Examples
-iex> get_workflow!(123)
-%Workflow{}
+iex> get_workflow!(123)
+%Workflow{}
-iex> get_workflow!(456)
+iex> get_workflow!(456)
** (Ecto.NoResultsError)
@@ -767,8 +767,8 @@ list_workflows()
Examples
-iex> list_workflows()
-[%Workflow{}, ...]
+iex> list_workflows()
+[%Workflow{}, ...]
@@ -798,8 +798,8 @@ mark_for_deletion(workflow, attrs \\ %{})
Examples
-iex> change_request_deletion(workflow)
-%Ecto.Changeset{data: %Workflow{}}
+iex> change_request_deletion(workflow)
+%Ecto.Changeset{data: %Workflow{}}
diff --git a/Lightning.epub b/Lightning.epub
index be236c905648a0331e56ab70129557f43596e00f..d10c41f396c3885f28ef767777288be2c2aeaee6 100644
GIT binary patch
delta 225289
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