dataview view impl

This commit is contained in:
Ralph Soika 2025-05-11 21:43:27 +02:00
parent d948742963
commit 303448d766
4 changed files with 174 additions and 85 deletions

View file

@ -49,6 +49,16 @@ import jakarta.servlet.http.HttpServletRequest;
/** /**
* The DataViewController is used to display a data view * The DataViewController is used to display a data view
* <p>
* The controller uses a cacheId provided together with the uniqueId of the
* dataViewDefinition in the URL. The bean reads optional cached query data form
* a session scoped cache EJB and reloads the last state. This is useful for
* situations where the user navigates to a new page (e.g. open a workitem) and
* late uses browser history back.
* <p>
* Note: This bean is ConversationScoped, because it uses the
* CustomFormController which expects conversion scope!
*
* *
* @author rsoika * @author rsoika
* @version 1.0 * @version 1.0
@ -59,7 +69,11 @@ import jakarta.servlet.http.HttpServletRequest;
public class DataViewController extends ViewController { public class DataViewController extends ViewController {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private List<CustomFormSection> sections; private List<CustomFormSection> sections = null;
private List<ItemCollection> viewItemDefinitions = null;
protected ItemCollection dataDefinition = null;
private ItemCollection filter;
private String query;
private String errorMessage; private String errorMessage;
@Inject @Inject
@ -77,9 +91,8 @@ public class DataViewController extends ViewController {
@Inject @Inject
ViewHandler viewHandler; ViewHandler viewHandler;
protected ItemCollection data = null; @Inject
private ItemCollection filter; DataViewDefinitionController dataViewDefinitionController;
private String query;
private static Logger logger = Logger.getLogger(DataViewController.class.getName()); private static Logger logger = Logger.getLogger(DataViewController.class.getName());
@ -118,7 +131,7 @@ public class DataViewController extends ViewController {
// alternative 'workitem=...' // alternative 'workitem=...'
uniqueid = paramMap.get("workitem"); uniqueid = paramMap.get("workitem");
} }
data = documentService.load(uniqueid); dataDefinition = documentService.load(uniqueid);
} }
logger.info("> cacheid=" + cacheid); logger.info("> cacheid=" + cacheid);
@ -130,8 +143,10 @@ public class DataViewController extends ViewController {
try { try {
// Init new Filter.... // Init new Filter....
if (data != null) { if (dataDefinition != null) {
filter.setItemValue("txtWorkflowEditorCustomForm", data.getItemValue("form")); filter.setItemValue("txtWorkflowEditorCustomForm", dataDefinition.getItemValue("form"));
viewItemDefinitions = DataViewDefinitionController
.computeDataViewItemDefinitions(dataDefinition);
customFormController.computeFieldDefinition(filter); customFormController.computeFieldDefinition(filter);
sections = customFormController.getSections(); sections = customFormController.getSections();
@ -151,13 +166,17 @@ public class DataViewController extends ViewController {
} }
public ItemCollection getDefinition() { public ItemCollection getDefinition() {
return data; return dataDefinition;
} }
public List<CustomFormSection> getSections() { public List<CustomFormSection> getSections() {
return sections; return sections;
} }
public List<ItemCollection> getViewItemDefinitions() {
return viewItemDefinitions;
}
public ItemCollection getFilter() { public ItemCollection getFilter() {
return filter; return filter;
} }
@ -188,7 +207,7 @@ public class DataViewController extends ViewController {
reset(); reset();
// build new query from template // build new query from template
query = data.getItemValueString("query"); query = dataDefinition.getItemValueString("query");
List<String> filterItems = filter.getItemNames(); List<String> filterItems = filter.getItemNames();
for (String itemName : filterItems) { for (String itemName : filterItems) {
@ -227,28 +246,28 @@ public class DataViewController extends ViewController {
return query; return query;
} }
/** // /**
* Returns the current workItem. If no workitem is defined the method // * Returns the current workItem. If no workitem is defined the method
* Instantiates a empty ItemCollection. // * Instantiates a empty ItemCollection.
* // *
* @return - current workItem or null if not set // * @return - current workItem or null if not set
*/ // */
public ItemCollection getData() { // public ItemCollection getData() {
// do initialize an empty workItem here if null // // do initialize an empty workItem here if null
if (data == null) { // if (data == null) {
reset(); // reset();
} // }
return data; // return data;
} // }
/** // /**
* Set the current workItem // * Set the current workItem
* // *
* @param workitem - new reference or null to clear the current workItem. // * @param workitem - new reference or null to clear the current workItem.
*/ // */
public void setData(ItemCollection document) { // public void setData(ItemCollection document) {
this.data = document; // this.data = document;
} // }
/** /**
* This method navigates back in the page index and caches the current page * This method navigates back in the page index and caches the current page

View file

@ -30,17 +30,14 @@ import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.imixs.workflow.ItemCollection; import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentEvent;
import org.imixs.workflow.exceptions.AccessDeniedException; import org.imixs.workflow.exceptions.AccessDeniedException;
import org.imixs.workflow.faces.data.AbstractDataController; import org.imixs.workflow.faces.data.AbstractDataController;
import org.imixs.workflow.faces.data.DocumentController; import org.imixs.workflow.faces.data.DocumentController;
import org.imixs.workflow.office.forms.ChildItemController;
import com.oracle.svm.core.annotate.Inject; import com.oracle.svm.core.annotate.Inject;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ConversationScoped; import jakarta.enterprise.context.ConversationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.faces.context.ExternalContext; import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext; import jakarta.faces.context.FacesContext;
import jakarta.inject.Named; import jakarta.inject.Named;
@ -59,9 +56,6 @@ public class DataViewDefinitionController extends AbstractDataController {
protected List<ItemCollection> attributeList = null; protected List<ItemCollection> attributeList = null;
@Inject
ChildItemController childItemController;
@Inject @Inject
DocumentController documentController; DocumentController documentController;
@ -103,22 +97,71 @@ public class DataViewDefinitionController extends AbstractDataController {
} }
/** /**
* Set the current worktItem * Set the current dataview definition.
* The method computes the attributes.
* *
* @param workitem - new reference or null to clear the current workItem. * @param document - the DataView definition
*/ */
public void setData(ItemCollection document) { // public void setData(ItemCollection document) {
this.data = document; // this.data = document;
// attributeList = computeDataViewItemDefinitions(this.data);
// }
attributeList = new ArrayList<ItemCollection>(); @Override
List<Object> mapItems = data.getItemValue("dataview.items"); public void load(String uniqueid) {
super.load(uniqueid);
attributeList = computeDataViewItemDefinitions(this.data);
}
/**
* Returns a List of ItemCollection instances representing the view column
* description.
* Each column has the items:
*
* name,label,format,convert
*
* @param dataViewDefinition
* @return
*
*/
@SuppressWarnings("unchecked")
public static List<ItemCollection> computeDataViewItemDefinitions(ItemCollection dataViewDefinition) {
ArrayList<ItemCollection> result = new ArrayList<ItemCollection>();
List<Object> mapItems = dataViewDefinition.getItemValue("dataview.items");
for (Object mapOderItem : mapItems) { for (Object mapOderItem : mapItems) {
if (mapOderItem instanceof Map) { if (mapOderItem instanceof Map) {
ItemCollection itemCol = new ItemCollection((Map) mapOderItem); ItemCollection itemCol = new ItemCollection((Map) mapOderItem);
attributeList.add(itemCol); // check label
String itemLabel = itemCol.getItemValueString("item.label");
if (itemLabel.isEmpty()) {
itemCol.setItemValue("item.label", itemLabel);
}
// check type
String itemType = itemCol.getItemValueString("item.type");
if (itemType.isEmpty()) {
itemCol.setItemValue("item.type", "xs:string");
}
result.add(itemCol);
} }
} }
// if no columns are defined we create the default columns
if (result.size() == 0) {
ItemCollection itemCol = new ItemCollection();
itemCol.setItemValue("item.name", "$workflowSummary");
itemCol.setItemValue("item.label", "Name");
itemCol.setItemValue("item.type", "xs:anyURI");
result.add(itemCol);
itemCol = new ItemCollection();
itemCol.setItemValue("item.name", "$modified");
itemCol.setItemValue("item.label", "Modified");
itemCol.setItemValue("item.type", "xs:date");
result.add(itemCol);
}
return result;
} }
/** /**
@ -133,9 +176,18 @@ public class DataViewDefinitionController extends AbstractDataController {
.getExternalContext(); .getExternalContext();
String sUser = externalContext.getRemoteUser(); String sUser = externalContext.getRemoteUser();
data.replaceItemValue("$editor", sUser); data.replaceItemValue("$editor", sUser);
List<Map> mapItemList = new ArrayList<Map>();
logger.fine("Convert attribute items into Map...");
// implode attributes
for (ItemCollection attrItem : attributeList) {
ItemCollection ding = (ItemCollection) attrItem.clone();
mapItemList.add(ding.getAllItems());
}
data.replaceItemValue("dataview.items", mapItemList);
data = this.getDocumentService().save(data); data = this.getDocumentService().save(data);
logger.finest("......ItemCollection saved");
} }
public String openTestView() { public String openTestView() {
@ -152,34 +204,35 @@ public class DataViewDefinitionController extends AbstractDataController {
* *
* *
*/ */
public void onEvent(@Observes DocumentEvent event) { // public void onEvent(@Observes DocumentEvent event) {
if (event == null || event.getDocument() == null || !"dataview".equals(event.getDocument().getType())) { // if (event == null || event.getDocument() == null ||
return; // !"dataview".equals(event.getDocument().getType())) {
} // return;
// update attribute list // }
if (event.getEventType() == DocumentEvent.ON_DOCUMENT_SAVE) { // // update attribute list
// if (event.getEventType() == DocumentEvent.ON_DOCUMENT_SAVE) {
// convert the option ItemCollection elements into a List of Map // // convert the option ItemCollection elements into a List of Map
if (attributeList != null) { // if (attributeList != null) {
List<Map> mapItemList = new ArrayList<Map>(); // List<Map> mapItemList = new ArrayList<Map>();
logger.fine("Convert option items into Map..."); // logger.fine("Convert option items into Map...");
// iterate over all items.. // // iterate over all items..
for (ItemCollection attrItem : attributeList) { // for (ItemCollection attrItem : attributeList) {
ItemCollection ding = (ItemCollection) attrItem.clone(); // ItemCollection ding = (ItemCollection) attrItem.clone();
mapItemList.add(ding.getAllItems()); // mapItemList.add(ding.getAllItems());
} // }
event.getDocument().replaceItemValue("dataview.items", mapItemList); // event.getDocument().replaceItemValue("dataview.items", mapItemList);
} // }
} // }
// update attribute list // // update attribute list
if (event.getEventType() == DocumentEvent.ON_DOCUMENT_LOAD) { // if (event.getEventType() == DocumentEvent.ON_DOCUMENT_LOAD) {
} // }
} // }
/** /**
* Adds a new attribute object. * Adds a new attribute object.

View file

@ -100,8 +100,11 @@
<span class="typcn typcn-lightbulb"></span> <span class="typcn typcn-lightbulb"></span>
Attribute definitions for the vew result. An attribute can adapt single item Attribute definitions for the vew result. An attribute can adapt single item
values. Each item of values. Each item of
the attribute list can define an optional label, converter, format and the attribute list can define an optional label, xs datatype and format.
aggregator. <br />
Convert - xml datatypes: xs:string (default), xs:decimal, xs:date,
xs:dateTime,
xs:anyURI
</p> </p>
<f:ajax render="attributelist" onevent="updateAttributeList"> <f:ajax render="attributelist" onevent="updateAttributeList">
@ -109,7 +112,7 @@
<tr> <tr>
<th style="width: 250px">Item</th> <th style="width: 250px">Item</th>
<th style="width: 250px;">Label</th> <th style="width: 250px;">Label</th>
<th style="width: 200px;">Convert</th> <th style="width: 200px;">Type</th>
<th style="">Format</th> <th style="">Format</th>
<th style="width: 100px"> <th style="width: 100px">
<!-- actions --> <!-- actions -->
@ -128,7 +131,7 @@
style="width:100%;" /> style="width:100%;" />
</td> </td>
<td> <td>
<h:inputText value="#{attribute.item['item.convert']}" <h:inputText value="#{attribute.item['item.type']}"
style="width:100%;" /> style="width:100%;" />
</td> </td>
<td> <td>

View file

@ -109,24 +109,38 @@
<h:dataTable id="view_body" styleClass="imixsdatatable" value="#{searchResult}" <h:dataTable id="view_body" styleClass="imixsdatatable" value="#{searchResult}"
var="record"> var="record">
<h:column>
<f:facet name="header">#{message.name}</f:facet>
<h:link outcome="/pages/workitems/workitem.xhtml?faces-redirect=true"
styleClass="imixs-viewentry-main-link">
<h:outputText value="#{record.item['$workflowsummary']}" />
<f:param name="id" value="#{record.item['$uniqueid']}" />
</h:link>
</h:column>
<h:column>
<f:facet name="header">#{message.modified}</f:facet>
<h:outputText value="#{record.item['$modified']}">
<f:convertDateTime timeZone="#{message.timeZone}" type="both"
pattern="#{message.dateTimePattern}" />
</h:outputText>
</h:column> <c:forEach items="#{dataViewController.viewItemDefinitions}" var="columnDef">
<h:column rendered="#{columnDef.item['item.type'] eq 'xs:anyURI'}">
<f:facet name="header">#{columnDef.item['item.label']}</f:facet>
<h:link outcome="/pages/workitems/workitem.xhtml?faces-redirect=true"
styleClass="imixs-viewentry-main-link">
<h:outputText value="#{record.item[columnDef.item['item.name']]}" />
<f:param name="id" value="#{record.item['$uniqueid']}" />
</h:link>
</h:column>
<h:column rendered="#{columnDef.item['item.type'] eq 'xs:string'}">
<f:facet name="header">#{columnDef.item['item.label']}</f:facet>
<h:outputText value="#{record.item[columnDef.item['item.name']]}" />
</h:column>
<h:column rendered="#{columnDef.item['item.type'] eq 'xs:date'}">
<f:facet name="header">#{columnDef.item['item.label']}</f:facet>
<h:outputText value="#{record.item[columnDef.item['item.name']]}">
<f:convertDateTime timeZone="#{message.timeZone}" type="both"
pattern="#{message.dateTimePattern}" />
</h:outputText>
</h:column>
</c:forEach>
</h:dataTable> </h:dataTable>