CCM NG/ccm-cms: Workflow tab

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4626 8810af33-2d31-482b-a856-94f89814c4df
jensp 2017-03-13 19:13:08 +00:00
parent 45f9e5bda0
commit 96b150582c
9 changed files with 210 additions and 74 deletions

View File

@ -293,10 +293,9 @@ abstract class BaseWorkflowItemPane extends BaseItemPane {
} }
// XXX Fix this. private static final String[] COLUMNS = new String[]{
private static final String[] s_columns = new String[]{ lz("cms.ui.workflow.task.name"),
lz("cms.ui.name"), lz("cms.ui.workflow.task.description"),
lz("cms.ui.description"),
lz("cms.ui.workflow.task.dependencies"), lz("cms.ui.workflow.task.dependencies"),
lz("cms.ui.workflow.task.state") lz("cms.ui.workflow.task.state")
}; };
@ -304,7 +303,7 @@ abstract class BaseWorkflowItemPane extends BaseItemPane {
private class TaskTable extends Table { private class TaskTable extends Table {
public TaskTable() { public TaskTable() {
super(new TaskTableModelBuilder(workflowRequestLocal), s_columns); super(new TaskTableModelBuilder(workflowRequestLocal), COLUMNS);
setEmptyView(new Label(gz("cms.ui.workflow.task.none"))); setEmptyView(new Label(gz("cms.ui.workflow.task.none")));

View File

@ -440,9 +440,11 @@ final class TaskItemPane extends BaseItemPane {
private int index = -1; private int index = -1;
private Model(final CmsTask task) { private Model(final CmsTask task) {
roles = task.getAssignments().stream() final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
.map(assignment -> assignment.getRole()) final WorkflowAdminPaneController controller = cdiUtil.findBean(
.collect(Collectors.toList()); WorkflowAdminPaneController.class);
roles = controller.findAssignees(task);
} }
@Override @Override

View File

@ -22,32 +22,29 @@ import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Table; import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.table.AbstractTableModelBuilder; import com.arsdigita.bebop.table.AbstractTableModelBuilder;
import com.arsdigita.bebop.table.TableModel; import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.util.Assert; import com.arsdigita.kernel.KernelConfig;
import com.arsdigita.util.GraphSet;
import com.arsdigita.util.Graphs;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.libreccm.workflow.Task; import org.libreccm.workflow.Task;
import org.libreccm.workflow.Workflow; import org.libreccm.workflow.Workflow;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.cdi.utils.CdiUtil;
import java.util.Locale;
class TaskTableModelBuilder extends AbstractTableModelBuilder { class TaskTableModelBuilder extends AbstractTableModelBuilder {
private static final Logger LOGGER = LogManager.getLogger( private static final Logger LOGGER = LogManager.getLogger(
TaskTableModelBuilder.class); TaskTableModelBuilder.class);
private final WorkflowRequestLocal m_workflow; private final WorkflowRequestLocal workflow;
TaskTableModelBuilder(final WorkflowRequestLocal workflow) { TaskTableModelBuilder(final WorkflowRequestLocal workflow) {
m_workflow = workflow; this.workflow = workflow;
} }
@Override @Override
@ -55,14 +52,14 @@ class TaskTableModelBuilder extends AbstractTableModelBuilder {
final PageState state) { final PageState state) {
LOGGER.debug("Creating a new table model for the current request"); LOGGER.debug("Creating a new table model for the current request");
return new Model(m_workflow.getWorkflow(state)); return new Model(workflow.getWorkflow(state));
} }
private static class Model implements TableModel { private static class Model implements TableModel {
private Task m_task; private Task currentTask;
private Iterator m_tasks; private Iterator<Task> tasksIterator;
private Map m_dependencies = new HashMap(); private Map<Task, String> dependencies;
private Model(final Workflow workflow) { private Model(final Workflow workflow) {
@ -70,46 +67,54 @@ class TaskTableModelBuilder extends AbstractTableModelBuilder {
final WorkflowAdminPaneController controller = cdiUtil.findBean( final WorkflowAdminPaneController controller = cdiUtil.findBean(
WorkflowAdminPaneController.class); WorkflowAdminPaneController.class);
final Iterator<Task> tasksIter = controller final TaskTableModelData data = controller
.getTasksForWorkflow(workflow) .getTaskTableModelData(workflow);
.iterator(); tasksIterator = data.getTasks();
GraphSet g = new GraphSet(); dependencies = data.getDependencies();
while (tasksIter.hasNext()) { // final Iterator<Task> tasksIter = controller
Task t = tasksIter.next(); // .getTasksForWorkflow(workflow)
final Iterator<Task> deps = t.getDependsOn().iterator(); // .iterator();
final StringBuffer buffer = new StringBuffer(); // GraphSet graphSet = new GraphSet();
while (deps.hasNext()) { //
Task dep = deps.next(); // while (tasksIter.hasNext()) {
g.addEdge(t, dep, null); // Task task = tasksIter.next();
buffer.append(dep.getLabel() + ", "); // final Iterator<Task> deps = task.getDependsOn().iterator();
} // final StringBuffer buffer = new StringBuffer();
// while (deps.hasNext()) {
final int len = buffer.length(); // Task dep = deps.next();
if (len >= 2) { // graphSet.addEdge(task, dep, null);
buffer.setLength(len - 2); // buffer
} else { // .append(dep.getLabel())
g.addNode(t); // .append(", ");
} // }
m_dependencies.put(t, buffer.toString()); //
} // final int len = buffer.length();
// if (len >= 2) {
List tasks = new ArrayList(); // buffer.setLength(len - 2);
outer: // } else {
while (g.nodeCount() > 0) { // graphSet.addNode(task);
List l = Graphs.getSinkNodes(g); // }
for (Iterator it = l.iterator(); it.hasNext();) { // m_dependencies.put(task, buffer.toString());
Task t = (Task) it.next(); // }
tasks.add(t); //
g.removeNode(t); // List tasks = new ArrayList();
continue outer; // outer:
} // while (graphSet.nodeCount() > 0) {
// break loop if no nodes removed // List list = Graphs.getSinkNodes(graphSet);
LOGGER.error("found possible loop in tasks for " + workflow); // for (Iterator it = list.iterator(); it.hasNext();) {
break; // Task t = (Task) it.next();
} // tasks.add(t);
// graphSet.removeNode(t);
m_tasks = tasks.iterator(); // continue outer;
// }
// // break loop if no nodes removed
// LOGGER.error("found possible loop in tasks for " + workflow);
// break;
// }
//
// m_tasks = tasks.iterator();
} }
@Override @Override
@ -119,8 +124,8 @@ class TaskTableModelBuilder extends AbstractTableModelBuilder {
@Override @Override
public final boolean nextRow() { public final boolean nextRow() {
if (m_tasks.hasNext()) { if (tasksIterator.hasNext()) {
m_task = (Task) m_tasks.next(); currentTask = tasksIterator.next();
return true; return true;
} else { } else {
return false; return false;
@ -129,18 +134,20 @@ class TaskTableModelBuilder extends AbstractTableModelBuilder {
@Override @Override
public final Object getKeyAt(final int column) { public final Object getKeyAt(final int column) {
return m_task.getTaskId(); return currentTask.getTaskId();
} }
@Override @Override
public final Object getElementAt(final int column) { public final Object getElementAt(final int column) {
final Locale defaultLocale = KernelConfig.getConfig().getDefaultLocale();
switch (column) { switch (column) {
case 0: case 0:
return m_task.getLabel(); return currentTask.getLabel().getValue(defaultLocale);
case 1: case 1:
return m_task.getDescription(); return currentTask.getDescription().getValue(defaultLocale);
case 2: case 2:
return m_dependencies.get(m_task); return dependencies.get(currentTask);
case 3: case 3:
return ""; return "";
// return m_task.getStateString(); // return m_task.getStateString();

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2017 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.cms.ui.workflow;
import org.libreccm.workflow.Task;
import java.util.Iterator;
import java.util.Map;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
class TaskTableModelData {
private final Iterator<Task> tasks;
private final Map<Task, String> dependencies;
protected TaskTableModelData(final Iterator<Task> tasks,
final Map<Task, String> dependencies) {
this.tasks = tasks;
this.dependencies = dependencies;
}
public Iterator<Task> getTasks() {
return tasks;
}
public Map<Task, String> getDependencies() {
return dependencies;
}
}

View File

@ -19,10 +19,15 @@
package com.arsdigita.cms.ui.workflow; package com.arsdigita.cms.ui.workflow;
import com.arsdigita.kernel.KernelConfig; import com.arsdigita.kernel.KernelConfig;
import com.arsdigita.util.GraphSet;
import com.arsdigita.util.Graphs;
import com.arsdigita.util.UncheckedWrapperException; 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.cdi.utils.CdiUtil;
import org.libreccm.configuration.ConfigurationManager; import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.security.Role;
import org.libreccm.workflow.CircularTaskDependencyException; import org.libreccm.workflow.CircularTaskDependencyException;
import org.libreccm.workflow.Task; import org.libreccm.workflow.Task;
import org.libreccm.workflow.TaskManager; import org.libreccm.workflow.TaskManager;
@ -40,6 +45,7 @@ import org.librecms.workflow.CmsTaskType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -56,6 +62,9 @@ import javax.transaction.Transactional;
@RequestScoped @RequestScoped
public class WorkflowAdminPaneController { public class WorkflowAdminPaneController {
private static final Logger LOGGER = LogManager
.getLogger(WorkflowAdminPaneController.class);
@Inject @Inject
private ConfigurationManager confManager; private ConfigurationManager confManager;
@ -132,10 +141,10 @@ public class WorkflowAdminPaneController {
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public CmsTask addTask(final Workflow workflow, public CmsTask addTask(final Workflow workflow,
final String name, final String name,
final String desc, final String desc,
final CmsTaskType type, final CmsTaskType type,
final String[] deps) { final String[] deps) {
final KernelConfig kernelConfig = confManager final KernelConfig kernelConfig = confManager
.findConfiguration(KernelConfig.class); .findConfiguration(KernelConfig.class);
final Locale defaultLocale = kernelConfig.getDefaultLocale(); final Locale defaultLocale = kernelConfig.getDefaultLocale();
@ -202,17 +211,82 @@ public class WorkflowAdminPaneController {
} }
} }
} }
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public List<Task> getDependencies(final Task task) { public List<Task> getDependencies(final Task task) {
final Task theTask = taskRepo final Task theTask = taskRepo
.findById(task.getTaskId()) .findById(task.getTaskId())
.orElseThrow(() -> new IllegalArgumentException(String.format( .orElseThrow(() -> new IllegalArgumentException(String.format(
"No Task with ID %d in the database. Where did that ID come from?", "No Task with ID %d in the database. Where did that ID come from?",
task.getTaskId()))); task.getTaskId())));
return new ArrayList<>(theTask.getDependsOn()); return new ArrayList<>(theTask.getDependsOn());
} }
@Transactional(Transactional.TxType.REQUIRED)
TaskTableModelData getTaskTableModelData(final Workflow workflow) {
final Map<Task, String> dependencies = new HashMap<>();
final Iterator<Task> tasksIter = getTasksForWorkflow(workflow)
.iterator();
final GraphSet graphSet = new GraphSet();
while (tasksIter.hasNext()) {
Task task = tasksIter.next();
final Iterator<Task> deps = task.getDependsOn().iterator();
final StringBuffer buffer = new StringBuffer();
while (deps.hasNext()) {
Task dep = deps.next();
graphSet.addEdge(task, dep, null);
buffer
.append(dep.getLabel())
.append(", ");
}
final int len = buffer.length();
if (len >= 2) {
buffer.setLength(len - 2);
} else {
graphSet.addNode(task);
}
dependencies.put(task, buffer.toString());
}
final List<Task> tasks = new ArrayList<>();
outer:
while (graphSet.nodeCount() > 0) {
@SuppressWarnings("unchecked")
final List<Task> list = Graphs.getSinkNodes(graphSet);
for (final Iterator<Task> it = list.iterator(); it.hasNext();) {
final Task currentTask = it.next();
tasks.add(currentTask);
graphSet.removeNode(currentTask);
continue outer;
}
// break loop if no nodes removed
LOGGER.error("found possible loop in tasks for " + workflow);
break;
}
final Iterator<Task> taskIterator = tasks.iterator();
return new TaskTableModelData(taskIterator, dependencies);
}
@Transactional(Transactional.TxType.REQUIRED)
public List<Role> findAssignees(final CmsTask task) {
final CmsTask theTask = (CmsTask) taskRepo
.findById(task.getTaskId())
.orElseThrow(() -> new IllegalArgumentException(String.format(
"No Task with ID %d in the database. Where did that ID come from?",
task.getTaskId())));
return theTask
.getAssignments()
.stream()
.map(assignment -> assignment.getRole())
.collect(Collectors.toList());
}
} }

View File

@ -165,3 +165,4 @@ cms.ui.workflow.task.dependencies=Dependencies
cms.workflow.task_type.AUTHOR=Author cms.workflow.task_type.AUTHOR=Author
cms.workflow.task_type.EDIT=Edit cms.workflow.task_type.EDIT=Edit
cms.workflow.task_type.DEPLOY=Deploy cms.workflow.task_type.DEPLOY=Deploy
cms.ui.workflow.task.state=Status

View File

@ -164,3 +164,4 @@ cms.ui.workflow.task.dependencies=Abh\u00e4ngigkeiten
cms.workflow.task_type.AUTHOR=Verfassen cms.workflow.task_type.AUTHOR=Verfassen
cms.workflow.task_type.EDIT=Bearbeiten cms.workflow.task_type.EDIT=Bearbeiten
cms.workflow.task_type.DEPLOY=Ver\u00f6ffentlichen cms.workflow.task_type.DEPLOY=Ver\u00f6ffentlichen
cms.ui.workflow.task.state=Status

View File

@ -133,3 +133,4 @@ cms.ui.workflow.task.dependencies=Dependencies
cms.workflow.task_type.AUTHOR=Author cms.workflow.task_type.AUTHOR=Author
cms.workflow.task_type.EDIT=Edit cms.workflow.task_type.EDIT=Edit
cms.workflow.task_type.DEPLOY=Deploy cms.workflow.task_type.DEPLOY=Deploy
cms.ui.workflow.task.state=Status

View File

@ -189,7 +189,7 @@ public class AssignableTaskManager {
} }
final TypedQuery<AssignableTask> query = entityManager.createNamedQuery( final TypedQuery<AssignableTask> query = entityManager.createNamedQuery(
"UserTask.findLockedBy", AssignableTask.class); "AssignableTask.findLockedBy", AssignableTask.class);
query.setParameter("user", user); query.setParameter("user", user);
return query.getResultList(); return query.getResultList();