Skip to content

Latest commit

 

History

History
217 lines (181 loc) · 7.95 KB

File metadata and controls

217 lines (181 loc) · 7.95 KB

Magnolia Appbuilder

The AppBuilder module is a builder for Magnolia apps in a java.

Setup

Add Maven dependency:

<dependency>
    <groupId>com.merkle.oss.magnolia</groupId>
    <artifactId>magnolia-appbuilder</artifactId>
    <version>1.4.0</version>
</dependency>

DI-Bindings

<module>
    <name>SomeModule</name>
    ...
    <components>
        <id>main</id>
        <configurer>
            <class>GuiceComponentConfigurer</class>
        </configurer>
        <component>
            <type>com.namics.oss.magnolia.appbuilder.builder.DefaultColumnDefinitionsFactory</type>
            <implementation>...</implementation>
        </component>
    </components>
    ...
</module>
import info.magnolia.objectfactory.guice.AbstractGuiceComponentConfigurer;

import org.apache.commons.lang3.reflect.TypeLiteral;
import org.reflections.Reflections;

import com.google.inject.multibindings.Multibinder;
import com.namics.oss.magnolia.appbuilder.annotations.AppFactories;
import com.namics.oss.magnolia.appbuilder.annotations.AppFactory;
import com.namics.oss.magnolia.appbuilder.annotations.ChooserDialogFactories;
import com.namics.oss.magnolia.appbuilder.annotations.ChooserDialogFactory;

public class GuiceComponentConfigurer extends AbstractGuiceComponentConfigurer {
    @Override
    protected void configure() {
        // Here we use Reflections, but you can also use ClassPathScanningCandidateComponentProvider or bind each factory manually 
        final Multibinder<Class<?>> appFactoryMultibinder = Multibinder.newSetBinder(binder(), new TypeLiteral<>() {}, AppFactories.class);
        new Reflections(getClass()).getTypesAnnotatedWith(AppFactory.class).forEach(clazz -> appFactoryMultibinder.addBinding().toInstance(clazz));

        final Multibinder<Class<?>> chooserDialogFactoryMultibinder = Multibinder.newSetBinder(binder(), new TypeLiteral<>() {}, ChooserDialogFactories.class);
        new Reflections(getClass()).getTypesAnnotatedWith(ChooserDialogFactory.class).forEach(clazz -> chooserDialogFactoryMultibinder.addBinding().toInstance(clazz));
    }
}

How to use

AppFactory

To create a new app, add a class with the @AppFactory annotation and at least one method annotated with @SubApp returning a info.magnolia.ui.api.app.SubAppDescriptor. Make sure the the class in in a package which is scanned for @AppFactorys.

ChooserDialog

By default Magnolia generates chooser dialogs with the workbench of the default supapp (See AppAwareWorkbenchChooserDefinition).

Examples

The following class is a demo app, made with the AppBuilder:

AppFactory

import com.merkle.oss.magnolia.definition.builder.contentapp.column.JcrStatusColumnDefinitionBuilder;
import com.merkle.oss.magnolia.definition.builder.contentapp.column.JcrTitleColumnDefinitionBuilder;
import com.merkle.oss.magnolia.definition.custom.contentapp.column.modificationdate.ModificationDateColumnDefinitionBuilder;
import com.namics.oss.magnolia.appbuilder.action.AppActionDefinitions;
import com.namics.oss.magnolia.appbuilder.action.AppActionGroupDefinition;
import com.namics.oss.magnolia.appbuilder.action.add.AddAppActionDefinition;
import com.namics.oss.magnolia.appbuilder.action.edit.EditAppActionDefinition;
import com.namics.oss.magnolia.appbuilder.annotations.AppFactory;
import com.namics.oss.magnolia.appbuilder.annotations.Icon;
import com.namics.oss.magnolia.appbuilder.annotations.SubApp;
import com.namics.oss.magnolia.appbuilder.builder.BrowserAppBuilder;

import info.magnolia.icons.MagnoliaIcons;
import info.magnolia.jcr.util.NodeTypes;
import info.magnolia.ui.api.app.SubAppDescriptor;
import info.magnolia.ui.contentapp.configuration.column.ColumnDefinition;
import info.magnolia.ui.datasource.jcr.JcrDatasourceDefinition;

import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.jcr.Item;

@AppFactory(
        id = SampleApp.ID,
        name = SampleApp.NAME,
        label = SampleApp.NAME
)
@Icon(MagnoliaIcons.TAG_2_APP)
public class SampleApp {
    public static final String NAME = "SampleApp";
    public static final String ID = "module:apps/" + NAME;

    private static final Map<String, String> NODE_TYPES_ICONS = Map.of(
            NodeTypes.Folder.NAME, MagnoliaIcons.FOLDER.getCssClass()
    );

    private final List<ColumnDefinition<Item>> columns = List.of(
            new JcrTitleColumnDefinitionBuilder().nodeTypeToIcon(NODE_TYPES_ICONS).buildTyped(),
            new JcrStatusColumnDefinitionBuilder().build(),
            new ModificationDateColumnDefinitionBuilder().build()
    );

    @SubApp
    public SubAppDescriptor getBrowser() {
        return new BrowserAppBuilder<Item, JcrDatasourceDefinition>()
                .icon(MagnoliaIcons.TAG_2_APP)
                .columns(columns)
                .rootActions(
                        new AppActionGroupDefinition("addingActions", AddAppActionDefinition.FOLDER),
                        new AppActionGroupDefinition("activationActions", AppActionDefinitions.ACTIVATION),
                        new AppActionGroupDefinition("importExportActions", AppActionDefinitions.IMPORT_EXPORT)
                )
                .nodeActions(
                        NodeTypes.Folder.NAME,
                        EditAppActionDefinition.FOLDER,
                        new AppActionGroupDefinition("editActions", AppActionDefinitions.editActions(EditAppActionDefinition.FOLDER)),
                        new AppActionGroupDefinition("activationActions", AppActionDefinitions.ACTIVATION),
                        new AppActionGroupDefinition("importExportActions", AppActionDefinitions.IMPORT_EXPORT)
                )
                .build("<WORKSPACE>", Set.of(NodeTypes.Folder.NAME));
    }
}

ChooserDialog sample:

import com.merkle.oss.magnolia.definition.builder.contentapp.column.ColumnDefinitionBuilder;
import com.namics.oss.magnolia.appbuilder.annotations.ChooserDialogFactory;

import info.magnolia.ui.contentapp.configuration.ContentViewDefinition;
import info.magnolia.ui.contentapp.configuration.ListViewDefinition;
import info.magnolia.ui.contentapp.configuration.TreeViewDefinition;
import info.magnolia.ui.contentapp.configuration.column.ColumnDefinition;

import javax.jcr.Item;

import java.util.List;

@ChooserDialogFactory(
        id = SampleChooserDialog.ID,
        label = SampleChooserDialog.NAME + ".title. label"
)
public class SampleChooserDialog {
    public static final String NAME = "SampleChooserDialog";
    public static final String ID = "SomeApp:dialogs/" + NAME;

    private final List<ColumnDefinition<Item>> columns = List.of(
            new ColumnDefinitionBuilder<Item>().build("someField")
    );

    public ContentViewDefinition<Item> tree() {
        final TreeViewDefinition<Item> tree = new TreeViewDefinition<>();
        tree.setName("tree");
        tree.setColumns(columns);
        return tree;
    }

    public ContentViewDefinition<Item> list() {
        final ListViewDefinition<Item> list = new ListViewDefinition<>();
        list.setName("list");
        list.setColumns(columns);
        return list;
    }
}
final LinkFieldDefinition<Node> definition = new LinkFieldDefinition<>();
definition.setChooserId(SampleChooserDialog.ID);
...

ValueProvider sample:

import com.namics.oss.magnolia.appbuilder.formatter.AbstractValueProvider;
import com.namics.oss.magnolia.powernode.PowerNodeService;

import javax.jcr.Node;
import javax.inject.Inject;
import java.util.Optional;

public class SampleValueProvider extends AbstractValueProvider {

	@Inject
	public SampleValueProvider(
			final PowerNodeService powerNodeService
    ) {
		super(powerNodeService, definition);
	}

	@Override
	protected Optional<String> getValue(final Node item) {
		final PowerNode powerNode = powerNodeService.convertToPowerNode(item);
		if (powerNode.isNodeType("<SOME_NODE_TYPE>")) {
			return powerNode.getPropertyValue("<SOME_FIELD>", String.class);
		}
		return Optional.empty();
	}
}