Operational Dashboard - Changes & Fixes

This page covers the changes and fixes provided to Operational Dashboard for IPF Release 2025.4.0

NPM Package Versions

Remove the following packages

The following packages have been removed and must be uninstalled:

npm uninstall @iconsolutions/audit @iconsolutions/htm @iconsolutions/ods @iconsolutions/ods-api

Install/Update the following packages

Update your package.json with the following npm package versions for IPF 2025.4.0. Note that @iconsolutions/ipf-operational-dashboard and @iconsolutions/ipf-operations are new packages that replace the packages removed above:

"@iconsolutions/common": "2025.4.5",
"@iconsolutions/htm-api": "2025.4.0",
"@iconsolutions/htm-bulk-api": "2025.4.0",
"@iconsolutions/ipf-operational-dashboard": "2025.4.5",
"@iconsolutions/ipf-operations": "2025.4.5",
"@iconsolutions/ods-gui-api": "2025.4.0",
"@iconsolutions/processing-settings": "2025.4.5",
"@iconsolutions/processing-settings-api": "2025.4.0",

Breaking Changes

Module Restructure

Remove all existing IPF routes excluding processing-settings, making sure to keep any of your own defined routes: e.g:(PAY-14560)

Old Configuration

import { Route } from '@angular/router';
import {
    AppHomeComponent,
    HomeComponent,
    LoginComponent,
    ProcessingEntityGuard,
    RoleGuard
} from '@iconsolutions/common';

export const appRoutes: Route[] = [
    { path: '', redirectTo: 'app', pathMatch: 'full' },
    { path: 'login', component: LoginComponent },
    {
        path: 'app',
        canActivate: [ProcessingEntityGuard],
        component: AppHomeComponent
    },
    {
        path: 'app/:processingEntityId',
        canActivate: [ProcessingEntityGuard],
        children: [
            {
                path: 'home',
                component: HomeComponent
            },
            {
                path: 'ods',
                data: { roles: ['ROLE_PAYMENT'] },
                canActivate: [RoleGuard],
                loadChildren: () => import('@iconsolutions/ods').then((m) => m.OdsModule)
            },
            {
                path: 'version-info',
                loadChildren: () => import('@iconsolutions/version-info').then((m) => m.VersionInfoModule)
            },
            {
                path: 'cluster-health',
                loadChildren: () => import('@iconsolutions/cluster-health').then((m) => m.ClusterHealthModule)
            },
            {
                path: 'processing-settings',
                loadChildren: () => import('@iconsolutions/processing-settings').then((m) => m.ProcessingSettingsModule)
            },
            {
                path: 'audit',
                canActivate: [RoleGuard],
                data: { roles: ['ROLE_AUDIT'] },
                loadChildren: () => import('@iconsolutions/audit').then((m) => m.AuditModule)
            },
            {
                path: 'metrics',
                canActivate: [RoleGuard],
                data: { roles: ['ROLE_METRICS'] },
                loadChildren: () => import('@iconsolutions/metrics').then((m) => m.MetricsModule)
            },
            {
                path: 'permissions',
                loadComponent: () => import('@iconsolutions/permissions').then((m) => m.PermissionsComponent)
            },
            {
                path: 'htm',
                loadChildren: () => import('@iconsolutions/htm').then((m) => m.HtmModule)
            }
        ]
    }
];

New Configuration (from this release)

import { Route } from '@angular/router';
import { ProcessingEntityGuard } from '@iconsolutions/common';

export const appRoutes: Route[] = [
    {
        path: 'app/:processingEntityId',
        canActivate: [ProcessingEntityGuard],
        children: [
            {
                path: 'processing-settings',
                loadChildren: () => import('@iconsolutions/processing-settings').then((m) => m.ProcessingSettingsModule)
            }
        ]
    }
];

Add IpfOperationalDashboardModule and IpfOperationsModule to your main module imports (most likely app.module.ts).

Remove the following npm dependencies:

    "@iconsolutions/audit": "189.3.3",
    "@iconsolutions/cluster-health": "189.3.3",
    "@iconsolutions/htm": "189.3.3",
    "@iconsolutions/metrics": "189.3.3",
    "@iconsolutions/ods": "189.3.3",
    "@iconsolutions/permissions": "189.3.3",
    "@iconsolutions/version-info": "189.3.3",

Then install the following npm dependencies:

npm i @iconsolutions/ipf-operational-dashboard
npm i @iconsolutions/ipf-operations

ODS Config Consolidation Per Journey Type

This release introduces a breaking change to the ODS module configuration structure. The configuration has been refactored to organize properties per journey type, providing better flexibility and maintainability.(PAY-14230)

Summary of Changes

  1. Properties are now organized per journey type: The following properties are now structured as maps keyed by journey type:

    • Search forms (search-form)

    • Table columns (table-columns)

    • Global statuses (global-statuses)

    • Date types (date-types)

    • Amount types (amount-types)

    • Alternative identifiers (alternative-identifiers)

    • Transaction types (transaction-types)

    • Details defaults (details-defaults)

  2. Removed default fallbacks: The default lists of amount types and date types have been removed. Each journey type must now define all required properties explicitly. There are no default fallback values.

Migration Steps

Complete Example Configuration

Here’s a complete example showing the new updated structure:

ipf.business-operations.payment-search {
  # Top-level property
  ods-page-results {
    size = 1000
  }

  # Top-level shared property
  system-event-names = [
    "ActionInvoked",
    "ActionRetriesExhausted",
    "ActionTimeout",
    # ... (full list)
  ]

  journeys {
    payment {
      alternative-identifiers = [
        {
          searchBy: "CLIENT_REQUEST_ID",
          displayName: "Client Request ID"
        }
      ]

      transaction-types = ["Credit", "Debit"]

      details-defaults {
        showGraphs = true
        flows {
          opened = "latest"
          sort = "asc"
        }
        events {
          opened = "all"
          sort = "asc"
        }
      }

      search-form {
        searchType: "payment"
        formSections: [
          # ... form sections
        ]
      }

      table-columns = [
        # ... column definitions
      ]

      global-statuses = [
        {
          name: "PENDING",
          category: "PENDING"
        },
        # ... more statuses
      ]

      date-types = [
        "CREATED_AT",
        "INSTRUCTION_RECEIVED_AT",
        "EXECUTION_STARTED_AT",
        "SETTLEMENT_COMPLETED_AT",
        "ACCEPTANCE_DATE_TIME",
        "INTERBANK_SETTLEMENT_DATE",
        "REQUESTED_EXECUTION_DATE"
      ]

      amount-types = [
        "INSTRUCTED",
        "TRANSACTION",
        "CREDIT",
        "DEBIT",
        "CONVERTED"
      ]
    }

    # Repeat for recall, bulk, batch...
  }
}
Step 1: Keep shared properties at the top level

Keep ods-page-results and system-event-names at the top of your configuration, outside of the journeys object. These are shared properties that apply to all journey types.

ipf.business-operations.payment-search {
  ods-page-results {
    size = 1000
  }

  system-event-names = [
    "ActionInvoked",
    "ActionRetriesExhausted",
    # ... (full list)
  ]

  journeys {
    # Journey-specific configuration goes here
  }
}
Step 2: Create the journeys object structure

Add a journeys object to your configuration, and create an object for each journey type (e.g., payment, recall, bulk, batch) inside the journeys object.

ipf.business-operations.payment-search {
  journeys {
    payment {
      # Journey-specific configuration goes here
    }
    recall {
      # Journey-specific configuration goes here
    }
    bulk {
      # Journey-specific configuration goes here
    }
    batch {
      # Journey-specific configuration goes here
    }
  }
}
Step 3: Remove any default lists you may have for amount types or date types, and add these lists for each of the journey types.
Step 4: Add Journey-Specific Properties to Each Journey Type

Add the following properties to each journey type:

Search Form
search-form {
  searchType: "payment"
  formSections: [
    {
      sectionName: "Basic Search"
      fields: [
        {
          fieldName: "paymentId"
          displayName: "Payment ID"
          fieldType: "text"
        }
      ]
    }
  ]
}
Table Columns
table-columns = [
  {
    columnName: "paymentId"
    displayName: "Payment ID"
    sortable: true
  },
  {
    columnName: "status"
    displayName: "Status"
    sortable: true
  }
]
Global Statuses
global-statuses = [
  {
    name: "PENDING"
    category: "PENDING"
  },
  {
    name: "COMPLETED"
    category: "COMPLETED"
  },
  {
    name: "FAILED"
    category: "FAILED"
  }
]
Date Types
date-types = [
  "CREATED_AT",
  "INSTRUCTION_RECEIVED_AT",
  "EXECUTION_STARTED_AT",
  "SETTLEMENT_COMPLETED_AT",
  "ACCEPTANCE_DATE_TIME",
  "INTERBANK_SETTLEMENT_DATE",
  "REQUESTED_EXECUTION_DATE"
]
Amount Types
amount-types = [
  "INSTRUCTED",
  "TRANSACTION",
  "CREDIT",
  "DEBIT",
  "CONVERTED"
]
Alternative Identifiers
alternative-identifiers = [
  {
    searchBy: "CLIENT_REQUEST_ID",
    displayName: "Client Request ID"
  }
]
Transaction Types
transaction-types = ["Credit", "Debit"]
Details Defaults
details-defaults {
  showGraphs = true
  flows {
    opened = "latest"
    sort = "asc"
  }
  events {
    opened = "all"
    sort = "asc"
  }
}

So your configuration for a journey type should look like this:

ipf.business-operations.payment-search {
  ods-page-results {
    size = 1000
  }

  system-event-names = [
    "ActionInvoked",
    "ActionRetriesExhausted",
    "ActionTimeout",
    # ... (full list)
  ]

  journeys {
    payment {
      alternative-identifiers = [
        {
          searchBy: "CLIENT_REQUEST_ID",
          displayName: "Client Request ID"
        }
      ]

      transaction-types = ["Credit", "Debit"]

      details-defaults {
        showGraphs = true
        flows {
          opened = "latest"
          sort = "asc"
        }
        events {
          opened = "all"
          sort = "asc"
        }
      }

      search-form {
        searchType: "payment"
        formSections: [
          # ... form sections
        ]
      }

      table-columns = [
        # ... column definitions
      ]

      global-statuses = [
        {
          name: "PENDING",
          category: "PENDING"
        },
        # ... more statuses
      ]

      date-types = [
        "CREATED_AT",
        "INSTRUCTION_RECEIVED_AT",
        "EXECUTION_STARTED_AT",
        "SETTLEMENT_COMPLETED_AT",
        "ACCEPTANCE_DATE_TIME",
        "INTERBANK_SETTLEMENT_DATE",
        "REQUESTED_EXECUTION_DATE"
      ]

      amount-types = [
        "INSTRUCTED",
        "TRANSACTION",
        "CREDIT",
        "DEBIT",
        "CONVERTED"
      ]
    }

    # Repeat for recall, bulk, batch...
  }
}

Custom Journey Types

The new structure fully supports custom journey types. To add a custom journey type add a new entry to the journeys map with all required properties:

ipf.business-operations.payment-search {
    ods-page-results {
        size = 1000
    }

  system-event-names = [...]

  journeys {
    payment { ... }
    recall { ... }
    bulk { ... }
    batch { ... }

    # Custom journey type
    sepa-instant {
      alternative-identifiers = [...]
      transaction-types = [...]
      details-defaults {...}
      search-form {...}
      table-columns = [...]
      global-statuses = [...]
      date-types = [...]
      amount-types = [...]
    }
  }
}

Table Column Configuration

If you have any configuration for payment-columns, recall-columns, bulk-columns or batch-columns then you need to update your configuration. You will need to set the journey configurations to be part of table-columns within each journey type, change columnName to name and provide a type.

For full configuration details see IPF Operational Dashboard ODS module.

Old Configuration: An array of objects at the top level:

payment-columns = [
  {
    columnName: "createdAt"
  },
  {
    columnName: "transactionType"
  },
  {
    columnName: "debtor"
  },
  {
    columnName: "amount"
  }
]

New Configuration: Table columns are now defined within each journey type with required name and type properties:

journeys {
  payment {
    table-columns = [
      {
        name: "createdAt",
        type: "DATETIME"
      },
      {
        name: "transactionType",
        type: "STRING"
      },
      {
        name: "debtor",
        type: "STRING",
        paths: ["debtorName", "debtorAccount", "debtorBic", "debtorAgentBic"]
      },
      {
        name: "amount",
        type: "PRE_DEFINED"
      }
    ]
  }

  recall {
    table-columns = [
      {
        name: "createdAt",
        type: "DATETIME"
      },
      {
        name: "agentDetails",
        type: "PRE_DEFINED"
      },
      {
        name: "reasonCode",
        type: "STRING"
      }
    ]
  }

  newJourney {
    table-columns = [
      {
        name: "createdAt",
        type: "DATETIME"
      },
      {
        name: "unitOfWorkdId",
        type: "STRING"
      }
    ]
  }
}

All column objects must provide a name and type. paths is optional; if not provided, the name is used by default.

Additionally, if there is no value provided for the table columns for a journey, then the following default will be used:

{
  name: "unitOfWorkdId",
  type: "STRING"
}
Name

The name value should be a unique name that will be correlated with the translation sheet to provide a column header for the frontend. It is also used as a fallback value if paths is not defined for that column.

Paths

The paths attribute accepts an array of strings, where the value correlates to the path within the object that is expected. If the path isn’t provided, the name will be used as default.

e.g. for an object like below:

{
  "createdAt": "01/01/2025",
  "field1": "value1",
  "field2": "value2",
  "object1": {
    "field3": "value3"
  }
}

The paths property:

paths: ["createdAt"]

Will get the value ["01/01/2025"]

And the paths property:

paths: ["field1", "object1.field3"]

Will get the value ["value1", "value3"]. Each of the string values will be separated by a line break in the table.

Type

There are six types you can choose from:

STRING

A standard text value

NUMBER

A standard number value

CURRENCY

A value that will be formatted to a currency value

DATE

A value that will be formatted to date and show date only

DATETIME

A value that will be formatted to date and include time

PRE_DEFINED

An inbuilt column definition that will handle more complicated columns (see definitions)

For the PRE_DEFINED columns, you can use these by providing both the type and the appropriate name.

Name

Description

Notes

amount

This will display transactionAmount, instructedAmount, convertedTransactionAmount or originalInterbankSettlementAmount, returnedInterbankSettlementAmount, convertedTransactionAmount depending on the journey type

It will also display an appropriate tooltip

bankingAccount

This will display debitAccount and creditAccount with prefixes

totalInterbankSettlementAmount

This will display totalInterbankSettlementAmount with totalInterbankSettlementAmountCurrency for the currency

agentDetails

This will display instructingAgent and instructedAgent

It will also display with a prefix of 'Instructing' and 'Instructed'

Global Status Configuration

We have also made some changes to how the global status configuration is defined. Global statuses are now defined within each journey type in the journeys object. This means that you can add custom global statuses for each of the different journey types independently.

Before: A single array at the top level:

global-statuses = [
  {
    name: "Pending",
    category: "PENDING"
  },
  {
    name: "Accepted",
    category: "ACCEPTED"
  },
  {
    name: "Completed",
    category: "ACCEPTED"
  },
  {
    name: "Rejected",
    category: "REJECTED"
  },
  {
    name: "Manual Action Required",
    category: "MANUAL_ACTION_REQUIRED"
  },
  {
    name: "Scheduled",
    category: "SCHEDULED"
  },
  {
    name: "Cancelled",
    category: "CANCELLED"
  }
]

After: Global statuses are defined within each journey type:

journeys {
  payment {
    global-statuses = [
      {
        name: "Pending",
        category: "PENDING"
      },
      {
        name: "Accepted",
        category: "ACCEPTED"
      },
      {
        name: "Completed",
        category: "ACCEPTED"
      }
    ]

    # ... other payment configuration
  }

  recall {
    global-statuses = [
      {
        name: "Pending",
        category: "PENDING"
      },
      {
        name: "Accepted",
        category: "ACCEPTED"
      },
      {
        name: "Scheduled",
        category: "SCHEDULED"
      },
      {
        name: "Cancelled",
        category: "CANCELLED"
      }
    ]

    # ... other recall configuration
  }

  bulk {
    global-statuses = [
      {
        name: "Rejected",
        category: "REJECTED"
      },
      {
        name: "Manual Action Required",
        category: "MANUAL_ACTION_REQUIRED"
      },
      {
        name: "Scheduled",
        category: "SCHEDULED"
      },
      {
        name: "Cancelled",
        category: "CANCELLED"
      }
    ]

    # ... other bulk configuration
  }

  batch {
    global-statuses = [
      {
        name: "Pending",
        category: "PENDING"
      },
      {
        name: "Accepted",
        category: "ACCEPTED"
      },
      {
        name: "Completed",
        category: "ACCEPTED"
      },
      {
        name: "Rejected",
        category: "REJECTED"
      },
      {
        name: "Cancelled",
        category: "CANCELLED"
      }
    ]

    # ... other batch configuration
  }
}