From 76807d8ec556d87b1d0c60d6fde7f7ff0bb35a8c 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{}
+
@@ -1577,10 +1577,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{}
+
@@ -1675,10 +1675,10 @@ iex> get_user(123)
+%User{}
-iex> get_user!(456)
+iex> get_user!(456)
nil
get_user_by_email(email)
Examples
-iex> get_user_by_email("foo@example.com")
-%User{}
+
@@ -1707,10 +1707,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{}
+
@@ -1739,10 +1739,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{}
+
@@ -1939,8 +1939,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
@@ -434,10 +434,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.Collections.html b/Lightning.Collections.html index 1ddaa8a5b0..1dd6894a79 100644 --- a/Lightning.Collections.html +++ b/Lightning.Collections.html @@ -308,11 +308,11 @@iex> create_collection(%{name: "New Collection", description: "Description here"})
-{:ok, %Collection{}}
+iex> create_collection(%{name: "New Collection", description: "Description here"})
+{:ok, %Collection{}}
-iex> create_collection(%{name: nil})
-{:error, %Ecto.Changeset{}}
+
iex> create_collection(%{name: nil})
+{:error, %Ecto.Changeset{}}
iex> list_collections()
-[%Collection{}, ...]
+iex> list_collections()
+[%Collection{}, ...]
-iex> list_collections(order_by: [asc: :inserted_at], preload: [:project, :user])
-[%Collection{}, ...]
+
iex> list_collections(order_by: [asc: :inserted_at], preload: [:project, :user])
+[%Collection{}, ...]
iex> update_collection(collection, %{name: "Updated Name"})
-{:ok, %Collection{}}
+iex> update_collection(collection, %{name: "Updated Name"})
+{:ok, %Collection{}}
-iex> update_collection(collection, %{name: nil})
-{:error, %Ecto.Changeset{}}
+
iex> update_collection(collection, %{name: nil})
+{:error, %Ecto.Changeset{}}
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 d56a79fcfa..7b362c8a19 100644
--- a/Lightning.Credentials.html
+++ b/Lightning.Credentials.html
@@ -408,8 +408,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
@@ -661,11 +661,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"]
@@ -705,9 +705,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}]
@@ -818,11 +818,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{}}
@@ -879,11 +879,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.Helpers.html b/Lightning.Helpers.html
index e8a8c71841..a53a85564d 100644
--- a/Lightning.Helpers.html
+++ b/Lightning.Helpers.html
@@ -327,10 +327,10 @@ copy_error(changeset, original_key, new_key
Example
-iex> changeset = %Ecto.Changeset{errors: [name: {"has already been taken", []}]}
-iex> updated_changeset = Lightning.Helpers.copy_error(changeset, :name, :raw_name)
+iex> changeset = %Ecto.Changeset{errors: [name: {"has already been taken", []}]}
+iex> updated_changeset = Lightning.Helpers.copy_error(changeset, :name, :raw_name)
iex> updated_changeset.errors
-[name: {"has already been taken", []}, raw_name: {"has already been taken", []}]
If the original_key
doesn't exist in the errors, or if the new_key
already exists and overwrite
is set to false
, the changeset is returned unchanged.
+[name: {"has already been taken", []}, raw_name: {"has already been taken", []}]
If the original_key
doesn't exist in the errors, or if the new_key
already exists and overwrite
is set to false
, the changeset is returned unchanged.
@@ -449,10 +449,10 @@ url_safe_name(name)
Examples
-iex> url_safe_name("My Project!!")
+iex> url_safe_name("My Project!!")
"my-project"
-iex> url_safe_name(nil)
+iex> url_safe_name(nil)
""
diff --git a/Lightning.Invocation.html b/Lightning.Invocation.html
index 2fd1f63f6e..c333e60323 100644
--- a/Lightning.Invocation.html
+++ b/Lightning.Invocation.html
@@ -531,8 +531,8 @@ change_dataclip(dataclip, attrs \\ %{})
Examples
-iex> change_dataclip(dataclip)
-%Ecto.Changeset{data: %Dataclip{}}
+iex> change_dataclip(dataclip)
+%Ecto.Changeset{data: %Dataclip{}}
@@ -562,8 +562,8 @@ change_step(step, attrs \\ %{})
Examples
-iex> change_step(step)
-%Ecto.Changeset{data: %Step{}}
+iex> change_step(step)
+%Ecto.Changeset{data: %Step{}}
@@ -623,11 +623,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{}}
@@ -655,11 +655,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{}}
@@ -729,14 +729,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{}
@@ -770,10 +770,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)
@@ -971,10 +971,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)
@@ -1103,8 +1103,8 @@ list_dataclips()
Examples
-iex> list_dataclips()
-[%Dataclip{}, ...]
+iex> list_dataclips()
+[%Dataclip{}, ...]
@@ -1213,8 +1213,8 @@ list_steps()
Examples
-iex> list_steps()
-[%Step{}, ...]
+iex> list_steps()
+[%Step{}, ...]
@@ -1341,7 +1341,7 @@ search_workorders(project)
Example:
-search_workorders(%Project{id: 1}, %SearchParams{status: ["completed"]})
+search_workorders(%Project{id: 1}, %SearchParams{status: ["completed"]})
@@ -1447,11 +1447,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 66d3fd4b47..ac52c51b2e 100644
--- a/Lightning.Jobs.html
+++ b/Lightning.Jobs.html
@@ -308,8 +308,8 @@ change_job(job, attrs \\ %{})
Examples
-iex> change_job(job)
-%Ecto.Changeset{data: %Job{}}
+iex> change_job(job)
+%Ecto.Changeset{data: %Job{}}
@@ -339,11 +339,11 @@ create_job(attrs \\ %{}, actor)
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{}}
@@ -407,10 +407,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)
@@ -622,11 +622,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 ecdcae5bbf..a86bcc797d 100644
--- a/Lightning.KafkaTriggers.MessageRecovery.html
+++ b/Lightning.KafkaTriggers.MessageRecovery.html
@@ -153,7 +153,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 3c141fcf0c..8a4fe4464e 100644
--- a/Lightning.OauthClients.html
+++ b/Lightning.OauthClients.html
@@ -269,8 +269,8 @@ change_client(client, attrs \\ %{})
Examples
-iex> change_client(%OauthClient{}, %{name: "New Client"})
-%Ecto.Changeset{...}
+iex> change_client(%OauthClient{}, %{name: "New Client"})
+%Ecto.Changeset{...}
@@ -355,11 +355,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{}}
@@ -405,10 +405,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)
@@ -449,9 +449,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}]
@@ -491,11 +491,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 e5bd44c625..9877bfcf33 100644
--- a/Lightning.Policies.Permissions.html
+++ b/Lightning.Policies.Permissions.html
@@ -139,13 +139,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
@@ -222,11 +222,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}
@@ -256,10 +256,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 ac3c8e437a..497c771b9b 100644
--- a/Lightning.Projects.html
+++ b/Lightning.Projects.html
@@ -692,8 +692,8 @@ change_project(project, attrs \\ %{})
Examples
-iex> change_project(project)
-%Ecto.Changeset{data: %Project{}}
+iex> change_project(project)
+%Ecto.Changeset{data: %Project{}}
@@ -725,11 +725,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{}}
@@ -758,11 +758,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{}}
@@ -917,8 +917,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}
@@ -990,10 +990,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)
@@ -1088,10 +1088,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)
@@ -1121,16 +1121,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
@@ -1181,10 +1181,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)
@@ -1386,8 +1386,8 @@ list_projects()
Examples
-iex> list_projects()
-[%Project{}, ...]
+iex> list_projects()
+[%Project{}, ...]
@@ -1869,11 +1869,11 @@ update_project(project, attrs, user \\ nil)
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{}}
@@ -1901,11 +1901,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{}}
@@ -1964,8 +1964,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 8d1b890f3c..7e5e2306c6 100644
--- a/Lightning.PromEx.html
+++ b/Lightning.PromEx.html
@@ -143,24 +143,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
...
@@ -168,7 +168,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 ce4b0d46d3..1bb61e99c5 100644
--- a/Lightning.Repo.html
+++ b/Lightning.Repo.html
@@ -1740,13 +1740,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 48e9767248..8153ea38ba 100644
--- a/Lightning.Runs.Query.html
+++ b/Lightning.Runs.Query.html
@@ -243,7 +243,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 42a540e9ff..53de407e01 100644
--- a/Lightning.Runs.html
+++ b/Lightning.Runs.html
@@ -479,7 +479,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 df70ad4b42..c555926a8e 100644
--- a/Lightning.Runtime.LogAgent.html
+++ b/Lightning.Runtime.LogAgent.html
@@ -139,9 +139,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 a2f79bc30d..cc31af3ce5 100644
--- a/Lightning.Runtime.RuntimeManager.html
+++ b/Lightning.Runtime.RuntimeManager.html
@@ -147,8 +147,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 dd88fab2f5..70a820b962 100644
--- a/Lightning.Scrubber.html
+++ b/Lightning.Scrubber.html
@@ -138,11 +138,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 3bfa7a83f8..96f0ef2ff3 100644
--- a/Lightning.Storage.GCS.html
+++ b/Lightning.Storage.GCS.html
@@ -151,10 +151,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 6e045e193b..7dcd07c584 100644
--- a/Lightning.Storage.Local.html
+++ b/Lightning.Storage.Local.html
@@ -157,11 +157,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 af1b1caa0a..dc089c57c4 100644
--- a/Lightning.Storage.ProjectFileDefinition.html
+++ b/Lightning.Storage.ProjectFileDefinition.html
@@ -139,13 +139,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)
@@ -654,8 +654,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
@@ -704,9 +704,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"})
+[]
@@ -754,9 +754,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"})
+[]
@@ -809,10 +809,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}}
@@ -866,9 +866,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{}}
@@ -918,9 +918,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{}}
@@ -976,9 +976,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 458c62e65b..ff5a9f621e 100644
--- a/Lightning.WorkOrders.ExportWorker.html
+++ b/Lightning.WorkOrders.ExportWorker.html
@@ -139,7 +139,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 153994e049..f2073e8173 100644
--- a/Lightning.WorkOrders.html
+++ b/Lightning.WorkOrders.html
@@ -453,7 +453,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)
@@ -505,7 +505,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 4f70240983..3d5a8b1ecc 100644
--- a/Lightning.Workflows.Job.html
+++ b/Lightning.Workflows.Job.html
@@ -358,17 +358,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 6b44906895..69015f9747 100644
--- a/Lightning.Workflows.Presence.html
+++ b/Lightning.Workflows.Presence.html
@@ -354,27 +354,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
-}
+}
@@ -518,8 +518,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}, ...}, ...]
@@ -555,12 +555,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
-}
+}
@@ -638,7 +638,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 a6f71221e8..e1bfbf6b29 100644
--- a/Lightning.Workflows.html
+++ b/Lightning.Workflows.html
@@ -458,8 +458,8 @@ change_workflow(workflow, attrs \\ %{})
Examples
-iex> change_workflow(workflow)
-%Ecto.Changeset{data: %Workflow{}}
+iex> change_workflow(workflow)
+%Ecto.Changeset{data: %Workflow{}}
@@ -521,12 +521,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
@@ -596,10 +596,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
@@ -654,14 +654,14 @@ get_workflow(id, opts \\ [])
Examples
-iex> get_workflow(123)
-%Workflow{}
+iex> get_workflow(123)
+%Workflow{}
-iex> get_workflow(456)
+iex> get_workflow(456)
nil
-iex> get_workflow(123, include: [:triggers])
-%Workflow{triggers: [...]}
+iex> get_workflow(123, include: [:triggers])
+%Workflow{triggers: [...]}
@@ -691,14 +691,14 @@ get_workflow!(id, opts \\ [])
Examples
-iex> get_workflow!(123)
-%Workflow{}
+iex> get_workflow!(123)
+%Workflow{}
-iex> get_workflow!(456)
+iex> get_workflow!(456)
** (Ecto.NoResultsError)
-iex> get_workflow!(123, include: [:triggers])
-%Workflow{triggers: [...]}
+iex> get_workflow!(123, include: [:triggers])
+%Workflow{triggers: [...]}
@@ -801,8 +801,8 @@ list_workflows()
Examples
-iex> list_workflows()
-[%Workflow{}, ...]
+iex> list_workflows()
+[%Workflow{}, ...]
@@ -832,8 +832,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{}}
@@ -1014,16 +1014,16 @@ Using an Ecto.Changeset
-changeset = Ecto.Changeset.change(%Workflow{}, %{triggers: [%Trigger{enabled: false}]})
-updated_changeset = update_triggers_enabled_state(changeset, true)
+changeset = Ecto.Changeset.change(%Workflow{}, %{triggers: [%Trigger{enabled: false}]})
+updated_changeset = update_triggers_enabled_state(changeset, true)
# The triggers in the changeset will now have `enabled: true`.
Using a Workflow
struct
-workflow = %Workflow{triggers: [%Trigger{enabled: false}]}
-updated_changeset = update_triggers_enabled_state(workflow, true)
+workflow = %Workflow{triggers: [%Trigger{enabled: false}]}
+updated_changeset = update_triggers_enabled_state(workflow, true)
# The returned changeset will have triggers with `enabled: true`.
diff --git a/Lightning.epub b/Lightning.epub
index f2cb5be0a5245cbe9f1f1038cbcd617a66ef0526..f09cc82e140fde512a3cf6777b1021ef65202f1e 100644
GIT binary patch
delta 241470
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