@lucw Just to confirm, your new field would reference another field and then show the translated results?
I think you are definitely on the right track if so. Here are some extra pointers:
Calling a rest API in row_of_dependency_updated
If I was you to get started I would call the API in a blocking fashion in this hook (and the others below if it makes sense). If that ends up being too slow, you could attempt to run this async using the bundled celery workers. But that will be more complex and I wouldn’t resort to it unless you really encounter issues with just blocking and waiting.
FieldType.get_field_dependencies
Your custom field type will need to implement and return FieldType.get_field_dependencies
which tells the field dependency system what fields a particular field of your type depends on.
This area is being refactored/changed on this MR Fix bugs with field dependency system (!752) · Merge requests · Bram Wiepjes / baserow · GitLab .
Currently this method should return a list of strings where the string is the user defined name of the field that your new field depends on (the field you are translating) eg:
return [field_instance.the_field_being_translated.name]
The change in the MR above which will affect you once it has been merged and released, and then you merge those new changes into your fork. Once that happens this is the change you need to deal with:
FieldType.get_field_dependencies
should then return a list of the FieldDependency
model itself. So in your situation this would look something like:
return [FieldDependency(dependant=field_instance, dependency=field_instance.the_field_being_translated)]
FieldType.field_dependency_updated
This is another hook called like the row_of_dependency_updated
hook you already found. But this hook is called when a field of your new type, depends on another field, and that other field has been updated somehow. For example someone could Edit->Change Field Type->Click change on the field being translated and change it into a boolean field. You’ll then have to handle this change in this hook.
In the formula field we set the field into an “error” state which is shown to the user if the dependency changes in some invalid way. I’d imagine you’d have to do the same thing as you can’t translate a boolean field. Alternatively you could just blank out all the cells in this situation, don’t do any translations and no need to put in the work to show an error if these fields are always going to be internal perhaps.
FieldType.field_dependency_deleted/created
There are two other hooks called when a field_dependency is deleted or created. One interesting thing to note, in what situations does it ever make sense for FieldType.field_dependency_created
to be called? I’ll try to explain:
- Field A depends on a field called field “B” in the same table
- Field B is deleted
- The field dependency system will do something special to the dependency between Field A and B. It will change it to a special state where Field A depends on an non-exsistant field called “B”.
- The user makes a new field called field “B”, renames another field to be called field “B” or restores the original field “B”
- The field dependency system now can see this new field will fix the old broken dependency. Hooks up field A to this new field B and then calls
FieldType.field_dependency_created
.
Now all this complexity really exists for a smooth formula UX. For your field you are either going to have to deal with the possibility that the field you are translated is deleted and put your field into some error state. Or just delete your translation field immediately if the source field is deleted. Or some other way not sure.
Crazy alternative idea
I was thinking, what if you instead added this translation functionality as a new function in the formula langauge. By doing it this way you don’t need to worry about making a new field type or doing anything with the field dependency system. Instead you just need to figure out how to do your translation using PostgreSQL as this is what formulas ultimately compile down to and execute as.
However theres a big problem doing it this way, its hard and a bit mad to call a rest api from SQL. You would have to do something like: rest - Calling RESTful Web Services from PostgreSQL procedure/function - Stack Overflow . By using some embedded language inside a postgresql function you’ll also need to enable and install that extension. This is perhaps fine for you however if you never intend to ship this new field type as a Baserow plugin for others to use. However we are currently reworking the plugin system and this repo is an example of the new type of Baserow plugin Nigel Gott / baserow_geo_plugin · GitLab which also installs a postgres extension automatically for users etc, so perhaps this is an option for you also.
Making a super API user
If you ever want to try out using webhooks again, I believe you could easily change baserow.core.models.Group.has_user
to always allow users which are a django superuser. Then you could use a django superuser to make changes to all tables etc.