Michael McGreal

Michael McGreal

A faster admin interface using coda packs?

Status: Draft

Admin interfaces

My initial problem

  • It just seems inefficient. An API endpoint with custom CRUD for every admin UI field.
  • Want to add a new field? More CRUD wiring.
  • I already have my database types in typescript, can't these admin UI's be generated automatically?
  • (It turns out there are some generators, but they have their own issues)
  • So lets explore the current options:

Can we just use a SQL gui client?

  • Can't admin's just use a SQL client?
  • SQL clients have type safety (i.e. you can't update a number column with a string)
  • Some even have access controls (so they can't accidentally cascade delete)

Sql client UI becomes limiting

  • What if you want to link 15 image records? Well create 15 new rows, which take 3 clicks each.
  • i.e. You can't simply paste an array of 15 image url strings
  • Then, what if you want to re-order these images (a manual sort)
  • Some sql clients allow manually ordering rows, but they don't preview the image at the URL, so you would be re-arraning the unknown!

Can Coda packs solve this?

  • Coda is awesome. Their formula language is powerful and expressive.
  • And Coda packs are even better. They allow you to run javascript on an input and output the result. You can even write the in VScode with typescript autocomplete.
  • For example, input an address, then have a coda pack to fetch to the google maps geocoding service, and return the latitude and longitude to coda.
  • Coda "sync tables" allow displaying an external data-source in a coda table (and then integrating it with your other tables)
  • In this way, I designed an admin interface

Did it work?

  • Yes! ...at first
  • After I learned the syntax of coda packs, I was creating magic. All the power of familiar javascript methods at my fingertips.
  • Beautiful coda UI for every column type I could need, and easy filtering controls to make custom and permission controlls views!

Ergonomic issues

However, some purely ergonomic issues rose.

When writing a pack, each input parameter must be specified as a coda type. Simple types are easy. Even arrays of simple types are relatively simply. But an array of custom object types? The coda object schema code gets more verbose.

If you're coda pack fetches to your database, and then displays your data in a sync table, well you have to write a coda shape of the data it's fetching. Even if you already have a typescript type representing the shape, coda packs currently does not understand it. [community link]

Luckily, there are packs that allow you to at least paste json, and it outputs the equivalent coda pack input schema. So I made an API endpoint that allowed me to quickly copy and paste the latest structure of each table, and easily pass it to the coda schema generator pack. However, I soon discovered that these basic schemas are not enough for coda sync tables, which require a few extra properties. No problem, add the extra properties manually. However, anytime I change the database structure and paste it to the generator pack, the output schema is missing those extra few required proeprties. I ended up using the generator for the initial bulk definitions, and then modifying them manually.

Finally, in the coda pack, when passing your input parameters to your javascript code, the parameters are passed as an array. Wow did I miss object destructuring (such as useQuery interface). Index based destructuring is prone to errors. Delete a parameter? Then all the other destructured parameters shift by 1 index. So now your variable b is receiving variable a data.

These things are not terrible, but the ergonomic inconveniences add up, especially when the database structure is evolving.

Maintenance issues

  • By using coda, I avoided solving the quirks of HTML input elements, but the net-maintenance cost might increased

Solving my initial issues with typescript

  • Alright, If I'm going to make a custom admin gui, then can I at least solve some of the original issues I had? I.e. avoid creating an api endpoint and CRUD operations for every single admin UI field?
  • The answer is yes! I was able to design a single flexible API endpoint and a single fetcher. By using typescript keyof and Partial features!

Other alternatives

  • Another interesting solution is retool, which provides the pre-built ui of coda, but requires writing raw SQL queries
  • For now, I am enjoying all the luxuries of my dev environment and nextjs app router