tmbb

tmbb

Mandarin + Forage - An admin tool for phoenix

I’ve been working on two packages (not on hex.pm yet) to build admin interfaces for phoenix apps:

  • bureaucrat - which contains a bunch of generators to create very feature-rich CRUD views for your resources (with filtering, sorting and proper pagination out of the box)

  • forage (the name comes from the rummage package) - which does the bulk of the work by allowing easy creating of dynamic ecto queries based on plug query parameters. It also contains widgets which make it easy to create search filters, pagination widgets, etc. It acts as a bridge between the form in the frontend and the ecto queries in the backend. Unlike rummage, it’s coupled to plug applications, while rummage tries to be frontend-independent. I don’t think that in the current state of the elixir ecosystem decoupling it from plug is worth it.

Documentation is severely lacking, but those who are interested can look at an example project here: https://github.com/tmbb/bureaucrat_demo_app

The packages lack a lot of documentation, and I’ll work on that over the next weeks now that I’m happy with the functionality.

Roadmap

I’m planning on doing the following:

  1. Documentation, documentation, documentation…

  2. In particular, documenting forage’s functionality, because it can be useful outside Bureaucrat. I do try very hard to make it work as a black box, that is, as longa s you use the correct widgets in the frontend things should just work, but people who want to extend it need some guidance.

  3. Make Paginator (a library which I use for pagination) support ecto 3.

  4. Improving forage so that it is less dependent on the Repo. Everything should work with “raw” ecto queries independent of the Repo. That will probably require some PRs to the paginator package which I use for pagination.

  5. Make bureaucrat play better with many-to-many relations. That will require working mostly on forage, and only minor changes to Bureaucrat itself

  6. Make bureaucrat independent of JQuery, and find a better way to packaging the necessary Javascript. The current generated templates get all JS and CSS from a CDN and embed some inline Javascript to make the Select2 widgets work.

  7. Write a proper tutorial, based on [this tutorial](https://flask-appbuilder.readthedocs.io/en/latest/quickminimal.html, for the Flask application framework (which is a python project)

Most Liked

tmbb

tmbb

As it turns out, bureaucrat was already of an elixir package on Hex.

I’ve changed the name to mandarin and published it as it is so that no one else takes the name in the mean time (renaming this project again is a chore I’d like to avoid). To publish mandarin, I’ve had to publish forage too. None of the packages are exactly ready for use in production. They have no tests and the documentation is still lacking.

“Mandarin” was the name given to the official of the Chinese empire by Portuguese explorers in the Far East in the 1500s. It is commonly said to come from the Portuguese word “mandar”, which means “to give orders/boss around”, but this etymology turns out to be fake (although it’s much cooler than the real one). Actually it comes from a Malay word for “boss” in use at the time. Basically a Mandarin is a Chinese bureaucrat, so it is a good replacement name.

Could a nice mod please change the title of this thread to “Mandarin + Forage - An admin tool for Phoenix”?

EDIT: Mandarin has the obvious advantage that it is derived from Portuguese (actually from “Old Portuguese”, because nowadays the word is written as “mandarim”), unlike Bureaucrat, which comes from French. As all French words, it’s impossible to write correctly on the first try, which can lead to countless typos in your code, so maybe this change is for the best :smile: C’est la vie… On the other hand, spelling rules in Portuguese are (mostly) consistent and Portuguese words are easy to write. Which only proves the superiority of the Portuguese language over everything else.

The above is obviously a joke

tmbb

tmbb

Now I believe I’m getting really close to 1.0. The main new features (already reflected in the GitHub repo) are the following:

  • Updated the generators in order to be more compatible with what Phoenix 1.6 generates

  • Made sure all tests pass (the generators weren’t buggy themselves, but the tests hadn’t been updated to reflect changes in the generators)

  • Use “vertical feature folders” which keep your controllers, views and templates together in the same directory, which makes it easy to modify related parts of the source code

  • As a consequence of the above, there is now a mix mandarin.uninstall MyContext which completely purges all the context diurectories and files and all references to that context from the router. This is very useful when your database design is still in flux and you might want to tear down the whole mandarin files and build them again

  • There is now a programatic interface to mandarin generators using the Mandarin.Design module, which allows you to generate the interface for a bunch of schemas from the comfort of an Elixir script instead of having to fiddle with the command line. To keep the design close to the normal Phoenix generators, I’m going to keep the command line interface as the main form of interaction with mandarin, but that might change in a putative 2.0 version

  • Mandarin now includes a mandarin.gen.auth AuthContext User users modelled on the phx.gen.auth generator but with support for “vertical feature folders” and support for prettier forms using forage widgets and a boostrap template by default

Things that haven’t changes:

  • Forage is still coupled to bootstrap; that’s pretty much unavoidable for a library of frontend widgets. The widgets must be styled with something, and bootstrap is still one of the easiest frameworks to use and customize, particularly for something like CRUD pages

  • Mandarin still dumps a bunch of files in your application. I’ve decided that mandarin will continue to focus on code generators instead of macros or other use of compile/runtime metaprogramming. No mandarin code runs at runtime.

  • No integration with LiveView. Simple CRUD pages are easy to do with normal controllers + minimal AJAX and more complex CRUD pages are outside of Mandarin’s scope. I’ve had some succes in integrating AlpineJS into mandarin pages (although neither Mandarin nor Forage contain any direct support for it)

The main problems I’ve had in getting to this stage are the fact that Phoenix continues to change the generators (for the better, of course!) on each minor version, and I took som etime to catch up to it. Although my generators are mostly copied from Phoenix, they have some important customizations, so thet job of updating them is not exactly simple. Note that this is not a case of Phoenix changing in backward-incompatible ways; it’s just a case of generators being different.

dimitarvp

dimitarvp

I’d use something like bureacratic or frontdesk.

Well, this is open source. Assuming a car doesn’t kill you on the spot one morning, you can always hand ownership over to somebody else. I see nothing wrong with a bit more official-looking name.

peerreynders

peerreynders

Go for an “adjacent” name then, for example:

The Bennu is an ancient Egyptian deity linked with the sun, creation, and rebirth. It may have been the inspiration for the phoenix in Greek mythology.

just as an example.

tmbb

tmbb

So I’ve made some progress. I can generate automatically the Controllers, the Views and the code to access the resources from the database. The only thing I haven’t solved yet how to handle templates. I’m trying to make this work without generating any files to the disk, but I want users to be able to supply their own templates for maximum customization.

Currently the following code generates a fully fledged admin interface that works with the templates generated by the Mandarin generators (only the templates, no need for views, controllers, etc.). I’m actually re-implementing a demo application with the new system by deleting the files I don’t need as I replace them with macros.

First, the code that creates an admin interface (aptly called Mandarin.Magik, but I’m open to new naming suggestions):

defmodule MandarinOfficeWeb.ExampleAdmin do
  alias MandarinOffice.Admin

  use Mandarin.Magik,
    app_web: MandarinOfficeWeb,
    scope: MandarinOfficeWeb.Admin,
    repo: MandarinOffice.Repo

  add_resource(Admin.Employee)
  add_resource(Admin.Department)
  add_resource(Admin.Function)
  add_resource(Admin.Benefit)
end

Now, the router (the magik part is at the end):

defmodule MandarinOfficeWeb.Router do
  use MandarinOfficeWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", MandarinOfficeWeb do
    pipe_through :browser

    get "/", PageController, :index
  end

  require MandarinOfficeWeb.ExampleAdmin, as: ExampleAdmin

  ExampleAdmin.scope "/back_office" do
    # You can (and should!) reuse your normal pipelines
    # inside the admin interface scope.
    pipe_through(:browser)
  end
end

The Admin.Employee, Admin.Department, Admin.Function and Admin.Benefit are completely ordinary Ecto modules which Mandarin.Magik introspects to generate the code (plus some small decorations).

I still haven’t published these changes because I’m still not sure on how to solve the template problem (I’ll probably just copy what Phoenix does when searching for the templates, and use the “default templates” if it doesn’t find any. I’ll post a video soon.

Where Next?

Popular in Libraries Top

New
Qqwy
Solution is a library to help you with working with ok/error-tuples in case and with-expressions by exposing special matching macros, as ...
New
Jskalc
Hi! Today, after a couple weeks of development I’ve released v0.1 of LiveVue. It’s a seamless integration of Vue and Phoenix LiveView, i...
New
devonestes
Introducing assertions, the library that helps you write really great test assertions! GitHub: https://github.com/devonestes/assertions ...
New
sasajuric
I’d like to announce a small library called boundaries. This is an experimental project which explores the idea of enforcing boundaries ...
New
woylie
I released Doggo, a collection of unstyled Phoenix components. Features Unstyled Phoenix components. Storybook that can be added to...
New
archan937
It is a well-know topic within the Elixir community: “To mock or not to mock? :)” Every alchemist probably has his / her own opinion con...
New
tmbb
I’ve published the first version of my Makeup library. It’s a syntax highlighter for Elixir in the spirit of Pygments, Currently it highl...
New
MRdotB
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New
bluzky
You may know https://ui.shadcn.com/, a UI component library for React. I really love it’s design style and components. I’ve built some co...
381 12391 119
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

Sub Categories:

We're in Beta

About us Mission Statement