CCM NG: First part of UI for editing configuration

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4045 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2016-05-02 15:17:14 +00:00
parent aed90bb782
commit f4c09e5739
16 changed files with 861 additions and 138 deletions

View File

@ -129,7 +129,7 @@ public class AdminServlet
new CategoriesTab()); new CategoriesTab());
tabbedPane.addTab( tabbedPane.addTab(
new Label(new GlobalizedMessage("ui.admin.tab.registry.title", new Label(new GlobalizedMessage("ui.admin.tab.configuration.title",
BUNDLE_NAME)), BUNDLE_NAME)),
new RegistryAdminTab()); new RegistryAdminTab());

View File

@ -0,0 +1,127 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.ui.admin.configuration;
import com.arsdigita.bebop.ActionLink;
import com.arsdigita.bebop.BoxPanel;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.ParameterSingleSelectionModel;
import com.arsdigita.bebop.SegmentedPanel;
import com.arsdigita.bebop.form.Submit;
import com.arsdigita.bebop.form.TextField;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.toolbox.ui.LayoutPanel;
import static com.arsdigita.ui.admin.AdminUiConstants.*;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ConfigurationTab extends LayoutPanel {
private static final String CONF_CLASSES_FILTER = "confClassesFilter";
private final StringParameter selectedConfParam;
private final ParameterSingleSelectionModel<String> selectedConf;
private final StringParameter selectedSettingParam;
private final ParameterSingleSelectionModel<String> selectedSetting;
private final Label confClassesFilterHeading;
private final Form confClassesFilterForm;
private final ConfigurationsTable configurationsTable;
public ConfigurationTab() {
super();
setClassAttr("sidebarNavPanel");
selectedConfParam = new StringParameter("selectedConfiguration");
selectedConf = new ParameterSingleSelectionModel<>(selectedConfParam);
selectedSettingParam = new StringParameter("selectedSetting");
selectedSetting = new ParameterSingleSelectionModel<>(
selectedSettingParam);
final SegmentedPanel left = new SegmentedPanel();
confClassesFilterHeading = new Label(new GlobalizedMessage(
"ui.admin.configuration.classes.filter.heading", ADMIN_BUNDLE));
confClassesFilterForm = new Form("confClassesForm");
final TextField confClassesFilter = new TextField(CONF_CLASSES_FILTER);
confClassesFilterForm.add(confClassesFilter);
confClassesFilterForm.add(new Submit(new GlobalizedMessage(
"ui.admin.configuration.classes.filter.submit", ADMIN_BUNDLE)));
final ActionLink clearLink = new ActionLink(new GlobalizedMessage(
"ui.admin.configuration.classes.filter.clear", ADMIN_BUNDLE));
clearLink.addActionListener(e -> {
final PageState state = e.getPageState();
confClassesFilter.setValue(state, null);
});
confClassesFilterForm.add(clearLink);
left.addSegment(confClassesFilterHeading, confClassesFilterForm);
setLeft(left);
final BoxPanel body = new BoxPanel(BoxPanel.VERTICAL);
configurationsTable = new ConfigurationsTable(
this, selectedConf, confClassesFilter);
body.add(configurationsTable);
setBody(body);
}
@Override
public void register(final Page page) {
super.register(page);
page.setVisibleDefault(confClassesFilterHeading, true);
page.setVisibleDefault(confClassesFilterForm, true);
page.setVisibleDefault(configurationsTable, true);
}
protected void showConfigurationsTable(final PageState state) {
confClassesFilterHeading.setVisible(state, true);
confClassesFilterForm.setVisible(state, true);
configurationsTable.setVisible(state, true);
}
protected void hideConfigurationsTable(final PageState state) {
confClassesFilterHeading.setVisible(state, false);
confClassesFilterForm.setVisible(state, false);
configurationsTable.setVisible(state, false);
}
protected void showConfiguration(final PageState state) {
hideConfigurationsTable(state);
}
protected void hideConfiguration(final PageState state) {
showConfigurationsTable(state);
}
}

View File

@ -0,0 +1,241 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.ui.admin.configuration;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.ControlLink;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.ParameterSingleSelectionModel;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.event.TableActionEvent;
import com.arsdigita.bebop.event.TableActionListener;
import com.arsdigita.bebop.table.TableCellRenderer;
import com.arsdigita.bebop.table.TableColumn;
import com.arsdigita.bebop.table.TableColumnModel;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.bebop.table.TableModelBuilder;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.util.LockableImpl;
import com.arsdigita.util.UncheckedWrapperException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.configuration.SettingInfo;
import org.libreccm.configuration.SettingManager;
import org.libreccm.l10n.GlobalizationHelper;
import java.util.List;
import java.util.logging.Level;
import static com.arsdigita.ui.admin.AdminUiConstants.*;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ConfigurationTable extends Table {
private static final Logger LOGGER = LogManager.getLogger(
ConfigurationTable.class);
private static final int COL_SETTING_LABEL = 0;
private static final int COL_SETTING_VALUE = 1;
private static final int COL_SETTING_DESC = 2;
private static final int COL_EDIT_SETTING = 3;
private ParameterSingleSelectionModel<String> selectedConf;
public ConfigurationTable(
final ConfigurationTab configurationTab,
final ParameterSingleSelectionModel<String> selectedConf,
final ParameterSingleSelectionModel<String> selectedSetting) {
super();
setIdAttr("configurationTable");
this.selectedConf = selectedConf;
setEmptyView(new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.none", ADMIN_BUNDLE)));
final TableColumnModel columnModel = getColumnModel();
columnModel.add(new TableColumn(
COL_SETTING_LABEL,
new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.table.col_setting_label.header",
ADMIN_BUNDLE))));
columnModel.add(new TableColumn(
COL_SETTING_VALUE,
new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.table.col_setting_value.header",
ADMIN_BUNDLE))));
columnModel.add(new TableColumn(
COL_SETTING_DESC,
new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.table.col_setting_desc.header",
ADMIN_BUNDLE))));
columnModel.add(new TableColumn(
COL_EDIT_SETTING,
new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.table.col_edit_setting.header",
ADMIN_BUNDLE))));
columnModel.get(COL_EDIT_SETTING).setCellRenderer(
new TableCellRenderer() {
@Override
public Component getComponent(final Table table,
final PageState state,
final Object value,
final boolean isSelected,
final Object key,
final int row,
final int column) {
return new ControlLink((String) value);
}
});
addTableActionListener(new TableActionListener() {
@Override
public void cellSelected(final TableActionEvent event) {
final PageState state = event.getPageState();
if (event.getColumn() == COL_EDIT_SETTING) {
final String settingName = (String) event.getRowKey();
selectedSetting.setSelectedKey(state, settingName);
}
}
@Override
public void headSelected(final TableActionEvent event) {
//Nothing
}
});
setModelBuilder(new ConfigurationTableModelBuilder());
}
private class ConfigurationTableModelBuilder
extends LockableImpl implements TableModelBuilder {
@Override
public TableModel makeModel(final Table table, final PageState state) {
final ConfigurationManager confManager = CdiUtil.createCdiUtil()
.findBean(ConfigurationManager.class);
final Class<?> confClass;
try {
confClass = Class.forName(selectedConf.getSelectedKey(state));
} catch (ClassNotFoundException ex) {
LOGGER.error("Configuration class '{}' not found.",
selectedConf.getSelectedKey(state));
throw new UncheckedWrapperException(String.format(
"Configuration class '%s not found'",
selectedConf.getSelectedKey(state)), ex);
}
final Object configuration = confManager
.findConfiguration(confClass);
return new ConfigurationTableModel(configuration, state);
}
}
private class ConfigurationTableModel implements TableModel {
private final Object configuration;
private final ConfigurationManager confManager;
private final SettingManager settingManager;
private final GlobalizationHelper globalizationHelper;
private final List<String> settings;
private int index = -1;
public ConfigurationTableModel(final Object configuration,
final PageState state) {
this.configuration = configuration;
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
confManager = cdiUtil.findBean(ConfigurationManager.class);
settingManager = cdiUtil.findBean(SettingManager.class);
globalizationHelper = cdiUtil.findBean(GlobalizationHelper.class);
settings = settingManager.getAllSettings(configuration.getClass());
}
@Override
public int getColumnCount() {
return 4;
}
@Override
public boolean nextRow() {
index++;
return index < settings.size();
}
@Override
public Object getElementAt(final int columnIndex) {
final String setting = settings.get(index);
final SettingInfo settingInfo = settingManager.getSettingInfo(
configuration.getClass(), setting);
switch (columnIndex) {
case COL_SETTING_LABEL:
return settingInfo.getLabel(globalizationHelper
.getNegotiatedLocale());
case COL_SETTING_VALUE: {
try {
return configuration.getClass().getField(setting).get(
configuration);
} catch (NoSuchFieldException | SecurityException | IllegalAccessException ex) {
LOGGER.error("Failed to read value from configuration.",
ex);
return new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.read_error",
ADMIN_BUNDLE));
}
}
case COL_SETTING_DESC:
return settingInfo.getDescription(globalizationHelper
.getNegotiatedLocale());
case COL_EDIT_SETTING:
return new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.edit", ADMIN_BUNDLE));
default:
throw new IllegalArgumentException("Illegal column index");
}
}
@Override
public Object getKeyAt(final int columnIndex) {
return settings.get(index);
}
}
}

View File

@ -0,0 +1,217 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.ui.admin.configuration;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.ControlLink;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.ParameterSingleSelectionModel;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.event.TableActionEvent;
import com.arsdigita.bebop.event.TableActionListener;
import com.arsdigita.bebop.form.TextField;
import com.arsdigita.bebop.table.TableCellRenderer;
import com.arsdigita.bebop.table.TableColumn;
import com.arsdigita.bebop.table.TableColumnModel;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.bebop.table.TableModelBuilder;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.util.LockableImpl;
import org.apache.logging.log4j.util.Strings;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.configuration.ConfigurationInfo;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.l10n.GlobalizationHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.SortedSet;
import java.util.stream.Collectors;
import static com.arsdigita.ui.admin.AdminUiConstants.*;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ConfigurationsTable extends Table {
private static final int COL_TITLE = 0;
private static final int COL_DESC = 1;
public ConfigurationsTable(
final ConfigurationTab configurationTab,
final ParameterSingleSelectionModel<String> selectedConf,
final TextField confClassesFilter) {
super();
setIdAttr("configurationsTable");
setEmptyView(new Label(new GlobalizedMessage(
"ui.admin.configuration.configurations.none", ADMIN_BUNDLE)));
final TableColumnModel columnModel = getColumnModel();
columnModel.add(new TableColumn(
COL_TITLE,
new Label(new GlobalizedMessage(
"ui.admin.configuration.configurations.table.name",
ADMIN_BUNDLE))));
columnModel.add(new TableColumn(
COL_DESC,
new Label(new GlobalizedMessage(
"ui.admin.configuration.configurations.table.desc",
ADMIN_BUNDLE))));
columnModel.get(COL_TITLE).setCellRenderer(new TableCellRenderer() {
@Override
public Component getComponent(final Table table,
final PageState state,
final Object value,
final boolean isSelected,
final Object key,
final int row,
final int column) {
return new ControlLink((String) value);
}
});
addTableActionListener(new TableActionListener() {
@Override
public void cellSelected(final TableActionEvent event) {
final PageState state = event.getPageState();
if (event.getColumn() == COL_TITLE) {
final String confClassName = (String) event.getRowKey();
selectedConf.setSelectedKey(state, confClassName);
}
}
@Override
public void headSelected(final TableActionEvent event) {
//Nothing
}
});
setModelBuilder(new ConfigurationsTableModelBuilder(confClassesFilter));
}
private class ConfigurationsTableModelBuilder
extends LockableImpl implements TableModelBuilder {
private final TextField confClassesFilter;
public ConfigurationsTableModelBuilder(
final TextField confClassesField) {
this.confClassesFilter = confClassesField;
}
@Override
public TableModel makeModel(final Table table,
final PageState state) {
table.getRowSelectionModel().clearSelection(state);
return new ConfigurationsTableModel(confClassesFilter, state);
}
}
private class ConfigurationsTableModel implements TableModel {
private final List<Class<?>> configurations;
private int index = -1;
private final ConfigurationManager confManager;
private final Locale negoiatedLocale;
public ConfigurationsTableModel(final TextField confClassesFilter,
final PageState state) {
final String filterTerm = (String) confClassesFilter
.getValue(state);
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
confManager = cdiUtil.findBean(ConfigurationManager.class);
final GlobalizationHelper globalizationHelper = cdiUtil.findBean(
GlobalizationHelper.class);
negoiatedLocale = globalizationHelper.getNegotiatedLocale();
final SortedSet<Class<?>> confs = confManager
.findAllConfigurations();
configurations = confs.stream()
.filter(c -> {
final ConfigurationInfo info = confManager
.getConfigurationInfo(c);
// return c.getName().startsWith(filterTerm);
return info.getTitle(negoiatedLocale).startsWith(filterTerm);
})
.collect(Collectors.toCollection(ArrayList::new));
configurations.sort((c1, c2) -> {
// return c1.getName().compareTo(c2.getName());
final ConfigurationInfo info1 = confManager
.getConfigurationInfo(c1);
final ConfigurationInfo info2 = confManager
.getConfigurationInfo(c2);
return info1.getTitle(negoiatedLocale)
.compareTo(info2.getTitle(negoiatedLocale));
});
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public boolean nextRow() {
index++;
return index < configurations.size();
}
@Override
public Object getElementAt(final int columnIndex) {
final ConfigurationInfo info = confManager.getConfigurationInfo(
configurations.get(index));
switch (columnIndex) {
case COL_TITLE:
if (Strings.isBlank(info.getTitle(negoiatedLocale))) {
return configurations.get(index).getSimpleName();
} else {
return info.getTitle(negoiatedLocale);
}
case COL_DESC:
return info.getDescription(negoiatedLocale);
default:
throw new IllegalArgumentException("Illegal column index");
}
}
@Override
public Object getKeyAt(final int columnIndex) {
return configurations.get(index).getName();
}
}
}

View File

@ -18,7 +18,6 @@
*/ */
package org.libreccm.configuration; package org.libreccm.configuration;
import org.libreccm.configuration.*;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -42,15 +41,22 @@ public @interface Configuration {
* @return Name of the configuration. * @return Name of the configuration.
*/ */
//String name() default ""; //String name() default "";
/** /**
* Points to the {@link ResourceBundle} containing the descriptions * Points to the {@link ResourceBundle} containing the descriptions of the
* of the configuration and all entries of the configuration. * configuration and all entries of the configuration.
* *
* @return Fully qualified name of the {@link ResourceBundle}. * @return Fully qualified name of the {@link ResourceBundle}.
*/ */
String descBundle() default ""; String descBundle() default "";
/**
* Key of the title of the description in the resource bundle provided by
* {@link #descBundle()}.
*
* @return Key of the title
*/
String titleKey() default "";
/** /**
* Key of the description of the configuration in the resource bundle * Key of the description of the configuration in the resource bundle
* provided by {@link #descBundle()}. * provided by {@link #descBundle()}.

View File

@ -26,8 +26,7 @@ import java.util.ResourceBundle;
import java.util.TreeMap; import java.util.TreeMap;
/** /**
* Describes a configuration. Useful for generating user * Describes a configuration. Useful for generating user interfaces.
* interfaces.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@ -44,6 +43,8 @@ public final class ConfigurationInfo {
*/ */
private String descBundle; private String descBundle;
private String titleKey;
/** /**
* The key for the description of the configuration in the resource bundle. * The key for the description of the configuration in the resource bundle.
*/ */
@ -79,6 +80,14 @@ public final class ConfigurationInfo {
return ResourceBundle.getBundle(descBundle); return ResourceBundle.getBundle(descBundle);
} }
public String getTitleKey() {
return titleKey;
}
void setTitleKey(final String titleKey) {
this.titleKey = titleKey;
}
public String getDescKey() { public String getDescKey() {
return descKey; return descKey;
} }
@ -87,6 +96,10 @@ public final class ConfigurationInfo {
this.descKey = descKey; this.descKey = descKey;
} }
public String getTitle(final Locale locale) {
return getDescriptionBundle(locale).getString(titleKey);
}
public String getDescription(final Locale locale) { public String getDescription(final Locale locale) {
return getDescriptionBundle(locale).getString(descKey); return getDescriptionBundle(locale).getString(descKey);
} }

View File

@ -19,12 +19,21 @@
package org.libreccm.configuration; package org.libreccm.configuration;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.util.Strings;
import org.libreccm.modules.CcmModule;
import org.libreccm.modules.Module;
import java.util.Arrays;
import java.util.ServiceLoader;
import java.util.SortedSet;
import java.util.TreeSet;
/** /**
* Maps between configuration classes and the settings stored in the database. * Maps between configuration classes and the settings stored in the database.
@ -43,8 +52,36 @@ public class ConfigurationManager {
@Inject @Inject
private SettingConverter settingConverter; private SettingConverter settingConverter;
@Inject /**
private EntityManager entityManager; * Finds all configuration classes listed by the installed modules.
*
* @return A sorted set containing all configuration classes.
*
* @see Module#configurations()
*/
public SortedSet<Class<?>> findAllConfigurations() {
final ServiceLoader<CcmModule> modules = ServiceLoader.load(
CcmModule.class);
final SortedSet<Class<?>> configurations = new TreeSet<>((c1, c2) -> {
return c1.getName().compareTo(c2.getName());
});
for(CcmModule module : modules) {
final Module annotation = module.getClass().getAnnotation(
Module.class);
if (annotation == null) {
continue;
}
Arrays.stream(annotation.configurations()).forEach(c -> {
configurations.add(c);
});
}
return configurations;
}
/** /**
* Load all settings of the provided configuration class. * Load all settings of the provided configuration class.
@ -170,8 +207,12 @@ public class ConfigurationManager {
} else { } else {
confInfo.setDescBundle(annotation.descBundle()); confInfo.setDescBundle(annotation.descBundle());
} }
if (annotation.descKey() == null if (Strings.isBlank(annotation.titleKey())) {
|| annotation.descKey().isEmpty()) { confInfo.setTitleKey("title");
} else {
confInfo.setTitleKey(annotation.titleKey());
}
if (Strings.isBlank(annotation.descKey())) {
confInfo.setDescKey("description"); confInfo.setDescKey("description");
} else { } else {
confInfo.setDescKey(annotation.descKey()); confInfo.setDescKey(annotation.descKey());

View File

@ -115,6 +115,10 @@ public final class SettingInfo {
this.labelKey = labelKey; this.labelKey = labelKey;
} }
public String getLabel(final Locale locale) {
return getDescriptionBundle(locale).getString(labelKey);
}
public String getDescKey() { public String getDescKey() {
return descKey; return descKey;
} }

View File

@ -20,13 +20,18 @@ package org.libreccm.configuration;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.List; import java.util.List;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.util.Strings;
import java.util.ArrayList;
/** /**
* *
@ -43,18 +48,55 @@ import org.apache.logging.log4j.Logger;
public class SettingManager { public class SettingManager {
private static final Logger LOGGER = LogManager.getLogger( private static final Logger LOGGER = LogManager.getLogger(
SettingManager.class); SettingManager.class);
@Inject @Inject
private EntityManager entityManager; private EntityManager entityManager;
/**
* Get the names of all settings of a configuration class.
*
* @param configuration The configuration class for which the settings are
* retrieved.
*
* @return A list with the names of all settings provided by the
* configuration class.
*/
public List<String> getAllSettings(final Class<?> configuration) {
if (configuration == null) {
throw new IllegalArgumentException("Configuration can't be null");
}
if (configuration.getAnnotation(Configuration.class) == null) {
throw new IllegalArgumentException(String.format(
"The class \"%s\" of the provided object is not annotated "
+ "with \"%s\".",
configuration.getClass().getName(),
Configuration.class.getName()));
}
final List<String> settings = new ArrayList<>();
final Field[] fields = configuration.getDeclaredFields();
for (Field field : fields) {
if (field.getAnnotation(Setting.class) != null) {
settings.add(field.getName());
}
}
settings.sort((s1, s2) -> {
return s1.compareTo(s2);
});
return settings;
}
/** /**
* Create a {@link SettingInfo} instance for a setting. * Create a {@link SettingInfo} instance for a setting.
* *
* @param configuration The configuration class to which the settings * @param configuration The configuration class to which the settings
* belongs. * belongs.
* @param name The name of the setting for which the {@link SettingInfo} is * @param name The name of the setting for which the
* generated. * {@link SettingInfo} is generated.
* *
* @return The {@link SettingInfo} for the provided configuration class. * @return The {@link SettingInfo} for the provided configuration class.
*/ */
@ -62,18 +104,18 @@ public class SettingManager {
"PMD.CyclomaticComplexity", "PMD.CyclomaticComplexity",
"PMD.StandardCyclomaticComplexity"}) "PMD.StandardCyclomaticComplexity"})
public SettingInfo getSettingInfo( public SettingInfo getSettingInfo(
final Class<?> configuration, final Class<?> configuration,
final String name) { final String name) {
if (configuration == null) { if (configuration == null) {
throw new IllegalArgumentException("Configuration can't be null"); throw new IllegalArgumentException("Configuration can't be null");
} }
if (configuration.getAnnotation(Configuration.class) == null) { if (configuration.getAnnotation(Configuration.class) == null) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"The class \"%s\" of the provided object is not annotated " "The class \"%s\" of the provided object is not annotated "
+ "with \"%s\".", + "with \"%s\".",
configuration.getClass().getName(), configuration.getClass().getName(),
Configuration.class.getName())); Configuration.class.getName()));
} }
final Field field; final Field field;
@ -81,10 +123,10 @@ public class SettingManager {
field = configuration.getDeclaredField(name); field = configuration.getDeclaredField(name);
} catch (SecurityException | NoSuchFieldException ex) { } catch (SecurityException | NoSuchFieldException ex) {
LOGGER.warn(String.format( LOGGER.warn(String.format(
"Failed to generate SettingInfo for field \"%s\" of " "Failed to generate SettingInfo for field \"%s\" of "
+ "configuration \"%s\". Ignoring field.", + "configuration \"%s\". Ignoring field.",
configuration.getClass().getName(), configuration.getClass().getName(),
name), name),
ex); ex);
return null; return null;
} }
@ -96,7 +138,7 @@ public class SettingManager {
final Setting settingAnnotation = field.getAnnotation(Setting.class); final Setting settingAnnotation = field.getAnnotation(Setting.class);
final SettingInfo settingInfo = new SettingInfo(); final SettingInfo settingInfo = new SettingInfo();
if (settingAnnotation.name() == null if (settingAnnotation.name() == null
|| settingAnnotation.name().isEmpty()) { || settingAnnotation.name().isEmpty()) {
settingInfo.setName(field.getName()); settingInfo.setName(field.getName());
} else { } else {
settingInfo.setName(settingAnnotation.name()); settingInfo.setName(settingAnnotation.name());
@ -109,7 +151,7 @@ public class SettingManager {
settingInfo.setDefaultValue(field.get(conf).toString()); settingInfo.setDefaultValue(field.get(conf).toString());
} catch (InstantiationException | IllegalAccessException ex) { } catch (InstantiationException | IllegalAccessException ex) {
LOGGER.warn(String.format("Failed to create instance of \"%s\" to " LOGGER.warn(String.format("Failed to create instance of \"%s\" to "
+ "get default values.", + "get default values.",
configuration.getName()), configuration.getName()),
ex); ex);
} }
@ -117,16 +159,14 @@ public class SettingManager {
settingInfo.setConfClass(configuration.getName()); settingInfo.setConfClass(configuration.getName());
settingInfo.setDescBundle(getDescBundle(configuration)); settingInfo.setDescBundle(getDescBundle(configuration));
if (settingAnnotation.labelKey() == null if (Strings.isBlank(settingAnnotation.labelKey())) {
|| settingAnnotation.labelKey().isEmpty()) {
settingInfo.setLabelKey(String.join(".", field.getName(), settingInfo.setLabelKey(String.join(".", field.getName(),
"label")); "label"));
} else { } else {
settingInfo.setLabelKey(name); settingInfo.setLabelKey(name);
} }
if (settingAnnotation.descKey() == null if (Strings.isBlank(settingAnnotation.descKey())) {
|| settingAnnotation.descKey().isEmpty()) {
settingInfo.setDescKey(String.join(".", settingInfo.setDescKey(String.join(".",
field.getName(), field.getName(),
"descripotion")); "descripotion"));
@ -140,25 +180,25 @@ public class SettingManager {
/** /**
* A low level method for finding a setting in the registry. * A low level method for finding a setting in the registry.
* *
* @param <T> Type of the value of the setting * @param <T> Type of the value of the setting
* @param confName Name of the configuration to which the setting belongs * @param confName Name of the configuration to which the setting belongs
* @param name The fully qualified name of the setting. * @param name The fully qualified name of the setting.
* @param clazz The class of the setting. * @param clazz The class of the setting.
* *
* @return The requested setting if it exists in the registry, {@code null} * @return The requested setting if it exists in the registry, {@code null}
* otherwise. * otherwise.
*/ */
public <T> AbstractSetting<T> findSetting(final String confName, public <T> AbstractSetting<T> findSetting(final String confName,
final String name, final String name,
final Class<T> clazz) { final Class<T> clazz) {
LOGGER.debug(String.format( LOGGER.debug(String.format(
"Trying to find setting \"%s\" of type \"%s\"", "Trying to find setting \"%s\" of type \"%s\"",
name, name,
clazz.getName())); clazz.getName()));
final TypedQuery<AbstractSetting> query = entityManager. final TypedQuery<AbstractSetting> query = entityManager.
createNamedQuery("AbstractSetting.findByClassAndName", createNamedQuery("AbstractSetting.findByClassAndName",
AbstractSetting.class); AbstractSetting.class);
query.setParameter("class", confName); query.setParameter("class", confName);
query.setParameter("name", name); query.setParameter("name", name);
final List<AbstractSetting> result = query.getResultList(); final List<AbstractSetting> result = query.getResultList();
@ -185,9 +225,9 @@ public class SettingManager {
private String getDescBundle(final Class<?> configuration) { private String getDescBundle(final Class<?> configuration) {
final Configuration confAnnotation = configuration.getAnnotation( final Configuration confAnnotation = configuration.getAnnotation(
Configuration.class); Configuration.class);
if (confAnnotation.descBundle() == null if (confAnnotation.descBundle() == null
|| confAnnotation.descBundle().isEmpty()) { || confAnnotation.descBundle().isEmpty()) {
return String.join("", return String.join("",
configuration.getClass().getName(), configuration.getClass().getName(),
"Description"); "Description");
@ -195,4 +235,5 @@ public class SettingManager {
return confAnnotation.descBundle(); return confAnnotation.descBundle();
} }
} }
} }

View File

@ -18,12 +18,18 @@
*/ */
package org.libreccm.core; package org.libreccm.core;
import com.arsdigita.bebop.BebopConfig;
import com.arsdigita.kernel.KernelConfig;
import com.arsdigita.mail.MailConfig;
import com.arsdigita.notification.NotificationConfig;
import com.arsdigita.ui.admin.AdminApplicationCreator; import com.arsdigita.ui.admin.AdminApplicationCreator;
import com.arsdigita.ui.admin.AdminServlet; import com.arsdigita.ui.admin.AdminServlet;
import com.arsdigita.ui.admin.AdminApplicationSetup; import com.arsdigita.ui.admin.AdminApplicationSetup;
import com.arsdigita.ui.login.LoginApplicationCreator; import com.arsdigita.ui.login.LoginApplicationCreator;
import com.arsdigita.ui.login.LoginServlet; import com.arsdigita.ui.login.LoginServlet;
import com.arsdigita.ui.login.LoginApplicationSetup; import com.arsdigita.ui.login.LoginApplicationSetup;
import com.arsdigita.workflow.simple.WorkflowConfig;
import com.arsdigita.xml.XmlConfig;
import org.libreccm.modules.CcmModule; import org.libreccm.modules.CcmModule;
import org.libreccm.modules.InitEvent; import org.libreccm.modules.InitEvent;
@ -31,9 +37,10 @@ import org.libreccm.modules.InstallEvent;
import org.libreccm.modules.Module; import org.libreccm.modules.Module;
import org.libreccm.modules.ShutdownEvent; import org.libreccm.modules.ShutdownEvent;
import org.libreccm.modules.UnInstallEvent; import org.libreccm.modules.UnInstallEvent;
import org.libreccm.security.EmailTemplates;
import org.libreccm.security.OneTimeAuthConfig;
import org.libreccm.security.SystemUsersSetup; import org.libreccm.security.SystemUsersSetup;
import org.libreccm.web.ApplicationType; import org.libreccm.web.ApplicationType;
/** /**
@ -51,48 +58,23 @@ import org.libreccm.web.ApplicationType;
singleton = true, singleton = true,
creator = AdminApplicationCreator.class, creator = AdminApplicationCreator.class,
servlet = AdminServlet.class)}, servlet = AdminServlet.class)},
entities = {org.libreccm.auditing.CcmRevision.class, configurations = {
org.libreccm.categorization.Categorization.class, com.arsdigita.bebop.BebopConfig.class,
org.libreccm.categorization.Category.class, com.arsdigita.dispatcher.DispatcherConfig.class,
org.libreccm.categorization.Domain.class, com.arsdigita.globalization.GlobalizationConfig.class,
org.libreccm.categorization.DomainOwnership.class, com.arsdigita.kernel.KernelConfig.class,
org.libreccm.core.CcmObject.class, com.arsdigita.kernel.security.SecurityConfig.class,
org.libreccm.core.Resource.class, com.arsdigita.mail.MailConfig.class,
org.libreccm.core.ResourceType.class, com.arsdigita.notification.NotificationConfig.class,
org.libreccm.modules.InstalledModule.class, com.arsdigita.templating.TemplatingConfig.class,
org.libreccm.formbuilder.Component.class, com.arsdigita.ui.UIConfig.class,
org.libreccm.formbuilder.DataDrivenSelect.class, com.arsdigita.web.WebConfig.class,
org.libreccm.formbuilder.FormSection.class, com.arsdigita.workflow.simple.WorkflowConfig.class,
org.libreccm.formbuilder.Listener.class, com.arsdigita.xml.XmlConfig.class,
org.libreccm.formbuilder.MetaObject.class, com.arsdigita.xml.formatters.DateFormatterConfig.class,
org.libreccm.formbuilder.ObjectType.class, org.libreccm.security.EmailTemplates.class,
org.libreccm.formbuilder.Option.class, org.libreccm.security.OneTimeAuthConfig.class,
org.libreccm.formbuilder.PersistentDataQuery.class, })
org.libreccm.formbuilder.ProcessListener.class,
org.libreccm.formbuilder.Widget.class,
org.libreccm.formbuilder.WidgetLabel.class,
org.libreccm.formbuilder.actions.ConfirmEmailListener.class,
org.libreccm.formbuilder.actions.ConfirmRedirectListener.class,
org.libreccm.formbuilder.actions.RemoteServerPostListener.class,
org.libreccm.formbuilder.actions.SimpleEmailListener.class,
org.libreccm.formbuilder.actions.TemplateEmailListener.class,
org.libreccm.formbuilder.actions.XmlEmailListener.class,
org.libreccm.messaging.Attachment.class,
org.libreccm.messaging.Message.class,
org.libreccm.messaging.MessageThread.class,
org.libreccm.notification.Digest.class,
org.libreccm.notification.Notification.class,
org.libreccm.notification.QueueItem.class,
org.libreccm.portal.Portal.class,
org.libreccm.portal.Portlet.class,
org.libreccm.runtime.Initalizer.class,
org.libreccm.search.lucene.Document.class,
org.libreccm.search.lucene.Index.class,
org.libreccm.web.CcmApplication.class,
org.libreccm.web.Host.class,
org.libreccm.workflow.Task.class,
org.libreccm.workflow.UserTask.class,
org.libreccm.workflow.Workflow.class})
public class CcmCore implements CcmModule { public class CcmCore implements CcmModule {
@Override @Override
@ -100,13 +82,15 @@ public class CcmCore implements CcmModule {
// final EntityManager entityManager = event.getEntityManager(); // final EntityManager entityManager = event.getEntityManager();
final SystemUsersSetup systemUsersSetup = new SystemUsersSetup( final SystemUsersSetup systemUsersSetup = new SystemUsersSetup(
event); event);
systemUsersSetup.setupSystemUsers(); systemUsersSetup.setupSystemUsers();
final AdminApplicationSetup adminSetup = new AdminApplicationSetup(event); final AdminApplicationSetup adminSetup
= new AdminApplicationSetup(event);
adminSetup.setup(); adminSetup.setup();
final LoginApplicationSetup loginSetup = new LoginApplicationSetup(event); final LoginApplicationSetup loginSetup
= new LoginApplicationSetup(event);
loginSetup.setup(); loginSetup.setup();
} }

View File

@ -18,6 +18,8 @@
*/ */
package org.libreccm.modules; package org.libreccm.modules;
import org.libreccm.configuration.Configuration;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.web.ApplicationType; import org.libreccm.web.ApplicationType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -36,16 +38,16 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Module { public @interface Module {
/** /**
* Name of the module, overriding the name provided by the pom.xml and the * Name of the module, overriding the name provided by the pom.xml and the
* module info file of the module. * module info file of the module.
* *
* @return The name of the module, overriding the value provided by the * @return The name of the module, overriding the value provided by the
* module-info file. * module-info file.
*/ */
String name() default ""; String name() default "";
/** /**
* Package name of resources of the package like DB migrations, overriding * Package name of resources of the package like DB migrations, overriding
* default value constructed from the group id and the artifact id of the * default value constructed from the group id and the artifact id of the
* module. * module.
@ -54,11 +56,11 @@ public @interface Module {
*/ */
String packageName() default ""; String packageName() default "";
/** /**
* The version of module, overriding the value provided by the module info * The version of module, overriding the value provided by the module info
* file of the module. * file of the module.
* *
* @return The version of the module. * @return The version of the module.
*/ */
String version() default ""; String version() default "";
@ -73,15 +75,19 @@ public @interface Module {
* ApplicationType types provided by the annotated module. * ApplicationType types provided by the annotated module.
* *
* @return An array containing the type descriptions for all application * @return An array containing the type descriptions for all application
* types provided by the annotated module. * types provided by the annotated module.
*/ */
ApplicationType[] applicationTypes() default {}; ApplicationType[] applicationTypes() default {};
/** /**
* The JPA entities provided by the annotated module. * Configuration classes provided by the module.
* *
* @return An array with the JPA entity classes of the annotated module. * @return An array containing all configuration classes provided by the
* module.
*
* @see Configuration
* @see ConfigurationManager
*/ */
Class<?>[] entities() default {}; Class<?>[] configurations() default {};
} }

View File

@ -59,10 +59,6 @@ public class ModuleInfo {
* The data package of the module (group id). * The data package of the module (group id).
*/ */
private String moduleDataPackage; private String moduleDataPackage;
/**
* The entities provided by the module.
*/
private Class<?>[] moduleEntities;
/** /**
* The version of the module. * The version of the module.
*/ */
@ -129,10 +125,6 @@ public class ModuleInfo {
return moduleVersion; return moduleVersion;
} }
public List<Class<?>> getModuleEntities() {
return Collections.unmodifiableList(Arrays.asList(moduleEntities));
}
public List<RequiredModule> getRequiredModules() { public List<RequiredModule> getRequiredModules() {
return Collections.unmodifiableList(Arrays.asList(requiredModules)); return Collections.unmodifiableList(Arrays.asList(requiredModules));
} }
@ -168,7 +160,6 @@ public class ModuleInfo {
LOGGER.info("Module version is \"{}.\"", moduleVersion); LOGGER.info("Module version is \"{}.\"", moduleVersion);
requiredModules = annotation.requiredModules(); requiredModules = annotation.requiredModules();
moduleEntities = annotation.entities();
} }
/** /**

View File

@ -154,7 +154,7 @@ ui.admin.user.userpasswordform.retrieving_user_failed=Failed to retrieve user
ui.admin.groups.couldnt_find_specified_group=Couldn't find the specified group ui.admin.groups.couldnt_find_specified_group=Couldn't find the specified group
ui.admin.tab.users_groups_roles.title=Users/Groups/Roles ui.admin.tab.users_groups_roles.title=Users/Groups/Roles
ui.admin.tab.categories.title=Categories ui.admin.tab.categories.title=Categories
ui.admin.tab.registry.title=Registry ui.admin.tab.configuration.title=Configuration
ui.admin.change_password=Change password ui.admin.change_password=Change password
ui.admin.tab.workflows.title=Workflows ui.admin.tab.workflows.title=Workflows
ui.admin.users_groups_roles.users.title=Users ui.admin.users_groups_roles.users.title=Users
@ -408,3 +408,16 @@ ui.admin.categories.doamin_details.mappings.error.please_select_app=Please selec
ui.admin.categories.domain_details.mappings.remove.confirm=Are you sure to remove this domain mapping? ui.admin.categories.domain_details.mappings.remove.confirm=Are you sure to remove this domain mapping?
ui.admin.categories.tree.header=Categories ui.admin.categories.tree.header=Categories
ui.admin.categories.tree.back=Back to domain properties ui.admin.categories.tree.back=Back to domain properties
ui.admin.configuration.classes.filter.heading=Filter configurations
ui.admin.configuration.classes.filter.submit=Apply
ui.admin.configuration.classes.filter.clear=Clear
ui.admin.configuration.configurations.none=No matching configurations found.
ui.admin.configuration.configurations.table.name=Name
ui.admin.configuration.configurations.table.desc=Description
ui.admin.configuration.settings.none=No settings
ui.admin.configuration.settings.table.col_setting_label.header=Setting
ui.admin.configuration.settings.table.col_setting_value.header=Value
ui.admin.configuration.settings.table.col_setting_desc.header=Description
ui.admin.configuration.settings.table.col_edit_setting.header=Edit
ui.admin.configuration.settings.edit=Edit
ui.admin.configuration.settings.read_error=Failed to read setting value.

View File

@ -154,7 +154,7 @@ ui.admin.user.userpasswordform.retrieving_user_failed=Konnte Benutzer nicht abru
ui.admin.groups.couldnt_find_specified_group=Konnte die spezifische Gruppe nicht finden ui.admin.groups.couldnt_find_specified_group=Konnte die spezifische Gruppe nicht finden
ui.admin.tab.users_groups_roles.title=Benutzer/Gruppen/Rollen ui.admin.tab.users_groups_roles.title=Benutzer/Gruppen/Rollen
ui.admin.tab.categories.title=Kategorien ui.admin.tab.categories.title=Kategorien
ui.admin.tab.registry.title=Registry ui.admin.tab.configuration.title=Konfiguration
ui.admin.change_password=Passwort \u00e4ndern ui.admin.change_password=Passwort \u00e4ndern
ui.admin.tab.workflows.title=Arbeitsabl\u00e4ufe ui.admin.tab.workflows.title=Arbeitsabl\u00e4ufe
ui.admin.users_groups_roles.users.title=Benutzer ui.admin.users_groups_roles.users.title=Benutzer
@ -411,3 +411,16 @@ ui.admin.categories.doamin_details.mappings.error.please_select_app=Bitte w\u00e
ui.admin.categories.domain_details.mappings.remove.confirm=Sind Sie sicher, dass Sie dieses Mapping entfernen wollen? ui.admin.categories.domain_details.mappings.remove.confirm=Sind Sie sicher, dass Sie dieses Mapping entfernen wollen?
ui.admin.categories.tree.header=Kategorien ui.admin.categories.tree.header=Kategorien
ui.admin.categories.tree.back=Zur\u00fcck zur Domain Eigenschaften ui.admin.categories.tree.back=Zur\u00fcck zur Domain Eigenschaften
ui.admin.configuration.classes.filter.heading=Konfigurationen filtern
ui.admin.configuration.classes.filter.submit=Anwenden
ui.admin.configuration.classes.filter.clear=Zur\u00fccksetzen
ui.admin.configuration.configurations.none=Keine passenden Konfigurationen gefunden.
ui.admin.configuration.configurations.table.name=Name
ui.admin.configuration.configurations.table.desc=Beschreibung
ui.admin.configuration.settings.none=Keine Parameter
ui.admin.configuration.settings.table.col_setting_label.header=Parameter
ui.admin.configuration.settings.table.col_setting_value.header=Wert
ui.admin.configuration.settings.table.col_setting_desc.header=Beschreibung
ui.admin.configuration.settings.table.col_edit_setting.header=Bearbeiten
ui.admin.configuration.settings.edit=Bearbeiten
ui.admin.configuration.settings.read_error=Fehler beim lesen des Parameters.

View File

@ -112,7 +112,7 @@ ui.admin.user.userpasswordform.retrieving_user_failed=Failed to retrieve user
ui.admin.groups.couldnt_find_specified_group=Couldn't find the specified group ui.admin.groups.couldnt_find_specified_group=Couldn't find the specified group
ui.admin.tab.users_groups_roles.title=Users/Groups/Roles ui.admin.tab.users_groups_roles.title=Users/Groups/Roles
ui.admin.tab.categories.title=Categories ui.admin.tab.categories.title=Categories
ui.admin.tab.registry.title=Registry ui.admin.tab.configuration.title=Configuration
ui.admin.change_password=Change password ui.admin.change_password=Change password
ui.admin.tab.workflows.title=Workflows ui.admin.tab.workflows.title=Workflows
ui.admin.tab.sysinfo.title=System information ui.admin.tab.sysinfo.title=System information
@ -384,3 +384,16 @@ ui.admin.categories.doamin_details.mappings.error.please_select_app=Please selec
ui.admin.categories.domain_details.mappings.remove.confirm=Are you sure to remove this domain mapping? ui.admin.categories.domain_details.mappings.remove.confirm=Are you sure to remove this domain mapping?
ui.admin.categories.tree.header=Categories ui.admin.categories.tree.header=Categories
ui.admin.categories.tree.back=Back to domain properties ui.admin.categories.tree.back=Back to domain properties
ui.admin.configuration.classes.filter.heading=Filter configurations
ui.admin.configuration.classes.filter.submit=Apply
ui.admin.configuration.classes.filter.clear=Clear
ui.admin.configuration.configurations.none=No matching configurations found.
ui.admin.configuration.configurations.table.name=Name
ui.admin.configuration.configurations.table.desc=Description
ui.admin.configuration.settings.none=No settings
ui.admin.configuration.settings.table.col_setting_label.header=Setting
ui.admin.configuration.settings.table.col_setting_value.header=Value
ui.admin.configuration.settings.table.col_setting_desc.header=Description
ui.admin.configuration.settings.table.col_edit_setting.header=Edit
ui.admin.configuration.settings.edit=Edit
ui.admin.configuration.settings.read_error=Failed to read setting value.

View File

@ -97,7 +97,7 @@ ui.admin.user.userpasswordform.retrieving_user_failed=Impossible de retrouver l'
ui.admin.groups.couldnt_find_specified_group=Impossible de trouver le groupe sp\u00e9cifi\u00e9 ui.admin.groups.couldnt_find_specified_group=Impossible de trouver le groupe sp\u00e9cifi\u00e9
ui.admin.tab.users_groups_roles.title= ui.admin.tab.users_groups_roles.title=
ui.admin.tab.categories.title=Categories ui.admin.tab.categories.title=Categories
ui.admin.tab.registry.title=Registry ui.admin.tab.configuration.title=Configuration
ui.admin.change_password=Change password ui.admin.change_password=Change password
ui.admin.tab.workflows.title=Workflows ui.admin.tab.workflows.title=Workflows
ui.admin.save=Save ui.admin.save=Save
@ -375,3 +375,16 @@ ui.admin.categories.doamin_details.mappings.error.please_select_app=Please selec
ui.admin.categories.domain_details.mappings.remove.confirm=Are you sure to remove this domain mapping? ui.admin.categories.domain_details.mappings.remove.confirm=Are you sure to remove this domain mapping?
ui.admin.categories.tree.header=Categories ui.admin.categories.tree.header=Categories
ui.admin.categories.tree.back=Back to domain properties ui.admin.categories.tree.back=Back to domain properties
ui.admin.configuration.classes.filter.heading=Filter configurations
ui.admin.configuration.classes.filter.submit=Apply
ui.admin.configuration.classes.filter.clear=Clear
ui.admin.configuration.configurations.none=No matching configurations found.
ui.admin.configuration.configurations.table.name=Name
ui.admin.configuration.configurations.table.desc=Description
ui.admin.configuration.settings.none=No settings
ui.admin.configuration.settings.table.col_setting_label.header=Setting
ui.admin.configuration.settings.table.col_setting_value.header=Value
ui.admin.configuration.settings.table.col_setting_desc.header=Description
ui.admin.configuration.settings.table.col_edit_setting.header=Edit
ui.admin.configuration.settings.edit=Edit
ui.admin.configuration.settings.read_error=Failed to read setting value.