Here is yet another example to show how cool and amazing Nuxeo Studio is and how it makes configuring business applications so easy.

This is a true story - a story about teamwork and how I got help from Anahide to achieve what I had to do. I was so grateful for her help that I let her be in charge of the playlist for this Nuxeo Studio Rocks episode. I even let her add her own footnotes in _my_ blog! This is a short blog and you’ll spend less than 15 seconds to reproduce the configuration in Studio (so we only have two songs and I am quite sure there will be no Status Quo(1) involved).

So plug your headphones in and start listening to Anahide’s first choice: Airbag, Radiohead (OK Computer, 1997) - not sure we can link to any valid version out there but you should buy the album anyway. Here is the story.

Once upon a time in New York, I received a call from my boss asking me to do - “quickly please” and repeated like every 10 seconds in Slack(2) - the following:

  • Say you have a Ticket document. It has the Folderish facet checked, so it can have a child. It also has custom fields, such as ticket:plate_number.
  • Such Ticket documents are created using the Nuxeo Platform’s REST APIs, and some pictures and videos are added to it.
  • One of these pictures will always be named “plate.jpg”. It’s a photo of the number plate of a vehicle taken by an automatic radar(3).

The goal is to display this picture in the Ticket UI tab along with some other fields of the Ticket document so the user can check whether the plate number detected by the OCR tool was correct or not and can fix it in case of a problem. Something like:

plate-review

How can we achieve this quickly? Well, as I have a lot of imagination I started with the following idea:

  • Add the file and picture schemas to Ticket
  • Add an event handler
    • For “document created” and for Picture.
    • The related Automation Chain would check whether the name is exactly “plate.jpg” and the parent is a Ticket or not. If yes, it would then duplicate the picture-blob and store it in the Ticket.
  • Then, add a Tab using a the “Picture View” widget on the left, and a toggleable form with the required fields on the right.
  • Lastly, add some XML extensions so that the default UI behavior of the Nuxeo Platform when the file and picture schemas are present is not applied a Ticket document.

But then I thought, “Yeah. This will work, for sure. But, is it elegant?” Nope. It’s not. It is duplication and denormalization.

Also, in our datamodel we could have chosen to directly store the picture in the Ticket (still using file and picture) when creating it from REST. This would have basically solved the whole problem. But the plate wouldn’t be visible to the user with the other pictures/videos in the content-view of the Ticket.

The second idea was to write a small Java plug-in, a Bean and an XHTML widget. The XHTML would basically display an img tag whose src property would be a URL calculated by the Bean (small query, current document is the Ticket, get the children, filter to find the one whose name is “plate.jpg”, and return the URL to the file). This is more elegant - no duplication/denormalization - but then you need to be elegant till the end, which means building Marketplace Packages, documentation, etc.

It is likely the first song of the playlist is still running and this blog is short. So either you wait for the song to finish or you just move to the next one in Anahide’s playlist: (We are) the road crew, Motörhead (Ace of spades, 1980, or look out the BBC Session ‘05 version)(1’)

So now I had what probably was my best idea ever: “Ask Anahide”!

Anahide is a Nuxeo Master Level 140(4), who knows everything about (and beyond) Studio, JSF, the Nuxeo Platform and 42 and still answers my questions(2’). So, after explaining what I wanted to do she took the time to think about it (200ms to get her answer, just because this was the connection latency between New York and Paris). The answer was crystal clear and worked immediately, of course!

  • [I am in my Tab]
  • Drop a Generic Widget
  • Set the Widget Type to picture_view
  • Add a field: Click this very nice “+” green button)
  • Enter the following expression: #{documentManager.getChild(currentDocument.ref, 'plate.jpg’)}
  • Save the widget configuration, save the Tab

And voilà! It’s that simple. Fast, elegant, and works like a charm.

Just to dig a little bit into this solution:

  • We are using the documentManager object which is a CoreSession and its getChild() is a very convenient API.
  • It works because we have this strict rule about always having a “plate.jpg” picture in first level of the Ticket.

If you need to build an expression, you can use the concat() Java API. For example, maybe the name of the picture is not always “plates.jpg” but there is a prefix which is the title of the ticket: #{documentManager.getChild(currentDocument.ref, currentDocument.title.concat('-plate.jpg’))}

Also, if you need to handle more logic or to get the plate’s picture in a more dynamic (and less hard-coded) way then a custom Seam component would be useful.

So this is how the story ends! I was ready to build something a bit cumbersome but Anahide helped me Keep It Simple. Thank you Anahide!

(1) Still: The best Rock Band Ever (2) This is part of a boss’s job I believe (3) Now, you probably understand “Ticket” is not about going to Madison Square Garden attend a NY Rangers game (4) Which is quite huge when you know that the max available level is 12
Notes from Anahide: (1’) As you can see, I was given a really strict criterion for this playlist (2’) As French people say, “ce blog vaut bien un fromage sans doute”