From 869ec626d6125e29bc66222baf846a2a6b4f8bcc 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 e6f060a72e..97d3d0790e 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 51ad7d3574..a3f559268a 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 334f675c64..5a35ace881 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 b36df85ba8..d5ffef4dd7 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 8b0f8532e2..b06358564d 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 bb493ea616..f70f6f6840 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 fb693ee227..b9ef0cc650 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 082a4abf87..9d08fb28cb 100644
--- a/Lightning.Projects.html
+++ b/Lightning.Projects.html
@@ -662,8 +662,8 @@ change_project(project, attrs \\ %{})
Examples
-iex> change_project(project)
-%Ecto.Changeset{data: %Project{}}
+iex> change_project(project)
+%Ecto.Changeset{data: %Project{}}
@@ -695,11 +695,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{}}
@@ -728,11 +728,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{}}
@@ -797,8 +797,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}
@@ -870,10 +870,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)
@@ -968,10 +968,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)
@@ -1001,16 +1001,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
@@ -1061,10 +1061,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)
@@ -1242,8 +1242,8 @@ list_projects()
Examples
-iex> list_projects()
-[%Project{}, ...]
+iex> list_projects()
+[%Project{}, ...]
@@ -1723,11 +1723,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{}}
@@ -1755,11 +1755,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{}}
@@ -1840,8 +1840,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 ef0c878461..8d7a393777 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 e4b46a7cc2..395cbdc3f0 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 ef44070bfd..f1877fc25e 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 f5ea36a1c4..9078c7f3ad 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 a9c100ed90..c50548d364 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 cbf504dcee..5a9e1f9ee4 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 90fd64e885..037f473dc9 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 2d8a480fb5..1f457f6f1b 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 c33f7cbc83..03e29540bd 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 dd76e1f5cb..d757cb1afe 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 6f6cd2eb86..1fc7e93aa5 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 49dbb3df20..affbdcd8e2 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 6a1b39a336..a101eebf98 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 5cef0bd3b7..89324d716b 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 e3a7648801..e1808ed355 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 1c109c0a9209aeca8c9c76cf13a39b00ac6928af..4600789fee36ce774cc6f5a81ce1fd131310a846 100644
GIT binary patch
delta 175828
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 g<74WkNS7i?I>n!8p%%>ZBjj-2ZX2N{IMo(XfC
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