21 Commits

Author SHA1 Message Date
eeef7c94cd fix emails 2024-07-28 13:35:34 -04:00
3c3391b3a6 update deps 2024-07-28 13:35:34 -04:00
52460024b9 update versions 2024-07-28 13:35:34 -04:00
48f7c8d18e fix empty invite index page 2024-02-24 13:14:38 -05:00
571e0b65b6 fix faq page copy 2024-02-23 23:36:00 -05:00
7dc2047e97 fix missing ssl and crypto packages 2024-02-23 22:44:36 -05:00
f769e710d8 sanitize tags while they are being typed 2024-02-23 22:39:01 -05:00
d09f698b71 remove requirement for note and content to have content 2024-02-23 22:34:08 -05:00
8666f663ba Prevent possible additional submissions 2024-02-23 22:31:51 -05:00
22ccea893c sanitize titles while they are being typed 2024-02-23 22:31:15 -05:00
362c406471 fix credo warning for is_owner? 2024-02-23 22:18:25 -05:00
2a87037f06 fix credo warning for is_owner_or_admin? 2024-02-23 22:17:56 -05:00
53d0dcfb15 fix credo warning for is_admin? 2024-02-23 22:17:19 -05:00
c892b5449b fix credo warning for is_already_admin? 2024-02-23 22:16:08 -05:00
7cd9dca958 update elixir deps 2024-02-23 22:14:28 -05:00
0e8ddc22c5 update npm deps 2024-02-23 22:14:28 -05:00
3671ad6199 update tool versions 2024-02-23 22:14:20 -05:00
7189c955c3 bump version 2023-11-26 17:30:20 -05:00
f56ecc0ba3 fix content being displayed when blank 2023-11-26 17:30:14 -05:00
fdfca3f7a5 bump version 2023-11-26 11:25:29 -05:00
c61b2c67b7 fix issue with displaying content 2023-11-26 11:25:26 -05:00
57 changed files with 4515 additions and 3533 deletions

@ -17,7 +17,7 @@ steps:
- .mix
- name: test
image: elixir:1.15.6-alpine
image: elixir:1.17.0-alpine
environment:
TEST_DATABASE_URL: ecto://postgres:postgres@database/memex_test
HOST: testing.example.tld
@ -26,8 +26,8 @@ steps:
MIX_ENV: test
commands:
- apk add --no-cache build-base npm git
- mix local.rebar --force --if-missing
- mix local.hex --force --if-missing
- mix local.rebar --force
- mix local.hex --force
- mix deps.get
- npm set cache .npm
- npm --prefix ./assets ci --no-audit --prefer-offline

@ -1,3 +1,3 @@
elixir 1.15.6-otp-26
erlang 26.1.2
nodejs 20.6.0
elixir 1.17.0-otp-27
erlang 27.0
nodejs 22.3.0

@ -1,4 +1,4 @@
FROM elixir:1.15.6-alpine AS build
FROM elixir:1.17.0-alpine AS build
# install build dependencies
RUN apk add --no-cache build-base npm git python3
@ -7,8 +7,8 @@ RUN apk add --no-cache build-base npm git python3
WORKDIR /app
# install hex + rebar
RUN mix local.hex --force && \
mix local.rebar --force
RUN mix local.rebar --force && \
mix local.hex --force
# set build ENV
ENV MIX_ENV=prod
@ -37,7 +37,7 @@ RUN mix do compile, release
FROM alpine:latest AS app
RUN apk upgrade --no-cache && \
apk add --no-cache bash openssl libssl1.1 libcrypto1.1 libgcc libstdc++ ncurses-libs
apk add --no-cache bash openssl libssl3 libcrypto3 libgcc libstdc++ ncurses-libs
WORKDIR /app

@ -30,13 +30,15 @@ import topbar from 'topbar'
import CtrlEnter from './ctrlenter'
import Date from './date'
import DateTime from './datetime'
import SanitizeTags from './sanitizetags'
import SanitizeTitles from './sanitizetitles'
const csrfTokenElement = document.querySelector("meta[name='csrf-token']")
let csrfToken
if (csrfTokenElement) { csrfToken = csrfTokenElement.getAttribute('content') }
const liveSocket = new LiveSocket('/live', Socket, {
params: { _csrf_token: csrfToken },
hooks: { CtrlEnter, Date, DateTime }
hooks: { CtrlEnter, Date, DateTime, SanitizeTags, SanitizeTitles }
})
// Show progress bar on live navigation and form submits

@ -7,6 +7,5 @@ export default {
}
})
},
mounted () { this.addFormSubmit(this) },
updated () { this.addFormSubmit(this) }
mounted () { this.addFormSubmit(this) }
}

11
assets/js/sanitizetags.js Normal file

@ -0,0 +1,11 @@
export default {
SanitizeTags (context) {
context.el.addEventListener('keyup', (e) => {
e.target.value = e.target.value
.replace(' ', ',')
.replace(',,', ',')
.replace(/[^a-zA-Z0-9,]/, '')
})
},
mounted () { this.SanitizeTags(this) }
}

@ -0,0 +1,10 @@
export default {
SanitizeTitles (context) {
context.el.addEventListener('keyup', (e) => {
e.target.value = e.target.value
.replace(' ', '-')
.replace(/[^a-zA-Z0-9-]/, '')
})
},
mounted () { this.SanitizeTitles(this) }
}

7142
assets/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -3,8 +3,8 @@
"description": " ",
"license": "MIT",
"engines": {
"node": "v20.6.0",
"npm": "9.8.1"
"node": "v22.3.0",
"npm": "10.8.1"
},
"scripts": {
"deploy": "NODE_ENV=production webpack --mode production",
@ -13,35 +13,35 @@
"test": "standard"
},
"dependencies": {
"@fontsource/nunito-sans": "^5.0.8",
"@fortawesome/fontawesome-free": "^6.4.2",
"@fontsource/nunito-sans": "^5.0.13",
"@fortawesome/fontawesome-free": "^6.6.0",
"phoenix": "file:../deps/phoenix",
"phoenix_html": "file:../deps/phoenix_html",
"phoenix_live_view": "file:../deps/phoenix_live_view",
"topbar": "^2.0.1"
"topbar": "^3.0.0"
},
"devDependencies": {
"@babel/core": "^7.23.2",
"@babel/preset-env": "^7.23.2",
"autoprefixer": "^10.4.16",
"@babel/core": "^7.24.9",
"@babel/preset-env": "^7.25.0",
"autoprefixer": "^10.4.19",
"babel-loader": "^9.1.3",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.8.1",
"css-minimizer-webpack-plugin": "^5.0.1",
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^7.1.2",
"css-minimizer-webpack-plugin": "^7.0.0",
"file-loader": "^6.2.0",
"mini-css-extract-plugin": "^2.7.6",
"npm-check-updates": "^16.14.6",
"postcss": "^8.4.31",
"postcss-import": "^15.1.0",
"postcss-loader": "^7.3.3",
"postcss-preset-env": "^9.3.0",
"sass": "^1.69.5",
"sass-loader": "^13.3.2",
"mini-css-extract-plugin": "^2.9.0",
"npm-check-updates": "^16.14.20",
"postcss": "^8.4.40",
"postcss-import": "^16.1.0",
"postcss-loader": "^8.1.1",
"postcss-preset-env": "^9.6.0",
"sass": "^1.77.8",
"sass-loader": "^16.0.0",
"standard": "^17.1.0",
"tailwindcss": "^3.3.5",
"terser-webpack-plugin": "^5.3.9",
"webpack": "^5.89.0",
"tailwindcss": "^3.4.7",
"terser-webpack-plugin": "^5.3.10",
"webpack": "^5.93.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
"webpack-dev-server": "^5.0.4"
}
}

@ -1,3 +1,19 @@
# v0.1.16
- Fix empty invite index page
- Fix faq copy
- Fix issue with emails
- Update deps
# v0.1.15
- Sanitize titles while they are being typed
- Sanitize tags while they are being typed
- Remove requirement for note and content to have content
- Prevent possible additional submissions
- Fix content being displayed when blank
# v0.1.14
- Fix issue with item content not able to be displayed sometimes
# v0.1.13
- Update dependencies
- Fix debounces

@ -32,4 +32,4 @@ config :logger, level: :warning
config :phoenix, :plug_init_mode, :runtime
# Disable Oban
config :memex, Oban, queues: false, plugins: false
config :memex, Oban, queues: false, plugins: false, testing: :manual

@ -405,15 +405,15 @@ defmodule Memex.Accounts do
## Examples
iex> is_admin?(%User{role: :admin})
iex> admin?(%User{role: :admin})
true
iex> is_admin?(%User{})
iex> admin?(%User{})
false
"""
@spec is_admin?(User.t()) :: boolean()
def is_admin?(%User{id: user_id}) do
@spec admin?(User.t()) :: boolean()
def admin?(%User{id: user_id}) do
Repo.exists?(from u in User, where: u.id == ^user_id, where: u.role == :admin)
end
@ -422,16 +422,16 @@ defmodule Memex.Accounts do
## Examples
iex> is_already_admin?(%User{role: :admin})
iex> already_admin?(%User{role: :admin})
true
iex> is_already_admin?(%User{})
iex> already_admin?(%User{})
false
"""
@spec is_already_admin?(User.t() | nil) :: boolean()
def is_already_admin?(%User{role: :admin}), do: true
def is_already_admin?(_invalid_user), do: false
@spec already_admin?(User.t() | nil) :: boolean()
def already_admin?(%User{role: :admin}), do: true
def already_admin?(_invalid_user), do: false
## Confirmation

@ -229,12 +229,12 @@ defmodule Memex.Contexts do
context |> Context.update_changeset(attrs, user)
end
@spec is_owner_or_admin?(Context.t(), User.t()) :: boolean()
def is_owner_or_admin?(%{user_id: user_id}, %{id: user_id}), do: true
def is_owner_or_admin?(_context, %{role: :admin}), do: true
def is_owner_or_admin?(_context, _other_user), do: false
@spec owner_or_admin?(Context.t(), User.t()) :: boolean()
def owner_or_admin?(%{user_id: user_id}, %{id: user_id}), do: true
def owner_or_admin?(_context, %{role: :admin}), do: true
def owner_or_admin?(_context, _other_user), do: false
@spec is_owner?(Context.t(), User.t()) :: boolean()
def is_owner?(%{user_id: user_id}, %{id: user_id}), do: true
def is_owner?(_context, _other_user), do: false
@spec owner?(Context.t(), User.t()) :: boolean()
def owner?(%{user_id: user_id}, %{id: user_id}), do: true
def owner?(_context, _other_user), do: false
end

@ -57,7 +57,7 @@ defmodule Memex.Contexts.Context do
|> validate_format(:slug, ~r/^[\p{L}\p{N}\-]+$/,
message: dgettext("errors", "invalid format: only numbers, letters and hyphen are accepted")
)
|> validate_required([:slug, :content, :user_id, :visibility])
|> validate_required([:slug, :user_id, :visibility])
|> unique_constraint(:slug)
|> unsafe_validate_unique(:slug, Repo)
end
@ -70,7 +70,7 @@ defmodule Memex.Contexts.Context do
|> validate_format(:slug, ~r/^[\p{L}\p{N}\-]+$/,
message: dgettext("errors", "invalid format: only numbers, letters and hyphen are accepted")
)
|> validate_required([:slug, :content, :visibility])
|> validate_required([:slug, :visibility])
|> unique_constraint(:slug)
|> unsafe_validate_unique(:slug, Repo)
end

@ -229,12 +229,12 @@ defmodule Memex.Notes do
note |> Note.update_changeset(attrs, user)
end
@spec is_owner_or_admin?(Note.t(), User.t()) :: boolean()
def is_owner_or_admin?(%{user_id: user_id}, %{id: user_id}), do: true
def is_owner_or_admin?(_context, %{role: :admin}), do: true
def is_owner_or_admin?(_context, _other_user), do: false
@spec owner_or_admin?(Note.t(), User.t()) :: boolean()
def owner_or_admin?(%{user_id: user_id}, %{id: user_id}), do: true
def owner_or_admin?(_context, %{role: :admin}), do: true
def owner_or_admin?(_context, _other_user), do: false
@spec is_owner?(Note.t(), User.t()) :: boolean()
def is_owner?(%{user_id: user_id}, %{id: user_id}), do: true
def is_owner?(_context, _other_user), do: false
@spec owner?(Note.t(), User.t()) :: boolean()
def owner?(%{user_id: user_id}, %{id: user_id}), do: true
def owner?(_context, _other_user), do: false
end

@ -56,7 +56,7 @@ defmodule Memex.Notes.Note do
|> validate_format(:slug, ~r/^[\p{L}\p{N}\-]+$/,
message: dgettext("errors", "invalid format: only numbers, letters and hyphen are accepted")
)
|> validate_required([:slug, :content, :user_id, :visibility])
|> validate_required([:slug, :user_id, :visibility])
|> unique_constraint(:slug)
|> unsafe_validate_unique(:slug, Repo)
end
@ -69,7 +69,7 @@ defmodule Memex.Notes.Note do
|> validate_format(:slug, ~r/^[\p{L}\p{N}\-]+$/,
message: dgettext("errors", "invalid format: only numbers, letters and hyphen are accepted")
)
|> validate_required([:slug, :content, :visibility])
|> validate_required([:slug, :visibility])
|> unique_constraint(:slug)
|> unsafe_validate_unique(:slug, Repo)
end

@ -231,12 +231,12 @@ defmodule Memex.Pipelines do
pipeline |> Pipeline.update_changeset(attrs, user)
end
@spec is_owner_or_admin?(Pipeline.t(), User.t()) :: boolean()
def is_owner_or_admin?(%{user_id: user_id}, %{id: user_id}), do: true
def is_owner_or_admin?(_context, %{role: :admin}), do: true
def is_owner_or_admin?(_context, _other_user), do: false
@spec owner_or_admin?(Pipeline.t(), User.t()) :: boolean()
def owner_or_admin?(%{user_id: user_id}, %{id: user_id}), do: true
def owner_or_admin?(_context, %{role: :admin}), do: true
def owner_or_admin?(_context, _other_user), do: false
@spec is_owner?(Pipeline.t(), User.t()) :: boolean()
def is_owner?(%{user_id: user_id}, %{id: user_id}), do: true
def is_owner?(_context, _other_user), do: false
@spec owner?(Pipeline.t(), User.t()) :: boolean()
def owner?(%{user_id: user_id}, %{id: user_id}), do: true
def owner?(_context, _other_user), do: false
end

@ -69,6 +69,7 @@ defmodule MemexWeb do
def html do
quote do
# credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse
use Phoenix.Component
# Import convenience functions from controllers
@ -82,11 +83,8 @@ defmodule MemexWeb do
defp html_helpers do
quote do
# credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse
use Phoenix.HTML
# credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse
import Phoenix.Component
use PhoenixHTMLHelpers
import Phoenix.{Component, HTML, HTML.Form}
import MemexWeb.{ErrorHelpers, Gettext, CoreComponents, HTMLHelpers}
# Shortcut for generating JS commands

@ -2,6 +2,7 @@ defmodule MemexWeb.CoreComponents do
@moduledoc """
Provides core UI components.
"""
use PhoenixHTMLHelpers
use Phoenix.Component
use MemexWeb, :verified_routes
import MemexWeb.{Gettext, HTMLHelpers}
@ -134,31 +135,36 @@ defmodule MemexWeb.CoreComponents do
def pipeline_content(assigns)
defp display_backlinks(record) do
defp display_links(record) do
record
|> get_text()
|> replace_links(record)
|> replace_triple_backlinks(record)
|> replace_double_backlinks(record)
|> replace_single_backlinks(record)
|> get_content()
|> replace_hyperlinks(record)
|> replace_triple_links(record)
|> replace_double_links(record)
|> replace_single_links(record)
|> HTML.raw()
end
defp get_text(%{content: content}), do: content
defp get_text(%{description: description}), do: description
defp get_content(%{content: content}), do: content |> get_text()
defp get_content(%{description: description}), do: description |> get_text()
defp get_content(_fallthrough), do: nil |> get_text()
defp get_text(string) when is_binary(string), do: string
defp get_text(_fallthrough), do: ""
# replaces hyperlinks like https://bubbletea.dev
#
# link regex from
# https://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url
# and modified with additional schemes from
# https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
defp replace_links(content, _record) do
defp replace_hyperlinks(content, _record) do
Regex.replace(
~r<((file|git|https?|ipfs|ipns|irc|jabber|magnet|mailto|mumble|tel|udp|xmpp):\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*))>,
content,
fn _whole_match, link ->
link =
HTML.Link.link(
link(
link,
to: link,
class: "link inline",
@ -173,13 +179,14 @@ defmodule MemexWeb.CoreComponents do
)
end
defp replace_triple_backlinks(content, _record) do
# replaces triple links like [[[slug-title]]]
defp replace_triple_links(content, _record) do
Regex.replace(
~r/(^|[^\[])\[\[\[([\p{L}\p{N}\-]+)\]\]\]($|[^\]])/,
content,
fn _whole_match, prefix, slug, suffix ->
link =
HTML.Link.link(
link(
"[[[#{slug}]]]",
to: ~p"/note/#{slug}",
class: "link inline"
@ -192,7 +199,8 @@ defmodule MemexWeb.CoreComponents do
)
end
defp replace_double_backlinks(content, record) do
# replaces double links like [[slug-title]]
defp replace_double_links(content, record) do
Regex.replace(
~r/(^|[^\[])\[\[([\p{L}\p{N}\-]+)\]\]($|[^\]])/,
content,
@ -205,7 +213,7 @@ defmodule MemexWeb.CoreComponents do
end
link =
HTML.Link.link(
link(
"[[#{slug}]]",
to: target,
class: "link inline"
@ -218,7 +226,8 @@ defmodule MemexWeb.CoreComponents do
)
end
defp replace_single_backlinks(content, record) do
# replaces single links like [slug-title]
defp replace_single_links(content, record) do
Regex.replace(
~r/(^|[^\[])\[([\p{L}\p{N}\-]+)\]($|[^\]])/,
content,
@ -232,7 +241,7 @@ defmodule MemexWeb.CoreComponents do
end
link =
HTML.Link.link(
link(
"[#{slug}]",
to: target,
class: "link inline"

@ -1,7 +1,8 @@
<div
:if={@context.content}
id={"show-context-content-#{@context.id}"}
class="input input-primary h-128 min-h-128 inline-block whitespace-pre-wrap overflow-x-hidden overflow-y-auto resize-y"
phx-update="ignore"
readonly
phx-no-format
><p class="inline"><%= display_backlinks(@context) %></p></div>
><p class="inline"><%= display_links(@context) %></p></div>

@ -1,7 +1,8 @@
<div
:if={@note.content}
id={"show-note-content-#{@note.id}"}
class="input input-primary h-128 min-h-128 inline-block whitespace-pre-wrap overflow-x-hidden overflow-y-auto resize-y"
phx-update="ignore"
readonly
phx-no-format
><p class="inline"><%= display_backlinks(@note) %></p></div>
><p class="inline"><%= display_links(@note) %></p></div>

@ -1,7 +1,8 @@
<div
:if={@pipeline.description}
id={"show-pipeline-description-#{@pipeline.id}"}
class="input input-primary h-32 min-h-32 inline-block whitespace-pre-wrap overflow-x-hidden overflow-y-auto resize-y"
phx-update="ignore"
readonly
phx-no-format
><p class="inline"><%= display_backlinks(@pipeline) %></p></div>
><p class="inline"><%= display_links(@pipeline) %></p></div>

@ -1,7 +1,8 @@
<div
:if={@step.content}
id={"show-step-content-#{@step.id}"}
class="input input-primary h-32 min-h-32 inline-block whitespace-pre-wrap overflow-x-hidden overflow-y-auto resize-y"
phx-update="ignore"
readonly
phx-no-format
><p class="inline"><%= display_backlinks(@step) %></p></div>
><p class="inline"><%= display_links(@step) %></p></div>

@ -38,7 +38,7 @@
<li class="mx-2 my-1 border-left border border-primary-700"></li>
<%= if @current_user do %>
<li :if={@current_user |> Accounts.is_already_admin?()} class="mx-2 my-1">
<li :if={@current_user |> Accounts.already_admin?()} class="mx-2 my-1">
<.link navigate={~p"/invites"} class="text-primary-400 hover:underline">
<%= gettext("invites") %>
</.link>

@ -10,7 +10,7 @@
phx-click="lv:clear-flash"
phx-value-key="info"
>
<%= live_flash(@flash, :info) %>
<%= Phoenix.Flash.get(@flash, :info) %>
</p>
<p
@ -20,7 +20,7 @@
phx-click="lv:clear-flash"
phx-value-key="error"
>
<%= live_flash(@flash, :error) %>
<%= Phoenix.Flash.get(@flash, :error) %>
</p>
</div>
</header>

@ -9,7 +9,7 @@
action={~p"/users/register"}
class="flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center"
>
<p :if={@changeset.action && not @changeset.valid?()} class="alert alert-danger col-span-3">
<p :if={@changeset.action && not @changeset.valid?} class="alert alert-danger col-span-3">
<%= dgettext("errors", "oops, something went wrong! please check the errors below.") %>
</p>

@ -9,7 +9,7 @@
action={~p"/users/reset_password/#{@token}"}
class="flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center"
>
<p :if={@changeset.action && not @changeset.valid?()} class="alert alert-danger col-span-3">
<p :if={@changeset.action && not @changeset.valid?} class="alert alert-danger col-span-3">
<%= dgettext("errors", "oops, something went wrong! please check the errors below.") %>
</p>

@ -16,7 +16,7 @@
</h3>
<div
:if={@email_changeset.action && not @email_changeset.valid?()}
:if={@email_changeset.action && not @email_changeset.valid?}
class="alert alert-danger col-span-3"
>
<%= dgettext("errors", "oops, something went wrong! please check the errors below") %>
@ -58,7 +58,7 @@
</h3>
<p
:if={@password_changeset.action && not @password_changeset.valid?()}
:if={@password_changeset.action && not @password_changeset.valid?}
class="alert alert-danger col-span-3"
>
<%= dgettext("errors", "oops, something went wrong! please check the errors below.") %>
@ -112,7 +112,7 @@
) %>
<div
:if={@locale_changeset.action && not @locale_changeset.valid?()}
:if={@locale_changeset.action && not @locale_changeset.valid?}
class="alert alert-danger col-span-3"
>
<%= dgettext("errors", "oops, something went wrong! please check the errors below") %>

@ -3,8 +3,8 @@ defmodule MemexWeb.ErrorHelpers do
Conveniences for translating and building error messages.
"""
use Phoenix.HTML
import Phoenix.Component
use PhoenixHTMLHelpers
import Phoenix.{Component, HTML.Form}
alias Ecto.Changeset
alias Phoenix.{HTML.Form, LiveView.Rendered}

@ -10,10 +10,11 @@
class="flex flex-col justify-start items-stretch space-y-4"
>
<%= text_input(f, :slug,
class: "input input-primary",
placeholder: gettext("slug"),
aria_label: gettext("slug"),
phx_debounce: 300
class: "input input-primary",
phx_debounce: 300,
phx_hook: "SanitizeTitles",
placeholder: gettext("slug")
) %>
<%= error_tag(f, :slug) %>
@ -30,11 +31,12 @@
<%= error_tag(f, :content) %>
<%= text_input(f, :tags_string,
id: "tags-input",
class: "input input-primary",
placeholder: gettext("tag1,tag2"),
aria_label: gettext("tag1,tag2"),
phx_debounce: 300
class: "input input-primary",
id: "tags-input",
phx_debounce: 300,
phx_hook: "SanitizeTags",
placeholder: gettext("tag1,tag2")
) %>
<%= error_tag(f, :tags_string) %>

@ -33,14 +33,14 @@
>
<:actions :let={context}>
<.link
:if={Contexts.is_owner?(context, @current_user)}
:if={Contexts.owner?(context, @current_user)}
patch={~p"/contexts/#{context}/edit"}
aria-label={dgettext("actions", "edit %{context_slug}", context_slug: context.slug)}
>
<%= dgettext("actions", "edit") %>
</.link>
<.link
:if={Contexts.is_owner_or_admin?(context, @current_user)}
:if={Contexts.owner_or_admin?(context, @current_user)}
href="#"
phx-click="delete"
phx-value-id={context.id}

@ -17,14 +17,14 @@
<div class="self-end flex space-x-4">
<.link
:if={Contexts.is_owner?(@context, @current_user)}
:if={Contexts.owner?(@context, @current_user)}
class="btn btn-primary"
patch={~p"/context/#{@context}/edit"}
>
<%= dgettext("actions", "edit") %>
</.link>
<button
:if={Contexts.is_owner_or_admin?(@context, @current_user)}
:if={Contexts.owner_or_admin?(@context, @current_user)}
type="button"
class="btn btn-primary"
phx-click="delete"

@ -89,7 +89,7 @@
<p>
<%= gettext("in my opinion, contexts should be like single-topic blog posts.") %>
<%= gettext(
"for instance, a good context could be what makes some physical designs spark joy for you, and in that context you could backlink to the spoon note as an example of how it fits nicely into your hand."
"for instance, a good context could be what makes some physical designs spark joy for you, and in that context you could link to the spoon note as an example of how it fits nicely into your hand."
) %>
</p>
</li>
@ -100,10 +100,10 @@
</b>
<p>
<%= gettext(
"in my opinion, pipelines should be pretty lightweight, and just backlink to contexts to provide most of the heavy lifting."
"in my opinion, pipelines should be pretty lightweight, and just link to contexts to provide most of the heavy lifting."
) %>
<%= gettext(
"for instance, a pipeline for buying an object could have a step where you consider how much it sparks joy, and it could backlink to the physical designs context, maybe with some notes about how it applies in this case."
"for instance, a pipeline for buying an object could have a step where you consider how much it sparks joy, and it could link to the physical designs context, maybe with some notes about how it applies in this case."
) %>
</p>
</li>
@ -117,7 +117,7 @@
"while memEx fully supports multiple users, each memEx instance should be treated as a single cohesive and collaborative document."
) %>
<%= gettext(
"note, context and pipeline slugs must be unique, and you are free to backlink to notes not written by you."
"note, context and pipeline slugs must be unique, and you are free to link to notes not written by you."
) %>
<%= gettext(
"so, i'd recommend inviting anyone you'd like to work on your collective memEx. however, when in doubt, hopefully setting up a new instance is easy enough. if it isn't, then feel free to let me know :)"

@ -13,7 +13,7 @@
phx-hook="CtrlEnter"
>
<div
:if={@changeset.action && not @changeset.valid?()}
:if={@changeset.action && not @changeset.valid?}
class="invalid-feedback col-span-3 text-center"
>
<%= changeset_errors(@changeset) %>

@ -4,12 +4,12 @@
</h1>
<%= if @invites |> Enum.empty?() do %>
<h1 class="title text-xl text-primary-400">
<h1 class="title text-xl text-primary-400 text-center">
<%= gettext("no invites 😔") %>
</h1>
<.link patch={~p"/invites"} class="btn btn-primary">
<%= dgettext("actions", "invite someone new!") %>
<.link patch={~p"/invites"} class="ml-auto btn btn-primary">
<%= dgettext("actions", "new invite") %>
</.link>
<% end %>

@ -10,10 +10,11 @@
class="flex flex-col justify-start items-stretch space-y-4"
>
<%= text_input(f, :slug,
class: "input input-primary",
placeholder: gettext("slug"),
aria_label: gettext("slug"),
phx_debounce: 300
class: "input input-primary",
phx_debounce: 300,
phx_hook: "SanitizeTitles",
placeholder: gettext("slug")
) %>
<%= error_tag(f, :slug) %>
@ -28,11 +29,12 @@
<%= error_tag(f, :content) %>
<%= text_input(f, :tags_string,
id: "tags-input",
class: "input input-primary",
placeholder: gettext("tag1,tag2"),
aria_label: gettext("tag1,tag2"),
phx_debounce: 300
class: "input input-primary",
id: "tags-input",
phx_debounce: 300,
phx_hook: "SanitizeTags",
placeholder: gettext("tag1,tag2")
) %>
<%= error_tag(f, :tags_string) %>

@ -33,14 +33,14 @@
>
<:actions :let={note}>
<.link
:if={Notes.is_owner?(note, @current_user)}
:if={Notes.owner?(note, @current_user)}
patch={~p"/notes/#{note}/edit"}
aria-label={dgettext("actions", "edit %{note_slug}", note_slug: note.slug)}
>
<%= dgettext("actions", "edit") %>
</.link>
<.link
:if={Notes.is_owner_or_admin?(note, @current_user)}
:if={Notes.owner_or_admin?(note, @current_user)}
href="#"
phx-click="delete"
phx-value-id={note.id}

@ -17,14 +17,14 @@
<div class="self-end flex space-x-4">
<.link
:if={Notes.is_owner?(@note, @current_user)}
:if={Notes.owner?(@note, @current_user)}
class="btn btn-primary"
patch={~p"/note/#{@note}/edit"}
>
<%= dgettext("actions", "edit") %>
</.link>
<button
:if={Notes.is_owner_or_admin?(@note, @current_user)}
:if={Notes.owner_or_admin?(@note, @current_user)}
type="button"
class="btn btn-primary"
phx-click="delete"

@ -10,10 +10,11 @@
class="flex flex-col justify-start items-stretch space-y-4"
>
<%= text_input(f, :slug,
class: "input input-primary",
placeholder: gettext("slug"),
aria_label: gettext("slug"),
phx_debounce: 300
class: "input input-primary",
phx_debounce: 300,
phx_hook: "SanitizeTitles",
placeholder: gettext("slug")
) %>
<%= error_tag(f, :slug) %>
@ -34,11 +35,12 @@
<%= error_tag(f, :description) %>
<%= text_input(f, :tags_string,
id: "tags-input",
class: "input input-primary",
placeholder: gettext("tag1,tag2"),
aria_label: gettext("tag1,tag2"),
phx_debounce: 300
class: "input input-primary",
id: "tags-input",
phx_debounce: 300,
phx_hook: "SanitizeTags",
placeholder: gettext("tag1,tag2")
) %>
<%= error_tag(f, :tags_string) %>

@ -33,14 +33,14 @@
>
<:actions :let={pipeline}>
<.link
:if={Pipelines.is_owner?(pipeline, @current_user)}
:if={Pipelines.owner?(pipeline, @current_user)}
patch={~p"/pipelines/#{pipeline}/edit"}
aria-label={dgettext("actions", "edit %{pipeline_slug}", pipeline_slug: pipeline.slug)}
>
<%= dgettext("actions", "edit") %>
</.link>
<.link
:if={Pipelines.is_owner_or_admin?(pipeline, @current_user)}
:if={Pipelines.owner_or_admin?(pipeline, @current_user)}
href="#"
phx-click="delete"
phx-value-id={pipeline.id}

@ -17,14 +17,14 @@
<div class="pb-4 self-end flex space-x-4">
<.link
:if={Pipelines.is_owner?(@pipeline, @current_user)}
:if={Pipelines.owner?(@pipeline, @current_user)}
class="btn btn-primary"
patch={~p"/pipeline/#{@pipeline}/edit"}
>
<%= dgettext("actions", "edit") %>
</.link>
<button
:if={Pipelines.is_owner_or_admin?(@pipeline, @current_user)}
:if={Pipelines.owner_or_admin?(@pipeline, @current_user)}
type="button"
class="btn btn-primary"
phx-click="delete"
@ -52,7 +52,7 @@
<%= gettext("%{position}. %{title}", position: position + 1, title: title) %>
</h3>
<%= if Pipelines.is_owner?(@pipeline, @current_user) do %>
<%= if Pipelines.owner?(@pipeline, @current_user) do %>
<div class="flex justify-between items-center space-x-4">
<%= if position <= 0 do %>
<i class="fas text-xl fa-chevron-up cursor-not-allowed opacity-25"></i>
@ -113,7 +113,7 @@
<% end %>
<.link
:if={Pipelines.is_owner?(@pipeline, @current_user)}
:if={Pipelines.owner?(@pipeline, @current_user)}
class="self-end btn btn-primary"
patch={~p"/pipeline/#{@pipeline}/add_step"}
>

@ -10,10 +10,11 @@
class="flex flex-col justify-start items-stretch space-y-4"
>
<%= text_input(f, :title,
class: "input input-primary",
placeholder: gettext("title"),
aria_label: gettext("title"),
phx_debounce: 300
class: "input input-primary",
phx_debounce: 300,
phx_hook: "SanitizeTitles",
placeholder: gettext("title")
) %>
<%= error_tag(f, :title) %>

39
mix.exs

@ -4,8 +4,8 @@ defmodule Memex.MixProject do
def project do
[
app: :memex,
version: "0.1.13",
elixir: "1.15.6",
version: "0.1.16",
elixir: "1.17.0",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
@ -47,29 +47,30 @@ defmodule Memex.MixProject do
defp deps do
[
{:bcrypt_elixir, "~> 3.0"},
{:phoenix, "~> 1.7.0"},
{:phoenix_ecto, "~> 4.4"},
{:phoenix_html, "~> 3.0"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 0.20.0"},
{:phoenix_live_dashboard, "~> 0.8"},
{:credo, "~> 1.5", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 1.0", only: [:dev, :test], runtime: false},
{:ecto_psql_extras, "~> 0.6"},
{:ecto_sql, "~> 3.6"},
{:postgrex, ">= 0.0.0"},
{:floki, ">= 0.30.0", only: :test},
{:eqrcode, "~> 0.1.10"},
# {:esbuild, "~> 0.3", runtime: Mix.env() == :dev},
{:ex_doc, "~> 0.27", only: :dev, runtime: false},
{:swoosh, "~> 1.6"},
{:floki, ">= 0.30.0", only: :test},
{:gen_smtp, "~> 1.0"},
{:oban, "~> 2.10"},
{:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"},
{:gettext, "~> 0.18"},
{:jason, "~> 1.2"},
{:plug_cowboy, "~> 2.5"},
{:ecto_psql_extras, "~> 0.6"},
{:eqrcode, "~> 0.1.10"},
{:credo, "~> 1.5", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 1.0", only: [:dev, :test], runtime: false}
{:oban, "~> 2.10"},
{:phoenix_ecto, "~> 4.4"},
{:phoenix_html_helpers, "~> 1.0"},
{:phoenix_html, "~> 4.0"},
{:phoenix_live_dashboard, "~> 0.8"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 0.20.0"},
{:phoenix, "~> 1.7.11"},
{:plug_cowboy, "~> 2.7.0"},
{:postgrex, ">= 0.0.0"},
{:swoosh, "~> 1.6"},
{:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"}
]
end

@ -1,54 +1,54 @@
%{
"bcrypt_elixir": {:hex, :bcrypt_elixir, "3.1.0", "0b110a9a6c619b19a7f73fa3004aa11d6e719a67e672d1633dc36b6b2290a0f7", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2ad2acb5a8bc049e8d5aa267802631912bb80d5f4110a178ae7999e69dca1bf7"},
"bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"},
"castore": {:hex, :castore, "1.0.4", "ff4d0fb2e6411c0479b1d965a814ea6d00e51eb2f58697446e9c41a97d940b28", [:mix], [], "hexpm", "9418c1b8144e11656f0be99943db4caf04612e3eaecefb5dae9a2a87565584f8"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"},
"comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"},
"cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"},
"credo": {:hex, :credo, "1.7.1", "6e26bbcc9e22eefbff7e43188e69924e78818e2fe6282487d0703652bc20fd62", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e9871c6095a4c0381c89b6aa98bc6260a8ba6addccf7f6a53da8849c748a58a2"},
"db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"},
"cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
"credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"},
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"dialyxir": {:hex, :dialyxir, "1.4.2", "764a6e8e7a354f0ba95d58418178d486065ead1f69ad89782817c296d0d746a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "516603d8067b2fd585319e4b13d3674ad4f314a5902ba8130cd97dc902ce6bbd"},
"earmark_parser": {:hex, :earmark_parser, "1.4.37", "2ad73550e27c8946648b06905a57e4d454e4d7229c2dafa72a0348c99d8be5f7", [:mix], [], "hexpm", "6b19783f2802f039806f375610faa22da130b8edc21209d0bff47918bb48360e"},
"ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"},
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.14", "7a20cfe913b0476542b43870e67386461258734896035e3f284039fd18bd4c4c", [:mix], [{:ecto_sql, "~> 3.7", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "22f5f98592dd597db9416fcef00effae0787669fdcb6faf447e982b553798e98"},
"ecto_sql": {:hex, :ecto_sql, "3.10.2", "6b98b46534b5c2f8b8b5f03f126e75e2a73c64f3c071149d32987a5378b0fdbd", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "68c018debca57cb9235e3889affdaec7a10616a4e3a80c99fa1d01fdafaa9007"},
"elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
"earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"},
"ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.8.0", "440719cd74f09b3f01c84455707a2c3972b725c513808e68eb6c5b0ab82bf523", [:mix], [{:ecto_sql, "~> 3.7", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 0.18.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1 or ~> 4.0.0", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "f1512812dc196bcb932a96c82e55f69b543dc125e9d39f5e3631a9c4ec65ef12"},
"ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"},
"elixir_make": {:hex, :elixir_make, "0.8.4", "4960a03ce79081dee8fe119d80ad372c4e7badb84c493cc75983f9d3bc8bde0f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040"},
"eqrcode": {:hex, :eqrcode, "0.1.10", "6294fece9d68ad64eef1c3c92cf111cfd6469f4fbf230a2d4cc905a682178f3f", [:mix], [], "hexpm", "da30e373c36a0fd37ab6f58664b16029919896d6c45a68a95cc4d713e81076f1"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"ex_doc": {:hex, :ex_doc, "0.30.9", "d691453495c47434c0f2052b08dd91cc32bc4e1a218f86884563448ee2502dd2", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "d7aaaf21e95dc5cddabf89063327e96867d00013963eadf2c6ad135506a8bc10"},
"expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"floki": {:hex, :floki, "0.35.2", "87f8c75ed8654b9635b311774308b2760b47e9a579dabf2e4d5f1e1d42c39e0b", [:mix], [], "hexpm", "6b05289a8e9eac475f644f09c2e4ba7e19201fd002b89c28c1293e7bd16773d9"},
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
"ex_doc": {:hex, :ex_doc, "0.34.2", "13eedf3844ccdce25cfd837b99bea9ad92c4e511233199440488d217c92571e8", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "5ce5f16b41208a50106afed3de6a2ed34f4acfd65715b82a0b84b49d995f95c1"},
"expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"},
"file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
"floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"},
"gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"},
"gettext": {:hex, :gettext, "0.23.1", "821e619a240e6000db2fc16a574ef68b3bd7fe0167ccc264a81563cc93e67a31", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "19d744a36b809d810d610b57c27b934425859d158ebd56561bc41f7eeb8795db"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"},
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"},
"oban": {:hex, :oban, "2.16.3", "33ebe7da637cce4da5438c1636bc25448a8628994a0c064ac6078bbe6dc97bd6", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4d8a7fb62f63cf2f2080c78954425f5fd8916ef57196b7f79b5bc657abb2ac5f"},
"phoenix": {:hex, :phoenix, "1.7.10", "02189140a61b2ce85bb633a9b6fd02dff705a5f1596869547aeb2b2b95edd729", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "cf784932e010fd736d656d7fead6a584a4498efefe5b8227e9f383bf15bb79d0"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.3", "86e9878f833829c3f66da03d75254c155d91d72a201eb56ae83482328dc7ca93", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "d36c401206f3011fefd63d04e8ef626ec8791975d9d107f9a0817d426f61ac07"},
"phoenix_html": {:hex, :phoenix_html, "3.3.3", "380b8fb45912b5638d2f1d925a3771b4516b9a78587249cabe394e0a5d579dc9", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "923ebe6fec6e2e3b3e569dfbdc6560de932cd54b000ada0208b5f45024bdd76c"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.3", "7ff51c9b6609470f681fbea20578dede0e548302b0c8bdf338b5a753a4f045bf", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "f9470a0a8bae4f56430a23d42f977b5a6205fdba6559d76f932b876bfaec652d"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.20.1", "92a37acf07afca67ac98bd326532ba8f44ad7d4bdf3e4361b03f7f02594e5ae9", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "be494fd1215052729298b0e97d5c2ce8e719c00854b82cd8cf15c1cd7fcf6294"},
"gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
"makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"},
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
"oban": {:hex, :oban, "2.18.0", "092d20bfd3d70c7ecb70960f8548d300b54bb9937c7f2e56b388f3a9ed02ec68", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aace1eff6f8227ae38d4274af967d96f051c2f0a5152f2ef9809dd1f97866745"},
"phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.6.2", "3b83b24ab5a2eb071a20372f740d7118767c272db386831b2e77638c4dcc606d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "3f94d025f59de86be00f5f8c5dd7b5965a3298458d21ab1c328488be3b5fcd59"},
"phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"},
"phoenix_html_helpers": {:hex, :phoenix_html_helpers, "1.0.1", "7eed85c52eff80a179391036931791ee5d2f713d76a81d0d2c6ebafe1e11e5ec", [:mix], [{:phoenix_html, "~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "cffd2385d1fa4f78b04432df69ab8da63dc5cf63e07b713a4dcf36a3740e3090"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.4", "4508e481f791ce62ec6a096e13b061387158cbeefacca68c6c1928e1305e23ed", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "2984aae96994fbc5c61795a73b8fb58153b41ff934019cfb522343d2d3817d59"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.3", "f2161c207fda0e4fb55165f650f7f8db23f02b29e3bff00ff7ef161d6ac1f09d", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b4ec9cd73cb01ff1bd1cac92e045d13e7030330b74164297d1aee3907b54803c"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.20.17", "f396bbdaf4ba227b82251eb75ac0afa6b3da5e509bc0d030206374237dfc9450", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61d741ffb78c85fdbca0de084da6a48f8ceb5261a79165b5a0b59e5f65ce98b"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
"phoenix_template": {:hex, :phoenix_template, "1.0.3", "32de561eefcefa951aead30a1f94f1b5f0379bc9e340bb5c667f65f1edfa4326", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "16f4b6588a4152f3cc057b9d0c0ba7e82ee23afa65543da535313ad8d25d8e2c"},
"plug": {:hex, :plug, "1.15.1", "b7efd81c1a1286f13efb3f769de343236bd8b7d23b4a9f40d3002fc39ad8f74c", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "459497bd94d041d98d948054ec6c0b76feacd28eec38b219ca04c0de13c79d30"},
"plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"},
"plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"},
"postgrex": {:hex, :postgrex, "0.17.3", "c92cda8de2033a7585dae8c61b1d420a1a1322421df84da9a82a6764580c503d", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "946cf46935a4fdca7a81448be76ba3503cff082df42c6ec1ff16a4bdfbfb098d"},
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
"plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
"plug_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"},
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
"postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"swoosh": {:hex, :swoosh, "1.14.0", "710e363e114dedb4080b737e0307f5410887ffc9a239f818231e5618b6b84e1b", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dccfc986ac99c18345ab3e1a8b934b2d817fd6d59a2494f0af78502184c71025"},
"table_rex": {:hex, :table_rex, "3.1.1", "0c67164d1714b5e806d5067c1e96ff098ba7ae79413cc075973e17c38a587caa", [:mix], [], "hexpm", "678a23aba4d670419c23c17790f9dcd635a4a89022040df7d5d772cb21012490"},
"swoosh": {:hex, :swoosh, "1.16.10", "04be6e2eb1a31aa0aa21a731175c81cc3998189456a92daf13d44a5c754afcf5", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "756be04db173c0cbe318f1dfe2bcc88aa63aed78cf5a4b02b61b36ee11fc716a"},
"table_rex": {:hex, :table_rex, "4.0.0", "3c613a68ebdc6d4d1e731bc973c233500974ec3993c99fcdabb210407b90959b", [:mix], [], "hexpm", "c35c4d5612ca49ebb0344ea10387da4d2afe278387d4019e4d8111e815df8f55"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"},
"telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
"websock_adapter": {:hex, :websock_adapter, "0.5.5", "9dfeee8269b27e958a65b3e235b7e447769f66b5b5925385f5a569269164a210", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b977ba4a01918acbf77045ff88de7f6972c2a009213c515a445c48f224ffce9"},
"websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"},
}

@ -66,11 +66,6 @@ msgstr ""
msgid "edit"
msgstr ""
#: lib/memex_web/live/invite_live/index.html.heex:12
#, elixir-autogen, elixir-format
msgid "invite someone new!"
msgstr ""
#: lib/memex_web/components/core_components/topbar.html.heex:85
#: lib/memex_web/controllers/user_confirmation_html/new.html.heex:28
#: lib/memex_web/controllers/user_registration_html/new.html.heex:44
@ -108,11 +103,11 @@ msgstr ""
msgid "register"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:49
#: lib/memex_web/live/context_live/form_component.html.heex:51
#: lib/memex_web/live/invite_live/form_component.html.heex:47
#: lib/memex_web/live/note_live/form_component.html.heex:47
#: lib/memex_web/live/pipeline_live/form_component.html.heex:53
#: lib/memex_web/live/step_live/form_component.html.heex:37
#: lib/memex_web/live/note_live/form_component.html.heex:49
#: lib/memex_web/live/pipeline_live/form_component.html.heex:55
#: lib/memex_web/live/step_live/form_component.html.heex:38
#, elixir-autogen, elixir-format
msgid "save"
msgstr ""
@ -217,3 +212,8 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "reset password"
msgstr ""
#: lib/memex_web/live/invite_live/index.html.heex:12
#, elixir-autogen, elixir-format
msgid "new invite"
msgstr ""

@ -66,11 +66,6 @@ msgstr ""
msgid "edit"
msgstr ""
#: lib/memex_web/live/invite_live/index.html.heex:12
#, elixir-autogen, elixir-format
msgid "invite someone new!"
msgstr ""
#: lib/memex_web/components/core_components/topbar.html.heex:85
#: lib/memex_web/controllers/user_confirmation_html/new.html.heex:28
#: lib/memex_web/controllers/user_registration_html/new.html.heex:44
@ -108,11 +103,11 @@ msgstr ""
msgid "register"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:49
#: lib/memex_web/live/context_live/form_component.html.heex:51
#: lib/memex_web/live/invite_live/form_component.html.heex:47
#: lib/memex_web/live/note_live/form_component.html.heex:47
#: lib/memex_web/live/pipeline_live/form_component.html.heex:53
#: lib/memex_web/live/step_live/form_component.html.heex:37
#: lib/memex_web/live/note_live/form_component.html.heex:49
#: lib/memex_web/live/pipeline_live/form_component.html.heex:55
#: lib/memex_web/live/step_live/form_component.html.heex:38
#, elixir-autogen, elixir-format
msgid "save"
msgstr ""
@ -217,3 +212,8 @@ msgstr ""
#, elixir-autogen, elixir-format, fuzzy
msgid "reset password"
msgstr ""
#: lib/memex_web/live/invite_live/index.html.heex:12
#, elixir-autogen, elixir-format, fuzzy
msgid "new invite"
msgstr ""

@ -237,20 +237,20 @@ msgstr ""
msgid "report bugs or request features"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:50
#: lib/memex_web/live/note_live/form_component.html.heex:48
#: lib/memex_web/live/pipeline_live/form_component.html.heex:54
#: lib/memex_web/live/step_live/form_component.html.heex:38
#: lib/memex_web/live/context_live/form_component.html.heex:52
#: lib/memex_web/live/note_live/form_component.html.heex:50
#: lib/memex_web/live/pipeline_live/form_component.html.heex:56
#: lib/memex_web/live/step_live/form_component.html.heex:39
#, elixir-autogen, elixir-format
msgid "saving..."
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:44
#: lib/memex_web/live/context_live/form_component.html.heex:45
#: lib/memex_web/live/note_live/form_component.html.heex:42
#: lib/memex_web/live/note_live/form_component.html.heex:43
#: lib/memex_web/live/pipeline_live/form_component.html.heex:48
#: lib/memex_web/live/pipeline_live/form_component.html.heex:49
#: lib/memex_web/live/context_live/form_component.html.heex:46
#: lib/memex_web/live/context_live/form_component.html.heex:47
#: lib/memex_web/live/note_live/form_component.html.heex:44
#: lib/memex_web/live/note_live/form_component.html.heex:45
#: lib/memex_web/live/pipeline_live/form_component.html.heex:50
#: lib/memex_web/live/pipeline_live/form_component.html.heex:51
#, elixir-autogen, elixir-format
msgid "select privacy"
msgstr ""
@ -266,12 +266,12 @@ msgstr ""
msgid "settings"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:35
#: lib/memex_web/live/context_live/form_component.html.heex:36
#: lib/memex_web/live/note_live/form_component.html.heex:33
#: lib/memex_web/live/note_live/form_component.html.heex:34
#: lib/memex_web/live/pipeline_live/form_component.html.heex:39
#: lib/memex_web/live/pipeline_live/form_component.html.heex:40
#: lib/memex_web/live/context_live/form_component.html.heex:34
#: lib/memex_web/live/context_live/form_component.html.heex:39
#: lib/memex_web/live/note_live/form_component.html.heex:32
#: lib/memex_web/live/note_live/form_component.html.heex:37
#: lib/memex_web/live/pipeline_live/form_component.html.heex:38
#: lib/memex_web/live/pipeline_live/form_component.html.heex:43
#, elixir-autogen, elixir-format
msgid "tag1,tag2"
msgstr ""
@ -379,12 +379,12 @@ msgstr ""
#: lib/memex_web/components/contexts_table_component.ex:47
#: lib/memex_web/components/notes_table_component.ex:47
#: lib/memex_web/components/pipelines_table_component.ex:47
#: lib/memex_web/live/context_live/form_component.html.heex:14
#: lib/memex_web/live/context_live/form_component.html.heex:15
#: lib/memex_web/live/note_live/form_component.html.heex:14
#: lib/memex_web/live/note_live/form_component.html.heex:15
#: lib/memex_web/live/pipeline_live/form_component.html.heex:14
#: lib/memex_web/live/pipeline_live/form_component.html.heex:15
#: lib/memex_web/live/context_live/form_component.html.heex:13
#: lib/memex_web/live/context_live/form_component.html.heex:17
#: lib/memex_web/live/note_live/form_component.html.heex:13
#: lib/memex_web/live/note_live/form_component.html.heex:17
#: lib/memex_web/live/pipeline_live/form_component.html.heex:13
#: lib/memex_web/live/pipeline_live/form_component.html.heex:17
#, elixir-autogen, elixir-format
msgid "slug"
msgstr ""
@ -457,8 +457,8 @@ msgstr ""
msgid "steps:"
msgstr ""
#: lib/memex_web/live/step_live/form_component.html.heex:14
#: lib/memex_web/live/step_live/form_component.html.heex:15
#: lib/memex_web/live/step_live/form_component.html.heex:13
#: lib/memex_web/live/step_live/form_component.html.heex:17
#, elixir-autogen, elixir-format
msgid "title"
msgstr ""
@ -468,16 +468,6 @@ msgstr ""
msgid "finally, i wanted to externalize the processes for common situations that use these thought processes at discrete steps. these are pipelines!"
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:91
#, elixir-autogen, elixir-format
msgid "for instance, a good context could be what makes some physical designs spark joy for you, and in that context you could backlink to the spoon note as an example of how it fits nicely into your hand."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:105
#, elixir-autogen, elixir-format
msgid "for instance, a pipeline for buying an object could have a step where you consider how much it sparks joy, and it could backlink to the physical designs context, maybe with some notes about how it applies in this case."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:59
#, elixir-autogen, elixir-format
msgid "i really admired the idea of a zettelkasten, especially with org-mode backlinks, however I felt like my notes would immediately become too messy by just putting everything into a single hierarchy."
@ -498,11 +488,6 @@ msgstr ""
msgid "in my opinion, notes should be written by any of the discrete objects or concepts that are meaningful to you in your life."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:102
#, elixir-autogen, elixir-format
msgid "in my opinion, pipelines should be pretty lightweight, and just backlink to contexts to provide most of the heavy lifting."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:28
#, elixir-autogen, elixir-format
msgid "memex"
@ -568,11 +553,6 @@ msgstr ""
msgid "how many people should i invite?"
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "note, context and pipeline slugs must be unique, and you are free to backlink to notes not written by you."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:122
#, elixir-autogen, elixir-format
msgid "so, i'd recommend inviting anyone you'd like to work on your collective memEx. however, when in doubt, hopefully setting up a new instance is easy enough. if it isn't, then feel free to let me know :)"
@ -692,22 +672,42 @@ msgstr ""
msgid "reset your password"
msgstr ""
#: lib/memex_web/live/pipeline_live/form_component.html.heex:25
#: lib/memex_web/live/pipeline_live/form_component.html.heex:29
#: lib/memex_web/live/step_live/form_component.html.heex:25
#: lib/memex_web/live/step_live/form_component.html.heex:29
#: lib/memex_web/live/pipeline_live/form_component.html.heex:26
#: lib/memex_web/live/pipeline_live/form_component.html.heex:30
#: lib/memex_web/live/step_live/form_component.html.heex:26
#: lib/memex_web/live/step_live/form_component.html.heex:30
#, elixir-autogen, elixir-format
msgid "use [[[note-slug]]] to link to a note or use [[context-slug]] to link to a context or [pipeline-slug] to link to a pipeline"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:25
#: lib/memex_web/live/context_live/form_component.html.heex:27
#: lib/memex_web/live/context_live/form_component.html.heex:26
#: lib/memex_web/live/context_live/form_component.html.heex:28
#, elixir-autogen, elixir-format, fuzzy
msgid "use [[note-slug]] to link to a note or [context-slug] to link to a context"
msgstr ""
#: lib/memex_web/live/note_live/form_component.html.heex:24
#: lib/memex_web/live/note_live/form_component.html.heex:25
#: lib/memex_web/live/note_live/form_component.html.heex:26
#, elixir-autogen, elixir-format, fuzzy
msgid "use [note-slug] to link to a note"
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:91
#, elixir-autogen, elixir-format, fuzzy
msgid "for instance, a good context could be what makes some physical designs spark joy for you, and in that context you could link to the spoon note as an example of how it fits nicely into your hand."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:105
#, elixir-autogen, elixir-format, fuzzy
msgid "for instance, a pipeline for buying an object could have a step where you consider how much it sparks joy, and it could link to the physical designs context, maybe with some notes about how it applies in this case."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:102
#, elixir-autogen, elixir-format, fuzzy
msgid "in my opinion, pipelines should be pretty lightweight, and just link to contexts to provide most of the heavy lifting."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:119
#, elixir-autogen, elixir-format, fuzzy
msgid "note, context and pipeline slugs must be unique, and you are free to link to notes not written by you."
msgstr ""

@ -66,12 +66,12 @@ msgstr ""
msgid "Welcome to memEx"
msgstr ""
#: lib/memex/accounts/email.ex:31
#: lib/memex/email.ex:31
#, elixir-autogen, elixir-format, fuzzy
msgid "confirm your memEx account"
msgstr ""
#: lib/memex/accounts/email.ex:37
#: lib/memex/email.ex:37
#, elixir-autogen, elixir-format, fuzzy
msgid "reset your memEx password"
msgstr ""
@ -86,7 +86,7 @@ msgstr ""
msgid "this email was sent from memEx at %{url}"
msgstr ""
#: lib/memex/accounts/email.ex:43
#: lib/memex/email.ex:43
#, elixir-autogen, elixir-format, fuzzy
msgid "update your memEx email"
msgstr ""

@ -235,20 +235,20 @@ msgstr ""
msgid "report bugs or request features"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:50
#: lib/memex_web/live/note_live/form_component.html.heex:48
#: lib/memex_web/live/pipeline_live/form_component.html.heex:54
#: lib/memex_web/live/step_live/form_component.html.heex:38
#: lib/memex_web/live/context_live/form_component.html.heex:52
#: lib/memex_web/live/note_live/form_component.html.heex:50
#: lib/memex_web/live/pipeline_live/form_component.html.heex:56
#: lib/memex_web/live/step_live/form_component.html.heex:39
#, elixir-autogen, elixir-format
msgid "saving..."
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:44
#: lib/memex_web/live/context_live/form_component.html.heex:45
#: lib/memex_web/live/note_live/form_component.html.heex:42
#: lib/memex_web/live/note_live/form_component.html.heex:43
#: lib/memex_web/live/pipeline_live/form_component.html.heex:48
#: lib/memex_web/live/pipeline_live/form_component.html.heex:49
#: lib/memex_web/live/context_live/form_component.html.heex:46
#: lib/memex_web/live/context_live/form_component.html.heex:47
#: lib/memex_web/live/note_live/form_component.html.heex:44
#: lib/memex_web/live/note_live/form_component.html.heex:45
#: lib/memex_web/live/pipeline_live/form_component.html.heex:50
#: lib/memex_web/live/pipeline_live/form_component.html.heex:51
#, elixir-autogen, elixir-format
msgid "select privacy"
msgstr ""
@ -264,12 +264,12 @@ msgstr ""
msgid "settings"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:35
#: lib/memex_web/live/context_live/form_component.html.heex:36
#: lib/memex_web/live/note_live/form_component.html.heex:33
#: lib/memex_web/live/note_live/form_component.html.heex:34
#: lib/memex_web/live/pipeline_live/form_component.html.heex:39
#: lib/memex_web/live/pipeline_live/form_component.html.heex:40
#: lib/memex_web/live/context_live/form_component.html.heex:34
#: lib/memex_web/live/context_live/form_component.html.heex:39
#: lib/memex_web/live/note_live/form_component.html.heex:32
#: lib/memex_web/live/note_live/form_component.html.heex:37
#: lib/memex_web/live/pipeline_live/form_component.html.heex:38
#: lib/memex_web/live/pipeline_live/form_component.html.heex:43
#, elixir-autogen, elixir-format
msgid "tag1,tag2"
msgstr ""
@ -377,12 +377,12 @@ msgstr ""
#: lib/memex_web/components/contexts_table_component.ex:47
#: lib/memex_web/components/notes_table_component.ex:47
#: lib/memex_web/components/pipelines_table_component.ex:47
#: lib/memex_web/live/context_live/form_component.html.heex:14
#: lib/memex_web/live/context_live/form_component.html.heex:15
#: lib/memex_web/live/note_live/form_component.html.heex:14
#: lib/memex_web/live/note_live/form_component.html.heex:15
#: lib/memex_web/live/pipeline_live/form_component.html.heex:14
#: lib/memex_web/live/pipeline_live/form_component.html.heex:15
#: lib/memex_web/live/context_live/form_component.html.heex:13
#: lib/memex_web/live/context_live/form_component.html.heex:17
#: lib/memex_web/live/note_live/form_component.html.heex:13
#: lib/memex_web/live/note_live/form_component.html.heex:17
#: lib/memex_web/live/pipeline_live/form_component.html.heex:13
#: lib/memex_web/live/pipeline_live/form_component.html.heex:17
#, elixir-autogen, elixir-format
msgid "slug"
msgstr ""
@ -455,8 +455,8 @@ msgstr ""
msgid "steps:"
msgstr ""
#: lib/memex_web/live/step_live/form_component.html.heex:14
#: lib/memex_web/live/step_live/form_component.html.heex:15
#: lib/memex_web/live/step_live/form_component.html.heex:13
#: lib/memex_web/live/step_live/form_component.html.heex:17
#, elixir-autogen, elixir-format
msgid "title"
msgstr ""
@ -466,16 +466,6 @@ msgstr ""
msgid "finally, i wanted to externalize the processes for common situations that use these thought processes at discrete steps. these are pipelines!"
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:91
#, elixir-autogen, elixir-format
msgid "for instance, a good context could be what makes some physical designs spark joy for you, and in that context you could backlink to the spoon note as an example of how it fits nicely into your hand."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:105
#, elixir-autogen, elixir-format
msgid "for instance, a pipeline for buying an object could have a step where you consider how much it sparks joy, and it could backlink to the physical designs context, maybe with some notes about how it applies in this case."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:59
#, elixir-autogen, elixir-format
msgid "i really admired the idea of a zettelkasten, especially with org-mode backlinks, however I felt like my notes would immediately become too messy by just putting everything into a single hierarchy."
@ -496,11 +486,6 @@ msgstr ""
msgid "in my opinion, notes should be written by any of the discrete objects or concepts that are meaningful to you in your life."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:102
#, elixir-autogen, elixir-format
msgid "in my opinion, pipelines should be pretty lightweight, and just backlink to contexts to provide most of the heavy lifting."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:28
#, elixir-autogen, elixir-format
msgid "memex"
@ -566,11 +551,6 @@ msgstr ""
msgid "how many people should i invite?"
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "note, context and pipeline slugs must be unique, and you are free to backlink to notes not written by you."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:122
#, elixir-autogen, elixir-format
msgid "so, i'd recommend inviting anyone you'd like to work on your collective memEx. however, when in doubt, hopefully setting up a new instance is easy enough. if it isn't, then feel free to let me know :)"
@ -690,22 +670,42 @@ msgstr ""
msgid "reset your password"
msgstr ""
#: lib/memex_web/live/pipeline_live/form_component.html.heex:25
#: lib/memex_web/live/pipeline_live/form_component.html.heex:29
#: lib/memex_web/live/step_live/form_component.html.heex:25
#: lib/memex_web/live/step_live/form_component.html.heex:29
#: lib/memex_web/live/pipeline_live/form_component.html.heex:26
#: lib/memex_web/live/pipeline_live/form_component.html.heex:30
#: lib/memex_web/live/step_live/form_component.html.heex:26
#: lib/memex_web/live/step_live/form_component.html.heex:30
#, elixir-autogen, elixir-format
msgid "use [[[note-slug]]] to link to a note or use [[context-slug]] to link to a context or [pipeline-slug] to link to a pipeline"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:25
#: lib/memex_web/live/context_live/form_component.html.heex:27
#: lib/memex_web/live/context_live/form_component.html.heex:26
#: lib/memex_web/live/context_live/form_component.html.heex:28
#, elixir-autogen, elixir-format
msgid "use [[note-slug]] to link to a note or [context-slug] to link to a context"
msgstr ""
#: lib/memex_web/live/note_live/form_component.html.heex:24
#: lib/memex_web/live/note_live/form_component.html.heex:25
#: lib/memex_web/live/note_live/form_component.html.heex:26
#, elixir-autogen, elixir-format
msgid "use [note-slug] to link to a note"
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:91
#, elixir-autogen, elixir-format
msgid "for instance, a good context could be what makes some physical designs spark joy for you, and in that context you could link to the spoon note as an example of how it fits nicely into your hand."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:105
#, elixir-autogen, elixir-format
msgid "for instance, a pipeline for buying an object could have a step where you consider how much it sparks joy, and it could link to the physical designs context, maybe with some notes about how it applies in this case."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:102
#, elixir-autogen, elixir-format
msgid "in my opinion, pipelines should be pretty lightweight, and just link to contexts to provide most of the heavy lifting."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "note, context and pipeline slugs must be unique, and you are free to link to notes not written by you."
msgstr ""

@ -66,12 +66,12 @@ msgstr ""
msgid "Welcome to memEx"
msgstr ""
#: lib/memex/accounts/email.ex:31
#: lib/memex/email.ex:31
#, elixir-autogen, elixir-format
msgid "confirm your memEx account"
msgstr ""
#: lib/memex/accounts/email.ex:37
#: lib/memex/email.ex:37
#, elixir-autogen, elixir-format
msgid "reset your memEx password"
msgstr ""
@ -86,7 +86,7 @@ msgstr ""
msgid "this email was sent from memEx at %{url}"
msgstr ""
#: lib/memex/accounts/email.ex:43
#: lib/memex/email.ex:43
#, elixir-autogen, elixir-format
msgid "update your memEx email"
msgstr ""

@ -67,11 +67,6 @@ msgstr ""
msgid "edit"
msgstr ""
#: lib/memex_web/live/invite_live/index.html.heex:12
#, elixir-autogen, elixir-format
msgid "invite someone new!"
msgstr ""
#: lib/memex_web/components/core_components/topbar.html.heex:85
#: lib/memex_web/controllers/user_confirmation_html/new.html.heex:28
#: lib/memex_web/controllers/user_registration_html/new.html.heex:44
@ -109,11 +104,11 @@ msgstr ""
msgid "register"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:49
#: lib/memex_web/live/context_live/form_component.html.heex:51
#: lib/memex_web/live/invite_live/form_component.html.heex:47
#: lib/memex_web/live/note_live/form_component.html.heex:47
#: lib/memex_web/live/pipeline_live/form_component.html.heex:53
#: lib/memex_web/live/step_live/form_component.html.heex:37
#: lib/memex_web/live/note_live/form_component.html.heex:49
#: lib/memex_web/live/pipeline_live/form_component.html.heex:55
#: lib/memex_web/live/step_live/form_component.html.heex:38
#, elixir-autogen, elixir-format
msgid "save"
msgstr ""
@ -218,3 +213,8 @@ msgstr ""
#, elixir-autogen, elixir-format, fuzzy
msgid "reset password"
msgstr ""
#: lib/memex_web/live/invite_live/index.html.heex:12
#, elixir-autogen, elixir-format, fuzzy
msgid "new invite"
msgstr ""

@ -236,20 +236,20 @@ msgstr ""
msgid "report bugs or request features"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:50
#: lib/memex_web/live/note_live/form_component.html.heex:48
#: lib/memex_web/live/pipeline_live/form_component.html.heex:54
#: lib/memex_web/live/step_live/form_component.html.heex:38
#: lib/memex_web/live/context_live/form_component.html.heex:52
#: lib/memex_web/live/note_live/form_component.html.heex:50
#: lib/memex_web/live/pipeline_live/form_component.html.heex:56
#: lib/memex_web/live/step_live/form_component.html.heex:39
#, elixir-autogen, elixir-format
msgid "saving..."
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:44
#: lib/memex_web/live/context_live/form_component.html.heex:45
#: lib/memex_web/live/note_live/form_component.html.heex:42
#: lib/memex_web/live/note_live/form_component.html.heex:43
#: lib/memex_web/live/pipeline_live/form_component.html.heex:48
#: lib/memex_web/live/pipeline_live/form_component.html.heex:49
#: lib/memex_web/live/context_live/form_component.html.heex:46
#: lib/memex_web/live/context_live/form_component.html.heex:47
#: lib/memex_web/live/note_live/form_component.html.heex:44
#: lib/memex_web/live/note_live/form_component.html.heex:45
#: lib/memex_web/live/pipeline_live/form_component.html.heex:50
#: lib/memex_web/live/pipeline_live/form_component.html.heex:51
#, elixir-autogen, elixir-format
msgid "select privacy"
msgstr ""
@ -265,12 +265,12 @@ msgstr ""
msgid "settings"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:35
#: lib/memex_web/live/context_live/form_component.html.heex:36
#: lib/memex_web/live/note_live/form_component.html.heex:33
#: lib/memex_web/live/note_live/form_component.html.heex:34
#: lib/memex_web/live/pipeline_live/form_component.html.heex:39
#: lib/memex_web/live/pipeline_live/form_component.html.heex:40
#: lib/memex_web/live/context_live/form_component.html.heex:34
#: lib/memex_web/live/context_live/form_component.html.heex:39
#: lib/memex_web/live/note_live/form_component.html.heex:32
#: lib/memex_web/live/note_live/form_component.html.heex:37
#: lib/memex_web/live/pipeline_live/form_component.html.heex:38
#: lib/memex_web/live/pipeline_live/form_component.html.heex:43
#, elixir-autogen, elixir-format
msgid "tag1,tag2"
msgstr ""
@ -378,12 +378,12 @@ msgstr ""
#: lib/memex_web/components/contexts_table_component.ex:47
#: lib/memex_web/components/notes_table_component.ex:47
#: lib/memex_web/components/pipelines_table_component.ex:47
#: lib/memex_web/live/context_live/form_component.html.heex:14
#: lib/memex_web/live/context_live/form_component.html.heex:15
#: lib/memex_web/live/note_live/form_component.html.heex:14
#: lib/memex_web/live/note_live/form_component.html.heex:15
#: lib/memex_web/live/pipeline_live/form_component.html.heex:14
#: lib/memex_web/live/pipeline_live/form_component.html.heex:15
#: lib/memex_web/live/context_live/form_component.html.heex:13
#: lib/memex_web/live/context_live/form_component.html.heex:17
#: lib/memex_web/live/note_live/form_component.html.heex:13
#: lib/memex_web/live/note_live/form_component.html.heex:17
#: lib/memex_web/live/pipeline_live/form_component.html.heex:13
#: lib/memex_web/live/pipeline_live/form_component.html.heex:17
#, elixir-autogen, elixir-format
msgid "slug"
msgstr ""
@ -456,8 +456,8 @@ msgstr ""
msgid "steps:"
msgstr ""
#: lib/memex_web/live/step_live/form_component.html.heex:14
#: lib/memex_web/live/step_live/form_component.html.heex:15
#: lib/memex_web/live/step_live/form_component.html.heex:13
#: lib/memex_web/live/step_live/form_component.html.heex:17
#, elixir-autogen, elixir-format
msgid "title"
msgstr ""
@ -467,16 +467,6 @@ msgstr ""
msgid "finally, i wanted to externalize the processes for common situations that use these thought processes at discrete steps. these are pipelines!"
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:91
#, elixir-autogen, elixir-format
msgid "for instance, a good context could be what makes some physical designs spark joy for you, and in that context you could backlink to the spoon note as an example of how it fits nicely into your hand."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:105
#, elixir-autogen, elixir-format
msgid "for instance, a pipeline for buying an object could have a step where you consider how much it sparks joy, and it could backlink to the physical designs context, maybe with some notes about how it applies in this case."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:59
#, elixir-autogen, elixir-format
msgid "i really admired the idea of a zettelkasten, especially with org-mode backlinks, however I felt like my notes would immediately become too messy by just putting everything into a single hierarchy."
@ -497,11 +487,6 @@ msgstr ""
msgid "in my opinion, notes should be written by any of the discrete objects or concepts that are meaningful to you in your life."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:102
#, elixir-autogen, elixir-format
msgid "in my opinion, pipelines should be pretty lightweight, and just backlink to contexts to provide most of the heavy lifting."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:28
#, elixir-autogen, elixir-format
msgid "memex"
@ -567,11 +552,6 @@ msgstr ""
msgid "how many people should i invite?"
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:119
#, elixir-autogen, elixir-format
msgid "note, context and pipeline slugs must be unique, and you are free to backlink to notes not written by you."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:122
#, elixir-autogen, elixir-format
msgid "so, i'd recommend inviting anyone you'd like to work on your collective memEx. however, when in doubt, hopefully setting up a new instance is easy enough. if it isn't, then feel free to let me know :)"
@ -691,22 +671,42 @@ msgstr ""
msgid "reset your password"
msgstr ""
#: lib/memex_web/live/pipeline_live/form_component.html.heex:25
#: lib/memex_web/live/pipeline_live/form_component.html.heex:29
#: lib/memex_web/live/step_live/form_component.html.heex:25
#: lib/memex_web/live/step_live/form_component.html.heex:29
#: lib/memex_web/live/pipeline_live/form_component.html.heex:26
#: lib/memex_web/live/pipeline_live/form_component.html.heex:30
#: lib/memex_web/live/step_live/form_component.html.heex:26
#: lib/memex_web/live/step_live/form_component.html.heex:30
#, elixir-autogen, elixir-format
msgid "use [[[note-slug]]] to link to a note or use [[context-slug]] to link to a context or [pipeline-slug] to link to a pipeline"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:25
#: lib/memex_web/live/context_live/form_component.html.heex:27
#: lib/memex_web/live/context_live/form_component.html.heex:26
#: lib/memex_web/live/context_live/form_component.html.heex:28
#, elixir-autogen, elixir-format, fuzzy
msgid "use [[note-slug]] to link to a note or [context-slug] to link to a context"
msgstr ""
#: lib/memex_web/live/note_live/form_component.html.heex:24
#: lib/memex_web/live/note_live/form_component.html.heex:25
#: lib/memex_web/live/note_live/form_component.html.heex:26
#, elixir-autogen, elixir-format, fuzzy
msgid "use [note-slug] to link to a note"
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:91
#, elixir-autogen, elixir-format, fuzzy
msgid "for instance, a good context could be what makes some physical designs spark joy for you, and in that context you could link to the spoon note as an example of how it fits nicely into your hand."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:105
#, elixir-autogen, elixir-format, fuzzy
msgid "for instance, a pipeline for buying an object could have a step where you consider how much it sparks joy, and it could link to the physical designs context, maybe with some notes about how it applies in this case."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:102
#, elixir-autogen, elixir-format, fuzzy
msgid "in my opinion, pipelines should be pretty lightweight, and just link to contexts to provide most of the heavy lifting."
msgstr ""
#: lib/memex_web/live/faq_live.html.heex:119
#, elixir-autogen, elixir-format, fuzzy
msgid "note, context and pipeline slugs must be unique, and you are free to link to notes not written by you."
msgstr ""

@ -67,12 +67,12 @@ msgstr ""
msgid "Welcome to memEx"
msgstr ""
#: lib/memex/accounts/email.ex:31
#: lib/memex/email.ex:31
#, elixir-autogen, elixir-format, fuzzy
msgid "confirm your memEx account"
msgstr ""
#: lib/memex/accounts/email.ex:37
#: lib/memex/email.ex:37
#, elixir-autogen, elixir-format, fuzzy
msgid "reset your memEx password"
msgstr ""
@ -87,7 +87,7 @@ msgstr ""
msgid "this email was sent from memEx at %{url}"
msgstr ""
#: lib/memex/accounts/email.ex:43
#: lib/memex/email.ex:43
#, elixir-autogen, elixir-format, fuzzy
msgid "update your memEx email"
msgstr ""

@ -0,0 +1,40 @@
defmodule Memex.EmailWorkerTest do
use Memex.DataCase, async: true
def perform_job(worker, args) do
Oban.Testing.perform_job(worker, args, [])
end
test "sending welcome email" do
user = user_fixture()
{:ok, _user} =
perform_job(Memex.EmailWorker, %{
"email" => "welcome",
"user_id" => user.id,
"attrs" => %{"url" => "test_url"}
})
end
test "sending reset password email" do
user = user_fixture()
{:ok, _user} =
perform_job(Memex.EmailWorker, %{
"email" => "reset_password",
"user_id" => user.id,
"attrs" => %{"url" => "test_url"}
})
end
test "sending update email email" do
user = user_fixture()
{:ok, _user} =
perform_job(Memex.EmailWorker, %{
"email" => "update_email",
"user_id" => user.id,
"attrs" => %{"url" => "test_url"}
})
end
end

@ -38,8 +38,9 @@ defmodule Memex.Fixtures do
def extract_user_token(fun) do
%{args: %{attrs: attrs, email: email_key, user_id: user_id}} = fun.(&"[TOKEN]#{&1}[TOKEN]")
# convert atoms to string keys
attrs = attrs |> Map.new(fn {atom_key, value} -> {atom_key |> Atom.to_string(), value} end)
attrs =
attrs
|> Map.new(fn {key, value} -> {Atom.to_string(key), value} end)
email =
email_key