beaconcms / beacon_live_admin Goto Github PK
View Code? Open in Web Editor NEWAdmin UI to manage content for sites built by Beacon
Home Page: https://beaconcms.org
License: MIT License
Admin UI to manage content for sites built by Beacon
Home Page: https://beaconcms.org
License: MIT License
On the Revisions tab in the Layouts or Pages interfaces, you can see the code editor displaying templates and Elixir code but there's no shortcut to copy such content. We want to add a copy button next to those elements using the beacon_admin:clipcopy event. The Media Library has implemented the same feature, that's a good example to check out.
Add a site
map assign with url
field to page snippets, which is useful for some meta tags like og:url
that could be defined as {{ site.url }}/{{ page.path }}
The url can be obtained from the config endpoint:
Beacon.Config.fetch!(site).endpoint.url()
[error] #PID<0.1084.0> running Phoenix.Endpoint.SyncCodeReloadPlug (connection #PID<0.891.0>, stream id 29) terminated
Server: localhost:4001 (https)
Request: GET /admin/shell/pages
** (exit) an exception was raised:
** (MatchError) no match of right hand side value: %{"_csrf_token" => "02NPbENSTJ_tS9dtH-7XCTx7", "live_socket_id" => "users_sessions:OsOtaeAOGX4zWeTzFKvVL3auSZ_pi2vUYNK3hn6imhA=", "locale" => "en", "pages" => [{"/layouts", Beacon.LiveAdmin.LayoutEditorLive.Index, :index, %{}}, {"/layouts/new", Beacon.LiveAdmin.LayoutEditorLive.New, :new, %{}}, {"/layouts/:id", Beacon.LiveAdmin.LayoutEditorLive.Edit, :edit, %{}}, {"/layouts/:id/meta_tags", Beacon.LiveAdmin.LayoutEditorLive.MetaTags, :meta_tags, %{}}, {"/layouts/:id/revisions", Beacon.LiveAdmin.LayoutEditorLive.Revisions, :revisions, %{}}, {"/layouts/:id/resource_links", Beacon.LiveAdmin.LayoutEditorLive.ResourceLinks, :resource_links, %{}}, {"/pages", Beacon.LiveAdmin.PageEditorLive.Index, :index, %{}}, {"/pages/new", Beacon.LiveAdmin.PageEditorLive.New, :new, %{}}, {"/pages/:id", Beacon.LiveAdmin.PageEditorLive.Edit, :edit, %{}}, {"/pages/:id/meta_tags", Beacon.LiveAdmin.PageEditorLive.MetaTags, :meta_tags, %{}}, {"/pages/:id/schema", Beacon.LiveAdmin.PageEditorLive.Schema, :schema, %{}}, {"/pages/:id/revisions", Beacon.LiveAdmin.PageEditorLive.Revisions, :revisions, %{}}, {"/pages/:page_id/events", Beacon.LiveAdmin.PageEditorLive.EventHandlers, :events, %{}}, {"/pages/:page_id/events/:event_handler_id", Beacon.LiveAdmin.PageEditorLive.EventHandlers, :events, %{}}, {"/pages/:page_id/variants", Beacon.LiveAdmin.PageEditorLive.Variants, :variants, %{}}, {"/pages/:page_id/variants/:variant_id", Beacon.LiveAdmin.PageEditorLive.Variants, :variants, %{}}, {"/components", Beacon.LiveAdmin.ComponentEditorLive.Index, :index, %{}}, {"/components/new", Beacon.LiveAdmin.ComponentEditorLive.New, :new, %{}}, {"/components/:id", Beacon.LiveAdmin.ComponentEditorLive.Edit, :edit, %{}}, {"/media_library", Beacon.LiveAdmin.MediaLibraryLive.Index, :index, %{}}, {"/media_library/upload", Beacon.LiveAdmin.MediaLibraryLive.Index, :upload, %{}}, {"/media_library/:id", Beacon.LiveAdmin.MediaLibraryLive.Index, :show, %{}}], "user_token" => <<58, 195, 173, 105, 224, 14, 25, 126, 51, 89, 228, 243, 20, 171, 213, 47, 118, 174, 73, 159, 233, 139, 107, 212, 96, 210, 183, 134, 126, 162, 154, 16>>}
(beacon_live_admin 0.1.0-dev) lib/beacon/live_admin/page_live.ex:29: Beacon.LiveAdmin.PageLive.mount/3
(phoenix_live_view 0.19.5) lib/phoenix_live_view/utils.ex:394: anonymous fn/6 in Phoenix.LiveView.Utils.maybe_call_live_view_mount!/5
(telemetry 1.2.1) /Users/kaygee/Sites/swell/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
(phoenix_live_view 0.19.5) lib/phoenix_live_view/static.ex:278: Phoenix.LiveView.Static.call_mount_and_handle_params!/5
(phoenix_live_view 0.19.5) lib/phoenix_live_view/static.ex:119: Phoenix.LiveView.Static.render/3
(phoenix_live_view 0.19.5) lib/phoenix_live_view/controller.ex:39: Phoenix.LiveView.Controller.live_render/3
(phoenix 1.7.7) lib/phoenix/router.ex:430: Phoenix.Router.__call__/5
(swell 1.5.2) lib/swell_web/endpoint.ex:1: SwellWeb.Endpoint.plug_builder_call/2
(swell 1.5.2) deps/plug/lib/plug/debugger.ex:136: SwellWeb.Endpoint."call (overridable 3)"/2
(swell 1.5.2) lib/swell_web/endpoint.ex:1: SwellWeb.Endpoint.call/2
(phoenix 1.7.7) lib/phoenix/endpoint/sync_code_reload_plug.ex:22: Phoenix.Endpoint.SyncCodeReloadPlug.do_call/4
(plug_cowboy 2.6.1) lib/plug/cowboy/handler.ex:11: Plug.Cowboy.Handler.init/2
(cowboy 2.10.0) /Users/kaygee/Sites/swell/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2
(cowboy 2.10.0) /Users/kaygee/Sites/swell/deps/cowboy/src/cowboy_stream_h.erl:306: :cowboy_stream_h.execute/3
(cowboy 2.10.0) /Users/kaygee/Sites/swell/deps/cowboy/src/cowboy_stream_h.erl:295: :cowboy_stream_h.request_process/3
(stdlib 5.0.2) proc_lib.erl:241: :proc_lib.init_p_do_apply/3
I get this error even if I add the on_mount
option to the router for beacon_admin_site
and log in successfully. This error also occurs on layouts, components, and media library.
I don't think this is a node
connection issue because I can see the site on the root admin
page but clicking on the button to navigate to the PageLive live_view
blows up.
I did some inspection of the tuple returned from Beacon.LiveAdmin.Router.__session_options__/3
and indeed there isn't a "beacon_live_admin_page_url"
key in there.
I put a dbg(session)
into the Beacon.LiveAdmin.PageLive.mount/3
and got this:
[(beacon_live_admin 0.1.0-dev) deps/beacon_live_admin/lib/beacon/live_admin/page_live.ex:29: Beacon.LiveAdmin.PageLive.mount/3]
session #=> %{
"_csrf_token" => "redacted",
"live_socket_id" => "users_sessions:redacted",
"locale" => "en",
"pages" => [
{"/layouts", Beacon.LiveAdmin.LayoutEditorLive.Index, :index, %{}},
{"/layouts/new", Beacon.LiveAdmin.LayoutEditorLive.New, :new, %{}},
{"/layouts/:id", Beacon.LiveAdmin.LayoutEditorLive.Edit, :edit, %{}},
{"/layouts/:id/meta_tags", Beacon.LiveAdmin.LayoutEditorLive.MetaTags,
:meta_tags, %{}},
{"/layouts/:id/revisions", Beacon.LiveAdmin.LayoutEditorLive.Revisions,
:revisions, %{}},
{"/layouts/:id/resource_links",
Beacon.LiveAdmin.LayoutEditorLive.ResourceLinks, :resource_links, %{}},
{"/pages", Beacon.LiveAdmin.PageEditorLive.Index, :index, %{}},
{"/pages/new", Beacon.LiveAdmin.PageEditorLive.New, :new, %{}},
{"/pages/:id", Beacon.LiveAdmin.PageEditorLive.Edit, :edit, %{}},
{"/pages/:id/meta_tags", Beacon.LiveAdmin.PageEditorLive.MetaTags,
:meta_tags, %{}},
{"/pages/:id/schema", Beacon.LiveAdmin.PageEditorLive.Schema, :schema, %{}},
{"/pages/:id/revisions", Beacon.LiveAdmin.PageEditorLive.Revisions,
:revisions, %{}},
{"/pages/:page_id/events", Beacon.LiveAdmin.PageEditorLive.EventHandlers,
:events, %{}},
{"/pages/:page_id/events/:event_handler_id",
Beacon.LiveAdmin.PageEditorLive.EventHandlers, :events, %{}},
{"/pages/:page_id/variants", Beacon.LiveAdmin.PageEditorLive.Variants,
:variants, %{}},
{"/pages/:page_id/variants/:variant_id",
Beacon.LiveAdmin.PageEditorLive.Variants, :variants, %{}},
{"/components", Beacon.LiveAdmin.ComponentEditorLive.Index, :index, %{}},
{"/components/new", Beacon.LiveAdmin.ComponentEditorLive.New, :new, %{}},
{"/components/:id", Beacon.LiveAdmin.ComponentEditorLive.Edit, :edit, %{}},
{"/media_library", Beacon.LiveAdmin.MediaLibraryLive.Index, :index, %{}},
{"/media_library/upload", Beacon.LiveAdmin.MediaLibraryLive.Index, :upload,
%{}},
{"/media_library/:id", Beacon.LiveAdmin.MediaLibraryLive.Index, :show, %{}}
],
"user_token" => <<redacted>>
}
I'm not sure why the session map passed to mount/3
in PageLive
doesn't include the "beacon_live_admin_page_url"
.
Can anyone provide any insight?
We can technically disable a variant by setting the :weight
to zero, but ideally we would also have a "delete" button which would remove the variant entirely, so it does not show up in the list and cannot be selected for editing.
Update the plugins
section of the tailwind.config.js.eex template to support heroicons.
The template used by Phoenix is https://github.com/phoenixframework/phoenix/blob/a310102eb0e20b918624bb2323a6afb124fcaddd/installer/templates/phx_assets/tailwind.config.js
The generated css must contain the icons.
See #89
Page preview feature before publishing
FYI @adam-phillips
Right now it is possible for sum(variant_weights)
to exceed 100, in which case some variants will be rendered less frequently than expected. Ideally we could have an additional validation when updating a variant, to sum all the weights together and ensure that it's less than 100.
On the Variant and Event subpages, the page initially starts off very blank. Once you click "Add a variant" or "Add an event" you start creating a list of items on the panel on the left, and their default name is always the same. When you select one to start editing, there is no visual indication of the current selection.
Small adjustments I'd like to propose that would go a long way in improving the user experience here includes:
Create and edit Page.Events in the Page Editor
This is a embeded field which may cause some issues and can be converted to a regular relational table, similar to Content.PageVariant
, but it will conflict with the existing PageEvent schema so we need to find a way to accommodate both schemas.
As a PO, I would like to know which pages are using exact assets. We should be able to show which pages are using a given asset, maybe even a grouping feature
Admin interface to manage snippet helpers (similar to layouts, components, and others).
Name is an input text and body is a code editor.
A single admin instance may manage multiple sites so we want to display a site selector in the navbar displaying all running sites which will redirect to the a chosen site.
Note that we don't currently have a dashboard or a main page for each site, so it can redirect to the /layouts page for the given site.
In the above instance, I have already uploaded a test file, shown in the thumbnail. But the uploader message is still "Choose a file, No file chosen" which leaves me wondering if the file is not actually queued, or if it's asking me to upload a second image, or would selecting the "choose a file" button override the image I just uploaded?
A second pain point in this modal is the lack of a clear path forward from this state. The only option is the "X"in the top right corner, but it's unclear whether that will "save and close" or "delete and close" my changes. Some options I think users would expect to see include "Save" (which would also close the modal and return me to the library), "Delete Image" which would clear the selected image but not close the modal and "Close without saving"
The .livemd files generated by Livebook can be used to write pages for Beacon since it's essentially markdown files as long as they are exported with outputs.
So we want to:
/pages/new
/pages/:id
That button will accept the upload of .livemd files, fill the page template with the file content, and change the template format to "Livemd (Livebook)" (see below).
We need to add a new template format named :livemd
along with :heex
and :md
to differentiate this kind of content and allow further customizations in the future.
?query=FOO&page=INT&sort=NAME
Beacon live data source is currently defined as a module in the host application but that impose a couple of problems:
For those reasons, we need to to:
The layout for that page may contain:
The data type allows us to display the correct "content" field.
One idea which came up during the original conversation with Brian around the page variants feature:
If we want to force a page to use a specific variant, we could pass a query param to specify which one.
So for example if a page deployed at mysite.com/blog has a variant named "featured_on_top" then one could force rendering that specific variant by visiting mysite.com/blog?variant=featured_on_top
On the Page Revisions tab you can see the variants and event handler code in a modal, but that modal is too small to properly inspect and read the code. We want to increase the height and width of that modal to around 70% or 80% of the viewport size.
Page Variants are saved in the snapshots, but currently not shown in the Revisions page content.
In order to prevent the Revisions page from growing too long, we should either:
Clicking on "Save Changes" on most pages won't display a flash message or any other visual feedback to tell the user if the operations has succeed or failed. That happens because there's no page redirect so the flash message isn't displayed.
We want to research a solution that's simple and capable of improving UX by displaying some visual feedback to users.
UX adjustments according to MarCom team
At this very moment we have layout, stylesheet, component, page_event, page_helper. But as well it'll be useful to have component editing
The code inserted into the page event handler is not validated which imposes some risks, including breaking the site with a malformed code. Similar to what is done with HEEx templates, we want to validate that code is semantically correct, ie: it compiles.
We could validate the code with something like Code.compile_string/2
Only issue is that the code expects a variable event_params
to exist and be a map. Since this variable is only created when the code is injected into the Page module, it will not be available during validation. One solution could be to append a dummy variable assignment just for validation i.e.
to_validate = "event_params = %{}\n" <> event_handler_code
?query=FOO&page=INT&sort=NAME
Managing app icons may be complex and time consuming for end users. We want to 1) have a page on beacon admin to upload icons, and 2) generate the html tags for displaying such icons.
Ideally users would upload a high-res .svg file that beacon can convert to:
We may allow users uploading individual files, either to overwrite the generated one or because users may not have the high-res .svg file.
The expected tags are:
<link rel="icon" href="{site_prefix}/favicon.ico" sizes="any">
<link rel="icon" href="{site_prefix}/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="{site_prefix}/apple-touch-icon.png"><!-- 180ร180 -->
<link rel="manifest" href="{site_prefix}/manifest.webmanifest">
Note that {site_prefix}
has to be replaced with router(conn).__beacon_site_prefix__(site)
, see asset_path/2
for example.
Read https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs for the full explanation.
Extra:
For organization purposes and because these apps will have separated release management. Also this is a good opportunity to reorganize Beacon core modules into a well defined public API.
Update: created https://github.com/BeaconCMS/beacon_live_admin
See #70 (comment)
Allow creating and updating external resource links in the Layout Editor. See BeaconCMS/beacon#322 for more info about external resource links.
The UI can be similar to https://github.com/BeaconCMS/beacon_live_admin/blob/main/lib/beacon/live_admin/live/meta_tags_component.ex where users can add new records (links in this case) and also include extra properties as they need.
Ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link
In the design system we have several variations of buttons, so I'd like to add support for these variants without needing to create a new component but modifying the existing component to render different styles based on the button type.
There are many places in the recent updates to the admin where we have large blue (primary) buttons where a more discreet secondary or tertiary button would be more fitting, since its not a primary action.
Also include support for an accessible icon-only button.
As a PO, I would like to have the ability to rename asset filename. Pay attention: don't allow for file extension rename
Beacon should be able to support multiple variants of a given URL and be able to set weights on the render frequency.
The variants should be infinite. When visiting the URL the variants are not present in the URL however we could selectively render a given variant with a query param:
https://dockyard.com/campaign-page?variant=a
something like that
for analytics and conversion testing we can embed the variant name.
Users should be able to inject custom links in the navbar to support adding a Sign Out link or any other link useful on their admin page.
The UX when authoring layouts and pages is not that great currently. In order to make changes I have to first press "save changes" followed by a "publish" and then reload my browser window to see the changes I did.
It would be much nicer to be able to preview the changes while editing without having to publish and refresh.
Some other random feedback:
Regular Markdown converter isn't capable of handling HEEx features. We want a subset of a regular Markdown that is capable of parsing and generating valid HEEx without losing features or breaking the compilation.
Beacon provides function components to display assets and will provide components for building pages, for eg:
<div>
<BeaconWeb.Components.image name="my_image.png" />
</div>
Using such component should generate the expected HTML tags as it would in a HEEx template.
A regular markdown link should probably generate the same markup as <.link navigate=...">
to include the phx-*
attributes and allow it to transition pages efficiently, otherwise it triggers a redirect.
MDX is a great solution for the JS ecosystem and we it can serve as inspiration to build something similar in Elixir.
The library md may be is capable of embedding heex but it doesn't support the CommonMark spec.
So a new library mdex was created to support what is needed for Beacon, but loading Phoenix Components is still a WIP.
I'm trying the project on my live_view app and getting... well, not very far.
/assets/svelte/HelloSvelte.svelte
looks like this:
<script>
alert('Does this work????');
</script>
<h1>I'm the hello world</h1>
On my live_view template I render it like this:
<%= if @visual_mode do %>
Before svelte component
<.svelte name="HelloSvelte" props={%{foo: "bar"}} socket={@socket} />
After svelte component
<% else %>
...
<%.end %>
After following the install steps, the app runs without any errors on the phoenix side of things, but nothing renders. The browser's console does show an error message: unknown hook found for "SvelteHook
.
What may I be missing?
As a PO I'd like to know a list of assets that are currently in use/not in use. We should be able to show a list of all assets that are currently in use and not in use
Add a search input to Components
page to search by "name". Similar to the search on Layouts and Pages.
User could create own error pages like 404, 500 etc
Add a button next to the "Path" input in the Page form to automatically generate and fill the path input.
This button most likely can be just an icon but need to experiment what works better.
Allow users to republish a page under a new path. It needs to:
Add filtering of assets by type to BeaconWeb.Admin.MediaLibraryLive.Index
. Filter by all types available https://github.com/BeaconCMS/beacon/blob/7790eb72769a026c0bdfc3167aab394a9b73ce91/lib/beacon/media_library/asset.ex#L9
Given this configuration for Resource Links:
It will generate:
<link as="" crossorigin="" href="https://cdn.mysite.com" rel="preconnect" type="">
<link as="font" crossorigin="anonymous" href="https://cdn.mysite.com/font.woff2" rel="preload" type="font/woff2">
But it should remove the keys that have a null
or ""
value, generating:
<link href="https://cdn.mysite.com" rel="preconnect">
<link as="font" crossorigin="anonymous" href="https://cdn.mysite.com/font.woff2" rel="preload" type="font/woff2">
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.