Skip to content

Commit 7260d31

Browse files
committed
Merge branch 'main' into apb/data-source
2 parents b6073e1 + cbe3bf7 commit 7260d31

34 files changed

+823
-106
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# How to contribute
1+
# How to Contribute
22

33
## Issue Tags
44

@@ -45,33 +45,3 @@ get accepted:
4545

4646
If your pull-request addresses an issue then please add the corresponding
4747
issue's number to the description of your pull-request.
48-
49-
# How to work with this project locally
50-
51-
## Installation
52-
53-
First clone this repository:
54-
55-
```sh
56-
git clone git@github.com:BeaconCMS/beacon.git
57-
```
58-
59-
Call setup to install deps:
60-
61-
```sh
62-
mix setup
63-
```
64-
65-
## Running tests
66-
67-
```sh
68-
mix test
69-
```
70-
71-
## Running a local app
72-
73-
```sh
74-
iex -S mix dev
75-
```
76-
77-
Check out https://github.com/BeaconCMS/beacon/blob/main/dev.exs and visit http://localhost:4001/dev/home

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ Main components:
2525
- Admin - LiveView UI to manage layouts, pages, and all other resources. See https://github.com/BeaconCMS/beacon_live_admin
2626
- Page Builder - An easy to use, drag & drop UI for building pages, targeted to non-technical users. Not released yet, in the initial stages of development.
2727

28+
## Contributing
29+
30+
Check out the [CONTRIBUTING.md](https://github.com/BeaconCMS/beacon/blob/main/CONTRIBUTING.md) doc for overall guidelines to contribute to this project,
31+
then follow the [Local Development](https://github.com/BeaconCMS/beacon#local-development) steps to run a local project or watch the video below to understand more
32+
about Beacon internals:
33+
34+
<a href="https://www.youtube.com/watch?v=5jk0fIJOFuc">
35+
<img src="https://raw.githubusercontent.com/BeaconCMS/beacon/main/assets/images/youtube_card.png" width="512" alt="YouTube card - ElixirConf 2023 - Leandro Pereira - Beacon: The next generation of CMS in Phoenix LiveView">
36+
</a>
37+
2838
## Local Development
2939

3040
The file `dev.exs` is a self-contained Phoenix application running Beacon with sample data and code reloading enabled. Follow these steps to get a site up and running:
@@ -48,3 +58,12 @@ Note that running a named node isn't required unless you're running Beacon LiveA
4858

4959
Finally, visit any of the routes defined in `dev.exs` as http://localhost:4001/dev/home
5060
or request resources from the API as http://localhost:4001/api/pages
61+
62+
## Looking for help with your Elixir project?
63+
64+
<img src="assets/images/dockyard_logo.png" width="256" alt="DockYard logo">
65+
66+
At DockYard we are [ready to help you build your next Elixir project](https://dockyard.com/phoenix-consulting).
67+
We have a unique expertise in Elixir and Phoenix development that is unmatched and we love to [write about Elixir](https://dockyard.com/blog/categories/elixir).
68+
69+
Have a project in mind? [Get in touch](https://dockyard.com/contact/hire-us)!

assets/images/dockyard_logo.png

24.4 KB
Loading

assets/images/youtube_card.png

1.54 MB
Loading

dev.exs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ Logger.configure(level: :debug)
1717

1818
Application.put_env(:phoenix, :json_library, Jason)
1919

20+
display_error_pages? = false
21+
2022
Application.put_env(:beacon, SamplePhoenix.Endpoint,
2123
http: [ip: {127, 0, 0, 1}, port: 4001],
2224
server: true,
2325
live_view: [signing_salt: "aaaaaaaa"],
2426
secret_key_base: String.duplicate("a", 64),
25-
debug_errors: true,
27+
debug_errors: !display_error_pages?,
28+
render_errors: [formats: [html: BeaconWeb.ErrorHTML]],
2629
check_origin: false,
2730
pubsub_server: SamplePhoenix.PubSub,
2831
live_reload: [

guides/deployment/fly.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Once you have a Beacon site up and running locally, you can have it deployed on
44

55
## Fly.io CLI
66

7-
Firstly instal the fly cli tool as described at https://fly.io/docs/hands-on/install-flyctl. You're gonna use it to deploy your beacon site.
7+
Firstly, install the Fly CLI tool as described at https://fly.io/docs/hands-on/install-flyctl. You're going to use it to deploy your beacon site.
88

99
## Sign in or sign up
1010

@@ -22,7 +22,7 @@ fly auth login
2222

2323
## Dockerfile
2424

25-
Aplications on Fly run on containers, let's generate a Dockerfile and other supporting files, and then make a couple of changes:
25+
Applications on Fly run on containers, let's generate a Dockerfile and other supporting files, and then make a couple of changes:
2626

2727
Run:
2828

@@ -122,7 +122,7 @@ Before we can access the deployed site let's run seeds to populate some sample d
122122
fly ssh console
123123
```
124124

125-
2. Open a IEx console:
125+
2. Open an IEx console:
126126

127127
```sh
128128
app/bin/my_app remote
@@ -134,11 +134,11 @@ app/bin/my_app remote
134134
MyApp.Release.beacon_seeds
135135
```
136136

137-
Note that you could save some commands and just call `fly ssh console --command "/app/bin/beacon_seeds"` to run seeds, but it may fail and at this momment it's recommended to connected to the instance as showed before.
137+
Note that you could save some commands and just call `fly ssh console --command "/app/bin/beacon_seeds"` to run seeds, but it may fail and at this momment it's recommended to connect to the instance as shown before.
138138

139139
## Open
140140

141-
Finally run the following command to see your site live:
141+
Finally, run the following command to see your site live:
142142

143143
```sh
144144
fly open my_site/home

guides/introduction/installation.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Beacon is an application that runs on top of an existing Phoenix LiveView applic
44

55
## TLDR
66

7-
We recomment following the guide thoroughly, but if you want a short version or to just recap the main steps:
7+
We recommend following the guide thoroughly, but if you want a short version or to just recap the main steps:
88

99
1. Install Elixir v1.14+
1010

@@ -30,7 +30,7 @@ We recomment following the guide thoroughly, but if you want a short version or
3030

3131
6. Run `mix deps.get`
3232

33-
7. Add `:beacon` dependency to `.formatter.exs` in `:
33+
7. Add `:beacon` to `import_deps` in the .formatter.exs file.
3434

3535
8. Run `mix beacon.install --site my_site`
3636

@@ -112,8 +112,8 @@ mix deps.get
112112

113113
```elixir
114114
[
115-
import_deps: [:ecto, :ecto_sql, :phoenix, :beacon],
116-
# rest of file
115+
import_deps: [:ecto, :ecto_sql, :phoenix, :beacon],
116+
# rest of file
117117
]
118118
```
119119

@@ -296,7 +296,7 @@ For more info on site options, check out `Beacon.start_link/1`.
296296
<main>
297297
<h2>A blog</h2>
298298
<ul>
299-
<li>Path Params Blog Slug: <%%= @beacon_path_params.blog_slug %></li>
299+
<li>Path Params Blog Slug: <%%= @beacon_path_params["blog_slug"] %></li>
300300
<li>Live Data blog_slug_uppercase: <%%= @beacon_live_data.blog_slug_uppercase %></li>
301301
</ul>
302302
</main>

lib/beacon/content.ex

Lines changed: 146 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ defmodule Beacon.Content do
2626
import Ecto.Query
2727

2828
alias Beacon.Content.Component
29+
alias Beacon.Content.ErrorPage
2930
alias Beacon.Content.Layout
3031
alias Beacon.Content.LayoutEvent
3132
alias Beacon.Content.LayoutSnapshot
@@ -48,7 +49,7 @@ defmodule Beacon.Content do
4849
@doc """
4950
Returns the list of meta tags that are applied to all pages by default.
5051
51-
These meta tags can be overwriten or extended on a Layout or Page level.
52+
These meta tags can be overwritten or extended on a Layout or Page level.
5253
"""
5354
@spec default_site_meta_tags() :: [map()]
5455
def default_site_meta_tags do
@@ -74,6 +75,18 @@ defmodule Beacon.Content do
7475
Layout.changeset(layout, attrs)
7576
end
7677

78+
@doc """
79+
Returns a map of attrs to load the default layout into new sites.
80+
"""
81+
@spec default_layout() :: map()
82+
@doc type: :layouts
83+
def default_layout do
84+
%{
85+
title: "Default",
86+
template: "<%= @inner_content %>"
87+
}
88+
end
89+
7790
@doc """
7891
Creates a layout.
7992
@@ -1676,7 +1689,7 @@ defmodule Beacon.Content do
16761689
16771690
Note that the `:page` assigns is made available as `assigns["page"]` (String.t) due to how Solid works.
16781691
1679-
Snipets can be used in:
1692+
Snippets can be used in:
16801693
16811694
* Meta Tag value
16821695
* Page Schema (structured Schema.org tags)
@@ -1705,6 +1718,137 @@ defmodule Beacon.Content do
17051718
end
17061719
end
17071720

1721+
# ERROR PAGES
1722+
1723+
@doc """
1724+
Returns an `%Ecto.Changeset{}` for tracking error page changes.
1725+
1726+
## Example
1727+
1728+
iex> change_error_page(error_page, %{status: 404})
1729+
%Ecto.Changeset{data: %ErrorPage{}}
1730+
1731+
"""
1732+
@doc type: :error_pages
1733+
@spec change_error_page(ErrorPage.t(), map()) :: Changeset.t()
1734+
def change_error_page(%ErrorPage{} = error_page, attrs \\ %{}) do
1735+
ErrorPage.changeset(error_page, attrs)
1736+
end
1737+
1738+
@doc """
1739+
Returns the error page for a given site and status code, or `nil` if no matching error page exists.
1740+
"""
1741+
@doc type: :error_pages
1742+
@spec get_error_page(Site.t(), ErrorPage.error_status()) :: ErrorPage.t() | nil
1743+
def get_error_page(site, status) do
1744+
Repo.one(
1745+
from e in ErrorPage,
1746+
where: e.site == ^site,
1747+
where: e.status == ^status
1748+
)
1749+
end
1750+
1751+
@doc """
1752+
Lists all error pages for a given site.
1753+
1754+
## Options
1755+
1756+
* `:per_page` - limit how many records are returned, or pass `:infinity` to return all records.
1757+
* `:preloads` - a list of preloads to load.
1758+
1759+
"""
1760+
@doc type: :error_pages
1761+
@spec list_error_pages(Site.t(), keyword()) :: [ErrorPage.t()]
1762+
def list_error_pages(site, opts \\ []) do
1763+
per_page = Keyword.get(opts, :per_page, 20)
1764+
preloads = Keyword.get(opts, :preloads, [])
1765+
1766+
site
1767+
|> query_list_error_pages_base()
1768+
|> query_list_error_pages_limit(per_page)
1769+
|> query_list_error_pages_preloads(preloads)
1770+
|> Repo.all()
1771+
end
1772+
1773+
defp query_list_error_pages_base(site) do
1774+
from p in ErrorPage,
1775+
where: p.site == ^site,
1776+
order_by: [asc: p.status]
1777+
end
1778+
1779+
defp query_list_error_pages_limit(query, limit) when is_integer(limit), do: from(q in query, limit: ^limit)
1780+
defp query_list_error_pages_limit(query, :infinity = _limit), do: query
1781+
defp query_list_error_pages_limit(query, _per_page), do: from(q in query, limit: 20)
1782+
1783+
defp query_list_error_pages_preloads(query, [_preload | _] = preloads) do
1784+
from(q in query, preload: ^preloads)
1785+
end
1786+
1787+
defp query_list_error_pages_preloads(query, _preloads), do: query
1788+
1789+
@doc """
1790+
Creates a new error page.
1791+
"""
1792+
@doc type: :error_pages
1793+
@spec create_error_page(%{site: Site.t(), status: ErrorPage.error_status(), template: binary(), layout_id: Ecto.UUID.t()}) ::
1794+
{:ok, ErrorPage.t()} | {:error, Changeset.t()}
1795+
def create_error_page(attrs) do
1796+
%ErrorPage{}
1797+
|> ErrorPage.changeset(attrs)
1798+
|> Repo.insert()
1799+
end
1800+
1801+
@doc """
1802+
Creates a new error page, raising if the operation fails.
1803+
"""
1804+
@doc type: :error_pages
1805+
@spec create_error_page!(%{site: Site.t(), status: ErrorPage.error_status(), template: binary(), layout_id: Ecto.UUID.t()}) ::
1806+
ErrorPage.t()
1807+
def create_error_page!(attrs) do
1808+
case create_error_page(attrs) do
1809+
{:ok, error_page} -> error_page
1810+
{:error, changeset} -> raise "failed to create error page, got: #{inspect(changeset.errors)}"
1811+
end
1812+
end
1813+
1814+
@doc """
1815+
Returns attr data to load the default error_pages into new sites.
1816+
"""
1817+
@spec default_error_pages() :: [map()]
1818+
@doc type: :error_pages
1819+
def default_error_pages do
1820+
for status <- [404, 500] do
1821+
%{
1822+
status: status,
1823+
template: Plug.Conn.Status.reason_phrase(status)
1824+
}
1825+
end
1826+
end
1827+
1828+
@doc """
1829+
Updates an error page.
1830+
"""
1831+
@doc type: :error_pages
1832+
@spec update_error_page(ErrorPage.t(), map()) :: {:ok, ErrorPage.t()} | {:error, Changeset.t()}
1833+
def update_error_page(error_page, attrs) do
1834+
error_page
1835+
|> ErrorPage.changeset(attrs)
1836+
|> Repo.update()
1837+
|> tap(&maybe_reload_error_page/1)
1838+
end
1839+
1840+
def maybe_reload_error_page({:ok, error_page}), do: PubSub.error_page_updated(error_page)
1841+
def maybe_reload_error_page({:error, _error_page}), do: :noop
1842+
1843+
@doc """
1844+
Deletes an error page.
1845+
"""
1846+
@doc type: :error_pages
1847+
@spec delete_error_page(ErrorPage.t()) :: {:ok, ErrorPage.t()} | {:error, Changeset.t()}
1848+
def delete_error_page(error_page) do
1849+
Repo.delete(error_page)
1850+
end
1851+
17081852
# PAGE EVENT HANDLERS
17091853

17101854
@doc """

0 commit comments

Comments
 (0)