diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/DefaultViewManager.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/DefaultViewManager.java index 5164d551caa4730de89d5d1ca91aa78c2118b659..6322789d8fb43e854ea3960a3a23d4b6dea84fb5 100644 --- a/modules/activiti-explorer/src/main/java/org/activiti/explorer/DefaultViewManager.java +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/DefaultViewManager.java @@ -44,6 +44,7 @@ import org.activiti.explorer.ui.process.simple.editor.SimpleTableEditor; import org.activiti.explorer.ui.profile.ProfilePopupWindow; import org.activiti.explorer.ui.reports.ReportsMenuBar; import org.activiti.explorer.ui.reports.RunReportsPage; +import org.activiti.explorer.ui.reports.SavedReportsPage; import org.activiti.explorer.ui.task.ArchivedPage; import org.activiti.explorer.ui.task.InboxPage; import org.activiti.explorer.ui.task.InvolvedPage; @@ -238,6 +239,10 @@ public class DefaultViewManager implements ViewManager, Serializable { public void showRunReportPage() { switchView(new RunReportsPage(), ViewManager.MAIN_NAVIGATION_REPORT, ReportsMenuBar.ENTRY_RUN_REPORTS); } + + public void showSavedReportPage() { + switchView(new SavedReportsPage(), ViewManager.MAIN_NAVIGATION_REPORT, ReportsMenuBar.ENTRY_SAVED_REPORTS); + } // Management diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/Messages.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/Messages.java index 3c13596de24bd519dcd8db031a7b9a3449317c02..11475f468061834a2409556eae6b4b1aa2962bb0 100644 --- a/modules/activiti-explorer/src/main/java/org/activiti/explorer/Messages.java +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/Messages.java @@ -288,6 +288,7 @@ public interface Messages { String REPORTING_SAVE_POPUP_NAME_EMPTY = "reporting.save.popup.name.empty"; String REPORTING_SAVE_POPUP_NAME_EXISTS = "reporting.save.popup.name.exists"; String REPORTING_SAVE_POPUP_NAME_TOO_LONG = "reporting.save.popup..name.too.long"; + String REPORTING_CREATE_TIME = "reporting.report.created"; // Management menu String MGMT_MENU_DATABASE = "management.menu.database"; diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ViewManager.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ViewManager.java index cddb5c2f773e6dde7c4a4f9dff18b9e419b39da8..c66db63d4e660b370a1c75ea591a4629eb3e888a 100644 --- a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ViewManager.java +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ViewManager.java @@ -89,6 +89,8 @@ public interface ViewManager { void showRunReportPage(); + void showSavedReportPage(); + // Management void showDatabasePage(); diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/navigation/NavigatorManager.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/navigation/NavigatorManager.java index 92c561982206542544dff47f3a35a52bc4ea223d..0eadc0c778faae5f79cbdede87273ab4838b39d3 100644 --- a/modules/activiti-explorer/src/main/java/org/activiti/explorer/navigation/NavigatorManager.java +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/navigation/NavigatorManager.java @@ -68,6 +68,7 @@ public class NavigatorManager implements InitializingBean, Serializable { addNavigator(new GroupNavigator()); addNavigator(new AdministrationNavigator()); addNavigator(new MyProcessesNavigator()); + addNavigator(new SavedReportNavigator()); } } diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/navigation/SavedReportNavigator.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/navigation/SavedReportNavigator.java new file mode 100644 index 0000000000000000000000000000000000000000..b6c99d20a98c913a9b7e23065d33b05650a7a2fe --- /dev/null +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/navigation/SavedReportNavigator.java @@ -0,0 +1,43 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.activiti.explorer.navigation; + +import org.activiti.explorer.ExplorerApp; + + + +/** + * @author Frederik Heremans + */ +public class SavedReportNavigator implements Navigator { + + private static final long serialVersionUID = 1L; + + public static final String SAVED_REPORT_URI_PART = "savedReport"; + + public String getTrigger() { + return SAVED_REPORT_URI_PART; + } + + public void handleNavigation(UriFragment uriFragment) { + String modelId = uriFragment.getUriPart(1); + + if(modelId != null) { + ExplorerApp.get().getViewManager().showSavedReportPage(); + } else { + ExplorerApp.get().getViewManager().showSavedReportPage(); + } + } + +} diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/Images.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/Images.java index a7bbf31bb9471362e04fb3f1d75bc83c3d8813f1..9bf18f8af4ad1ef81c94754e1c50e690c311df72 100644 --- a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/Images.java +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/Images.java @@ -93,5 +93,6 @@ public class Images { // Reports public static final Resource REPORT_50 = new ThemeResource("img/report-50.png"); + public static final Resource REPORT_22 = new ThemeResource("img/report-22.png"); } diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/ReportsMenuBar.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/ReportsMenuBar.java index 080a335be8636f9f75a5cd2c838dd1f66b0df654..ae29d32fdfef2e617fc54b0dc9368ba3d8a95094 100644 --- a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/ReportsMenuBar.java +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/ReportsMenuBar.java @@ -56,7 +56,7 @@ public class ReportsMenuBar extends ToolBar { protected void addSavedReportsToolbarEntry() { addToolbarEntry(ENTRY_SAVED_REPORTS, i18nManager.getMessage(Messages.REPORTING_MENU_SAVED_REPORTS), new ToolbarCommand() { public void toolBarItemSelected() { - viewManager.showRunReportPage(); + viewManager.showSavedReportPage(); } }); } diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/SavedReportDetailPanel.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/SavedReportDetailPanel.java new file mode 100644 index 0000000000000000000000000000000000000000..b866da3a66fc249632195f3c694c38672b52b694 --- /dev/null +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/SavedReportDetailPanel.java @@ -0,0 +1,126 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.activiti.explorer.ui.reports; + +import org.activiti.engine.ProcessEngines; +import org.activiti.engine.history.HistoricProcessInstance; +import org.activiti.engine.history.HistoricVariableInstance; +import org.activiti.explorer.ExplorerApp; +import org.activiti.explorer.I18nManager; +import org.activiti.explorer.Messages; +import org.activiti.explorer.ui.Images; +import org.activiti.explorer.ui.custom.DetailPanel; +import org.activiti.explorer.ui.form.FormPropertiesForm; +import org.activiti.explorer.ui.mainlayout.ExplorerLayout; +import org.activiti.explorer.util.time.HumanTime; + +import com.vaadin.ui.Embedded; +import com.vaadin.ui.GridLayout; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.Reindeer; + + +/** + * @author Frederik Heremans + */ +public class SavedReportDetailPanel extends DetailPanel { + + private static final long serialVersionUID = 1L; + + protected HistoricProcessInstance historicProcessInstance; + protected I18nManager i18nManager; + + protected VerticalLayout detailPanelLayout; + protected HorizontalLayout detailContainer; + protected FormPropertiesForm processDefinitionStartForm; + + public SavedReportDetailPanel(String historicProcessInstance) { + this.i18nManager = ExplorerApp.get().getI18nManager(); + + this.historicProcessInstance = ProcessEngines.getDefaultProcessEngine() + .getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(historicProcessInstance).singleResult(); + + initUi(); + } + + protected void initUi() { + setSizeFull(); + addStyleName(Reindeer.LAYOUT_WHITE); + + detailPanelLayout = new VerticalLayout(); + detailPanelLayout.setWidth(100, UNITS_PERCENTAGE); + detailPanelLayout.setMargin(true); + setDetailContainer(detailPanelLayout); + + initHeader(); + + detailContainer = new HorizontalLayout(); + detailContainer.addStyleName(Reindeer.PANEL_LIGHT); + detailPanelLayout.addComponent(detailContainer); + detailContainer.setSizeFull(); + + initForm(); + + } + + protected void initHeader() { + GridLayout details = new GridLayout(2, 2); + details.setWidth(100, UNITS_PERCENTAGE); + details.addStyleName(ExplorerLayout.STYLE_TITLE_BLOCK); + details.setSpacing(true); + details.setMargin(false, false, true, false); + details.setColumnExpandRatio(1, 1.0f); + detailPanelLayout.addComponent(details); + + // Image + Embedded image = new Embedded(null, Images.REPORT_50); + details.addComponent(image, 0, 0, 0, 1); + + // Name + Label nameLabel = new Label(SavedReportListItem.getReportDisplayName(historicProcessInstance)); + nameLabel.addStyleName(Reindeer.LABEL_H2); + details.addComponent(nameLabel, 1, 0); + + // Properties + HorizontalLayout propertiesLayout = new HorizontalLayout(); + propertiesLayout.setSpacing(true); + details.addComponent(propertiesLayout); + + // Created Time + String createLabel = i18nManager.getMessage(Messages.REPORTING_CREATE_TIME, new HumanTime(i18nManager).format(historicProcessInstance.getEndTime())); + Label versionLabel = new Label(createLabel); + versionLabel.addStyleName(ExplorerLayout.STYLE_PROCESS_HEADER_START_TIME); + propertiesLayout.addComponent(versionLabel); + } + + protected void initForm() { + // Report dataset is stored as historical variable as json + HistoricVariableInstance historicVariableInstance = ProcessEngines.getDefaultProcessEngine().getHistoryService() + .createHistoricVariableInstanceQuery() + .processInstanceId(historicProcessInstance.getId()) + .variableName("reportData") + .singleResult(); + + // Generate chart + byte[] reportData = (byte[]) historicVariableInstance.getValue(); + ChartComponent chart = ChartGenerator.generateChart(reportData); + chart.setWidth(100, UNITS_PERCENTAGE); + chart.setHeight(100, UNITS_PERCENTAGE); + + // Put chart on screen + detailContainer.addComponent(chart); + } + +} diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/SavedReportListItem.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/SavedReportListItem.java new file mode 100644 index 0000000000000000000000000000000000000000..e69359e3d166f6a1905e18553ee4a3b9fb695646 --- /dev/null +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/SavedReportListItem.java @@ -0,0 +1,65 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.activiti.explorer.ui.reports; + +import java.text.DateFormat; +import java.util.Date; + +import org.activiti.engine.ActivitiIllegalArgumentException; +import org.activiti.engine.history.HistoricProcessInstance; +import org.activiti.engine.impl.identity.Authentication; + +import com.vaadin.data.Property; +import com.vaadin.data.util.ObjectProperty; +import com.vaadin.data.util.PropertysetItem; + +/** + * @author Frederik Heremans + */ +public class SavedReportListItem extends PropertysetItem implements Comparable { + + private static final long serialVersionUID = 1L; + + public SavedReportListItem(HistoricProcessInstance historicProcessInstance) { + addItemProperty("id", new ObjectProperty(historicProcessInstance.getId(), String.class)); + addItemProperty("name", getNameProperty(historicProcessInstance)); + + if(historicProcessInstance.getEndTime() == null) { + throw new ActivitiIllegalArgumentException("The given process-instance is not ended yet"); + } + addItemProperty("createTime", new ObjectProperty(historicProcessInstance.getEndTime(), Date.class)); + } + + public int compareTo(SavedReportListItem other) { + Date createTime = (Date) getItemProperty("createTime"); + Date otherCreateTime = (Date) other.getItemProperty("createTime"); + + return createTime.compareTo(otherCreateTime); + } + + protected Property getNameProperty(HistoricProcessInstance historicProcessInstance) { + return new ObjectProperty(getReportDisplayName(historicProcessInstance), String.class); + } + + public static String getReportDisplayName(HistoricProcessInstance historicProcessInstance) { + if(historicProcessInstance.getBusinessKey() != null && !historicProcessInstance.getBusinessKey().isEmpty()) { + if(Authentication.getAuthenticatedUserId() != null) { + return historicProcessInstance.getBusinessKey().replaceFirst(Authentication.getAuthenticatedUserId() + "\\_", ""); + } else { + return historicProcessInstance.getBusinessKey(); + } + } else { + return DateFormat.getDateTimeInstance().format(historicProcessInstance.getEndTime()); + } + } +} \ No newline at end of file diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/SavedReportsListQuery.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/SavedReportsListQuery.java new file mode 100644 index 0000000000000000000000000000000000000000..a8810d2b6c1de08c01e80e4fb85f1d84b86f2f4a --- /dev/null +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/SavedReportsListQuery.java @@ -0,0 +1,72 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.activiti.explorer.ui.reports; + +import java.util.ArrayList; +import java.util.List; + +import org.activiti.engine.HistoryService; +import org.activiti.engine.ProcessEngines; +import org.activiti.engine.history.HistoricProcessInstance; +import org.activiti.engine.history.HistoricProcessInstanceQuery; +import org.activiti.explorer.data.AbstractLazyLoadingQuery; + +import com.vaadin.data.Item; + + +/** + * @author Frederik Heremans + */ +public class SavedReportsListQuery extends AbstractLazyLoadingQuery { + + private static final long serialVersionUID = -7865037930384885968L; + + protected transient HistoryService historyService; + + public SavedReportsListQuery() { + this.historyService = ProcessEngines.getDefaultProcessEngine().getHistoryService(); + } + + public int size() { + return (int) createQuery().count(); + } + + public List loadItems(int start, int count) { + List processInstances = createQuery().listPage(start, count); + + List reportItems = new ArrayList(); + for (HistoricProcessInstance instance : processInstances) { + reportItems.add(new SavedReportListItem(instance)); + } + + return reportItems; + } + + protected HistoricProcessInstanceQuery createQuery() { + // TODO: Add additional "processDefinitionCategory" on HistoricProcessInstanceQuery instead of + // using variables to find all completed reports. This is more robust and performant + return historyService.createHistoricProcessInstanceQuery() + .finished() + .variableValueNotEquals("reportData", null); + } + + public Item loadSingleResult(String id) { + return new SavedReportListItem(historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult()); + } + + public void setSorting(Object[] propertyIds, boolean[] ascending) { + throw new UnsupportedOperationException(); + } + +} diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/SavedReportsPage.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/SavedReportsPage.java new file mode 100644 index 0000000000000000000000000000000000000000..52540619cf6e65452dc9b89afba5b9624cd72d65 --- /dev/null +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/reports/SavedReportsPage.java @@ -0,0 +1,88 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.activiti.explorer.ui.reports; + +import org.activiti.explorer.ExplorerApp; +import org.activiti.explorer.data.LazyLoadingContainer; +import org.activiti.explorer.data.LazyLoadingQuery; +import org.activiti.explorer.navigation.SavedReportNavigator; +import org.activiti.explorer.navigation.UriFragment; +import org.activiti.explorer.ui.AbstractTablePage; +import org.activiti.explorer.ui.Images; +import org.activiti.explorer.ui.custom.ToolBar; +import org.activiti.explorer.ui.util.ThemeImageColumnGenerator; + +import com.vaadin.data.Item; +import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.ui.Table; + + +/** + * @author Frederik Heremans + */ +public class SavedReportsPage extends AbstractTablePage { + + private static final long serialVersionUID = -5259331126409002997L; + + protected Table reportTable; + protected LazyLoadingQuery reportListQuery; + protected LazyLoadingContainer reportListContainer; + + + protected Table createList() { + reportTable = new Table(); + reportListQuery = new SavedReportsListQuery(); + reportListContainer = new LazyLoadingContainer(reportListQuery); + reportTable.setContainerDataSource(reportListContainer); + + // Column headers + reportTable.addGeneratedColumn("icon", new ThemeImageColumnGenerator(Images.REPORT_22)); + reportTable.setColumnWidth("icon", 22); + + reportTable.addContainerProperty("name", String.class, null); + reportTable.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN); + + + // Listener to change right panel when clicked on a report + reportTable.addListener(new Property.ValueChangeListener() { + + private static final long serialVersionUID = 1L; + + public void valueChange(ValueChangeEvent event) { + Item item = reportTable.getItem(event.getProperty().getValue()); // the value of the property is the itemId of the table entry + if (item != null) { + String historicProcessInstanceId = (String) item.getItemProperty("id").getValue(); + setDetailComponent(new SavedReportDetailPanel(historicProcessInstanceId)); + + // Update URL + ExplorerApp.get().setCurrentUriFragment( + new UriFragment(SavedReportNavigator.SAVED_REPORT_URI_PART, historicProcessInstanceId)); + + } else { + // Nothing selected + setDetailComponent(null); + ExplorerApp.get().setCurrentUriFragment(new UriFragment(SavedReportNavigator.SAVED_REPORT_URI_PART)); + } + } + + }); + + return reportTable; + } + + protected ToolBar createMenuBar() { + return new ReportsMenuBar(); + } + +} diff --git a/modules/activiti-explorer/src/main/resources/messages.properties b/modules/activiti-explorer/src/main/resources/messages.properties index 99f1b3cd74164353a4ae34b6d4af2cb3fa71c0af..696408ff2d397877258535092c6c46b7dcf902e3 100644 --- a/modules/activiti-explorer/src/main/resources/messages.properties +++ b/modules/activiti-explorer/src/main/resources/messages.properties @@ -269,6 +269,7 @@ reporting.save.popup.name = Name reporting.save.popup.name.exists = Invalid name: a report with this name already exists reporting.save.popup.name.too.long = Invalid name: name is too long reporting.save.popup.name.empty = Name must be provided +reporting.report.created = Created: {0} # Management menu management.menu.database = Database