Nuxeo Studio Rocks - Blog Series

We(1) recently had this question: “How easy would it be to implement a feature where a user can build an ordered set of icons and synchronize it with their Desktop?”. The use case was about building toolbars for custom software. As you might have guessed, the answer to this “How easy” question is, of course, “E_xtremely_ easy”. Instead of just answering “It’s easy”, we actually built it with Nuxeo Studio (which is why it’s so easy).Nuxeo Studio is the coolest configuration tool in the universe!

I have created a short video showing what we built. I’ll explain the steps in detail after you have watched the video. As usual, since this blog is in the “Nuxeo Studio Rocks” series, we have a playlist starting with the famous Queen’s We Will Rock You(2). (Listening to the music while reading the blog (or watching the videos) should be mandatory, but it is not ;) )

Here’s the video:

As you can see, we have four main parts here:

  1. Find images
  2. Order the list (using drag and drop)
  3. Approve/Reject
  4. Synchronize with Desktop

Let me walk you through this list.

Step 1: Find Images

For this step, even though the search screen was built using Nuxeo Studio, we are mainly using native, out-of-the-box Nuxeo features:

  • Full text search
  • Select 1-n images
  • Click the “Add to Collection” button and:
    • Create a new collection
    • Add to this collection

Step 2: Order the List

This step requires the wonderful nuxeo-palette plug-in written by The Great Fred. (We have already used nuxeo-palette in a previous blog, so you might be familiar with it).

First, we must install this plug-in on our server. Then, we want to provide the UI in order to allow the user to drag-drop and organize the images. What we have here is actually a perfect example of how cool Studio is: It knows nothing about this “palette.xml” widget, but still lets us use it!

Now, let’s create this “Palette” tab that you saw in the video:

  1. Playlist song#2: Status Quo’s Rockin’ All Over the World.
  2. Add a new “Tab” and name it “Palette”.
  3. We want this tab to be displayed only for a Collection and nothing else. So, click the “Activation” subtab, and set “Current document has facet” to “Collection”.
  4. Now, go back to the “Definition” subtab:
    • Set the “Label” to “Palette”(3), and the order to -1 because we want this tab to be the first one displayed when the collection is open.
    • Remove the default row and add a new one. Select the one that has a single column.
    • Drop a “Template” widget. It is located in the “More Widgets/Advanced Widgets” part of the list:

Drop-widget-template

  • Now, here is the cool feature: In the Layout Widget Editor, scroll down, expand “Custom Properties Configuration”, set the value to “template” and the key to “palette.xhtml” (keep in mind that they are case sensitive), save and voilà (no need to import “palette.xml” in the “Resources” part of your project):

set-widget-template

Once you deploy the project, you will have the “Palette” tab allowing the user to organize the documents of the collection as they want, using drag and drop.

Step 3: Approve/Reject

Our user is happy with the toolbar and now it’s time to send it for validation.

All this was done - of course - in Nuxeo Studio. Let’s not go into details here and just link to the features:

  1. First, we create a workflow named “PaletteValidation”. It is a classic approval workflow where a user can reject/approve the asset. If the user rejects it then the flow returns to the first user. The first user must then change the icons and/or change the order (based on the manager’s comments, for instance). In our case, assignment to “manager” (and possibly back to the workflow initiator) is done in each task.
  2. Then, we create a User Action. It’s a toolbar button displayed only for documents with the “Collection” facet. (We could be more user friendly here. For example, by making sure a workflow is not already running for this collection. But when we are building a demo or just showing an example, we can avoid too much details.)
  3. This User Action runs a basic automation chain which starts the workflow:

startworkflowchain

Now, when the manager approves the palette, we want the palette to be synchronized with their Desktop and it must keep the order of each image. To keep the order, we decided to add a prefix or a number to each file. This means we can’t simply ask Nuxeo Drive to synchronize the collection itself (which it could do) because Nuxeo Drive uses the file names. We don’t want to change the file names in the Nuxeo repository because the same image may be used in different palettes (renaming one will change the order in other palettes too). So, instead we decide to copy the Documents and rename the copies. We created the “Approved Palettes” folder in which we will copy and handle each image.

Since it requires loops and tests, it is a perfect use case for Scripting Automation. As I am a big JavaScript fan, I have a small tendency to see every use case as requesting Scripting Automation. But the point here is that, in this case, it is true (which does not mean it is false in other cases!). The fact that nuxeo-palette’s Services.GetPaletteItems operation returns a JSON string also helped make this decision. The algorithm is as follows:

  • Use nuxeo-palette’s Services.GetPaletteItems operation to get the ordered list of items.
  • Create a new Folder in the “Approved Palettes” folder (all this is hard coded for a demo. In a production environment, you will write something more flexible).
  • In this folder, copy every Document in the ordered list.
  • For each copy, change the title and change the file name, making them start with a number.
  • (the whole script is in a few lines)

Step 4: Synchronize with Desktop

This step is actually part of the same Automation Scripting Chain.

After all the renamed copies have been created, we want to make the Desktop Synchronization automatic (so that the user does not need to manually activate it). For this, we can directly call the NuxeoDrive.SetSynchronization operation and we are done with this workflow.

Here is the final script:

// A *lot* of assumptions and hard coded values. This is for a demo.
function run(input, params) {
  var APPROVED_PALETTES_FOLDER_PATH = "/default-domain/Approved Palettes";
  var docListStr, docListJson, approvedPalettesFolder, approvedPalette, doc, docCopy, blob, i;  docListStr = Services.GetPaletteItems(input, {});
  if(docListStr !== "") {
    docListJson = JSON.parse(docListStr);
    approvedPalettesFolder = Repository.GetDocument(input, {'value': APPROVED_PALETTES_FOLDER_PATH});    approvedPalette = Document.Create(approvedPalettesFolder, {
      'type': "Folder",
      'name': input.title,
       'properties': "dc:title=" + input.title
    });    i = 0;
    docListJson.forEach(function(oneObj) {
      i += 1;
      doc = Repository.GetDocument(input, {'value': oneObj.id});
      blob = doc.getPropertyValue("file:content");      docCopy = Document.Copy(doc, {
    'target': approvedPalette,
    'name': formatInteger2Zeros(i) + "-" + doc.title
      });      docCopy = Document.SetProperty(docCopy, {
    'xpath': "dc:title",
    'save': false,
    'value': formatInteger2Zeros(i) + "-" + doc.title
      });      docCopy = Document.SetBlobName(docCopy, {
    'name': formatInteger2Zeros(i) + "-" + blob.getFilename(),
    'save': true,
    'xpath': "file:content"
      });
    });
    NuxeoDrive.SetSynchronization(approvedPalette, {'enable': true});
  }
  return approvedPalette;
}function formatInteger2Zeros(inValue) {
  if(("" + inValue).length > 2) {
    return inValue;
  }
  return ('00' + inValue).substr(-2);
}

JavaScript in Automation makes my day every day. And thanks to Amazing Vlad for making the JavaScript Editor in Studio more and more performant and easy to use!

(1) The Nuxeo Solutions Architects Team. Just “The” for people who know us. (2) Not sure it’s easy to watch this serious video while listening to this song. This song, somehow, forces you to stand up and play the rhythm. (3) Or Whatever you Want. It will also work with “Toolbar”, “Icons”, “Free Beer”, etc.