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
PortalTemplateas 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
PortalStartprocess fromPortalTemplateto 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
PortalCasesHTML dialog.Tip
This action overrides
Case widgetin: 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
extendSortmethod 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
getDefaultColumnsof 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/inPortalStyleor override methodgetColumnLabel(see the methods’ Javadoc comments)In
caseListHeadersection, useCaseColumnHeadercomponentIn
caseHeadersection, useCaseCustomFieldcomponent 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 namewhich 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
InitializeCaseDataModelcallable 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
caseFiltersection inPortalCases.xhtmlof 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 onXicon.Filter
validate()is called when click onApplybutton.

Introduce a java class extends CaseFilterContainer. This filter container contains your filters, you can reuse default filters, refer to
DefaultCaseFilterContainer.javaTip
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
initFilterContainermethod and initialize filter container (see javadoc comments)Use Axon Ivy Override to override the
InitializeCaseDataModelcallable 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@JsonIgnoreto 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 (extendsCaseLazyDataModelclass).By default, filters are stored/restored in process model level. You can change this by setting the ui:param
filterGroupIdinPortalCases.xhtmlto a new Long value.Tip
If you have multiple case lists in your project, you may want to set
filterGroupIdto an unique identifier for each of yourPortalCases.xhtmlacross 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
OpenPortalCasescallable process with theCaseViewparameter. 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
getColumnNamemethod.
@Override protected String getColumnName(String column) { String columnName = getSpecialColumnName(column); return columnName != null ? columnName : Ivy.cms().co("/DefaultColumns/caseList/" + column); }
Override the
getColumnValuemethod.
@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"> <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"> <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
CaseCustomFieldcomponent 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-menuto 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 "> <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 "> <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.