The 5.7 branch of Magnolia reached End-of-Life on December 31, 2023, as specified in our End-of-life policy. This means the 5.7 branch is no longer maintained or supported. Please upgrade to the latest Magnolia release. By upgrading, you will get the latest release of Magnolia featuring significant improvements to the author and developer experience. For a successful upgrade, please consult our Magnolia 6.2 documentation. If you need help, please contact info@magnolia-cms.com.

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

In this tutorial you will get to know about content apps and how are they created. 

What is a content app?

Content app is a specialized app type for managing structured content. The content app user interface consists of a browser subapp and one or more detail subapps. Content apps make it easy to enter items such as products or events. Many native Magnolia apps such as Tours and Contacts are content apps. Because this app style is used often, the framework provides convenience classes to make building a content app faster.

See the content app page to know more about content apps.

 

Create a module

Your content app needs to be deployed as a Magnolia module. Choose from these options depending on your skill level. 

Option 1: Clone the project in Git

Choose this option if you know how to work with a Magnolia project and Git. You get a project that you can edit it in your IDE and customize to your needs.

  1. Clone the app-tutorial  repository.
git clone https://git.magnolia-cms.com/scm/documentation/app-tutorial.git
  1. skip
  2. Import the project into your IDE. Here's what the project looks like in IntelliJ IDEA:
  3. Build the project into a JAR and deploy it to Magnolia instance. Or run the project in your IDE.

Option 2: Download the module JAR

Choose this option if you are new to Magnolia. Download the module JAR and follow the standard module installation instructions. You get the complete content app and can learn how it works.

  1. Download

    Error rendering macro 'artifact-resource-macro'

    com.sun.jersey.api.client.ClientHandlerException: java.net.NoRouteToHostException: No route to host (Host unreachable)

    from Nexus.
  2. Copy the JAR into <CATALINA_HOME>/webapps/<contextPath>/WEB-INF/lib folder. Typically this is <CATALINA_HOME>/webapps/magnoliaAuthor/WEB-INF/lib.
  3. Restart your Magnolia instance and run the Web update. This will install the App Tutorial module.

Option 3: Run a Groovy Script

If you already have a module, and want to quickly create a new App, you can use the Groovy App:

  1. Open the Groovy app.
  2. Edit the script /createAppScript.
  3. Update the parameters you can see between line 9 and 14:
    1. app_display_name, here you can specify the name of your app

    2. parent_module, this is where the app will be created (enter your module name)

    3. app_group, the group on the app launcher in which your app should display.

    4. app_icon, the icon of your app

    5. app_repository, here you can keep the default repository

    6. app_folder_support, if you want to be able to create folders within your app

When the app is created, do not forget to export the configuration. 

Module contents

The module contains the following source files:

  • Module descriptor: magnolia-module-app-tutorial.xml
  • App configuration products.yaml
  • App Launcher layout bootstrap: config.modules.ui-admincentral.config.appLauncherLayout.groups.edit.apps.products.xml
  • Sample products (cars): products.cars.xml
  • Images: dam.cars.xml
  • Custom node type app-tutorial-nodetypes.xml
  • User interface text in English: app-products-messages_en.properties
  • User interface text in Spanish: app-products-messages_es.properties

App configuration

The app is configured in YAML in products.yaml . Equivalent JCR configuration examples are provided below.

App descriptor

App descriptor configuration describes an app. The descriptor assigns the app a name, icon and implementation class. The name of the app content node must be unique as it is used to refer to the app across the system. This means you cannot name your own app pages since a Pages app already exists.

/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
# subapps definition
Node nameValue

 
modules


 
my-module


 
apps


 
products


 
appClass

info.magnolia.ui.contentapp.ContentApp

 
class

info.magnolia.ui.contentapp.ContentAppDescriptor

App launcher layout

(warning) The app launcher can only be configured in the JCR.

In the app launcher layout we add the app to the Edit group.

Node name

 
modules

 
ui-admincentral

 
config

 
appLauncherLayout

 
groups

 
edit

 
apps

 
pages

 
assets

 
contacts

 
products

Go to the app launcher and verify that you can see the Products app icon.

If you move the app to another group, log out and back in to see the change.

Browser subapp

The browser subapp allows you to view and organize items. It is part of every content app.

/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
subApps:
  browser:
    subAppClass: info.magnolia.ui.contentapp.browser.BrowserSubApp
    class: info.magnolia.ui.contentapp.browser.BrowserSubAppDescriptor
Node nameValue

 
modules


 
app-tutorial


 
apps


 
products


 
subApps


 
browser


 
class

info.magnolia.ui.contentapp.browser.BrowserSubAppDescriptor

 
subAppClass

info.magnolia.ui.contentapp.browser.BrowserSubApp

Content connector

A content connector tells the app where the content resides. In this case we store products in the repository so we use a JCR content connector. The configuration identifies the workspace and a path. It also configures the node type the app operates on. 

/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
subApps:
  browser:
    subAppClass: info.magnolia.ui.contentapp.browser.BrowserSubApp
    class: info.magnolia.ui.contentapp.browser.BrowserSubAppDescriptor
    contentConnector:
      includeProperties: false
      workspace: products
      rootPath: /
      defaultOrder: jcrName
      nodeTypes:
        - name: mgnl:product
          icon: icon-items
        - name: mgnl:folder
          icon: icon-folder
Node nameValue
 
subApps

 
browser


 
contentConnector


 
nodeTypes


 
product


 
icon

icon-items

 
name

mgnl:product

 
folders


 
icon

icon-folder

 
name

mgnl:folder

 
defaultOrder

jcrName

 
includeProperties

false

 
rootPath

/

 
workspace

products

Workbench

Workbench is a view that displays a list of content items in a workspace. It is part of the content app framework, typically defined in the browser subapp. The workbench contains at list of content views. Typical view types are tree, list and thumbnail. The workbench also provides a search box; results from search are displayed in the search view.

In this app, the workbench displays two node types: mgnl:folder and mgnl:product.

/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
subApps:
  browser:
    subAppClass: info.magnolia.ui.contentapp.browser.BrowserSubApp
    class: info.magnolia.ui.contentapp.browser.BrowserSubAppDescriptor
  # contentConnector definition
    workbench:
      dropConstraintClass: info.magnolia.ui.workbench.tree.drop.AlwaysTrueDropConstraint
      editable: false
Node nameValue

 
browser


 
workbench


 
dropConstraintClass

info.magnolia.ui.workbench.tree.drop.AlwaysTrueDropConstraint

 
editable

false

Content views

A content view defines how the content is displayed to the user. Under workbench, we have four views: tree, list, thumbnail and search. The tree view defines columns: Name, Status and Modification date. The other views extend the tree view, displaying the same columns.

/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
subApps:
  browser:
    subAppClass: info.magnolia.ui.contentapp.browser.BrowserSubApp
    class: info.magnolia.ui.contentapp.browser.BrowserSubAppDescriptor
  # contentConnector definition
    workbench:
      dropConstraintClass: info.magnolia.ui.workbench.tree.drop.AlwaysTrueDropConstraint
      editable: false
      contentViews:
        - name: tree
          class: info.magnolia.ui.workbench.tree.TreePresenterDefinition
          columns: myColumns
            - name: name
              editable: true
              sortable: true
              propertyName: jcrName
              class: info.magnolia.ui.workbench.column.definition.PropertyColumnDefinition
            - name: status
              width: 45
              displayInChooseDialog: false
              formatterClass: info.magnolia.ui.workbench.column.StatusColumnFormatter
              class: info.magnolia.ui.workbench.column.definition.StatusColumnDefinition
            - name: moddate
              width: 160
              sortable: true
              displayInChooseDialog: false
              formatterClass: info.magnolia.ui.workbench.column.DateColumnFormatter
              propertyName: mgnl:lastModified
              class: info.magnolia.ui.workbench.column.definition.MetaDataColumnDefinition
        - name: list
          class: info.magnolia.ui.workbench.list.ListPresenterDefinition
          columns: *myColumns
        - name: thumbnail
          class: info.magnolia.ui.workbench.thumbnail.ThumbnailPresenterDefinition
        - name: search
          class: info.magnolia.ui.workbench.search.SearchPresenterDefinition
          columns: *myColumns
Node nameValue
 
workbench

 
contentViews


 
tree


 
columns


 
name


 
class

info.magnolia.ui.workbench.column.definition.PropertyColumnDefinition

 
editable

true

 
label

Product name

 
propertyName

jcrName

 
sortable

true

 
status


 
class

info.magnolia.ui.workbench.column.definition.StatusColumnDefinition

 
displayInChooseDialog

false

 
formatterClass

info.magnolia.ui.workbench.column.StatusColumnFormatter

 
label

Status

 
width

45

 
moddate


 
class

info.magnolia.ui.workbench.column.definition.MetaDataColumnDefinition

 
displayInChooseDialog

false

 
formatterClass

info.magnolia.ui.workbench.column.DateColumnFormatter

 
label

Modification date

 
propertyName

mgnl:lastModified

 
sortable

true

 
width

160

 
class

info.magnolia.ui.workbench.tree.TreePresenterDefinition

 
list


 
columns


 
extends

../../tree/columns

 
class

info.magnolia.ui.workbench.list.ListPresenterDefinition

 
thumbnail


 
class

info.magnolia.ui.workbench.thumbnail.ThumbnailPresenterDefinition

 
search


 
columns


 
extends

../../tree/columns

 
class

info.magnolia.ui.workbench.search.SearchPresenterDefinition

Here's the tree view:

Test the other views too. Search is case sensitive by default.

Actions

Actions allow you to add, edit and delete folders and products. Each action adheres to an action definition.

/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
subApps:
  browser:
    subAppClass: info.magnolia.ui.contentapp.browser.BrowserSubApp
    class: info.magnolia.ui.contentapp.browser.BrowserSubAppDescriptor
  # contentConnector definition
  # workbench definition
    actions:
      addProduct:
        subAppId: detail
        icon: icon-add-item
        nodeType: mgnl:product
        appName: products
        class: info.magnolia.ui.contentapp.detail.action.CreateItemActionDefinition
        availability:
          root: true
          nodeTypes:
            - mgnl:folder
      addFolder:
        icon: icon-add-folder
        class: info.magnolia.ui.framework.action.AddFolderActionDefinition
        availability:
          root: true
      editFolder:
        icon: icon-edit
        dialogName: ui-framework:folder
        class: info.magnolia.ui.framework.action.OpenEditDialogActionDefinition
      deleteFolder:
        icon: icon-delete
        class: info.magnolia.ui.framework.action.DeleteItemActionDefinition
      editProduct:
        subAppId: detail
        icon: icon-edit
        appName: products
        class: info.magnolia.ui.contentapp.detail.action.EditItemActionDefinition
        availability:
          nodeTypes:
            - mgnl:product
      deleteProduct:
        icon: icon-delete
        class: info.magnolia.ui.framework.action.DeleteItemActionDefinition
Node nameValue
 
browser

 
actions


 
addProduct


 
availability


 
nodeTypes


 
folder

mgnl:folder

 
root

true

 
appName

products 

 
class

info.magnolia.ui.contentapp.detail.action.CreateItemActionDefinition

 
icon

icon-add-item

 
nodeType

mgnl:product

 
subAppId

detail

 
addFolder


 
availability


 
root

true

 
class

info.magnolia.ui.framework.action.AddFolderActionDefinition

 
icon

icon-add-folder

 
editFolder


 
class

info.magnolia.ui.framework.action.OpenEditDialogActionDefinition

 
dialogName

ui-framework:folder

 
icon

icon-edit

 
deleteFolder


 
class

info.magnolia.ui.framework.action.DeleteItemActionDefinition

 
icon

icon-delete

 
editProduct


 
availability


 
nodeTypes


 
product

mgnl:product

 
appName

products

 
class

info.magnolia.ui.contentapp.detail.action.EditItemActionDefinition

 
icon

 icon-edit

 
subAppId

 detail

 
deleteProduct


 
class

info.magnolia.ui.framework.action.DeleteItemActionDefinition

 
icon

 icon-delete

Action bar

An action bar makes actions available to users. The action bar is typically displayed on the right-hand side of the browser subapp. The action bar definition organizes actions into sections (green label) and groups (between horizontal lines). Availability rules determine which section is displayed to the user. For example, when the user selects a content item in the browser subapp, availability rules display only actions that are relevant to working with that item. A group contains actions that have something in common, such as actions for adding things.

/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
subApps:
  browser:
    subAppClass: info.magnolia.ui.contentapp.browser.BrowserSubApp
    class: info.magnolia.ui.contentapp.browser.BrowserSubAppDescriptor
  # contentConnector definition
  # workbench definition
  # actions definition
    actionbar:
      defaultAction: editProduct
      sections:
        - name: root
          groups:
            - name: addActions
              items:
                - name: addProduct
                - name: addFolder
          availability:
            nodes: false
            root: true
        - name: folder
          groups:
            - name: addActions
              items:
                - name: addProduct
                - name: addFolder
            - name: editActions
              items:
                - name: editFolder
                - name: deleteFolder
          availability:
            nodeTypes:
              - mgnl:folder
        - name: product
          groups:
            - name: editActions
              items:
                - name: editProduct
                - name: deleteProduct
          availability:
            nodeTypes:
              - mgnl:product

Node nameValue

 
browser


 
actionbar


 
sections


 
root


 
groups


 
addActions


 
items


 
addProduct


 
addFolder


 
availability


 
nodes

false

 
root

true

 
folder


 
groups


 
addActions


 
items


 
addProduct


 
addFolder


 
editActions


 
items


 
editFolder


 
deleteFolder


 
availability


 
nodeTypes


 
folder

mgnl:folder

 
product


 
groups


 
editActions


 
items


 
editProduct


 
deleteProduct


 
availability


 
nodeTypes


 
product

mgnl:product

 
defaultAction

editProduct

Image provider

Image provider is a component that renders images used in apps. It generates the portrait image at the bottom of the action bar and the thumbnails for the thumbnail view. 

/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
subApps:
  browser:
    subAppClass: info.magnolia.ui.contentapp.browser.BrowserSubApp
    class: info.magnolia.ui.contentapp.browser.BrowserSubAppDescriptor
  # contentConnector definition
  # workbench definition
  # actions definition
  # actionbar definition
    imageProvider:
       class: info.magnolia.dam.app.ui.imageprovider.DamLinkImageProviderDefinition
       damLinkPropertyName: image
Node nameValue

 
browser


 
imageProvider


 
class

info.magnolia.dam.app.ui.imageprovider.DamLinkImageProviderDefinition

 
damLinkPropertyName

image

Select an item in the browser subapp to test the preview. The preview image is displayed at the bottom of the action bar.

Detail subapp

A detail subapp allows you to edit a product. It is configured with a subapp descriptor just like a browser subapp but the classes are different.

/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
subApps:
# browser subapp definition
  detail:
    subAppClass: info.magnolia.ui.contentapp.detail.DetailSubApp
    class: info.magnolia.ui.contentapp.detail.DetailSubAppDescriptor
Node nameValue

 
subApps


 
detail


 
class

 info.magnolia.ui.contentapp.detail.DetailSubAppDescriptor

 
subAppClass

 info.magnolia.ui.contentapp.detail.DetailSubApp

Content connector

A JCR content connector is also needed in the detail subapp. Here the definition is simpler. You just need to name the workspace. 

/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
subApps:
# browser subapp definition
  detail:
    subAppClass: info.magnolia.ui.contentapp.detail.DetailSubApp
    class: info.magnolia.ui.contentapp.detail.DetailSubAppDescriptor
    contentConnector:
      workspace: products
Node nameValue
 
subApps

 
detail


 
contentConnector


 
workspace

products

The rootPath property is omitted because the default value is / which is the same as in browser subapp content connector. If you define these properties they must have the same value in both subapps. However, since / is the default value you could omit the property in both subapps.

We highly recommend using the same rootPath in both the detail and browser sub-apps, to benefit from our standard set of actions provided out of the box.

Editor

Editor is a component that edits a content item. The editor typically contains a form. In a content app, you should create an editor definition under the detail subapp. Define the node types the editor edits, a form for editing them, and actions for saving the edit.

Node types
/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
subApps:
# browser subapp definition
  detail:
    subAppClass: info.magnolia.ui.contentapp.detail.DetailSubApp
    class: info.magnolia.ui.contentapp.detail.DetailSubAppDescriptor
  # contentConnector definition
    editor:
      nodeType:
        icon: icon-items
        name: mgnl:product 
Node nameValue

 
detail


 
editor


 
nodeType


 
icon

icon-items

 
name

mgnl:product

Form

Your app can edit any kind of content. What you plan to edit determines what fields you need on the form. In this tutorial the items are products so we create a form with three fields: product name, photo and photo credit.

/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
subApps:
# browser subapp definition
  detail:
    subAppClass: info.magnolia.ui.contentapp.detail.DetailSubApp
    class: info.magnolia.ui.contentapp.detail.DetailSubAppDescriptor
  # contentConnector configuration
    editor:
    # nodeType definition
      form:
        tabs:
          - name: product
            fields:
              - name: jcrName
                class: info.magnolia.ui.form.field.definition.TextFieldDefinition
              - name: title
                class: info.magnolia.ui.form.field.definition.TextFieldDefinition
              - name: image
                class: info.magnolia.ui.form.field.definition.LinkFieldDefinition
                targetWorkspace: dam
                appName: assets
                label: Select image
                identifierToPathConverter:
                  class: info.magnolia.dam.app.assets.field.translator.AssetCompositeIdKeyTranslator
                contentPreviewDefinition:
                  contentPreviewClass: info.magnolia.dam.app.ui.field.DamFilePreviewComponent
              - name: description
                class: info.magnolia.ui.form.field.definition.RichTextFieldDefinition 

Node name

Value

 
editor


 
form


 
tabs


 
product


 
fields


 
jcrName


 
class

info.magnolia.ui.form.field.definition.TextFieldDefinition

 
name

jcrName

 
title


 
class

info.magnolia.ui.form.field.definition.TextFieldDefinition

 
name

title

 
image


 
identifierToPathConverter


 
class

info.magnolia.dam.app.assets.field.translator.AssetCompositeIdKeyTranslator

 
contentPreviewDefinition


 
contentPreviewClass

info.magnolia.dam.app.ui.field.DamFilePreviewComponent

 
appName

assets

 
class

info.magnolia.ui.form.field.definition.LinkFieldDefinition

 
label

Select image

 
targetWorkspace

dam

 
description


 
class

info.magnolia.ui.form.field.definition.RichTextFieldDefinition

Commit and cancel actions

Commit and cancel are generic reusable actions that save the form data. They are defined under the detail subapp. The corresponding dialog buttons are in the editor (see above).

/app-tutorial/apps/products.yaml
appClass: info.magnolia.ui.contentapp.ContentApp
class: info.magnolia.ui.contentapp.ContentAppDescriptor
subApps:
# browser subapp definition
  detail:
    subAppClass: info.magnolia.ui.contentapp.detail.DetailSubApp
    class: info.magnolia.ui.contentapp.detail.DetailSubAppDescriptor
  # contentConnector definition
    editor:
    # nodeType definition
    # form definition
      actions:
        - name: commit
        - name: cancel
Node nameValue

 
detail


 
actions


 
commit


 
cancel


Create a few items. Verify that you can edit existing items too.

Now do it yourself

Here are ways to create your own content app:

Option 1: Copy an app

  1. Copy the configuration nodes of an existing content app into a new app. You can copy one of Magnolia's native apps such as Contacts.
  2. Export the copied configuration nodes into XML.
  3. Open the XML in a text editor. Search and replace the item names. For example, if your app manages apples instead of oranges, replace apple  with orange .
  4. Import the XML back to Magnolia.
  5. Register a new workspace in the module descriptor and create a new node type.

Option 2: Extend an app

This method works well if one of Magnolia's native apps does almost what you need. You don't need to change much. Extend the native app to get all its functionality and add something special. For example, configure a special Pages app that displays only one website branch. If editors mostly work in that branch the app saves them from having to navigate there.

  1. Extend an existing app to inherit configuration. For example, see how the JCR Browser app extends the Configuration app by inheriting its subapps.
  2. Define exceptions in your own app.

See also  3.3.5 Create an app in Magnolia Academy.

Enhancements

Here are ideas for enhancing your content app and making it ready for production use:

Add import and export actions

Add export and import actions so you can export products into XML. See how the actions are implement in the Contacts app. Copy the action configuration to your app. The Magnolia UI framework provides generic export and import actions that you can use out of the box.

Import and export actions in the Contacts app
/modules/contacts/apps/contacts/subApps/browser/actions/export
/modules/contacts/apps/contacts/subApps/browser/actions/import
/modules/contacts/apps/contacts/subApps/browser/actionbar/sections/root/groups/importExportActions
/modules/contacts/apps/contacts/subApps/browser/actionbar/sections/contact/groups/importExportActions
/modules/contacts/apps/contacts/subApps/browser/actionbar/sections/folder/groups/importExportActions

Add publishing actions

To add publishing actions:

  1. Add activate and deactivate actions so that you can publish products to the public instance. Copy the actions from the Contacts app.
  2. Add the activate  and  deactivate  actions in the action bar. You can copy these also from the Contacts app.
  3. Add a subscription to the  products workspace so that public instances receive the content.

(warning) Don't forget to install your module also on the public instance! You may not need the app on the public instance but you will need the products workspace so that products can be activated.

Add deletion approval

Prevent editors from deleting products with a single click. The best practice is to mark an item for deletion and require the editor to publish the change:

  1. Display a confirmation message, asking if the user really wants to delete the item.
  2. Mark the item as deleted.
  3. Activate the change. This finally deletes the item.

See how the Contacts app handles this and replicate the actions in your app. See also how the  info.magnolia.ui.api.availability.IsNotDeletedRule action availability rule is used in the activate action to make sure that the activatable item is not marked for deletion. 

Display products on the website

You may want to display product images on the website or in a shop. Add a URI2RepositoryMapping for the products workspace. The mapping tells Magnolia to serve content from the products workspace when the request URL contains the /products prefix.

To add a URI2RepositoryMapping:

  1. Go to Configuration > /server/URI2RepositoryMapping/mappings.
  2. Map the /products URI prefix to the products workspace.

    Node nameValue

     
    server


     
    URI2RepositoryMapping


     
    mappings


     
    products


     
    URIPrefix

    /products

     
    handlePrefix


     
    repository

    products

  3. Activate the products node and its properties to the public instance.
  4. Optional: Grant the anonymous role permission to read the products workspace. This allows visitors to view the images on the public instance.
     



Photo credits:

  • No labels