From 7b7d14fc1842a83f2e8b0561088c07a78f8ee0b1 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 868549d0f2..aab5149c5d 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 b43763a399..aa05edcea4 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 a59368ca44..5ff16a1873 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 0f02af469f..104a9848b4 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 52d6d1db19..dd3f3fb345 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 748dddff50..afec540ff0 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 9d57a4a91e..0a3123d5e4 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 00a65dd905..a71fc1aeb4 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 bd238faa34..9c9e56c61b 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 8491cd2d08..b3afada48a 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 2ff5c27cb3..bd3cd55bb3 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 7a7da31ebc..9184d7ec30 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 256ceb3492..6c0f513cb4 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 ead7646b57..768442e97a 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 b3332533ef..6e4b9dea00 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 b970c7b15c..7869eca249 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 394a2f7018..86e543b6da 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 db22843ab7..5097c51a7e 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 4f9cdac591..f2728fc4a6 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 743932a0bf..c3bffdc76f 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 adca6451b2..3f5f58b914 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 029b263943..758aeff1e0 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 f9f62d992e..b158d56de4 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 f8d0db5eb4d7b70ec083708b2fc0efaececa7bb9..4f49a6036948294077b99f931268607186132482 100644
GIT binary patch
delta 226914
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
wla@
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