Magnolia 5.6 reached end of life on June 25, 2020. This branch is no longer supported, see End-of-life policy.
In this tutorial you will get to know about content apps and how are they created.
See the content app page to know more about content apps.
Your content app needs to be deployed as a Magnolia module. Choose from these options depending on your skill level.
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.
app-tutorial
repository.git clone https://git.magnolia-cms.com/scm/documentation/app-tutorial.git
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.
<CATALINA_HOME>/webapps/<contextPath>/WEB-INF/lib folder. Typically this is <CATALINA_HOME>/webapps/magnoliaAuthor/WEB-INF/lib.If you already have a module, and want to quickly create a new App, you can use the Groovy App:
/createAppScript.app_display_name, here you can specify the name of your app
parent_module, this is where the app will be created (enter your module name)
app_group, the group on the app launcher in which your app should display.
app_icon, the icon of your app
app_repository, here you can keep the default repository
app_folder_support, if you want to be able to create folders within your app
The module contains the following source files:
magnolia-module-app-tutorial.xmlproducts.yamlconfig.modules.ui-admincentral.config.appLauncherLayout.groups.edit.apps.products.xmlproducts.cars.xmldam.cars.xmlapp-tutorial-nodetypes.xmlapp-products-messages_en.propertiesapp-products-messages_es.propertiesThe app is configured in YAML in products.yaml . Equivalent JCR configuration examples are provided below.
pages since a Pages app already exists.appClass: info.magnolia.ui.contentapp.ContentApp class: info.magnolia.ui.contentapp.ContentAppDescriptor # subapps definition
| Node name | Value |
|---|---|
info.magnolia.ui.contentapp.ContentApp | |
info.magnolia.ui.contentapp.ContentAppDescriptor |
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 |
|---|
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.
The browser subapp allows you to view and organize items. It is part of every content app.
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 name | Value |
|---|---|
info.magnolia.ui.contentapp.browser.BrowserSubAppDescriptor | |
info.magnolia.ui.contentapp.browser.BrowserSubApp |
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.
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 name | Value |
|---|---|
icon-items | |
mgnl:product | |
icon-folder | |
mgnl:folder | |
| jcrName | |
false | |
| / | |
| products |
In this app, the workbench displays two node types: mgnl:folder and mgnl:product.
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 name | Value |
|---|---|
info.magnolia.ui.workbench.tree.drop.AlwaysTrueDropConstraint | |
false |
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.
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 name | Value |
|---|---|
info.magnolia.ui.workbench.column.definition.PropertyColumnDefinition | |
true | |
Product name | |
jcrName | |
true | |
info.magnolia.ui.workbench.column.definition.StatusColumnDefinition | |
false | |
info.magnolia.ui.workbench.column.StatusColumnFormatter | |
Status | |
45 | |
info.magnolia.ui.workbench.column.definition.MetaDataColumnDefinition | |
false | |
info.magnolia.ui.workbench.column.DateColumnFormatter | |
Modification date | |
mgnl:lastModified | |
true | |
160 | |
info.magnolia.ui.workbench.tree.TreePresenterDefinition | |
| ../../tree/columns | |
| info.magnolia.ui.workbench.list.ListPresenterDefinition | |
| info.magnolia.ui.workbench.thumbnail.ThumbnailPresenterDefinition | |
| ../../tree/columns | |
| info.magnolia.ui.workbench.search.SearchPresenterDefinition |
Here's the tree view:
Test the other views too. Search is case sensitive by default.
Actions allow you to add, edit and delete folders and products. Each action adheres to an action definition.
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 name | Value |
|---|---|
mgnl:folder | |
true | |
products | |
info.magnolia.ui.contentapp.detail.action.CreateItemActionDefinition | |
icon-add-item | |
mgnl:product | |
detail | |
true | |
info.magnolia.ui.framework.action.AddFolderActionDefinition | |
icon-add-folder | |
info.magnolia.ui.framework.action.OpenEditDialogActionDefinition | |
| ui-framework:folder | |
| icon-edit | |
info.magnolia.ui.framework.action.DeleteItemActionDefinition | |
icon-delete | |
mgnl:product | |
products | |
| info.magnolia.ui.contentapp.detail.action.EditItemActionDefinition | |
icon-edit | |
detail | |
info.magnolia.ui.framework.action.DeleteItemActionDefinition | |
| icon-delete |
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 name | Value |
|---|---|
false | |
true | |
mgnl:folder | |
mgnl:product | |
| editProduct |
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.
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 name | Value |
|---|---|
info.magnolia.dam.app.ui.imageprovider.DamLinkImageProviderDefinition | |
image |
Select an item in the browser subapp to test the preview. The preview image is displayed at the bottom of the action bar.
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.
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 name | Value |
|---|---|
info.magnolia.ui.contentapp.detail.DetailSubAppDescriptor | |
info.magnolia.ui.contentapp.detail.DetailSubApp |
A JCR content connector is also needed in the detail subapp. Here the definition is simpler. You just need to name the workspace.
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 name | Value |
|---|---|
| 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.
detail subapp. Define the node types the editor edits, a form for editing them, and actions for saving the edit.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 name | Value |
|---|---|
icon-items | |
mgnl:product |
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.
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 |
|---|---|
info.magnolia.ui.form.field.definition.TextFieldDefinition | |
jcrName | |
info.magnolia.ui.form.field.definition.TextFieldDefinition | |
title | |
| info.magnolia.dam.app.assets.field.translator.AssetCompositeIdKeyTranslator | |
| info.magnolia.dam.app.ui.field.DamFilePreviewComponent | |
assets | |
info.magnolia.ui.form.field.definition.LinkFieldDefinition | |
Select image | |
dam | |
info.magnolia.ui.form.field.definition.RichTextFieldDefinition |
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).
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 name | Value |
|---|---|
Create a few items. Verify that you can edit existing items too.
Here are ways to create your own content app:
apple
with
orange
.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.
See also 3.3.5 Create an app in Magnolia Academy.
Here are ideas for enhancing your content app and making it ready for production use:
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.
/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
To add publishing actions:
activate and deactivate actions so that you can publish products to the public instance. Copy the actions from the Contacts app.activate and deactivate actions in the action bar. You can copy these also from the Contacts app. products workspace so that public instances receive the content. 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.
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:
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.
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:
/server/URI2RepositoryMapping/mappings.Map the /products URI prefix to the products workspace.
| Node name | Value |
|---|---|
/products | |
products |
products node and its properties to the public instance.anonymous role permission to read the products workspace. This allows visitors to view the images on the public instance.Photo credits:
Aston Martin DB5, Aston Martin Works
Aston Martin V8, Beltane43, Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
2 Comments
David Caviedes Marquez
Hi all,
in section "Content views" the following line:
columns:myColumnsmust be:
columns:&myColumnsTake care of ampersand. If not, an "Error parsing yaml file: mapping values are not allowed here" error will occur.
Best regards
Ravindra Kumar Verma
Christoph Meier Martin Drápela David Caviedes Marquez As mentioned in the documentation I have chosen the option 1 and clone the app-tutorial module code , Build the jar using mvn install command. and deploy the same in Magnolia WEB-INF/lib folder. the app is installed and visible in App launcher layout but in the configuration UI it is not showing JCR tree structure. I have attached the screenshot of the same, can anyone help me to fix the same , I can see contact app showing the JCR tree. ?
https://ibb.co/gWKKjGX