Merge remote-tracking branch 'origin/master' into v2.x
authorMathieu Baudier <mbaudier@argeo.org>
Sun, 14 Feb 2021 16:33:15 +0000 (17:33 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Sun, 14 Feb 2021 16:33:15 +0000 (17:33 +0100)
Conflicts:
pom.xml

16 files changed:
core/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/AbstractTermsPart.java
core/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/MultiTermsPart.java
core/org.argeo.entity.ui/src/org/argeo/entity/ui/forms/SingleTermPart.java
core/org.argeo.suite.ui/OSGI-INF/footer.xml [new file with mode: 0644]
core/org.argeo.suite.ui/OSGI-INF/header.xml
core/org.argeo.suite.ui/bnd.bnd
core/org.argeo.suite.ui/config/footer.properties [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java
core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultFooter.java [new file with mode: 0644]
core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultHeader.java
core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java
core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteStyle.java
core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUi.java
core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/TabbedArea.java
publishing/org.argeo.publishing.ui/src/org/argeo/docbook/ui/AbstractDbkViewer.java
sdk/init/node/ou=roles,ou=node.ldif

index 1d9b6bc713b7e59dfce9f97915111520434448d9..36ae2746f8a5e83d74b1205ec961a2cc8987dd70 100644 (file)
@@ -27,7 +27,7 @@ public abstract class AbstractTermsPart extends StyledControl implements Editabl
        protected final TermsManager termsManager;
        protected final Typology typology;
 
-       protected final boolean editable;
+       private final boolean editable;
 
        private CmsIcon deleteIcon;
        private CmsIcon addIcon;
@@ -37,7 +37,7 @@ public abstract class AbstractTermsPart extends StyledControl implements Editabl
        private Composite highlight;
 
        protected final CmsTheme theme;
-
+       
        public AbstractTermsPart(Composite parent, int style, Item item, TermsManager termsManager, String typology) {
                super(parent, style, item);
                if (item == null)
@@ -49,6 +49,10 @@ public abstract class AbstractTermsPart extends StyledControl implements Editabl
                highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
        }
 
+       public boolean isEditable() {
+               return editable;
+       }
+
        protected void createHighlight(Composite block) {
                highlight = new Composite(block, SWT.NONE);
                highlight.setBackground(highlightColor);
index 9c3618d8d262c981449480d82af77be14209513f..af8df82b0184f574e1f0a74dc81e88377020f65c 100644 (file)
@@ -55,7 +55,8 @@ public class MultiTermsPart extends AbstractTermsPart {
                                String display = getTermLabel(value);
                                lbl.setText(display);
                                CmsUiUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
-                               if (editable)
+                               processTermListLabel(value, lbl);
+                               if (isEditable())
                                        lbl.addMouseListener((MouseDoubleClick) (e) -> {
                                                startEditing();
                                        });
@@ -79,7 +80,7 @@ public class MultiTermsPart extends AbstractTermsPart {
                                }
                        }
                else {// empty
-                       if (editable && !isEditing()) {
+                       if (isEditable() && !isEditing()) {
                                ToolBar toolBar = new ToolBar(placeholder, SWT.HORIZONTAL);
                                ToolItem addItem = new ToolItem(toolBar, SWT.FLAT);
                                styleAdd(addItem);
index 0dcf13d128c5e43659ceeff3950336d126dc500a..0b5948a1221f3ad3f89c1de5238a47895f496719 100644 (file)
@@ -101,17 +101,21 @@ public class SingleTermPart extends AbstractTermsPart {
                                String display = getTermLabel(currentValue);
                                lbl.setText(display);
                                CmsUiUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
-
-                               lbl.addMouseListener((MouseDoubleClick) (e) -> {
-                                       startEditing();
-                               });
+                               processTermListLabel(currentValue, lbl);
+                               if (isEditable()) {
+                                       lbl.addMouseListener((MouseDoubleClick) (e) -> {
+                                               startEditing();
+                                       });
+                               }
                        } else {
-                               ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
-                               ToolItem addItem = new ToolItem(toolBar, SWT.FLAT);
-                               styleAdd(addItem);
-                               addItem.addSelectionListener((Selected) (e) -> {
-                                       startEditing();
-                               });
+                               if (isEditable()) {
+                                       ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
+                                       ToolItem addItem = new ToolItem(toolBar, SWT.FLAT);
+                                       styleAdd(addItem);
+                                       addItem.addSelectionListener((Selected) (e) -> {
+                                               startEditing();
+                                       });
+                               }
                        }
                        return block;
                }
diff --git a/core/org.argeo.suite.ui/OSGI-INF/footer.xml b/core/org.argeo.suite.ui/OSGI-INF/footer.xml
new file mode 100644 (file)
index 0000000..3499b4f
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="false" name="Default Suite Footer">
+   <implementation class="org.argeo.suite.ui.DefaultFooter"/>
+   <service>
+      <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
+   </service>
+   <properties entry="config/footer.properties"/>
+</scr:component>
index a8fc66d32edccbf3c6e9b57e1e5471f7d599b219..526d9f9634ed6dd3d5dfbba00ec074fbf52969bd 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" immediate="false" name="Default Work Header">
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" immediate="false" name="Default Suite Header">
    <implementation class="org.argeo.suite.ui.DefaultHeader"/>
    <service>
       <provide interface="org.argeo.cms.ui.CmsUiProvider"/>
-      <provide interface="org.osgi.service.cm.ManagedService"/>
    </service>
    <properties entry="config/header.properties"/>
 </scr:component>
index a94d10a990f80830137f16d1b56732b803b8d485..abd4ae23e85a2f74b5236a889f03036c6a7b7393 100644 (file)
@@ -1,6 +1,7 @@
 Service-Component:\
 OSGI-INF/cmsApp.xml,\
 OSGI-INF/header.xml,\
+OSGI-INF/footer.xml,\
 OSGI-INF/leadPane.xml,\
 OSGI-INF/loginScreen.xml,\
 OSGI-INF/recentItems.xml,\
diff --git a/core/org.argeo.suite.ui/config/footer.properties b/core/org.argeo.suite.ui/config/footer.properties
new file mode 100644 (file)
index 0000000..12aca56
--- /dev/null
@@ -0,0 +1 @@
+service.pid=argeo.suite.ui.footer
index d017ee7d7f5f0a33897bfe66085dd8b289aa1853..68081b4e646d944b9066c855f98cdc941b48f2ff 100644 (file)
@@ -105,9 +105,9 @@ public class DefaultEditionLayer implements SuiteLayer {
        }
 
        public void destroy(BundleContext bundleContext, Map<String, String> properties) {
-               
+
        }
-       
+
        public void setEntryArea(CmsUiProvider entryArea) {
                this.entryArea = entryArea;
        }
@@ -159,7 +159,11 @@ public class DefaultEditionLayer implements SuiteLayer {
                        }
                        if (startMaximized)
                                setMaximizedControl(editorArea);
-                       editorArea.setLayout(new GridLayout());
+                       GridLayout editorAreaLayout = new GridLayout();
+                       editorAreaLayout.verticalSpacing = 0;
+                       editorAreaLayout.marginBottom = 0;
+                       editorAreaLayout.marginHeight = 0;
+                       editorArea.setLayout(editorAreaLayout);
 
                        if (DefaultEditionLayer.this.workArea == null) {
                                tabbedArea = createTabbedArea(editorArea, theme);
diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultFooter.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultFooter.java
new file mode 100644 (file)
index 0000000..7821e22
--- /dev/null
@@ -0,0 +1,38 @@
+package org.argeo.suite.ui;
+
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.osgi.framework.BundleContext;
+
+/** Footer of a standard Argeo Suite application. */
+public class DefaultFooter implements CmsUiProvider {
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               parent.setLayout(CmsUiUtils.noSpaceGridLayout());
+               Composite content = new Composite(parent, SWT.NONE);
+               Control contentControl = createContent(content, context);
+
+               // TODO support and guarantee
+
+               return contentControl;
+       }
+
+       protected Control createContent(Composite parent, Node context) throws RepositoryException {
+               return parent;
+       }
+
+       public void init(BundleContext bundleContext, Map<String, String> properties) {
+       }
+
+       public void destroy(BundleContext bundleContext, Map<String, String> properties) {
+
+       }
+}
index 84a5ebd394197d0c51658f3c91bc26fa42740567..91154c3b9f7f09b7ca2ac936c56e28c58ac2cabe 100644 (file)
@@ -1,8 +1,6 @@
 package org.argeo.suite.ui;
 
-import java.util.Dictionary;
 import java.util.Map;
-import java.util.TreeMap;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
@@ -13,7 +11,6 @@ import org.argeo.cms.ui.CmsTheme;
 import org.argeo.cms.ui.CmsUiProvider;
 import org.argeo.cms.ui.CmsView;
 import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.util.LangUtils;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
@@ -25,14 +22,10 @@ import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Label;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.wiring.BundleWiring;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
 
-/** HEader of a standard Argeo Suite application. */
-public class DefaultHeader implements CmsUiProvider, ManagedService {
+/** Header of a standard Argeo Suite application. */
+public class DefaultHeader implements CmsUiProvider {
        public final static String TITLE_PROPERTY = "argeo.suite.ui.header.title";
-       private Map<String, String> properties;
-
        private Localized title = null;
 
        @Override
@@ -92,7 +85,6 @@ public class DefaultHeader implements CmsUiProvider, ManagedService {
        }
 
        public void init(BundleContext bundleContext, Map<String, String> properties) {
-               this.properties = new TreeMap<>(properties);
                String titleStr = (String) properties.get(TITLE_PROPERTY);
                if (titleStr != null) {
                        if (titleStr.startsWith("%")) {
@@ -120,12 +112,6 @@ public class DefaultHeader implements CmsUiProvider, ManagedService {
 
        }
 
-       @Override
-       public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
-               if (properties != null)
-                       this.properties.putAll(LangUtils.dictToStringMap(properties));
-       }
-
        public Localized getTitle() {
                return title;
        }
index fcf7e1f7c150de332cf59747cb8c1788bfcddb2b..63a09f1b7290671d4664471d0b57b46699a1a295 100644 (file)
@@ -60,6 +60,7 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler {
 
        private String pidPrefix;
        private String headerPid;
+       private String footerPid;
        private String leadPanePid;
        private String loginScreenPid;
 
@@ -99,6 +100,7 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler {
                        throw new IllegalArgumentException("PID prefix must be set.");
 
                headerPid = pidPrefix + "header";
+               footerPid = pidPrefix + "footer";
                leadPanePid = pidPrefix + "leadPane";
                loginScreenPid = pidPrefix + "loginScreen";
        }
@@ -151,6 +153,7 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler {
                        SuiteUi ui = (SuiteUi) parent;
                        CmsView cmsView = CmsView.getCmsView(parent);
                        CmsUiProvider headerUiProvider = findUiProvider(headerPid);
+                       CmsUiProvider footerUiProvider = findUiProvider(footerPid);
                        Localized appTitle = null;
                        if (headerUiProvider instanceof DefaultHeader) {
                                appTitle = ((DefaultHeader) headerUiProvider).getTitle();
@@ -159,9 +162,12 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler {
 
                        if (cmsView.isAnonymous() && publicBasePath == null) {// internal app, must login
                                ui.logout();
-                               refreshPart(headerUiProvider, ui.getHeader(), context);
+                               if (headerUiProvider != null)
+                                       refreshPart(headerUiProvider, ui.getHeader(), context);
                                ui.refreshBelowHeader(false);
                                refreshPart(findUiProvider(loginScreenPid), ui.getBelowHeader(), context);
+                               if (footerUiProvider != null)
+                                       refreshPart(footerUiProvider, ui.getFooter(), context);
                                ui.layout(true, true);
                                setState(ui, LOGIN);
                        } else {
@@ -169,7 +175,8 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler {
                                        state = null;
                                CmsSession cmsSession = cmsView.getCmsSession();
                                if (ui.getUserDir() == null) {
-                                       if (cmsView.isAnonymous()) {
+                                       // FIXME NPE on CMSSession when logging in from anonymous
+                                       if (cmsSession==null || cmsView.isAnonymous()) {
                                                assert publicBasePath != null;
                                                ui.initSessions(getRepository(), publicBasePath);
                                        } else {
@@ -188,13 +195,16 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler {
                                if (context == null)
                                        context = ui.getUserDir();
 
-                               refreshPart(headerUiProvider, ui.getHeader(), context);
+                               if (headerUiProvider != null)
+                                       refreshPart(headerUiProvider, ui.getHeader(), context);
                                ui.refreshBelowHeader(true);
                                for (String key : layersByPid.keySet()) {
                                        SuiteLayer layer = layersByPid.get(key).get();
                                        ui.addLayer(key, layer);
                                }
                                refreshPart(findUiProvider(leadPanePid), ui.getLeadPane(), context);
+                               if (footerUiProvider != null)
+                                       refreshPart(footerUiProvider, ui.getFooter(), context);
                                ui.layout(true, true);
                                setState(parent, state != null ? state : defaultLayerPid);
                        }
@@ -219,13 +229,13 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler {
 
        private CmsUiProvider findUiProvider(String pid) {
                if (!uiProvidersByPid.containsKey(pid))
-                       throw new IllegalArgumentException("No UI provider registered as " + pid);
+                       return null;
                return uiProvidersByPid.get(pid).get();
        }
 
        private SuiteLayer findLayer(String pid) {
                if (!layersByPid.containsKey(pid))
-                       throw new IllegalArgumentException("No UI provider registered as " + pid);
+                       return null;
                return layersByPid.get(pid).get();
        }
 
index 5183fa464a1dd6d4a62daccb741fdc2e7878f2f1..0156801c32d555656fde0b5e954e77d665805745 100644 (file)
@@ -4,15 +4,17 @@ import org.argeo.cms.ui.util.CmsStyle;
 
 /** Styles used by Argeo Suite work UI. */
 public enum SuiteStyle implements CmsStyle {
-       // Header
+       // header
        header, headerTitle, headerMenu, headerMenuItem,
-       // Recent items
+       // footer
+       footer,
+       // recent items
        recentItems,
-       // Lead pane
+       // lead pane
        leadPane, leadPaneItem, leadPaneSectionTitle, leadPaneSubSectionTitle,
-       // Group composite
+       // group composite
        titleContainer, titleLabel, subTitleLabel, formLine, formColumn, navigationBar, navigationTitle, navigationButton,
-       // Forms elements
+       // forms elements
        simpleLabel, simpleText, simpleInput,
        // table
        titleCell,
@@ -20,7 +22,7 @@ public enum SuiteStyle implements CmsStyle {
        workArea,
        // tabbed area
        mainTabBody, mainTabSelected, mainTab,
-       // Buttons
+       // buttons
        inlineButton;
 
        @Override
index 3c4474ff66edc12e0e3beee9f33323c7ed024f3c..816c65818605761c73d4713d3fda98471ba48806 100644 (file)
@@ -26,6 +26,7 @@ class SuiteUi extends Composite {
 
        private Localized title;
        private Composite header;
+       private Composite footer;
        private Composite belowHeader;
        private Composite leadPane;
        private Composite dynamicArea;
@@ -52,6 +53,11 @@ class SuiteUi extends Composite {
 
                belowHeader = new Composite(this, SWT.NONE);
                belowHeader.setLayoutData(CmsUiUtils.fillAll());
+
+               footer = new Composite(this, SWT.NONE);
+               footer.setLayout(CmsUiUtils.noSpaceGridLayout());
+               CmsUiUtils.style(footer, SuiteStyle.footer);
+               footer.setLayoutData(CmsUiUtils.fillWidth());
        }
 
        public void refreshBelowHeader(boolean initApp) {
@@ -181,6 +187,10 @@ class SuiteUi extends Composite {
                return header;
        }
 
+       Composite getFooter() {
+               return footer;
+       }
+
        Composite getLeadPane() {
                return leadPane;
        }
index e1cf15451d4b35cf0662070e05166a798001cdb0..8ce5fedb736249fd9581c885f6d740bc224641b8 100644 (file)
@@ -91,7 +91,9 @@ public class TabbedArea extends Composite {
                        title.setLayoutData(CmsUiUtils.fillWidth());
                        title.addSelectionListener((Selected) (e) -> showTab(tabIndex(section.getNode())));
                        Node node = section.getNode();
-                       title.setText(Jcr.getTitle(node));
+                       String titleStr = Jcr.getTitle(node);
+                       // TODO internationalize
+                       title.setText(titleStr);
                        if (!singleTab) {
                                ToolBar toolBar = new ToolBar(sectionHeader, SWT.NONE);
                                ToolItem closeItem = new ToolItem(toolBar, SWT.FLAT);
index 814cfb3415e129dcdc28164e27ad72f03d7f78ed..044b675d3f0e530cd98cc4c73e9a7e36c0121e9d 100644 (file)
@@ -75,6 +75,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
        private boolean showMainTitle = true;
 
        private Integer maxMediaWidth = null;
+       private String defaultSectionStyle;
 
        protected AbstractDbkViewer(Section parent, int style, CmsEditable cmsEditable) {
                super(parent, style, cmsEditable);
@@ -106,6 +107,11 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                        CmsUiUtils.clear(section);
                        Node node = section.getNode();
                        TextSection textSection = (TextSection) section;
+                       String style = node.hasProperty(DbkAttr.role.name()) ? node.getProperty(DbkAttr.role.name()).getString()
+                                       : getDefaultSectionStyle();
+                       if (style != null)
+                               CmsUiUtils.style(textSection, style);
+
                        if (node.hasNode(DbkType.title.get())) {
                                boolean showTitle = getMainSection() == section ? showMainTitle : true;
                                if (showTitle) {
@@ -143,7 +149,7 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                        for (NodeIterator ni = section.getNode().getNodes(DbkType.section.get()); ni.hasNext();) {
                                Node child = ni.nextNode();
                                if (isDbk(child, DbkType.section)) {
-                                       TextSection newSection = new TextSection(section, SWT.NONE, child);
+                                       TextSection newSection = newTextSection(section, child);
                                        newSection.setLayoutData(CmsUiUtils.fillWidth());
                                        refresh(newSection);
                                }
@@ -155,6 +161,11 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                // section.layout(true, true);
        }
 
+       /** To be overridden in order to provide additional SectionPart types */
+       protected TextSection newTextSection(Section section, Node node) {
+               return new TextSection(section, SWT.NONE, node);
+       }
+
        /** To be overridden in order to provide additional SectionPart types */
        protected SectionPart newSectionPart(TextSection textSection, Node node) {
                return null;
@@ -946,6 +957,14 @@ public abstract class AbstractDbkViewer extends AbstractPageViewer implements Ke
                this.showMainTitle = showMainTitle;
        }
 
+       public String getDefaultSectionStyle() {
+               return defaultSectionStyle;
+       }
+
+       public void setDefaultSectionStyle(String defaultSectionStyle) {
+               this.defaultSectionStyle = defaultSectionStyle;
+       }
+
        // FILE UPLOAD LISTENER
        private class FUL implements FileUploadListener {
                public void uploadProgress(FileUploadEvent event) {
index d608c2b49e63b9239dff410842e129b7477adc62..3c70185f176cf96563d7fbb6b054384308d484a7 100644 (file)
@@ -4,68 +4,20 @@ objectClass: top
 cn: admin
 member: uid=root,ou=People,dc=example,dc=com
 
-dn: cn=org.argeo.activities.editor,ou=roles,ou=node
+dn: cn=org.argeo.suite.coworker,ou=roles,ou=node
 objectClass: groupOfNames
 objectClass: top
-cn: org.argeo.activities.editor
-member: cn=org.argeo.office.manager,ou=roles,ou=node
-
-dn: cn=org.argeo.activities.reader,ou=roles,ou=node
-objectClass: groupOfNames
-objectClass: top
-cn: org.argeo.activities.reader
-member: cn=org.argeo.office.coworker,ou=roles,ou=node
-
-dn: cn=org.argeo.connect.resources.editor,ou=roles,ou=node
-objectClass: groupOfNames
-objectClass: top
-cn: org.argeo.connect.resources.editor
-member: cn=org.argeo.office.manager,ou=roles,ou=node
-
-dn: cn=org.argeo.connect.resources.reader,ou=roles,ou=node
-objectClass: groupOfNames
-objectClass: top
-cn: org.argeo.connect.resources.reader
-member: cn=org.argeo.office.coworker,ou=roles,ou=node
-
-dn: cn=org.argeo.office.coworker,ou=roles,ou=node
-objectClass: groupOfNames
-objectClass: top
-cn: org.argeo.office.coworker
-member: cn=org.argeo.office.manager,ou=roles,ou=node
+cn: org.argeo.suite.coworker
+member: cn=org.argeo.suite.manager,ou=roles,ou=node
 member: uid=coworker,ou=People,dc=example,dc=com
 
-dn: cn=org.argeo.office.manager,ou=roles,ou=node
+dn: cn=org.argeo.suite.manager,ou=roles,ou=node
 objectClass: groupOfNames
 objectClass: top
-cn: org.argeo.office.manager
+cn: org.argeo.suite.manager
 member: uid=manager,ou=People,dc=example,dc=com
 member: uid=root,ou=People,dc=example,dc=com
 
-dn: cn=org.argeo.people.editor,ou=roles,ou=node
-objectClass: groupOfNames
-objectClass: top
-cn: org.argeo.people.editor
-member: cn=org.argeo.office.manager,ou=roles,ou=node
-
-dn: cn=org.argeo.people.reader,ou=roles,ou=node
-objectClass: groupOfNames
-objectClass: top
-cn: org.argeo.people.reader
-member: cn=org.argeo.office.coworker,ou=roles,ou=node
-
-dn: cn=org.argeo.tracker.editor,ou=roles,ou=node
-objectClass: groupOfNames
-objectClass: top
-cn: org.argeo.tracker.editor
-member: cn=org.argeo.office.manager,ou=roles,ou=node
-
-dn: cn=org.argeo.tracker.reader,ou=roles,ou=node
-objectClass: groupOfNames
-objectClass: top
-cn: org.argeo.tracker.reader
-member: cn=org.argeo.office.coworker,ou=roles,ou=node
-
 dn: cn=userAdmin,ou=roles,ou=node
 objectClass: groupOfNames
 objectClass: top