CategoryManagement

Jens Pelzetter 2020-11-21 21:57:44 +01:00
parent 5552ad9342
commit 8a1effe4bb
15 changed files with 565 additions and 240 deletions

View File

@ -30,6 +30,8 @@ import org.libreccm.ui.Message;
import org.libreccm.ui.MessageType; import org.libreccm.ui.MessageType;
import org.libreccm.ui.admin.AdminMessages; import org.libreccm.ui.admin.AdminMessages;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import java.util.Optional; import java.util.Optional;
@ -38,13 +40,17 @@ import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.mvc.Controller; import javax.mvc.Controller;
import javax.mvc.Models; import javax.mvc.Models;
import javax.mvc.MvcContext; import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import javax.ws.rs.Consumes;
import javax.ws.rs.Encoded;
import javax.ws.rs.FormParam; import javax.ws.rs.FormParam;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
/** /**
* *
@ -163,7 +169,37 @@ public class CategoriesController {
public String newSubCategory( public String newSubCategory(
@PathParam("categoryIdentifier") final String categoryIdentifier @PathParam("categoryIdentifier") final String categoryIdentifier
) { ) {
return "org/libreccm/ui/admin/categories/category-form.xhtml"; final Identifier identifier = identifierParser.parseIdentifier(
categoryIdentifier
);
final Optional<Category> result;
switch (identifier.getType()) {
case ID:
result = categoryRepository.findById(
Long.parseLong(identifier.getIdentifier())
);
break;
default:
result = categoryRepository.findByUuid(
identifier.getIdentifier()
);
break;
}
if (result.isPresent()) {
categoryDetailsModel.setParentCategory(result.get());
return "org/libreccm/ui/admin/categories/category-form.xhtml";
} else {
categoryDetailsModel.addMessage(
new Message(
adminMessages.getMessage(
"categories.not_found.message",
Arrays.asList(categoryIdentifier)
), MessageType.WARNING
)
);
return "org/libreccm/ui/admin/categories/category-not-found.xhtml";
}
} }
@POST @POST
@ -306,17 +342,16 @@ public class CategoriesController {
} }
@POST @POST
@Path("/{categoryIdentifier}/title/add") @Path("/{identifier}/title/add")
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public String addTitle( public String addTitle(
@PathParam("categoryIdentifier") @PathParam("identifier") final String identifierParam,
final String categoryIdentifierParam,
@FormParam("locale") final String localeParam, @FormParam("locale") final String localeParam,
@FormParam("value") final String value @FormParam("value") final String value
) { ) {
final Identifier identifier = identifierParser.parseIdentifier( final Identifier identifier = identifierParser.parseIdentifier(
categoryIdentifierParam identifierParam
); );
final Optional<Category> result; final Optional<Category> result;
switch (identifier.getType()) { switch (identifier.getType()) {
@ -347,7 +382,7 @@ public class CategoriesController {
new Message( new Message(
adminMessages.getMessage( adminMessages.getMessage(
"categories.not_found.message", "categories.not_found.message",
Arrays.asList(categoryIdentifierParam) Arrays.asList(identifierParam)
), MessageType.WARNING ), MessageType.WARNING
) )
); );
@ -356,17 +391,16 @@ public class CategoriesController {
} }
@POST @POST
@Path("/{categoryIdentifier}/title/${locale}/edit") @Path("/{identifier}/title/{locale}/edit")
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public String editTitle( public String editTitle(
@PathParam("categoryIdentifier") @PathParam("identifier") final String identifierParam,
final String categoryIdentifierParam,
@PathParam("locale") final String localeParam, @PathParam("locale") final String localeParam,
@FormParam("value") final String value @FormParam("value") final String value
) { ) {
final Identifier identifier = identifierParser.parseIdentifier( final Identifier identifier = identifierParser.parseIdentifier(
categoryIdentifierParam identifierParam
); );
final Optional<Category> result; final Optional<Category> result;
switch (identifier.getType()) { switch (identifier.getType()) {
@ -397,7 +431,7 @@ public class CategoriesController {
new Message( new Message(
adminMessages.getMessage( adminMessages.getMessage(
"categories.not_found.message", "categories.not_found.message",
Arrays.asList(categoryIdentifierParam) Arrays.asList(identifierParam)
), MessageType.WARNING ), MessageType.WARNING
) )
); );
@ -406,10 +440,11 @@ public class CategoriesController {
} }
@POST @POST
@Path("/{categoryIdentifier}/title/${locale}/remove") @Path("/{identifier}/title/{locale}/remove")
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String removeTitle( public String removeTitle(
@PathParam("categoryIdentifier") @PathParam("identifier")
final String categoryIdentifierParam, final String categoryIdentifierParam,
@PathParam("locale") final String localeParam @PathParam("locale") final String localeParam
) { ) {
@ -454,16 +489,16 @@ public class CategoriesController {
} }
@POST @POST
@Path("/{categoryIdentifier}description/add") @Path("/{identifier}decsription/add")
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String addDescription( public String addDescription(
@PathParam("categoryIdentifier") @PathParam("identifier") final String identifierParam,
final String categoryIdentifierParam,
@FormParam("locale") final String localeParam, @FormParam("locale") final String localeParam,
@FormParam("value") final String value @FormParam("value") final String value
) { ) {
final Identifier identifier = identifierParser.parseIdentifier( final Identifier identifier = identifierParser.parseIdentifier(
categoryIdentifierParam identifierParam
); );
final Optional<Category> result; final Optional<Category> result;
switch (identifier.getType()) { switch (identifier.getType()) {
@ -494,7 +529,7 @@ public class CategoriesController {
new Message( new Message(
adminMessages.getMessage( adminMessages.getMessage(
"categories.not_found.message", "categories.not_found.message",
Arrays.asList(categoryIdentifierParam) Arrays.asList(identifierParam)
), MessageType.WARNING ), MessageType.WARNING
) )
); );
@ -503,16 +538,17 @@ public class CategoriesController {
} }
@POST @POST
@Path("/{categoryIdentifier}/description/${locale}/edit") @Path("/{identifier}/description/{locale}/edit")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String editDescription( public String editDescription(
@PathParam("categoryIdentifier") @PathParam("identifier") final String identifierParam,
final String categoryIdentifierParam,
@PathParam("locale") final String localeParam, @PathParam("locale") final String localeParam,
@FormParam("value") final String value @FormParam("value") final String value
) { ) {
final Identifier identifier = identifierParser.parseIdentifier( final Identifier identifier = identifierParser.parseIdentifier(
categoryIdentifierParam identifierParam
); );
final Optional<Category> result; final Optional<Category> result;
switch (identifier.getType()) { switch (identifier.getType()) {
@ -543,7 +579,7 @@ public class CategoriesController {
new Message( new Message(
adminMessages.getMessage( adminMessages.getMessage(
"categories.not_found.message", "categories.not_found.message",
Arrays.asList(categoryIdentifierParam) Arrays.asList(identifierParam)
), MessageType.WARNING ), MessageType.WARNING
) )
); );
@ -552,15 +588,15 @@ public class CategoriesController {
} }
@POST @POST
@Path("/{categoryIdentifier}/description/${locale}/remove") @Path("/{identifier}/description/{locale}/remove")
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String removeDescription( public String removeDescription(
@PathParam("categoryIdentifier") @PathParam("identifier") final String identifierParam,
final String categoryIdentifierParam,
@PathParam("locale") final String localeParam @PathParam("locale") final String localeParam
) { ) {
final Identifier identifier = identifierParser.parseIdentifier( final Identifier identifier = identifierParser.parseIdentifier(
categoryIdentifierParam identifierParam
); );
final Optional<Category> result; final Optional<Category> result;
switch (identifier.getType()) { switch (identifier.getType()) {
@ -591,7 +627,7 @@ public class CategoriesController {
new Message( new Message(
adminMessages.getMessage( adminMessages.getMessage(
"categories.not_found.message", "categories.not_found.message",
Arrays.asList(categoryIdentifierParam) Arrays.asList(identifierParam)
), MessageType.WARNING ), MessageType.WARNING
) )
); );

View File

@ -20,14 +20,19 @@ package org.libreccm.ui.admin.categories;
import org.libreccm.categorization.Category; import org.libreccm.categorization.Category;
import org.libreccm.categorization.CategoryManager; import org.libreccm.categorization.CategoryManager;
import org.libreccm.categorization.Domain;
import org.libreccm.categorization.DomainRepository;
import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.ui.Message; import org.libreccm.ui.Message;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -47,6 +52,12 @@ public class CategoryDetailsModel {
@Inject @Inject
private CategoryManager categoryManager; private CategoryManager categoryManager;
@Inject
private DomainRepository domainRepository;
@Inject
private GlobalizationHelper globalizationHelper;
private long categoryId; private long categoryId;
private String uuid; private String uuid;
@ -59,8 +70,12 @@ public class CategoryDetailsModel {
private Map<String, String> title; private Map<String, String> title;
private List<String> unusedTitleLocales;
private Map<String, String> description; private Map<String, String> description;
private List<String> unusedDescriptionLocales;
private boolean enabled; private boolean enabled;
private boolean visible; private boolean visible;
@ -71,6 +86,8 @@ public class CategoryDetailsModel {
private CategoryNodeModel parentCategory; private CategoryNodeModel parentCategory;
private CategoryPathModel categoryPath;
private long categoryOrder; private long categoryOrder;
private final List<Message> messages; private final List<Message> messages;
@ -109,10 +126,26 @@ public class CategoryDetailsModel {
return Collections.unmodifiableMap(title); return Collections.unmodifiableMap(title);
} }
public List<String> getUnusedTitleLocales() {
return Collections.unmodifiableList(unusedTitleLocales);
}
public boolean hasUnusedTitleLocales() {
return !unusedTitleLocales.isEmpty();
}
public Map<String, String> getDescription() { public Map<String, String> getDescription() {
return Collections.unmodifiableMap(description); return Collections.unmodifiableMap(description);
} }
public List<String> getUnusedDescriptionLocales() {
return Collections.unmodifiableList(unusedDescriptionLocales);
}
public boolean hasUnusedDescriptionLocales() {
return !unusedDescriptionLocales.isEmpty();
}
public boolean isEnabled() { public boolean isEnabled() {
return enabled; return enabled;
} }
@ -137,6 +170,10 @@ public class CategoryDetailsModel {
parentCategory = buildCategoryNodeModel(parent); parentCategory = buildCategoryNodeModel(parent);
} }
public CategoryPathModel getCategoryPath() {
return categoryPath;
}
public long getCategoryOrder() { public long getCategoryOrder() {
return categoryOrder; return categoryOrder;
} }
@ -174,6 +211,9 @@ public class CategoryDetailsModel {
uniqueId = category.getUniqueId(); uniqueId = category.getUniqueId();
name = category.getName(); name = category.getName();
path = categoryManager.getCategoryPath(category); path = categoryManager.getCategoryPath(category);
final List<Locale> availableLocales = globalizationHelper
.getAvailableLocales();
title = category title = category
.getTitle() .getTitle()
.getValues() .getValues()
@ -185,6 +225,16 @@ public class CategoryDetailsModel {
entry -> entry.getValue() entry -> entry.getValue()
) )
); );
final Set<Locale> titleLocales = category
.getTitle()
.getAvailableLocales();
unusedTitleLocales = availableLocales
.stream()
.filter(locale -> !titleLocales.contains(locale))
.map(Locale::toString)
.sorted()
.collect(Collectors.toList());
description = category description = category
.getDescription() .getDescription()
.getValues() .getValues()
@ -196,6 +246,16 @@ public class CategoryDetailsModel {
entry -> entry.getValue() entry -> entry.getValue()
) )
); );
final Set<Locale> descriptionLocales = category
.getDescription()
.getAvailableLocales();
unusedDescriptionLocales = availableLocales
.stream()
.filter(locale -> !descriptionLocales.contains(locale))
.map(Locale::toString)
.sorted()
.collect(Collectors.toList());
enabled = category.isEnabled(); enabled = category.isEnabled();
visible = category.isVisible(); visible = category.isVisible();
abstractCategory = category.isAbstractCategory(); abstractCategory = category.isAbstractCategory();
@ -205,10 +265,23 @@ public class CategoryDetailsModel {
.map(this::buildCategoryNodeModel) .map(this::buildCategoryNodeModel)
.sorted() .sorted()
.collect(Collectors.toList()); .collect(Collectors.toList());
parentCategory = buildCategoryNodeModel(category.getParentCategory()); if (category.getParentCategory() != null) {
parentCategory
= buildCategoryNodeModel(category.getParentCategory());
}
categoryPath = buildCategoryPathModel(category);
categoryOrder = category.getCategoryOrder(); categoryOrder = category.getCategoryOrder();
} }
private DomainNodeModel buildDomainNodeModel(final Domain domain) {
final DomainNodeModel model = new DomainNodeModel();
model.setDomainId(domain.getObjectId());
model.setUuid(domain.getUuid());
model.setDomainKey(domain.getDomainKey());
return model;
}
private CategoryNodeModel buildCategoryNodeModel(final Category category) { private CategoryNodeModel buildCategoryNodeModel(final Category category) {
final CategoryNodeModel model = new CategoryNodeModel(); final CategoryNodeModel model = new CategoryNodeModel();
model.setCategoryId(category.getObjectId()); model.setCategoryId(category.getObjectId());
@ -217,7 +290,32 @@ public class CategoryDetailsModel {
model.setName(category.getName()); model.setName(category.getName());
model.setPath(categoryManager.getCategoryPath(category)); model.setPath(categoryManager.getCategoryPath(category));
model.setCategoryOrder(category.getCategoryOrder()); model.setCategoryOrder(category.getCategoryOrder());
model.setEnabled(category.isEnabled());
model.setVisible(category.isVisible());
model.setAbstractCategory(category.isAbstractCategory());
return model; return model;
} }
private CategoryPathModel buildCategoryPathModel(final Category category) {
return buildCategoryPathModel(category, new CategoryPathModel());
}
private CategoryPathModel buildCategoryPathModel(
final Category category,
final CategoryPathModel categoryPathModel
) {
categoryPathModel.addCategoryAtBegin(buildCategoryNodeModel(category));
final Category parent = category.getParentCategory();
if (parent == null) {
final Optional<Domain> domain = domainRepository
.findByRootCategory(category);
if (domain.isPresent()) {
categoryPathModel.setDomain(buildDomainNodeModel(domain.get()));
}
return categoryPathModel;
} else {
return buildCategoryPathModel(parent, categoryPathModel);
}
}
} }

View File

@ -23,6 +23,8 @@ import org.libreccm.api.IdentifierParser;
import org.libreccm.categorization.Category; import org.libreccm.categorization.Category;
import org.libreccm.categorization.CategoryManager; import org.libreccm.categorization.CategoryManager;
import org.libreccm.categorization.CategoryRepository; import org.libreccm.categorization.CategoryRepository;
import org.libreccm.categorization.Domain;
import org.libreccm.categorization.DomainRepository;
import org.libreccm.core.CoreConstants; import org.libreccm.core.CoreConstants;
import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.RequiresPrivilege; import org.libreccm.security.RequiresPrivilege;
@ -63,6 +65,9 @@ public class CategoryFormController {
@Inject @Inject
private CategoryRepository categoryRepository; private CategoryRepository categoryRepository;
@Inject
private DomainRepository domainRepository;
@Inject @Inject
private IdentifierParser identifierParser; private IdentifierParser identifierParser;
@ -73,13 +78,13 @@ public class CategoryFormController {
private String name; private String name;
@FormParam("enabled") @FormParam("enabled")
private boolean enabled; private String enabled;
@FormParam("visible") @FormParam("visible")
private boolean visible; private String visible;
@FormParam("abstractCategory") @FormParam("abstractCategory")
private boolean abstractCategory; private String abstractCategory;
@POST @POST
@Path("/{parentCategoryIdentifier}/new") @Path("/{parentCategoryIdentifier}/new")
@ -113,17 +118,33 @@ public class CategoryFormController {
final Category category = new Category(); final Category category = new Category();
category.setUniqueId(uniqueId); category.setUniqueId(uniqueId);
category.setName(name); category.setName(name);
category.setEnabled(enabled); category.setEnabled(enabled != null);
category.setVisible(visible); category.setVisible(visible != null);
category.setAbstractCategory(abstractCategory); category.setAbstractCategory(abstractCategory != null);
categoryRepository.save(category); categoryRepository.save(category);
categoryManager.addSubCategoryToCategory(category, parentCategory); categoryManager.addSubCategoryToCategory(category, parentCategory);
return String.format( if (parentCategory.getParentCategory() == null) {
"redirect:categorymanager/categories/ID-%s", final Optional<Domain> categorySystem = domainRepository
parentCategory.getObjectId() .findByRootCategory(parentCategory);
); if (categorySystem.isPresent()) {
return String.format(
"redirect:categorymanager/categorysystems/ID-%d/details",
categorySystem.get().getObjectId()
);
} else {
return String.format(
"redirect:categorymanager/categories/ID-%d/details",
parentCategory.getObjectId()
);
}
} else {
return String.format(
"redirect:categorymanager/categories/ID-%d/details",
parentCategory.getObjectId()
);
}
} else { } else {
categoryDetailsModel.addMessage( categoryDetailsModel.addMessage(
new Message( new Message(
@ -143,7 +164,7 @@ public class CategoryFormController {
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public String updateCategory( public String updateCategory(
@PathParam("categoryIdentifierParam") @PathParam("categoryIdentifier")
final String categoryIdentifierParam final String categoryIdentifierParam
) { ) {
final Identifier identifier = identifierParser.parseIdentifier( final Identifier identifier = identifierParser.parseIdentifier(
@ -169,9 +190,9 @@ public class CategoryFormController {
final Category category = result.get(); final Category category = result.get();
category.setUniqueId(uniqueId); category.setUniqueId(uniqueId);
category.setName(name); category.setName(name);
category.setEnabled(enabled); category.setEnabled(enabled != null);
category.setVisible(visible); category.setVisible(visible != null);
category.setAbstractCategory(abstractCategory); category.setAbstractCategory(abstractCategory != null);
categoryRepository.save(category); categoryRepository.save(category);

View File

@ -18,8 +18,6 @@
*/ */
package org.libreccm.ui.admin.categories; package org.libreccm.ui.admin.categories;
import org.libreccm.categorization.Category;
import java.util.Objects; import java.util.Objects;
/** /**
@ -38,6 +36,12 @@ public class CategoryNodeModel implements Comparable<CategoryNodeModel> {
private String path; private String path;
private boolean enabled;
private boolean visible;
private boolean abstractCategory;
private long categoryOrder; private long categoryOrder;
public long getCategoryId() { public long getCategoryId() {
@ -92,6 +96,30 @@ public class CategoryNodeModel implements Comparable<CategoryNodeModel> {
this.categoryOrder = categoryOrder; this.categoryOrder = categoryOrder;
} }
public boolean isEnabled() {
return enabled;
}
protected void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
public boolean isVisible() {
return visible;
}
protected void setVisible(final boolean visible) {
this.visible = visible;
}
public boolean isAbstractCategory() {
return abstractCategory;
}
protected void setAbstractCategory(final boolean abstractCategory) {
this.abstractCategory = abstractCategory;
}
@Override @Override
public int compareTo(final CategoryNodeModel other) { public int compareTo(final CategoryNodeModel other) {
int result = Long.compare( int result = Long.compare(

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2020 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 org.libreccm.ui.admin.categories;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class CategoryPathModel {
private DomainNodeModel domain;
private List<CategoryNodeModel> categories;
public CategoryPathModel() {
categories = new ArrayList<>();
}
public DomainNodeModel getDomain() {
return domain;
}
protected void setDomain(final DomainNodeModel domain) {
this.domain = domain;
}
public List<CategoryNodeModel> getCategories() {
return Collections.unmodifiableList(categories);
}
protected void addCategory(final CategoryNodeModel category) {
categories.add(category);
}
protected void addCategoryAtBegin(final CategoryNodeModel category) {
categories.add(0, category);
}
protected void setCategories(final List<CategoryNodeModel> categories) {
this.categories = new ArrayList<>(categories);
}
}

View File

@ -18,6 +18,8 @@
*/ */
package org.libreccm.ui.admin.categories; package org.libreccm.ui.admin.categories;
import org.libreccm.categorization.Category;
import org.libreccm.categorization.CategoryManager;
import org.libreccm.categorization.Domain; import org.libreccm.categorization.Domain;
import org.libreccm.categorization.DomainOwnership; import org.libreccm.categorization.DomainOwnership;
import org.libreccm.l10n.GlobalizationHelper; import org.libreccm.l10n.GlobalizationHelper;
@ -54,6 +56,9 @@ public class CategorySystemDetailsModel {
@Inject @Inject
private ApplicationRepository applicationRepository; private ApplicationRepository applicationRepository;
@Inject
private CategoryManager categoryManager;
@Inject @Inject
private GlobalizationHelper globalizationHelper; private GlobalizationHelper globalizationHelper;
@ -83,7 +88,7 @@ public class CategorySystemDetailsModel {
private String rootIdentifier; private String rootIdentifier;
private List<CategoryTableRow> categories; private List<CategoryNodeModel> categories;
private final List<Message> messages; private final List<Message> messages;
@ -194,7 +199,7 @@ public class CategorySystemDetailsModel {
return Collections.unmodifiableList(ownerOptions); return Collections.unmodifiableList(ownerOptions);
} }
public List<CategoryTableRow> getCategories() { public List<CategoryNodeModel> getCategories() {
return Collections.unmodifiableList(categories); return Collections.unmodifiableList(categories);
} }
@ -238,6 +243,7 @@ public class CategorySystemDetailsModel {
.withZone(ZoneOffset.systemDefault()) .withZone(ZoneOffset.systemDefault())
.format(domain.getReleased()); .format(domain.getReleased());
} }
final List<Locale> availableLocales = globalizationHelper final List<Locale> availableLocales = globalizationHelper
.getAvailableLocales(); .getAvailableLocales();
title = domain title = domain
@ -310,7 +316,7 @@ public class CategorySystemDetailsModel {
.getRoot() .getRoot()
.getSubCategories() .getSubCategories()
.stream() .stream()
.map(CategoryTableRow::new) .map(this::buildCategoryTableRow)
.sorted() .sorted()
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -332,4 +338,18 @@ public class CategorySystemDetailsModel {
return ownerRow; return ownerRow;
} }
private CategoryNodeModel buildCategoryTableRow(final Category category) {
final CategoryNodeModel row = new CategoryNodeModel();
row.setCategoryId(category.getObjectId());
row.setUuid(category.getUuid());
row.setUniqueId(category.getUniqueId());
row.setName(category.getName());
row.setPath(categoryManager.getCategoryPath(category));
row.setEnabled(category.isEnabled());
row.setVisible(category.isVisible());
row.setAbstractCategory(category.isAbstractCategory());
row.setCategoryOrder(category.getCategoryOrder());
return row;
}
} }

View File

@ -1,137 +0,0 @@
/*
* Copyright (C) 2020 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 org.libreccm.ui.admin.categories;
import org.libreccm.categorization.Category;
import java.util.Objects;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class CategoryTableRow implements Comparable<CategoryTableRow> {
private long categoryId;
private String uuid;
private String uniqueId;
private String name;
private boolean enabled;
private boolean visible;
private boolean abstractCategory;
private long categoryOrder;
public CategoryTableRow() {
super();
}
public CategoryTableRow(final Category category) {
categoryId = category.getObjectId();
uuid = category.getUuid();
uniqueId = category.getUniqueId();
name = category.getName();
enabled = category.isEnabled();
visible = category.isVisible();
abstractCategory = category.isAbstractCategory();
categoryOrder = category.getCategoryOrder();
}
public long getCategoryId() {
return categoryId;
}
protected void setCategoryId(final long categoryId) {
this.categoryId = categoryId;
}
public String getUuid() {
return uuid;
}
protected void setUuid(final String uuid) {
this.uuid = uuid;
}
public String getIdentifier() {
return String.format("UUID-%s", uuid);
}
public String getUniqueId() {
return uniqueId;
}
protected void setUniqueId(final String uniqueId) {
this.uniqueId = uniqueId;
}
public String getName() {
return name;
}
protected void setName(final String name) {
this.name = name;
}
public boolean isEnabled() {
return enabled;
}
protected void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
public boolean isVisible() {
return visible;
}
protected void setVisible(final boolean visible) {
this.visible = visible;
}
public boolean isAbstractCategory() {
return abstractCategory;
}
protected void setAbstractCategory(final boolean abstractCategory) {
this.abstractCategory = abstractCategory;
}
public long getCategoryOrder() {
return categoryOrder;
}
protected void setCategoryOrder(final long categoryOrder) {
this.categoryOrder = categoryOrder;
}
@Override
public int compareTo(final CategoryTableRow other) {
return Long.compare(
categoryOrder, Objects.requireNonNull(other).getCategoryOrder()
);
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2020 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 org.libreccm.ui.admin.categories;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class DomainNodeModel {
private long domainId;
private String uuid;
private String domainKey;
public long getDomainId() {
return domainId;
}
protected void setDomainId(final long domainId) {
this.domainId = domainId;
}
public String getIdentifier() {
return String.format("ID-%s", domainId);
}
public String getUuid() {
return uuid;
}
protected void setUuid(final String uuid) {
this.uuid = uuid;
}
public String getDomainKey() {
return domainKey;
}
protected void setDomainKey(final String domainKey) {
this.domainKey = domainKey;
}
}

View File

@ -9,7 +9,7 @@
shortDescription="URL to POST request is send." /> shortDescription="URL to POST request is send." />
<cc:attribute name="buttonText" <cc:attribute name="buttonText"
required="true" required="true"
shortDescription="Text pf the button toggleing the modal form." shortDescription="Text of the button toggleing the modal form."
type="String" /> type="String" />
<cc:attribute name="buttonTextClass" <cc:attribute name="buttonTextClass"
default="" default=""
@ -70,35 +70,35 @@
<c:choose> <c:choose>
<c:when test="#{cc.attrs.headingLevel == 1}"> <c:when test="#{cc.attrs.headingLevel == 1}">
<h2 class="modal-title" <h2 class="modal-title"
id="#{cc.attrs.editorId}-dialog-title">#{cc.attrs.addDialogTitle}</h2> id="#{cc.attrs.dialogId}-dialog-title">#{cc.attrs.dialogTitle}</h2>
</c:when> </c:when>
<c:when test="#{cc.attrs.headingLevel == 2}"> <c:when test="#{cc.attrs.headingLevel == 2}">
<h3 class="modal-title" <h3 class="modal-title"
id="#{cc.attrs.editorId}-dialog-title">#{cc.attrs.addDialogTitle}</h3> id="#{cc.attrs.dialogId}-dialog-title">#{cc.attrs.dialogTitle}</h3>
</c:when> </c:when>
<c:when test="#{cc.attrs.headingLevel == 3}"> <c:when test="#{cc.attrs.headingLevel == 3}">
<h4 class="modal-title" <h4 class="modal-title"
id="#{cc.attrs.editorId}-dialog-title">#{cc.attrs.addDialogTitle}</h4> id="#{cc.attrs.dialogId}-dialog-title">#{cc.attrs.dialogTitle}</h4>
</c:when> </c:when>
<c:when test="#{cc.attrs.headingLevel == 4}"> <c:when test="#{cc.attrs.headingLevel == 4}">
<h5 class="modal-title" <h5 class="modal-title"
id="#{cc.attrs.editorId}-dialog-title">#{cc.attrs.addDialogTitle}</h5> id="#{cc.attrs.dialogId}-dialog-title">#{cc.attrs.dialogTitle}</h5>
</c:when> </c:when>
<c:when test="#{cc.attrs.headingLevel == 5}"> <c:when test="#{cc.attrs.headingLevel == 5}">
<h6 class="modal-title" <h6 class="modal-title"
id="#{cc.attrs.editorId}-dialog-title">#{cc.attrs.addDialogTitle}</h6> id="#{cc.attrs.dialogId}-dialog-title">#{cc.attrs.dialogTitle}</h6>
</c:when> </c:when>
<c:otherwise> <c:otherwise>
<div>#{cc.attrs.addDialogTitle}</div> <div>#{cc.attrs.dialogTitle}</div>
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
<button aria-label="#{cc.attrs.addDialogCancelLabel}"
class="close"
data-dismiss="modal"
type="button" >
<span aria-hidden="true">&times;</span>
</button>
</div> </div>
<button aria-label="#{cc.attrs.cancelLabel}"
class="close"
data-dismiss="modal"
type="button" >
<span aria-hidden="true">&times;</span>
</button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<p> <p>

View File

@ -345,7 +345,8 @@
id="#{cc.attrs.editorId}-#{entry.key}-edit-dialog" id="#{cc.attrs.editorId}-#{entry.key}-edit-dialog"
tabindex="-1"> tabindex="-1">
<div class="modal-dialog"> <div class="modal-dialog">
<form action="#{mvc.uri(cc.attrs.addMethod, { 'identifier': cc.attrs.objectIdentifier, 'locale': entry.key })}" <form accept-charset="UTF-8"
action="#{mvc.uri(cc.attrs.editMethod, { 'identifier': cc.attrs.objectIdentifier, 'locale': entry.key })}"
class="modal-content" class="modal-content"
method="post"> method="post">
<div class="modal-header"> <div class="modal-header">

View File

@ -45,6 +45,23 @@
<dt>#{AdminMessages['categories.details.name']}</dt> <dt>#{AdminMessages['categories.details.name']}</dt>
<dd>#{CategoryDetailsModel.name}</dd> <dd>#{CategoryDetailsModel.name}</dd>
</div> </div>
<div>
<dt>#{AdminMessages['categories.details.path']}</dt>
<dd>
<c:if test="#{CategoryDetailsModel.categoryPath.domain != null}">
<a href="#{mvc.uri('CategorySystemsController#getCategorySystemDetails', {'categorySystemIdentifier': CategoryDetailsModel.categoryPath.domain.identifier})}">
#{CategoryDetailsModel.categoryPath.domain.domainKey}
</a>
</c:if>
<c:forEach items="#{CategoryDetailsModel.categoryPath.categories}"
var="category" >
<span>/</span>
<a href="#{mvc.uri('CategoriesController#getCategory', {'categoryIdentifier': category.identifier})}">
#{category.name}
</a>
</c:forEach>
</dd>
</div>
<div> <div>
<dt>#{AdminMessages['categories.details.enabled']}</dt> <dt>#{AdminMessages['categories.details.enabled']}</dt>
<dd> <dd>
@ -62,7 +79,7 @@
<dt>#{AdminMessages['categories.details.visible']}</dt> <dt>#{AdminMessages['categories.details.visible']}</dt>
<dd> <dd>
<c:choose> <c:choose>
<c:when test="#{CategoryDetailsModel.enabled}"> <c:when test="#{CategoryDetailsModel.visible}">
#{AdminMessages['categories.details.visible.yes']} #{AdminMessages['categories.details.visible.yes']}
</c:when> </c:when>
<c:otherwise> <c:otherwise>
@ -75,7 +92,7 @@
<dt>#{AdminMessages['categories.details.abstract_category']}</dt> <dt>#{AdminMessages['categories.details.abstract_category']}</dt>
<dd> <dd>
<c:choose> <c:choose>
<c:when test="#{CategoryDetailsModel.enabled}"> <c:when test="#{CategoryDetailsModel.abstractCategory}">
#{AdminMessages['categories.details.abstract_category.yes']} #{AdminMessages['categories.details.abstract_category.yes']}
</c:when> </c:when>
<c:otherwise> <c:otherwise>
@ -110,10 +127,10 @@
editDialogValueHelp="#{AdminMessages['categories.details.title.edit.dialog.value.help']}" editDialogValueHelp="#{AdminMessages['categories.details.title.edit.dialog.value.help']}"
editDialogValueLabel="#{AdminMessages['categories.details.title.edit.dialog.value.label']}" editDialogValueLabel="#{AdminMessages['categories.details.title.edit.dialog.value.label']}"
editMethod="CategoriesController#editTitle" editMethod="CategoriesController#editTitle"
editorId="categorysystem-title" editorId="category-title"
emptyText="#{AdminMessages['categories.details.title.none']}" emptyText="#{AdminMessages['categories.details.title.none']}"
hasUnusedLocales="#{CategorySystemDetailsModel.hasUnusedTitleLocales()}" hasUnusedLocales="#{CategoryDetailsModel.hasUnusedTitleLocales()}"
objectIdentifier="#{CategorySystemDetailsModel.identifier}" objectIdentifier="#{CategoryDetailsModel.identifier}"
removeButtonLabel="#{AdminMessages['categories.details.title.table.actions.remove']}" removeButtonLabel="#{AdminMessages['categories.details.title.table.actions.remove']}"
removeDialogCancelLabel="#{AdminMessages['categories.details.title.remove.dialog.close']}" removeDialogCancelLabel="#{AdminMessages['categories.details.title.remove.dialog.close']}"
removeDialogSubmitLabel="#{AdminMessages['categories.details.title.remove.dialog.submit']}" removeDialogSubmitLabel="#{AdminMessages['categories.details.title.remove.dialog.submit']}"
@ -124,8 +141,8 @@
tableLocaleHeading="#{AdminMessages['categories.details.title.table.headings.locale']}" tableLocaleHeading="#{AdminMessages['categories.details.title.table.headings.locale']}"
tableValueHeading="#{AdminMessages['categories.details.title.table.headings.value']}" tableValueHeading="#{AdminMessages['categories.details.title.table.headings.value']}"
title="#{AdminMessages['categories.details.title.heading']}" title="#{AdminMessages['categories.details.title.heading']}"
unusedLocales="#{CategorySystemDetailsModel.unusedTitleLocales}" unusedLocales="#{CategoryDetailsModel.unusedTitleLocales}"
values="#{CategorySystemDetailsModel.title}" /> values="#{CategoryDetailsModel.title}" />
<libreccm:localizedStringEditor addMethod="CategoriesController#addDescription" <libreccm:localizedStringEditor addMethod="CategoriesController#addDescription"
addButtonLabel="#{AdminMessages['categories.details.description.add']}" addButtonLabel="#{AdminMessages['categories.details.description.add']}"
@ -143,10 +160,10 @@
editDialogValueHelp="#{AdminMessages['categories.details.description.edit.dialog.value.help']}" editDialogValueHelp="#{AdminMessages['categories.details.description.edit.dialog.value.help']}"
editDialogValueLabel="#{AdminMessages['categories.details.description.edit.dialog.value.label']}" editDialogValueLabel="#{AdminMessages['categories.details.description.edit.dialog.value.label']}"
editMethod="CategoriesController#editDescription" editMethod="CategoriesController#editDescription"
editorId="categorysystem-description" editorId="category-description"
emptyText="#{AdminMessages['categories.details.description.none']}" emptyText="#{AdminMessages['categories.details.description.none']}"
hasUnusedLocales="#{CategorySystemDetailsModel.hasUnusedDescriptionLocales()}" hasUnusedLocales="#{CategoryDetailsModel.hasUnusedDescriptionLocales()}"
objectIdentifier="#{CategorySystemDetailsModel.identifier}" objectIdentifier="#{CategoryDetailsModel.identifier}"
removeButtonLabel="#{AdminMessages['categories.details.description.table.actions.remove']}" removeButtonLabel="#{AdminMessages['categories.details.description.table.actions.remove']}"
removeDialogCancelLabel="#{AdminMessages['categories.details.description.remove.dialog.close']}" removeDialogCancelLabel="#{AdminMessages['categories.details.description.remove.dialog.close']}"
removeDialogSubmitLabel="#{AdminMessages['categories.details.description.remove.dialog.submit']}" removeDialogSubmitLabel="#{AdminMessages['categories.details.description.remove.dialog.submit']}"
@ -157,15 +174,15 @@
tableLocaleHeading="#{AdminMessages['categories.details.description.table.headings.locale']}" tableLocaleHeading="#{AdminMessages['categories.details.description.table.headings.locale']}"
tableValueHeading="#{AdminMessages['categories.details.description.table.headings.value']}" tableValueHeading="#{AdminMessages['categories.details.description.table.headings.value']}"
title="#{AdminMessages['categories.details.description.heading']}" title="#{AdminMessages['categories.details.description.heading']}"
unusedLocales="#{CategorySystemDetailsModel.unusedTitleLocales}" unusedLocales="#{CategoryDetailsModel.unusedDescriptionLocales}"
useTextarea="true" useTextarea="true"
values="#{CategorySystemDetailsModel.description}" /> values="#{CategoryDetailsModel.description}" />
<h2>#{AdminMessages['categories.details.subcategories.heading']}</h2> <h2>#{AdminMessages['categories.details.subcategories.heading']}</h2>
<div class="mb-2"> <div class="mb-2">
<div class="text-right"> <div class="text-right">
<a class="btn btn-secondary" <a class="btn btn-secondary"
href="#{mvc.uri('CategoriesController#newSubCategory', {'categoryIdentifier': CategorySystemDetailsModel.parentIdentifier})}"> href="#{mvc.uri('CategoriesController#newSubCategory', {'categoryIdentifier': CategoryDetailsModel.identifier})}">
<bootstrap:svgIcon icon="plus-circle" /> <bootstrap:svgIcon icon="plus-circle" />
<span>#{AdminMessages['categories.details.subcategories.add']}</span> <span>#{AdminMessages['categories.details.subcategories.add']}</span>
</a> </a>
@ -247,6 +264,7 @@
</tr> </tr>
</c:forEach> </c:forEach>
</tbody> </tbody>
</table>
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>

View File

@ -24,7 +24,7 @@
</c:when> </c:when>
<c:otherwise> <c:otherwise>
<li class="breadcrumb-item active"> <li class="breadcrumb-item active">
#{AdminMessages.getMessage('categories.edit.breadcrumb', CategoryDetailsModel.name)} #{AdminMessages.getMessage('categories.edit.breadcrumb', [ CategoryDetailsModel.name ])}
</li> </li>
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
@ -35,44 +35,49 @@
<h1> <h1>
<c:choose> <c:choose>
<c:when test="#{CategoryDetailsModel.new}"> <c:when test="#{CategoryDetailsModel.new}">
#{AdminMessage.getMessage('categories.new.label', CategoryDetailsModel.parent.path)} #{AdminMessage.getMessage('categories.new.label', [ CategoryDetailsModel.parent.path ])}
</c:when> </c:when>
<c:otherwise> <c:otherwise>
#{AdminMessage.getMessage('categories.edit.label', CategoryDetailsModel.path)} #{AdminMessage.getMessage('categories.edit.label', [ CategoryDetailsModel.path ])}
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
#{AdminMessages['categories.label']} #{AdminMessages['categories.label']}
</h1> </h1>
<form action="#{CategoryDetailsModel.new ? mvc.uri('CategoryFormController#createCategory', {'parentCategoryIdentifier', CategoryDetailsModel.parentCategory.identifier }) : mvc.uri('CategoryFormController#updateCategory', {'categoryIdentifier', CategoryDetailsModel.identifier })}" <form action="#{CategoryDetailsModel.new ? mvc.uri('CategoryFormController#createCategory', {'parentCategoryIdentifier': CategoryDetailsModel.parentCategory.identifier }) : mvc.uri('CategoryFormController#updateCategory', {'categoryIdentifier': CategoryDetailsModel.identifier })}"
method="post"> method="post">
<bootstrap:formGroupText help="#{AdminMessages['categories.form.name.help']}" <bootstrap:formGroupText help="#{AdminMessages['categories.form.name.help']}"
inputId="name" inputId="name"
label="#{AdminMessages['categories.form.name.label']}" label="#{AdminMessages['categories.form.name.label']}"
name="name" name="name"
pattern="[\\w-.]*" pattern="[\\w-.]*"
required="true" /> required="true"
value="#{CategoryDetailsModel.name}" />
<bootstrap:formGroupText help="#{AdminMessages['categories.form.uniqueId.help']}" <bootstrap:formGroupText help="#{AdminMessages['categories.form.uniqueId.help']}"
inputId="uniqueId" inputId="uniqueId"
label="#{AdminMessages['categories.form.uniqueId.label']}" label="#{AdminMessages['categories.form.uniqueId.label']}"
name="uniqueId" name="uniqueId"
required="false" /> required="false"
value="#{CategoryDetailsModel.uniqueId}" />
<bootstrap:formCheck label="#{AdminMessages['categories.form.enabled.label']}" <bootstrap:formCheck label="#{AdminMessages['categories.form.enabled.label']}"
inputId="enabled" inputId="enabled"
name="enabled" /> name="enabled"
value="#{CategoryDetailsModel.new ? true : CategoryDetailsModel.enabled}" />
<bootstrap:formCheck label="#{AdminMessages['categories.form.visible.label']}" <bootstrap:formCheck label="#{AdminMessages['categories.form.visible.label']}"
inputId="visible" inputId="visible"
name="visible" /> name="visible"
value="#{CategoryDetailsModel.new ? true : CategoryDetailsModel.visible}"/>
<bootstrap:formCheck label="#{AdminMessages['categories.form.abstractCategory.label']}" <bootstrap:formCheck label="#{AdminMessages['categories.form.abstractCategory.label']}"
inputId="abstractCategory" inputId="abstractCategory"
name="abstractCategory" /> name="abstractCategory"
value="#{CategoryDetailsModel.new ? false : CategoryDetailsModel.abstractCategory}" />
<a class="btn btn-warning" <a class="btn btn-warning"
href="#{mvc.uri('CategorySystemsController#getCategorySystems')}"> href="#{mvc.uri('CategoriesController#getCategory', {'categoryIdentifier': CategoryDetailsModel.identifier })}">
#{AdminMessages['categories.form.buttons.cancel']} #{AdminMessages['categories.form.buttons.cancel']}
</a> </a>
<button class="btn btn-success" type="submit"> <button class="btn btn-success" type="submit">
<c:choose> <c:choose>
<c:when test="#{CategorySystemDetailsModel.new}"> <c:when test="#{CategoryDetailsModel.new}">
#{AdminMessages['categories.form.buttons.create']} #{AdminMessages['categories.form.buttons.create']}
</c:when> </c:when>
<c:otherwise> <c:otherwise>

View File

@ -336,6 +336,9 @@
<th> <th>
#{AdminMessages['categorysystems.details.categories.table.headings.abstract']} #{AdminMessages['categorysystems.details.categories.table.headings.abstract']}
</th> </th>
<th class="text-center">
#{AdminMessages['categorysystems.details.categories.table.headings.actions']}
</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -380,7 +383,7 @@
<td> <td>
<libreccm:deleteDialog <libreccm:deleteDialog
actionTarget="#{mvc.uri('CategoriesController#removeSubCategory', {'categoryIdentifier': category.identifier})}" actionTarget="#{mvc.uri('CategoriesController#removeSubCategory', {'categoryIdentifier': category.identifier})}"
buttonText="#{AdminMeesages['categories.details.subcategories.delete']}" buttonText="#{AdminMessages['categories.details.subcategories.delete']}"
buttonTextClass="text-center" buttonTextClass="text-center"
cancelLabel="#{AdminMessages['categories.details.subcategories.delete.cancel']}" cancelLabel="#{AdminMessages['categories.details.subcategories.delete.cancel']}"
confirmLabel="#{AdminMessages['categories.details.subcategories.delete.confirm']}" confirmLabel="#{AdminMessages['categories.details.subcategories.delete.confirm']}"

View File

@ -397,3 +397,57 @@ categories.details.subcategories.delete.cancel=Cancel
categories.details.subcategories.delete.confirm=Delete category categories.details.subcategories.delete.confirm=Delete category
categories.details.subcategories.delete.title=Delete category? categories.details.subcategories.delete.title=Delete category?
categories.details.subcategories.delete.message=Are you sure to delete category {0}? categories.details.subcategories.delete.message=Are you sure to delete category {0}?
categories.details.path=Path
categories.details.id=ID
categories.details.uuid=UUID
categories.details.uniqueId=Unique ID
categories.details.name=Name
categories.details.title.heading=Localized Title
categories.details.title.add=Add localized title
categories.details.title.none=No localized title available
categories.details.description.heading=Localized description
categories.details.description.add=Add localized description
categories.details.description.none=No localized description available
categories.details.title.add.dialog.close=Cancel
categories.details.title.add.dialog.locale.help=Select the locale of the localized title
categories.details.title.add.dialog.locale.label=Locale
categories.details.title.add.dialog.submit=Add
categories.details.title.add.dialog.title=Add localized title
categories.details.title.add.dialog.value.help=The localized title
categories.details.title.add.dialog.value.label=Localized title
categories.details.title.table.actions.edit=Edit
categories.details.title.edit.dialog.close=Cancel
categories.details.title.edit.dialog.submit=Save
categories.details.title.table.actions.edit.dialog.title=Edit localized title
categories.details.title.edit.dialog.value.help=The localized title
categories.details.title.edit.dialog.value.label=Localized title
categories.details.title.table.actions.remove=Remove
categories.details.title.remove.dialog.close=Cancel
categories.details.title.remove.dialog.submit=Remove
categories.details.title.remove.dialog.message=Are you sure to remove the localized title for the following locale:
categories.details.title.table.actions.remove.dialog.title=Remove localized title?
categories.details.title.table.headings.actions=Actions
categories.details.title.table.headings.locale=Locale
categories.details.title.table.headings.value=Value
categories.details.description.add.dialog.close=Cancel
categories.details.description.add.dialog.locale.help=The locale of the localized description
categories.details.description.add.dialog.locale.label=Localized description
categories.details.description.add.dialog.submit=Add
categories.details.description.add.dialog.title=Add localized description
categories.details.description.add.dialog.value.help=The localized description
categories.details.description.add.dialog.value.label=Localized description
categories.details.description.table.actions.edit=Edit
categories.details.description.edit.dialog.close=Cancel
categories.details.description.edit.dialog.submit=Save
categories.details.description.table.actions.edit.dialog.title=Edit localized description
categories.details.description.edit.dialog.value.help=The localized description
categories.details.description.edit.dialog.value.label=Localized description
categories.details.description.table.actions.remove=Remove
categories.details.description.remove.dialog.close=Cancel
categories.details.description.remove.dialog.submit=Remove
categories.details.description.remove.dialog.message=Are you sure to remove the localized description for the following locale:
categories.details.description.table.actions.remove.dialog.title=Remove localized description?
categories.details.description.table.headings.actions=Actions
categories.details.description.table.headings.locale=Locale
categories.details.description.table.headings.value=Value
categorysystems.details.categories.table.headings.actions=Actions

View File

@ -397,3 +397,57 @@ categories.details.subcategories.delete.cancel=Abbrechen
categories.details.subcategories.delete.confirm=Kategorie l\u00f6schen categories.details.subcategories.delete.confirm=Kategorie l\u00f6schen
categories.details.subcategories.delete.title=Kategorie l\u00f6schen? categories.details.subcategories.delete.title=Kategorie l\u00f6schen?
categories.details.subcategories.delete.message=Sind Sie sicher, dass Sie die Kategorie {0} l\u00f6schen wollen? categories.details.subcategories.delete.message=Sind Sie sicher, dass Sie die Kategorie {0} l\u00f6schen wollen?
categories.details.path=Pfad
categories.details.id=ID
categories.details.uuid=UUID
categories.details.uniqueId=Eindeutige ID
categories.details.name=Name
categories.details.title.heading=Lokalisierter Titel
categories.details.title.add=Lokalisierten Titel hinzuf\u00fcgen
categories.details.title.none=Keine lokalisierten Titel vorhanden
categories.details.description.heading=Lokalisierte Beschreibung
categories.details.description.add=Lokalisierte Beschreibung hinzuf\u00fcgen
categories.details.description.none=Keine lokalisierte Beschreibung vorhanden
categories.details.title.add.dialog.close=Abbrechen
categories.details.title.add.dialog.locale.help=W\u00e4hlen Sie die Sprache des lokalisierten Titels
categories.details.title.add.dialog.locale.label=Sprache
categories.details.title.add.dialog.submit=Hinzuf\u00fcgen
categories.details.title.add.dialog.title=Lokalisierten Titel hinzuf\u00fcgen
categories.details.title.add.dialog.value.help=Der lokalisierte Titel
categories.details.title.add.dialog.value.label=Lokalisierter Titel
categories.details.title.table.actions.edit=Bearbeiten
categories.details.title.edit.dialog.close=Abbrechen
categories.details.title.edit.dialog.submit=Speichern
categories.details.title.table.actions.edit.dialog.title=Lokalisierten Titel bearbeiten
categories.details.title.edit.dialog.value.help=Der lokalisierte Titel
categories.details.title.edit.dialog.value.label=Lokalisierter Titel
categories.details.title.table.actions.remove=Entfernen
categories.details.title.remove.dialog.close=Abbrechen
categories.details.title.remove.dialog.submit=Entfernen
categories.details.title.remove.dialog.message=Sind Sie sicher, dass die den lokalisierten Titlel f\u00fcr die folgende Sprache entfernen wollen:
categories.details.title.table.actions.remove.dialog.title=Lokalisierten Titel entfernen?
categories.details.title.table.headings.actions=Aktionen
categories.details.title.table.headings.locale=Sprache
categories.details.title.table.headings.value=Wert
categories.details.description.add.dialog.close=Abbrechen
categories.details.description.add.dialog.locale.help=Die Sprache der lokalisierten Beschreibung
categories.details.description.add.dialog.locale.label=Lokalisierte Beschreibung
categories.details.description.add.dialog.submit=Hinzuf\u00fcgen
categories.details.description.add.dialog.title=Lokalisierte Beschreibung hinzuf\u00fcgen
categories.details.description.add.dialog.value.help=Die lokalisierte Beschreibung
categories.details.description.add.dialog.value.label=Localized description
categories.details.description.table.actions.edit=Bearbeiten
categories.details.description.edit.dialog.close=Abbrechen
categories.details.description.edit.dialog.submit=Speichern
categories.details.description.table.actions.edit.dialog.title=Lokalisierte Beschreibung bearbeiten
categories.details.description.edit.dialog.value.help=Die lokalisierte Beschreibung
categories.details.description.edit.dialog.value.label=Lokalisierte Beschreibung
categories.details.description.table.actions.remove=Entfernen
categories.details.description.remove.dialog.close=Abbrechen
categories.details.description.remove.dialog.submit=Entfernen
categories.details.description.remove.dialog.message=Sind Sie sicher, dass Sie die lokalisierte Beschreibung f\u00fcr die folgende Sprache entfernen wollen:
categories.details.description.table.actions.remove.dialog.title=Lokalisierte Beschreibung entfernen?
categories.details.description.table.headings.actions=Aktionen
categories.details.description.table.headings.locale=Sprache
categories.details.description.table.headings.value=Wert
categorysystems.details.categories.table.headings.actions=Aktionen