neue Ansicht Businesspartner
This commit is contained in:
parent
a65ae59950
commit
c15efc106c
6 changed files with 1664 additions and 0 deletions
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Imixs Workflow Technology
|
||||||
|
* Copyright (C) 2003, 2008 Imixs Software Solutions GmbH,
|
||||||
|
* http://www.imixs.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You can receive a copy of the GNU General Public
|
||||||
|
* License at http://www.gnu.org/licenses/gpl.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Imixs Software Solutions GmbH - initial API and implementation
|
||||||
|
* Ralph Soika
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.imixs.workflow.office.forms;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.imixs.workflow.dataview.DataViewService;
|
||||||
|
import org.imixs.workflow.exceptions.QueryException;
|
||||||
|
import org.imixs.workflow.faces.data.WorkflowController;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import jakarta.enterprise.context.Conversation;
|
||||||
|
import jakarta.enterprise.context.ConversationScoped;
|
||||||
|
import jakarta.faces.context.FacesContext;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.inject.Named;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DataViewFormSectionController provides methods to display a data view in
|
||||||
|
* as a
|
||||||
|
* custom form section
|
||||||
|
*
|
||||||
|
* @see pages/workitems/sections/dataview.xhtml
|
||||||
|
* @author rsoika
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Named
|
||||||
|
@ConversationScoped
|
||||||
|
public class DataViewSectionController implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public static final int MAX_SEARCH_RESULT = 1000;
|
||||||
|
public static Logger logger = Logger.getLogger(DataViewSectionController.class.getName());
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
WorkflowController workflowController;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Conversation conversation;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
DataViewService dataViewService;
|
||||||
|
|
||||||
|
private Map<String, DataViewSectionDataSet> dataSets = null;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
startConversation();
|
||||||
|
dataSets = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a new conversation
|
||||||
|
*/
|
||||||
|
protected void startConversation() {
|
||||||
|
if (conversation.isTransient()) {
|
||||||
|
conversation.setTimeout(
|
||||||
|
((HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest())
|
||||||
|
.getSession().getMaxInactiveInterval() * 1000);
|
||||||
|
conversation.begin();
|
||||||
|
logger.log(Level.FINEST, "......start new conversation, id={0}",
|
||||||
|
conversation.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a single value from a Option key/value list
|
||||||
|
*
|
||||||
|
* @param options - options
|
||||||
|
* @param key - option key
|
||||||
|
* @return option value
|
||||||
|
*/
|
||||||
|
public String getOptionValue(String options, String key) {
|
||||||
|
// Null checks
|
||||||
|
if (options == null || key == null || options.trim().isEmpty() || key.trim().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split options into key/value pairs (separated by semicolon)
|
||||||
|
String[] pairs = options.split(";");
|
||||||
|
|
||||||
|
for (String pair : pairs) {
|
||||||
|
// Split each pair into key and value (separated by equals sign)
|
||||||
|
String[] keyValue = pair.split("=", 2); // Limit to 2 in case value contains "="
|
||||||
|
|
||||||
|
if (keyValue.length == 2) {
|
||||||
|
String currentKey = keyValue[0].trim();
|
||||||
|
String currentValue = keyValue[1].trim();
|
||||||
|
|
||||||
|
// Check if the searched key was found
|
||||||
|
if (key.equals(currentKey)) {
|
||||||
|
return currentValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key not found
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new DataViewSectionDataSet based on the given options
|
||||||
|
* (parameter 'name').
|
||||||
|
*
|
||||||
|
* The expected format of the options string is:
|
||||||
|
* <p>
|
||||||
|
* "name=DATAVIEWNAME"
|
||||||
|
* <p>
|
||||||
|
* The method loads the corresponding dataView definition immediately and stores
|
||||||
|
* the dataSet in a local cache.
|
||||||
|
*
|
||||||
|
* @return view result
|
||||||
|
* @throws QueryException
|
||||||
|
*/
|
||||||
|
public DataViewSectionDataSet loadDataSet(String options) throws QueryException {
|
||||||
|
DataViewSectionDataSet dataSet = dataSets.get(options);
|
||||||
|
// Extract and set dataViewName from options
|
||||||
|
if (dataSet == null) {
|
||||||
|
String _dataViewName = getOptionValue(options, "name");
|
||||||
|
if (_dataViewName != null) {
|
||||||
|
logger.info("...build new dataSet by options: " + options);
|
||||||
|
dataSet = new DataViewSectionDataSet(_dataViewName, workflowController.getWorkitem(), dataViewService);
|
||||||
|
dataSets.put(options, dataSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dataSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,260 @@
|
||||||
|
package org.imixs.workflow.office.forms;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.imixs.workflow.FileData;
|
||||||
|
import org.imixs.workflow.ItemCollection;
|
||||||
|
import org.imixs.workflow.dataview.DataViewController;
|
||||||
|
import org.imixs.workflow.dataview.DataViewExportEvent;
|
||||||
|
import org.imixs.workflow.dataview.DataViewPOIHelper;
|
||||||
|
import org.imixs.workflow.dataview.DataViewService;
|
||||||
|
import org.imixs.workflow.exceptions.PluginException;
|
||||||
|
import org.imixs.workflow.exceptions.QueryException;
|
||||||
|
|
||||||
|
public class DataViewSectionDataSet implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public static Logger logger = Logger.getLogger(DataViewSectionController.class.getName());
|
||||||
|
|
||||||
|
List<ItemCollection> data = null;
|
||||||
|
private ItemCollection dataViewDefinition;
|
||||||
|
private String dataViewName;
|
||||||
|
private List<ItemCollection> viewItemDefinitions = null;
|
||||||
|
private String query = null;
|
||||||
|
private boolean endOfList = false;
|
||||||
|
|
||||||
|
private long totalCount = 0;
|
||||||
|
private long totalPages = 0;
|
||||||
|
|
||||||
|
private String sortBy = null;
|
||||||
|
private boolean sortReverse = false;
|
||||||
|
private int pageSize = 10;
|
||||||
|
private int pageIndex = 0;
|
||||||
|
|
||||||
|
private DataViewService dataViewService;
|
||||||
|
|
||||||
|
private ItemCollection workitem;
|
||||||
|
|
||||||
|
public DataViewSectionDataSet(String dataViewName, ItemCollection workitem, DataViewService dataViewService) {
|
||||||
|
this.dataViewName = dataViewName;
|
||||||
|
this.workitem = workitem;
|
||||||
|
this.dataViewService = dataViewService;
|
||||||
|
|
||||||
|
dataViewDefinition = dataViewService.loadDataViewDefinition(dataViewName);
|
||||||
|
|
||||||
|
boolean debug = dataViewDefinition.getItemValueBoolean("debug");
|
||||||
|
if (debug) {
|
||||||
|
logger.info("resolve query by dataView '" + dataViewName + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// preload the viewItem definitions
|
||||||
|
viewItemDefinitions = this.dataViewService.computeDataViewItemDefinitions(dataViewDefinition);
|
||||||
|
|
||||||
|
// resove query by dataView
|
||||||
|
query = this.dataViewService.parseQuery(dataViewDefinition, this.workitem);
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forward() {
|
||||||
|
if (!isEndOfList()) {
|
||||||
|
pageIndex++;
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void back() {
|
||||||
|
if (pageIndex > 0) {
|
||||||
|
pageIndex--;
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load current page
|
||||||
|
*/
|
||||||
|
private void loadData() {
|
||||||
|
try {
|
||||||
|
data = dataViewService.getWorkflowService().getDocumentService().find(query, getPageSize(), getPageIndex(),
|
||||||
|
getSortBy(), isSortReverse());
|
||||||
|
|
||||||
|
// The end of a list is reached when the size is below or equal the
|
||||||
|
// pageSize. See issue #287
|
||||||
|
totalCount = dataViewService.getWorkflowService().getDocumentService().count(query);
|
||||||
|
totalPages = (long) Math.ceil((double) totalCount / pageSize);
|
||||||
|
|
||||||
|
if (data.size() < pageSize) {
|
||||||
|
setEndOfList(true);
|
||||||
|
} else {
|
||||||
|
// look ahead if we have more entries...
|
||||||
|
int iAhead = (getPageSize() * (getPageIndex() + 1)) + 1;
|
||||||
|
if (totalCount < iAhead) {
|
||||||
|
// there is no more data
|
||||||
|
setEndOfList(true);
|
||||||
|
} else {
|
||||||
|
setEndOfList(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (QueryException e) {
|
||||||
|
logger.warning("Failed to load data: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ItemCollection> getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemCollection getDataViewDefinition() {
|
||||||
|
return dataViewDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalCount() {
|
||||||
|
return totalCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalPages() {
|
||||||
|
return totalPages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPageIndex() {
|
||||||
|
return pageIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPageIndex(int pageIndex) {
|
||||||
|
this.pageIndex = pageIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEndOfList() {
|
||||||
|
return endOfList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndOfList(boolean endOfList) {
|
||||||
|
this.endOfList = endOfList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataViewName() {
|
||||||
|
return dataViewName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ItemCollection> getViewItemDefinitions() {
|
||||||
|
return viewItemDefinitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the maximum size of a search result
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getPageSize() {
|
||||||
|
return pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the maximum size of a search result
|
||||||
|
*
|
||||||
|
* @param searchCount
|
||||||
|
*/
|
||||||
|
public void setPageSize(int pageSize) {
|
||||||
|
this.pageSize = pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSortBy() {
|
||||||
|
return sortBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortBy(String sortBy) {
|
||||||
|
this.sortBy = sortBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSortReverse() {
|
||||||
|
return sortReverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortReverse(boolean sortReverse) {
|
||||||
|
this.sortReverse = sortReverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports data into a excel template processed by apache-poi. The method sends
|
||||||
|
* a DataViewExport event to allow clients to adapt the export process.
|
||||||
|
*
|
||||||
|
* @see DataViewExportEvent
|
||||||
|
*
|
||||||
|
* @throws PluginException
|
||||||
|
* @throws QueryException
|
||||||
|
*/
|
||||||
|
public String export() throws PluginException, QueryException {
|
||||||
|
|
||||||
|
// Build target filename
|
||||||
|
boolean debug = dataViewDefinition.getItemValueBoolean("debug");
|
||||||
|
|
||||||
|
// start export
|
||||||
|
if (debug) {
|
||||||
|
logger.info("│ ├── Query: " + query);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// test if query exceeds max count
|
||||||
|
int totalCount = dataViewService.getWorkflowService().getDocumentService().count(query);
|
||||||
|
// start export
|
||||||
|
if (debug) {
|
||||||
|
logger.info("│ ├── Count: " + totalCount);
|
||||||
|
}
|
||||||
|
if (totalCount > DataViewService.MAX_ROWS) {
|
||||||
|
throw new PluginException(DataViewController.class.getSimpleName(), DataViewService.ERROR_CONFIG,
|
||||||
|
"Data can not be exported into Excel because dataset exceeds " + DataViewService.MAX_ROWS
|
||||||
|
+ " rows!");
|
||||||
|
}
|
||||||
|
String sortBy = dataViewDefinition.getItemValueString("sort.by");
|
||||||
|
if (sortBy.isEmpty()) {
|
||||||
|
sortBy = "$modified"; // default
|
||||||
|
}
|
||||||
|
List<ItemCollection> workitems = dataViewService.getWorkflowService().getDocumentService().find(query,
|
||||||
|
DataViewService.MAX_ROWS, 0, sortBy,
|
||||||
|
dataViewDefinition.getItemValueBoolean("sort.reverse"));
|
||||||
|
|
||||||
|
FileData fileDataExport = dataViewService.poiExport(workitems, dataViewDefinition, viewItemDefinitions);
|
||||||
|
|
||||||
|
// create a temp event
|
||||||
|
ItemCollection event = new ItemCollection().setItemValue("txtActivityResult",
|
||||||
|
dataViewDefinition.getItemValue("poi.update"));
|
||||||
|
ItemCollection poiConfig = dataViewService.getWorkflowService().evalWorkflowResult(event, "poi-update",
|
||||||
|
dataViewDefinition,
|
||||||
|
false);
|
||||||
|
|
||||||
|
// merge workitem fields (Workaround because custom forms did hard coded map to
|
||||||
|
// workflowController instead of workitem
|
||||||
|
|
||||||
|
DataViewPOIHelper.poiUpdate(workitem, fileDataExport, poiConfig, dataViewService.getWorkflowService());
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
logger.info("├── POI Export completed!");
|
||||||
|
}
|
||||||
|
// See:
|
||||||
|
// https://stackoverflow.com/questions/9391838/how-to-provide-a-file-download-from-a-jsf-backing-bean
|
||||||
|
DataViewPOIHelper.downloadExcelFile(fileDataExport);
|
||||||
|
} catch (IOException | QueryException e) {
|
||||||
|
throw new PluginException(DataViewController.class.getSimpleName(), DataViewService.ERROR_CONFIG,
|
||||||
|
"Failed to generate Excel Export: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// return "/pages/admin/excel_export_rechnungsausgang.jsf?faces-redirect=true";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a poi export is defined
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean hasPoiExport() {
|
||||||
|
if (dataViewDefinition != null && !dataViewDefinition.getItemValueString("poi.targetfilename").isBlank()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
|
||||||
|
xmlns:f="http://java.sun.com/jsf/core" xmlns:c="http://java.sun.com/jsp/jstl/core"
|
||||||
|
xmlns:h="http://java.sun.com/jsf/html" xmlns:i="http://java.sun.com/jsf/composite/imixs"
|
||||||
|
xmlns:marty="http://java.sun.com/jsf/composite/marty">
|
||||||
|
|
||||||
|
<!-- preload view options -->
|
||||||
|
|
||||||
|
|
||||||
|
<h:panelGroup styleClass="imixs-view imixs-search" layout="block" id="dataview_result_id">
|
||||||
|
<ui:param name="dataViewDataSet" value="#{dataViewSectionController.loadDataSet(options)}" />
|
||||||
|
<ui:param name="searchPage"
|
||||||
|
value="#{(dataViewDataSet.getPageIndex()+1)}/#{(dataViewDataSet.getTotalPages())}" />
|
||||||
|
<table class="imixsdatatable imixs-orderitems">
|
||||||
|
<tr>
|
||||||
|
<ui:repeat value="#{dataViewDataSet.getViewItemDefinitions()}" var="columnDef">
|
||||||
|
<th>#{columnDef.item['item.label']}</th>
|
||||||
|
</ui:repeat>
|
||||||
|
</tr>
|
||||||
|
<ui:repeat value="#{dataViewDataSet.data}" var="record">
|
||||||
|
<tr>
|
||||||
|
<ui:repeat value="#{dataViewDataSet.getViewItemDefinitions()}" var="columnDef">
|
||||||
|
<td>
|
||||||
|
<ui:fragment rendered="#{columnDef.item['item.type'] eq 'xs:anyURI'}">
|
||||||
|
<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>
|
||||||
|
</ui:fragment>
|
||||||
|
|
||||||
|
<ui:fragment rendered="#{columnDef.item['item.type'] eq 'xs:string'}">
|
||||||
|
<h:outputText value="#{record.item[columnDef.item['item.name']]}" />
|
||||||
|
</ui:fragment>
|
||||||
|
|
||||||
|
<ui:fragment rendered="#{columnDef.item['item.type'] eq 'xs:date'}"
|
||||||
|
styleClass="align-center">
|
||||||
|
<h:outputText value="#{record.item[columnDef.item['item.name']]}">
|
||||||
|
<f:convertDateTime timeZone="#{message.timeZone}" type="both"
|
||||||
|
pattern="#{message.datePatternShort}" />
|
||||||
|
</h:outputText>
|
||||||
|
</ui:fragment>
|
||||||
|
|
||||||
|
<ui:fragment rendered="#{columnDef.item['item.type'] eq 'xs:double'}"
|
||||||
|
styleClass="align-right">
|
||||||
|
<h:outputText value="#{record.item[columnDef.item['item.name']]}">
|
||||||
|
<f:convertNumber minFractionDigits="2" locale="de" />
|
||||||
|
</h:outputText>
|
||||||
|
</ui:fragment>
|
||||||
|
<ui:fragment rendered="#{columnDef.item['item.type'] eq 'xs:float'}"
|
||||||
|
styleClass="align-right">
|
||||||
|
<h:outputText value="#{record.item[columnDef.item['item.name']]}">
|
||||||
|
<f:convertNumber minFractionDigits="2" locale="de" />
|
||||||
|
</h:outputText>
|
||||||
|
</ui:fragment>
|
||||||
|
|
||||||
|
<ui:fragment rendered="#{columnDef.item['item.type'] eq 'xs:dateTime'}">
|
||||||
|
<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.dateTimePatternShort}" />
|
||||||
|
</h:outputText>
|
||||||
|
</ui:fragment>
|
||||||
|
</td>
|
||||||
|
</ui:repeat>
|
||||||
|
</tr>
|
||||||
|
</ui:repeat>
|
||||||
|
</table>
|
||||||
|
<!-- navigation -->
|
||||||
|
<div
|
||||||
|
style="background-color: #f9f9f9; font-size:0.85rem; border-bottom: 1px solid var(--input-border);border-left: 1px solid var(--input-border);border-right: 1px solid var(--input-border); height: 30px; display: flex; justify-content: space-between; align-items: center;padding: 5px 10px;">
|
||||||
|
<span style="display: flex; align-items: center;gap: 10px;">
|
||||||
|
<h:commandLink title="Excel Export" rendered="false" actionListener="#{dataGroupController.export()}"
|
||||||
|
onclick="handleSubmit(this)">
|
||||||
|
<i class="fa-solid fa-file-csv"></i>
|
||||||
|
</h:commandLink>
|
||||||
|
<h:commandLink title="Excel Export" rendered="#{dataViewDataSet.hasPoiExport()}"
|
||||||
|
actionListener="#{dataViewDataSet.export()}" onclick="handleSubmit(this)">
|
||||||
|
<span class="typcn typcn-vendor-microsoft"></span>
|
||||||
|
</h:commandLink>
|
||||||
|
</span>
|
||||||
|
<span style="display: flex; align-items: center; gap: 10px;">
|
||||||
|
<h:outputText value=" #{(dataViewDataSet.pageIndex+1)} / #{dataViewDataSet.totalPages}" />
|
||||||
|
<h:commandLink value="" action="#{dataViewDataSet.back()}">
|
||||||
|
<f:ajax render="dataview_result_id" />
|
||||||
|
<i class="fa-solid fa-backward" style=" #{(dataViewDataSet.pageIndex == 0)?'opacity:0.5':''}"></i>
|
||||||
|
</h:commandLink>
|
||||||
|
<h:commandLink value="" action="#{dataViewDataSet.forward()}">
|
||||||
|
<f:ajax render="dataview_result_id" />
|
||||||
|
<i class="fa-solid fa-forward" style=" #{(dataViewDataSet.endOfList)?'opacity:0.5':''}"></i>
|
||||||
|
</h:commandLink>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</h:panelGroup>
|
||||||
|
<script type="text/javascript">
|
||||||
|
/*<![CDATA[*/
|
||||||
|
function handleSubmit(event) {
|
||||||
|
// remove ajax loader 1sec after trigger excel export
|
||||||
|
setTimeout(function () {
|
||||||
|
document.body.classList.remove('loading');
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
/*]]>*/
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</ui:composition>
|
||||||
BIN
templates/invoice_outbound_de_template.xlsx
Normal file
BIN
templates/invoice_outbound_de_template.xlsx
Normal file
Binary file not shown.
BIN
templates/invoice_outbound_en_template.xlsx
Normal file
BIN
templates/invoice_outbound_en_template.xlsx
Normal file
Binary file not shown.
1143
workflow/businesspartner-de-1.0.4.bpmn
Normal file
1143
workflow/businesspartner-de-1.0.4.bpmn
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue