Case widget
CaseWidget is a built-in component of Portal which contains the cases which users can interact with. In order to show needed case’s information, Portal supports overriding concept for CaseWidget. Each CaseWidget contains 2 parts:
UI : CaseListHeader, CaseHeader and CaseFilter
Data query : display the cases as you want by modifying data query
Important
Case header customization currently support responsive design. Refer to this part for more detail.
Case header’s buttons cannot be modified (they stay where they are)
How to override case widget’s UI
Refer to portal-developer-examples
project for examples
Introduce an Axon Ivy project which has
PortalTemplate
as a required library.To customize case widget, you must customize Portal Home first. Refer to Customize Portal home to set new home page.
Copy the
PortalStart
process fromPortalTemplate
to your project. Point PortalHome element to your custom home page in previous step. This process is new home page and administrator should register this link by Portal’s Admin Settings.Use Axon Ivy HtmlOverride wizard to override
PortalCases
HTML dialog.Tip
This action overrides
Case widget
in: CaseList page, Case Search result.After previous steps, you can override CaseHeader and CaseListHeader and CaseFilter
Case List Header and Case Header
Refer to the caseListHeader (1)
and caseHeader (2)
sections in
PortalCases.xhtml
of PortalTemplate. In case your case widget has
new columns, you should override CaseLazyDataModel to make the sort
function of these columns work:
Introduce a java class extends CaseLazyDataModel
Override the
extendSort
method and extend the sort function for the added columns (see the method’s Javadoc comments)Default caseList supports user to config display/hide column:
Custom SortFields (1)
,Custom Checkboxes (2)
andCustom header column (3)
.In case you have new columns, override method
getDefaultColumns
of the extended class from CaseLazyDataModel to display checkboxes in Config columns panel and display/hide sortFields (see the methods’ Javadoc comments)To add cms for checkboxes’s label, add new entries to folder
/ch.ivy.addon.portalkit.ui.jsf/caseList/defaultColumns/
inPortalStyle
or override methodgetColumnLabel
(see the methods’ Javadoc comments)In
caseListHeader
section, useCaseColumnHeader
componentIn
caseHeader
section, useCaseCustomField
component for each additional column. This component will handle display/hide new columns on case list.Currently, CaseCustomField only supports text field. If you want to create your own component, remember to add
rendered="#{caseView.dataModel.isSelectedColumn('YOUR_CUSTOM_COLUMN')}"
For example: Show custom field
customer name
which stored incase.customVarCharField1
<ic:ch.ivy.addon.portalkit.component.cases.column.CaseCustomField id="case-customer-name-component" panelGroupId="customVarCharField1-column-case-header-panel" componentId="customVarCharField1-column-case-header-text" column="customVarCharField1" dataModel="#{caseView.dataModel}" labelValue="#{case.customVarCharField1}" />
Use Axon Ivy Override to override the
InitializeCaseDataModel
callable and initialize data model by your customized one.In your customized Portal cases HTMLDialog, the customized data model should be passed as a parameter to components (refer to
PortalCases.xhtml
).
Case filter
Refer to the
caseFilter
section inPortalCases.xhtml
of PortalTemplate.In order to introduce new filter, create a new java class extends CaseFilter and override its methods (see javadoc comments)
Filter
label()
andvalue()
method.Filter
resetValue()
is called when click onX
icon.Filter
validate()
is called when click onApply
button.
Introduce a java class extends CaseFilterContainer. This filter container contains your filters, you can reuse default filters, refer to
DefaultCaseFilterContainer.java
Tip
StateFilter is added as default to container. If you don’t need it, use this code in constructor:
filters.remove(stateFilter);
Introduce a java class extends CaseLazyDataModel. Override the
initFilterContainer
method and initialize filter container (see javadoc comments)Use Axon Ivy Override to override the
InitializeCaseDataModel
callable and initialize data model by your customized one.In your customized Portal cases HTMLDialog, the customized data model and filter container should be passed as parameters to components (refer to
PortalCases.xhtml
).Portal supports storing/restoring filters. Your filter class (extends
CaseFilter
) is stored in business data. Properties stored user input values should be persisted, properties controlled logic should not be persisted to reduce persisted data size in business data. Use annotation@JsonIgnore
to exclude properties. By default, Portal takes care storing/restoring filters. If you want to customize storing/restoring filter data, do it in your data model class (extendsCaseLazyDataModel
class).By default, filters are stored/restored in process model level. You can change this by setting the ui:param
filterGroupId
inPortalCases.xhtml
to a new Long value.Tip
If you have multiple case lists in your project, you may want to set
filterGroupId
to an unique identifier for each of yourPortalCases.xhtml
across your projects
How to override case widget’s data query
Override the BuildCaseQuery
callable process of PortalKit and build
your own query to effect the data of case widget.
Apply the following steps in case you would like to provide data for case list after navigating to case list from your page:
Use the
OpenPortalCases
callable process with theCaseView
parameter. It is used to define which information are displayed in CaseWidget.Refer to CaseView, CaseSearchCriteria to build your CaseView
CaseLazyDataModel dataModel = new CaseLazyDataModel(); dataModel.getCriteria().setCustomCaseQuery(YOUR_CASE_QUERY); // Set your CaseQuery dataModel.getCriteria().setAdminQuery(true); // Display the cases of all users out.caseView = CaseView.create().dataModel(dataModel) .withTitle("My Cases").buildNewView();
How to override export feature
Extend the CaseExporter java class of PortalKit.
Override the
getColumnName
method.
@Override protected String getColumnName(String column) { String columnName = getSpecialColumnName(column); return columnName != null ? columnName : Ivy.cms().co("/DefaultColumns/caseList/" + column); }
Override the
getColumnValue
method.
@Override protected Object getColumnValue(String column, ICase caseItem) { switch (column) { case CustomizedCaseLazyDataModel.CUSTOM_VARCHAR_FIELD1: return caseItem.customFields().stringField(CustomFields.CUSTOM_VARCHAR_FIELD1).getOrNull(); case CustomizedCaseLazyDataModel.CUSTOM_TIMESTAMP_FIELD1: return caseItem.customFields().timestampField(CustomFields.CUSTOM_TIMESTAMP_FIELD1).getOrNull(); default: return getCommonColumnValue(column, caseItem); } }
Override the ExportCaseToExcel callable process and apply your extended CaseExporter java class.
CaseExporter exporter = new CustomizedCaseExporter(in.columnsVisibility); in.exportedFile = exporter.getStreamedContent(in.collectedCasesForExporting);
How to make responsive case list
If you have customized case list and want it responsive on different screen sizes, please follow below steps.
You can refer to portal-developer-examples
project for examples
Add responsiveStyleClass param (in case you’re using Portal component), or styleClass (in case you’re using Primefaces or JSF component) with the same responsive css class for both caseListHeader and caseHeader. You can find responsive class in this part.
<!-- New field --> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseColumnHeader id="customVarCharField1-column-header" styleClass="TexAlCenter customized-case-header-column" responsiveStyleClass="u-hidden-lg-down js-hidden-when-expand-menu" value="#{ivy.cms.co('/DefaultColumns/caseList/customVarCharField1')}" sortedField="customVarCharField1" sortable="true" dataModel="#{caseView.dataModel}" /> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseColumnHeader id="customTimestampField1-column-header" styleClass="TexAlCenter customized-case-header-column" responsiveStyleClass="u-hidden-lg-down js-hidden-when-expand-menu " value="#{ivy.cms.co('/DefaultColumns/caseList/customTimestampField1')}" sortedField="customTimestampField1" sortable="true" dataModel="#{caseView.dataModel}" /> </ui:define> <ui:define name="caseHeader"> <div class="case-header-name-desc-cell u-truncate-text"> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseName caseNameId="case-header-name-cell" caseDescriptionId="description-cell" case="#{case}" dataModel="#{caseView.getDataModel()}" /> </div> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseId componentId="case-id-cell" case="#{case}" dataModel="#{caseView.getDataModel()}" /> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseCreator componentId="case-creator-cell" case="#{case}" dataModel="#{caseView.getDataModel()}" /> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseDate componentId="case-creation-date-cell" rendered="#{caseView.dataModel.isSelectedColumn('CREATION_TIME')}" value="#{case.startTimestamp}" /> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseDate componentId="case-expiry-date-cell" rendered="#{caseView.dataModel.isSelectedColumn('FINISHED_TIME')}" value="#{case.endTimestamp}" responsiveStyleClass="js-hidden-when-expand-menu u-hidden-md-down" /> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseState componentId="case-state-cell" case="#{case}" dataModel="#{caseView.getDataModel()}" /> <!-- New field --> <h:panelGroup styleClass="customized-case-header-column js-hidden-when-expand-menu u-hidden-lg-down" rendered="#{caseView.dataModel.isSelectedColumn('customVarCharField1')}"> <h:outputText value="#{case.customFields().stringField('CustomVarCharField1').getOrNull()}" styleClass="case-header-default-cell customized-case-header-column" /> </h:panelGroup> <h:panelGroup styleClass="customized-case-header-column js-hidden-when-expand-menu u-hidden-lg-down" rendered="#{caseView.dataModel.isSelectedColumn('customTimestampField1')}"> <h:outputText value="#{case.customFields().timestampField('CustomTimestampField1').getOrNull()}" styleClass="case-header-default-cell"> <f:convertDateTime pattern="#{dateTimePatternBean.configuredPattern}" /> </h:outputText> </h:panelGroup> </ui:define>
Tip
CaseCustomField
component has default responsiveStyleClass isu-hidden-sm-down
Responsiveness could be broken when you anchor left menu. In this case, to maintain the responsiveness, you could hide some columns by add
js-hidden-when-expand-menu
to responsiveStyleClass or styleClass param of caseListHeader and caseHeader.<!-- New field --> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseColumnHeader id="customVarCharField1-column-header" styleClass="TexAlCenter customized-case-header-column" responsiveStyleClass="u-hidden-lg-down js-hidden-when-expand-menu" value="#{ivy.cms.co('/DefaultColumns/caseList/customVarCharField1')}" sortedField="customVarCharField1" sortable="true" dataModel="#{caseView.dataModel}" /> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseColumnHeader id="customTimestampField1-column-header" styleClass="TexAlCenter customized-case-header-column" responsiveStyleClass="u-hidden-lg-down js-hidden-when-expand-menu " value="#{ivy.cms.co('/DefaultColumns/caseList/customTimestampField1')}" sortedField="customTimestampField1" sortable="true" dataModel="#{caseView.dataModel}" /> </ui:define> <ui:define name="caseHeader"> <div class="case-header-name-desc-cell u-truncate-text"> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseName caseNameId="case-header-name-cell" caseDescriptionId="description-cell" case="#{case}" dataModel="#{caseView.getDataModel()}" /> </div> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseId componentId="case-id-cell" case="#{case}" dataModel="#{caseView.getDataModel()}" /> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseCreator componentId="case-creator-cell" case="#{case}" dataModel="#{caseView.getDataModel()}" /> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseDate componentId="case-creation-date-cell" rendered="#{caseView.dataModel.isSelectedColumn('CREATION_TIME')}" value="#{case.startTimestamp}" /> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseDate componentId="case-expiry-date-cell" rendered="#{caseView.dataModel.isSelectedColumn('FINISHED_TIME')}" value="#{case.endTimestamp}" responsiveStyleClass="js-hidden-when-expand-menu u-hidden-md-down" /> <ic:ch.ivy.addon.portalkit.component.cases.column.CaseState componentId="case-state-cell" case="#{case}" dataModel="#{caseView.getDataModel()}" /> <!-- New field --> <h:panelGroup styleClass="customized-case-header-column u-hidden-lg-down js-hidden-when-expand-menu " rendered="#{caseView.dataModel.isSelectedColumn('customVarCharField1')}"> <h:outputText value="#{case.customFields().stringField('CustomVarCharField1').getOrNull()}" styleClass="case-header-default-cell customized-case-header-column" /> </h:panelGroup> <h:panelGroup styleClass="customized-case-header-column u-hidden-lg-down js-hidden-when-expand-menu " rendered="#{caseView.dataModel.isSelectedColumn('customTimestampField1')}"> <h:outputText value="#{case.customFields().timestampField('CustomTimestampField1').getOrNull()}" styleClass="case-header-default-cell"> <f:convertDateTime pattern="#{dateTimePatternBean.configuredPattern}" /> </h:outputText> </h:panelGroup> </ui:define>
Tip
The smallest browser width you can anchor the left menu is 1025. So you could reduce width of browser to 1025 to test and decide which columns need to be hidden.