Skip to content

Commit 95bf0a0

Browse files
authored
Merge branch 'develop' into copilot/fix-login-page-title-issue
2 parents bb48bc1 + 70bf3be commit 95bf0a0

File tree

14 files changed

+560
-109
lines changed

14 files changed

+560
-109
lines changed

.github/workflows/publish-toolkit-to-npm.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,14 @@ jobs:
3838
run: |
3939
PACKAGE_VERSION=$(node -p "require('../../package.json').version")
4040
if [ "$GITHUB_REF_TYPE" = "tag" ]; then
41-
TOOLKIT_VERSION="$GITHUB_REF_NAME"
41+
TAG_NAME="$GITHUB_REF_NAME"
42+
if [[ "$TAG_NAME" =~ ([0-9]+)\.([0-9]+)\.([0-9]+)([-+][A-Za-z0-9.-]+)?$ ]]; then
43+
TOOLKIT_VERSION="${BASH_REMATCH[0]}"
44+
echo "✅ Using semantic version: $TOOLKIT_VERSION"
45+
else
46+
echo "❌ Tag '$TAG_NAME' is not a valid semantic version (expected something like 1.2.3 or v1.2.3)"
47+
exit 1
48+
fi
4249
else
4350
TOOLKIT_VERSION="$PACKAGE_VERSION-rc.$(git rev-parse --short=7 HEAD)"
4451
fi

CHANGELOG.md

Lines changed: 268 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Changelog
22

3-
## 1.9.1
3+
## 1.9.1 Release Candidate
44

55
### Breaking changes
66

@@ -21,10 +21,276 @@
2121
- `RECORD_REGISTRATION_VERIFY_CERTIFIED_COPIES`
2222
- `PROFILE_UPDATE`
2323

24-
## 1.9.0 Release candidate
24+
## [1.9.0](https://github.com/opencrvs/opencrvs-core/compare/v1.8.1...v1.9.0)
25+
26+
### Breaking changes
27+
28+
* Dashboard configuration through **Metabase** has been fully migrated to **countryconfig**, and the standalone dashboard package has been removed.
29+
For details on configuring dashboards and information about the latest updates, refer to the [ANALYTICS.md](https://github.com/opencrvs/opencrvs-countryconfig/blob/v1.9.0/ANALYTICS.md) documentation.
2530

2631
### New features
2732

33+
#### Events V2
34+
35+
We are excited to announce a major overhaul of our events system: **Events V2**.
36+
This is a complete rewrite that introduces a new level of flexibility and configurability to how life events are defined and managed across the system.
37+
38+
The new Events V2 architecture is built around a set of core concepts designed to make event management more powerful and customizable.
39+
40+
##### Events
41+
42+
An **Event** represents a life event (or any kind of event), such as a birth or a marriage.
43+
Each event is defined by a configuration that specifies the sequence of **Actions** required to register it.
44+
45+
##### Actions
46+
47+
###### Declaration Actions
48+
49+
Declaration actions are used to modify an event’s declaration.
50+
These actions must be executed in a defined order and cannot be skipped.
51+
52+
1. **DECLARE**
53+
2. **VALIDATE**
54+
3. **REGISTER**
55+
56+
Each action must be accepted by **countryconfig** before the next one can be performed.
57+
58+
59+
###### Rejecting and Archiving
60+
61+
After declaration, instead of proceeding with registration, an event may be either **rejected** or **archived**.
62+
63+
If **deduplication** is enabled for an action, performing that action may trigger a **DUPLICATE_DETECTED** action if duplicates are found.
64+
When this occurs, two additional actions become available:
65+
66+
* **MARK_AS_DUPLICATE** – archives the event.
67+
* **MARK_AS_NOT_DUPLICATE** – resumes the normal action flow.
68+
69+
If an event is rejected by a user, the preceding action must be repeated before continuing.
70+
71+
72+
###### Actions Before Declaration
73+
74+
1. **NOTIFY** – a partial version of the `DECLARE` action.
75+
2. **DELETE** – an event can be deleted only if no declaration action has yet been performed.
76+
77+
78+
###### Actions After Registration
79+
80+
Once an event has been registered, a certificate may be printed.
81+
If a correction is required due to an error in the registered declaration, a correction workflow must be initiated.
82+
83+
1. **PRINT_CERTIFICATE**
84+
2. **REQUEST_CORRECTION**
85+
3. **REJECT_CORRECTION**
86+
4. **APPROVE_CORRECTION**
87+
88+
89+
###### General / Meta Actions
90+
91+
1. **READ** – appended to the action trail whenever a complete event record is retrieved.
92+
2. **ASSIGN** – required before any action can be performed. By default, the user is automatically unassigned after completing an action.
93+
3. **UNASSIGN** – triggered either automatically by the system or manually by a user (if the record is assigned to themselves or if the user has the appropriate permission).
94+
95+
##### Forms, Pages, and Fields
96+
97+
Event data is collected through **Forms**, which come in two types:
98+
99+
* **Declaration Form** – collects data about the event itself
100+
* **Action Form** – collects data specific to a particular action, also known as annotation data in the system
101+
102+
Forms are composed of **Pages**, and pages are composed of **Fields**.
103+
Fields can be shown, hidden, or enabled dynamically based on the values of other fields, allowing for a responsive and intuitive user experience.
104+
105+
To simplify configuration, we’ve introduced a set of helper functions:
106+
107+
```ts
108+
defineDeclarationForm()
109+
defineActionForm()
110+
definePage()
111+
defineFormPage()
112+
```
113+
114+
All of these are available in a **type-safe** manner via the new `@opencrvs/toolkit` npm package.
115+
116+
##### Conditionals & Validation
117+
118+
Validation has been significantly improved through the adoption of **AJV** and **JSON Schema**, providing standardized, robust, and extensible validation.
119+
120+
The `field` function (exported from `@opencrvs/toolkit`) includes a set of helpers for defining complex validation rules and conditional logic.
121+
122+
##### Available helpers include:
123+
124+
* **Boolean connectors**: `and`, `or`, `not`
125+
* **Basic conditions**: `alwaysTrue`, `never`
126+
* **Comparisons**: `isAfter`, `isBefore`, `isGreaterThan`, `isLessThan`, `isBetween`, `isEqualTo`
127+
* **Field state checks**: `isFalsy`, `isUndefined`, `inArray`, `matches` (regex patterns)
128+
* **Age-specific helpers**: `asAge`, `asDob` (to compare age or date of birth)
129+
* **Nested fields**:
130+
131+
```ts
132+
field('parent.field.name').get('nested.field').isTruthy()
133+
```
134+
135+
The `user` object, also exported from `@opencrvs/toolkit`, includes helpers for user-based conditions such as:
136+
137+
```ts
138+
user.hasScope()
139+
user.hasRole()
140+
user.isOnline()
141+
```
142+
143+
These conditions can control:
144+
145+
* `SHOW` – whether a component is visible
146+
* `ENABLE` – whether a component is interactive
147+
* `DISPLAY_ON_REVIEW` – whether a field appears on review pages
148+
149+
They can also be used to validate form data dynamically based on the current form state or user context.
150+
151+
#### Drafts
152+
153+
The new **Drafts** feature allows users to save progress on an event that has not yet been registered.
154+
Drafts act as temporary storage for an action and are visible only to the user who created them.
155+
156+
#### Advanced Search
157+
158+
Advanced search is now configurable through the `EventConfig.advancedSearch` property, allowing different sections of an advanced search form to be defined.
159+
160+
You can search across:
161+
162+
* **Declaration Fields** – using the same `field` function from declaration forms with helpers such as `range`, `exact`, `fuzzy`, and `within`
163+
* **Event Metadata** – using the `event` function to search against metadata such as:
164+
165+
* `trackingId`
166+
* `status`
167+
* `legalStatuses.REGISTERED.acceptedAt`
168+
* `legalStatuses.REGISTERED.createdAtLocation`
169+
* `updatedAt`
170+
171+
More details about the metadata fields are available in `packages/commons/src/events/EventMetadata.ts`.
172+
173+
#### Deduplication
174+
175+
Event deduplication is now configurable **per action** via the `EventConfig.actions[].deduplication` property.
176+
Helpers for defining deduplication logic—such as `and`, `or`, `not`, and `field`—are available from `@opencrvs/toolkit/events/deduplication`.
177+
178+
The `field` helper can reference declaration form fields and be combined with:
179+
180+
```ts
181+
strictMatches()
182+
fuzzyMatches()
183+
dateRangeMatches()
184+
```
185+
186+
to define precise deduplication rules.
187+
188+
#### Greater Control over Actions
189+
190+
Each action now progresses through three possible states: **`requested`**, **`accepted`**, and **`rejected`**.
191+
When a user performs an action, it is first marked as **`requested`** and forwarded to **countryconfig** via the `/trigger/events/{event}/actions/{action}` route, with the complete event details included in the payload.
192+
193+
Countryconfig has full control over how the action is processed and may choose to **accept** or **reject** the action either **synchronously** or **asynchronously**.
194+
195+
By hooking into these action trigger routes, countryconfig can also:
196+
197+
* Send customized **Notifications**
198+
* Access the full event data at the time an action is performed
199+
200+
#### Configurable Workqueues
201+
202+
Workqueues can now be configured from countryconfig using the `defineWorkqueues` function from `@opencrvs/toolkit/events`.
203+
This enables the creation of role- or workflow-specific queues without requiring code changes in core.
204+
205+
* The **`actions`** property is used to define the default actions displayed for records within a workqueue.
206+
* The **`query`** property is used to determine which events are included in the workqueue.
207+
* The **`workqueue[id=workqueue-one|workqueue-two]`** scope is used to control the visibility of workqueues for particular roles.
208+
209+
Details on the available configuration options can be found in the `WorkqueueConfig.ts` file.
210+
211+
212+
#### Event Overview
213+
214+
The configuration of the event overview page (formerly known as *Record Audit*) has been made customizable through the `EventConfig.summary` property.
215+
The record details displayed on this page can be referenced directly from the declaration form or defined as custom fields that combine multiple form values. If some value contains PII data, they can optionally be hidden via the `secured` flag so that the data will only be visible once the record is assigned to the user.
216+
217+
218+
#### Quick Search
219+
220+
The dropdown previously available in the search bar has been removed.
221+
Any search performed through the **Quick Search** bar is now executed against common record properties such as names, tracking ID, and registration number by default, providing a more streamlined and consistent search experience.
222+
223+
#### Certificate Template Variables
224+
225+
The following variables are available for use within certificate templates:
226+
227+
* **`$declaration`** – Contains the latest raw declaration form data. Typically used with the `$lookup` Handlebars helper to resolve values into human-readable text.
228+
* **`$metadata`** – Contains the `EventMetadata` object. Commonly used with the `$lookup` helper for resolving metadata fields into readable values.
229+
* **`$review`** – A boolean flag indicating whether the certificate is being rendered in review mode.
230+
* **`$references`** – Contains reference data for locations and users, accessible via `{{ $references.locations }}` and `{{ $references.users }}`.
231+
This is useful when manually resolving values from `$declaration`, `$metadata` or `action`.
232+
233+
##### Handlebars Helpers
234+
235+
The following helpers are supported within certificate templates:
236+
237+
* **`$lookup`** – Resolves values from `$declaration`, `$metadata`, or `action` data into a human-readable format.
238+
* **`$intl`** – Dynamically constructs a translation key by joining multiple string parts.
239+
Example:
240+
241+
```hbs
242+
{{ $intl 'constants.greeting' (lookup $declaration "child.name") }}
243+
```
244+
* **`$intlWithParams`** – Enables dynamic translations with parameters.
245+
Takes a translation ID as the first argument, followed by parameter name–value pairs.
246+
Example:
247+
248+
```hbs
249+
{{ $intlWithParams 'constants.greeting' 'name' (lookup $declaration "child.name") }}
250+
```
251+
* **`$actions`** – Resolves all actions for a specified action type.
252+
Example:
253+
254+
```hbs
255+
{{ $actions "PRINT_CERTIFICATE" }}
256+
```
257+
* **`$action`** – Retrieves the latest action data for a specific action type.
258+
Example:
259+
260+
```hbs
261+
{{ $action "PRINT_CERTIFICATE" }}
262+
```
263+
* **`ifCond`** – Compares two values (`v1` and `v2`) using the specified operator and conditionally renders a block based on the result.
264+
**Supported operators:**
265+
266+
* `'==='` – strict equality
267+
* `'!=='` – strict inequality
268+
* `'<'`, `'<='`, `'>'`, `'>='` – numeric or string comparisons
269+
* `'&&'` – both values must be truthy
270+
* `'||'` – at least one value must be truthy
271+
272+
**Usage example:**
273+
274+
```hbs
275+
{{#ifCond value1 '===' value2}}
276+
...
277+
{{/ifCond}}
278+
```
279+
* **`$or`** – Returns the first truthy value among the provided arguments.
280+
* **`$json`** – Converts any value to its JSON string representation (useful for debugging).
281+
282+
Besides the ones introduced above, all built-in [Handlebars helpers](https://handlebarsjs.com/guide/builtin-helpers.html) are available.
283+
284+
Custom helpers can also be added by exposing functions from this [file](https://github.com/opencrvs/opencrvs-countryconfig/blob/develop/src/form/common/certificate/handlebars/helpers.ts#L0-L1).
285+
286+
---
287+
288+
To see Events V2 in action, check out the example configurations in the **countryconfig** repository.
289+
290+
---
291+
292+
293+
28294
- **Redis password support with authorization and authentication** [#9338](https://github.com/opencrvs/opencrvs-core/pull/9338). By default password is disabled for local development environment and enabled on server environments.
29295
- **Switch back to default redis image** [#10173](https://github.com/opencrvs/opencrvs-core/issues/10173)
30296
- **Certificate Template Conditionals**: Certificate template conditionals allow dynamic template selection based on print history using the template conditional helpers.. [#7585](https://github.com/opencrvs/opencrvs-core/issues/7585)

packages/api-docs/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@opencrvs/api-docs",
3-
"version": "1.8.0",
3+
"version": "1.9.0",
44
"description": "OpenCRVS API documentation",
55
"license": "MPL-2.0",
66
"scripts": {

packages/client/src/v2-events/features/events/actions/correct/request/CorrectionRequest.stories.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ const validateAction = generateActionDocument({
8080
}
8181
})
8282

83+
const declarationActionWithDob = generateActionDocument({
84+
configuration: tennisClubMembershipEvent,
85+
action: ActionType.DECLARE,
86+
defaults: {
87+
declaration: {
88+
'applicant.dob': '2006-01-23'
89+
}
90+
}
91+
})
92+
8393
const registerAction = generateActionDocument({
8494
configuration: tennisClubMembershipEvent,
8595
action: ActionType.REGISTER,
@@ -141,16 +151,6 @@ export const SummaryChangingDobToAge: Story = {
141151
}
142152
}
143153

144-
const declarationActionWithDob = generateActionDocument({
145-
configuration: tennisClubMembershipEvent,
146-
action: ActionType.DECLARE,
147-
defaults: {
148-
declaration: {
149-
'applicant.dob': '2006-01-23'
150-
}
151-
}
152-
})
153-
154154
const eventCorrectionDobToAge = {
155155
trackingId: generateUuid(prng),
156156
type: tennisClubMembershipEvent.id,

packages/client/src/v2-events/features/events/components/SearchToolbar.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ import React, { useEffect, useState } from 'react'
1212
import styled from 'styled-components'
1313
import { useIntl } from 'react-intl'
1414
import { useLocation, useNavigate } from 'react-router-dom'
15+
import { useSelector } from 'react-redux'
1516
import { ClearText } from '@opencrvs/components/src/icons'
1617
import { Button } from '@opencrvs/components/src/Button'
1718
import { Icon } from '@opencrvs/components/src/Icon'
1819
import { ROUTES } from '@client/v2-events/routes'
1920
import { serializeSearchParams } from '@client/v2-events/features/events/Search/utils'
21+
import { getScope } from '@client/profile/profileSelectors'
2022

2123
const SearchBox = styled.div`
2224
background: ${({ theme }) => theme.colors.grey100};
@@ -115,6 +117,13 @@ export const SearchToolbar = () => {
115117
const navigate = useNavigate()
116118
const location = useLocation()
117119

120+
const scopes = useSelector(getScope) ?? []
121+
122+
const hasSearchScope = scopes.some((scope) => scope.startsWith('search'))
123+
if (!hasSearchScope) {
124+
return null
125+
}
126+
118127
const onChangeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
119128
setSearchTerm(event.target.value)
120129
}

0 commit comments

Comments
 (0)