Mandarin + Forage - An admin tool for phoenix

Please do!

In general: great project! I have an app that’s basically RailsAdmin over a PostgreSQL database so this would be a great case for replacing it with Elixir.

We are running ecto 3 with paginator in production right now without any issues :slight_smile:

I know it’s compatible. But the dependency needs to be updated in the package so that it works without overrides. And there are pther smaller changes to Paginator which I’d like to submit if it’s not too disruptive to the rest of the code.

I have been using Webpack for asset management because it’s a requirement to not have external dependencies (deploy to corporate intranet).

It generates a JS file per action, I don’t like to inline JS or CSS so based on this article I have set up something similar.

Also, I’m generating additional JS files at compile time, based on phoenix_jsroutes

  • routes.js routes helper for JS
  • defaults.js default config for the widgets
  • i18n.js translation keys for the widgets

Agree, my original intent was to generate a React + Phoenix app but due to time constraints I had to switch to jQuery widgets.

So far, the front-end stack is using Hyperaxe, jQuery, Popper.js, Bootstrap,, Select2 and jQuery.Upload

I use the same approach, It generates an API action for each widget. i.e. /api/users/datatable, /api/users/select

1 Like

That seems a pretty heavy stack for something that’s mostly server-driven.

1 Like

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


Joke or not, it’s true.

When I played WoW years and years ago, people just never got tired mistaking “rogue” with “rouge”. 99% of the time.

1 Like

I’m open for ideas on how to test mandarin In a relevant way. Ideally, I’d generate a Phoenix application inside the test directory, run the mandarin generators on it and use a headless browser to send requests and validate the responses.

It does seem very heavy, though. Maybe I should start by testing whether some regexs are present, but that doesn’t test much actually.

1 Like

@tmbb I’d like to give mandarin a try. Where do I start?

You can follow the instructions here:

Just replace the depndencies by their hex package names and versions, and replace all occurrencies of bureaucrat by mandarin in the commands.

This will generate the correct files right where you need them. The hardest part is to learn how to use the forage package, but you ca learn a lot by looking at the generated .ex and .eex files.

Thanks, I’ll try that tomorrow! My next question is: do you have any roadmap or commitments for the project? I’m looking for a solution that I can put on production.

1 Like

I’m not thinking about changing a lot of things in the Mandarin generators. I’ll add some features to the routing macros to make them more customizable. But that’s probably it.

Regarding forage, I’m very happy with the current API. But I need to add tests.

I still need to add support for many to many relationships somehow, between Forage and Mandarin.

But mainly my goal is to make things stable and well tested so that ir can be used in production. Mandarin is very safe to use, because it’s mostly generators which generate “normal” phoenix files. Forage is another question, because it’s the project that actually runs some code at runtime…

By the way, did you find Mandarin simple to use?

Somewhat. Couple of points:

  1. It would be great to add an extended description of what this package really does and what’s the use case. I’m a bit confused. My use case is that I have an existing DB and I’m putting a read-only RESTful API on top of that (with a little help from phx.gen), but I would also like to have an admin interface for modifying the data. Can mandarin help me? I find myself doing hacks so that the generators do not overwrite my schemas and controllers. I might go with creating a separate schemas for mandarin but this requires manual work.
  2. I’m not fully convinced about the idea of using generators. If I need any customization, then I can’t re-generate the admin panel. What if mandarin gets a major bump and I’d like to update my admin panel? Seems that I would have to start from scratch.
  3. If I understand this right, mandarin “just” provides better generators then the default Phoenix ones, right? If so, why do I have to include it in prod build? Or maybe that’s not the case?
  4. There are some places that require renaming from the old name: for example here and here.
  5. There seems to be a bug when a schema references another one and the id can be null. Not sure if all the relationship are preloaded, but in this line I get an error: is undefined.
  6. The templates assume that the timestamps are present in the schemas. My schemas actually use timestamps(inserted_at: :created_at).
  7. I’ve tried torch as well - the advantage of mandarin is that it works with Ecto 3.x.
  8. I wanted to give ExAdmin a try, but it’s not actively maintained and the deps are pinned to pretty old versions.

In the end, I think I would find it more useful to have a library of generic views/templates/helpers so that I can throw any struct at it and render it (possibly exclude some fields) or build something in just a few lines of code.


I think it’s clear that Mandarin is not for your use case then. What you describe (and what ExAdmin does) is very hard to customize, and that’s why I’ve chosen the current architecture.

You have to include it because of the Router macros and the mandarin respuce plug, which must be present at least when the app is compiled.

Back to Mandarin after a long time away… What is the recomended approach to testing a package that mostly dumps text int your Phoenix apps? I don’t think unit tests or integration tests are easy to write for this… Do people just use manual testing? Anyone has any tips?

1 Like

Example application built using mandarin (and forage, of course): (the README explains how to generate the project).

I need to document forage better and expand on the readme to explain what the generated files do. It’s true that the generator dump a lot of code into your files, but doing that instead of using clever macros makes everything much more extendable (even if a little harder to understand due to the raw volume of code you have to read).

Thank you very much to share this app. I would like to use it but when I run mix ecto.reset, I have the following error:

10:05:25.545 [info]  create table employees
** (Postgrex.Error) ERROR 42804 (datatype_mismatch) foreign key constraint "employees_department_id_fkey" cannot be implemented

Key columns "department_id" and "id" are of incompatible types: uuid and bigint.

For 10. on your Readme, I used

mix mandarin.gen.html Admin Function functions name:string --binary-id

since 10 is the same than 8

Add a  `Function`  resource:  `mix mandarin.gen.html Admin Department departments name:string`

To make it work, I had to delete the file bureaucrat.ex in deps/mandarin/mix/ (I also deleted the folder bureaucrat) because I had the following error:

== Compilation error in file lib/mix/mandarin.ex ==

** (CompileError) lib/mix/mandarin.ex:1: cannot define module Mix.Mandarin because it is currently being defined in lib/mix/bureaucrat.ex:1

(stdlib) erl_eval.erl:680: :erl_eval.do_apply/6

**could not compile dependency :mandarin, "mix compile" failed. You can recompile this dependency with "mix deps.compile mandarin", update it with "mix deps.update mandarin" or clean it with "mix deps.clean mandarin"**

I think it’a because you haven’t created the Department resource with —binary-id. That’s my mistake, of course.

Thank you very much. It’s now working. I really like the Admin interface.
You should update the readme to add —binary-id for 8.

Of course, my mistake