Skip to content

Commit de3d3db

Browse files
committed
Merge branch 'develop' into merge-v1.9.1-to-develop
2 parents 6cfd522 + 7fcc722 commit de3d3db

File tree

337 files changed

+8605
-6936
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

337 files changed

+8605
-6936
lines changed

.husky/pre-push

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/sh
2+
3+
branch=$(git rev-parse --abbrev-ref HEAD)
4+
pattern='^[a-z][a-z0-9\/\-]{1,29}$'
5+
6+
if [[ ! "$branch" =~ $pattern ]]; then
7+
echo """
8+
❌ Invalid branch name: '$branch'
9+
➡️ Branch names must match regex: $pattern
10+
- Start with a lowercase letter
11+
- Can contain lowercase letters, numbers, and hyphens
12+
- Length between 2 and 30 characters
13+
- Slashes '/' are allowed for hierarchical branch names
14+
Example: ocrvs-12345, feature-login, fix-bug123, refactor-api
15+
"""
16+
exit 1
17+
fi
18+
19+
exit 0

ACTIONS.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Actions
2+
3+
Actions represent operations performed on an event record, such as a birth declaration. They determine the resulting state of the record and include, for example, form data submitted to that record.
4+
5+
## Core actions
6+
7+
Core actions, as the name suggests, are defined within the core and are available for all event types. They often contain specific UI elements or logic. In v2.0, the available core actions are:
8+
9+
- `CREATE`
10+
- `READ`
11+
- `ASSIGN` & `UNASSIGN`
12+
- `DELETE`
13+
- `NOTIFY`
14+
- `DECLARE`\*, `VALIDATE`\* & `REGISTER`\*
15+
- `REJECT`\*
16+
- `ARCHIVE`
17+
- `PRINT_CERTIFICATE`\*
18+
- `REQUEST_CORRECTION`\*, `APPROVE_CORRECTION` & `REJECT_CORRECTION`
19+
- `DUPLICATE_DETECTED`, `MARK_AS_DUPLICATE` & `MARK_AS_NOT_DUPLICATE`
20+
21+
_\* are configurable core actions, this is related to the action configurations section below_
22+
23+
Core actions can also change the event’s status, which custom actions cannot do.
24+
In v2.0, the available event statuses are:
25+
26+
`CREATED`, `NOTIFIED`, `DECLARED`, `REGISTERED`, `ARCHIVED`
27+
28+
The status is applied by the corresponding action.
29+
30+
> [!NOTE]
31+
> Beyond v2.0, we will review which core actions could be removed (and implemented instead as custom actions within our Farajaland configuration). We expect the following actions may be transitioned to custom actions: `VALIDATE`, `REJECT`
32+
33+
## Custom actions
34+
35+
Custom actions are non-core actions that are defined only in the country configuration using `ActionType.CUSTOM`. All custom actions are “quick actions”, executed via a dialog on the event overview page. They can be configured with flag configurations, action conditionals, and a custom form displayed in the dialog.
36+
37+
All custom actions are configurable.
38+
39+
<!-- TODO: add screenshot of custom action dialog here -->
40+
41+
## Action configurations
42+
43+
All custom actions and certain core actions are configurable.
44+
45+
Actions are configured on a per–event-type basis, meaning different event types do not share action configurations.
46+
47+
Below we describe two configuration options: flag configurations and action conditionals. It is important to note that additional configuration options are available and that many core actions have configuration options specific to their action type.
48+
49+
### Flag configurations
50+
51+
Flag configurations define flags that should be added to or removed from a record when an action is executed. They can be applied either unconditionally (if no conditionals are specified) or conditionally based on factors such as form data, the role of the executing user, or the record’s current status or flags.
52+
53+
**Example:** Adding the flag `approval-required-for-late-registration` when `child.dob` is more than 365 days in the past:
54+
55+
```js
56+
flags: [
57+
{
58+
id: 'approval-required-for-late-registration',
59+
operation: 'add',
60+
conditional: not(field('child.dob').isAfter().days(365).inPast())
61+
}
62+
]
63+
```
64+
65+
### Action conditionals
66+
67+
Action conditionals determine whether an action should be visible or enabled based on the record’s status or flags.
68+
69+
Action conditionals support two different types of conditional types: `ConditionalType.SHOW` & `ConditionalType.ENABLE`.
70+
71+
When executing an action, our backend also checks that the action conditions are met: if `SHOW` or `ENABLE` condition is not met, the backend will return HTTP 409.
72+
73+
**Example:** Showing an action only when the record has the approval-required-for-late-registration flag:
74+
75+
```js
76+
conditionals: [
77+
{
78+
type: ConditionalType.SHOW,
79+
conditional: flag('approval-required-for-late-registration')
80+
}
81+
]
82+
```

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## 2.0.0 Release Candidate
4+
5+
### New features
6+
7+
#### HTTP Input
8+
9+
HTTP input now accepts `field('..')` references in the HTTP body definition.
10+
11+
#### Jurisdiction
12+
13+
- Elasticsearch now stores location IDs as a full administrative hierarchy, with the leaf representing the actual event location. This enables searching events by any jurisdiction level (district, province, office, health facility etc.).
14+
315
## [1.9.1](https://github.com/opencrvs/opencrvs-core/compare/v1.9.0...v1.9.1)
416

517
### Breaking changes

packages/client/.storybook/decorators.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
} from '@opencrvs/commons/client'
2020
import { testDataGenerator } from '@client/tests/test-data-generators'
2121
import { getLeafLocationIds } from '@client/v2-events/hooks/useLocations'
22-
import { V2_DEFAULT_MOCK_LOCATIONS } from '../.storybook/default-request-handlers'
22+
import { V2_DEFAULT_MOCK_LOCATIONS_MAP } from '../.storybook/default-request-handlers'
2323

2424
const generator = testDataGenerator()
2525

@@ -41,7 +41,7 @@ export const DataDisplayWithConditionallyHiddenFields: StoryObj<
4141
> = {
4242
parameters: {
4343
layout: 'centered',
44-
userRole: TestUserRole.Enum.REGISTRATION_AGENT
44+
userRole: TestUserRole.enum.REGISTRATION_AGENT
4545
}
4646
}
4747
*/
@@ -60,11 +60,11 @@ export const withValidatorContext: Decorator = (Story, context) => {
6060
export function getTestValidatorContext(userRole?: TestUserRole) {
6161
let token
6262

63-
if (userRole === TestUserRole.Enum.FIELD_AGENT) {
63+
if (userRole === TestUserRole.enum.FIELD_AGENT) {
6464
token = generator.user.token.fieldAgent
65-
} else if (userRole === TestUserRole.Enum.LOCAL_SYSTEM_ADMIN) {
65+
} else if (userRole === TestUserRole.enum.LOCAL_SYSTEM_ADMIN) {
6666
token = generator.user.token.localSystemAdmin
67-
} else if (userRole === TestUserRole.Enum.REGISTRATION_AGENT) {
67+
} else if (userRole === TestUserRole.enum.REGISTRATION_AGENT) {
6868
token = generator.user.token.registrationAgent
6969
} else {
7070
token = generator.user.token.localRegistrar
@@ -76,7 +76,7 @@ export function getTestValidatorContext(userRole?: TestUserRole) {
7676
)
7777

7878
const leafAdminStructureLocationIds = getLeafLocationIds(
79-
V2_DEFAULT_MOCK_LOCATIONS,
79+
V2_DEFAULT_MOCK_LOCATIONS_MAP,
8080
[LocationType.enum.ADMIN_STRUCTURE]
8181
)
8282

packages/client/.storybook/default-request-handlers.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ export const V2_DEFAULT_MOCK_LOCATIONS = [
214214
}
215215
]
216216

217+
export const V2_DEFAULT_MOCK_LOCATIONS_MAP = new Map(
218+
V2_DEFAULT_MOCK_LOCATIONS.map((l) => [l.id, l])
219+
)
220+
217221
export const handlers = {
218222
drafts: [
219223
tRPCMsw.event.draft.list.query(() => {

packages/client/.storybook/preview.tsx

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@ import {
3939
setDraftData
4040
} from '@client/v2-events/features/events/useEvents/api'
4141
import {
42+
ActionType,
4243
Draft,
4344
EventDocument,
4445
tennisClubMembershipEvent,
4546
TestUserRole,
4647
TokenUserType,
47-
UUID
48+
UUID,
49+
ChildOnboardingEvent
4850
} from '@opencrvs/commons/client'
4951
import {
5052
tennisClubMembershipEventDocument,
@@ -165,6 +167,36 @@ export const parameters = {
165167

166168
const generator = testDataGenerator()
167169

170+
const tennisClubMembershipEventWithCustomAction = {
171+
...tennisClubMembershipEvent,
172+
actions: tennisClubMembershipEvent.actions.concat([
173+
{
174+
type: ActionType.CUSTOM,
175+
customActionType: 'CONFIRM',
176+
label: {
177+
id: 'event.tennis-club-membership.action.confirm.label',
178+
defaultMessage: 'Confirm',
179+
description:
180+
'This is shown as the action name anywhere the user can trigger the action from'
181+
},
182+
// @TODO: once action conditionals are implemented, add some conditional here?
183+
form: [
184+
{
185+
id: 'notes',
186+
type: 'TEXTAREA',
187+
required: true,
188+
label: {
189+
defaultMessage: 'Notes',
190+
description: 'This is the label for the field for a custom action',
191+
id: 'event.birth.custom.action.approve.field.notes.label'
192+
}
193+
}
194+
],
195+
flags: []
196+
}
197+
])
198+
}
199+
168200
const preview: Preview = {
169201
loaders: [
170202
mswLoader,
@@ -192,11 +224,11 @@ const preview: Preview = {
192224
queryClient.clear()
193225
const primaryOfficeId = '028d2c85-ca31-426d-b5d1-2cef545a4902' as UUID
194226

195-
if (options.parameters.userRole === TestUserRole.Enum.FIELD_AGENT) {
227+
if (options.parameters.userRole === TestUserRole.enum.FIELD_AGENT) {
196228
window.localStorage.setItem('opencrvs', generator.user.token.fieldAgent)
197229
addUserToQueryData(generator.user.fieldAgent().v2)
198230
} else if (
199-
options.parameters.userRole === TestUserRole.Enum.REGISTRATION_AGENT
231+
options.parameters.userRole === TestUserRole.enum.REGISTRATION_AGENT
200232
) {
201233
window.localStorage.setItem(
202234
'opencrvs',
@@ -205,7 +237,7 @@ const preview: Preview = {
205237

206238
addUserToQueryData(generator.user.registrationAgent().v2)
207239
} else if (
208-
options.parameters.userRole === TestUserRole.Enum.LOCAL_SYSTEM_ADMIN
240+
options.parameters.userRole === TestUserRole.enum.LOCAL_SYSTEM_ADMIN
209241
) {
210242
window.localStorage.setItem(
211243
'opencrvs',
@@ -215,12 +247,12 @@ const preview: Preview = {
215247
addUserToQueryData({
216248
id: generator.user.id.localSystemAdmin,
217249
name: [{ use: 'en', given: ['Alex'], family: 'Ngonga' }],
218-
role: TestUserRole.Enum.LOCAL_SYSTEM_ADMIN,
250+
role: TestUserRole.enum.LOCAL_SYSTEM_ADMIN,
219251
primaryOfficeId,
220252
type: TokenUserType.enum.user
221253
})
222254
} else if (
223-
options.parameters.userRole === TestUserRole.Enum.NATIONAL_SYSTEM_ADMIN
255+
options.parameters.userRole === TestUserRole.enum.NATIONAL_SYSTEM_ADMIN
224256
) {
225257
window.localStorage.setItem(
226258
'opencrvs',
@@ -249,7 +281,10 @@ const preview: Preview = {
249281
*/
250282

251283
const offlineConfigs: Array<EventConfig> = options.parameters?.offline
252-
?.configs ?? [tennisClubMembershipEvent]
284+
?.configs ?? [
285+
tennisClubMembershipEventWithCustomAction,
286+
ChildOnboardingEvent
287+
]
253288

254289
offlineConfigs.forEach((config) => {
255290
addLocalEventConfig(config)

packages/client/.stylelintrc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
2-
"processors": ["stylelint-processor-styled-components"],
2+
"customSyntax": "postcss-styled-syntax",
3+
34
"extends": [
45
"stylelint-config-recommended",
56
"stylelint-config-styled-components"
@@ -9,7 +10,11 @@
910
"color-named": "never",
1011
"no-descending-specificity": null,
1112
"property-no-vendor-prefix": null,
12-
"opencrvs/no-font-styles": true
13+
"opencrvs/no-font-styles": true,
14+
"function-no-unknown": [true, { "ignoreFunctions": ["/\\$/"] }],
15+
"block-no-empty": null,
16+
"no-extra-semicolons": null,
17+
"annotation-no-unknown": null
1318
},
1419
"plugins": ["./no-font-styles.js"],
1520
"ignoreFiles": "**/*.stories.tsx"

packages/client/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
"test:watch": "vitest",
1616
"lint": "yarn lint:css && yarn lint:ts",
1717
"lint:css": "stylelint 'src/**/*.{ts,tsx}'",
18-
"lint:ts": "eslint -c eslint.config.js --max-warnings=0",
19-
"test:compilation": "tsc --noEmit",
18+
"lint:ts": "NODE_OPTIONS=--max_old_space_size=8000 eslint -c eslint.config.js --max-warnings=0",
19+
"test:compilation": "NODE_OPTIONS=\"--max-old-space-size=8192\" tsc --noEmit",
2020
"extract:translations": "bash extract-translations.sh",
2121
"generate-gateway-types": "NODE_OPTIONS=--dns-result-order=ipv4first graphql-codegen --config codegen.ts && prettier --write src/utils/gateway.ts",
2222
"build:clean": "rm -rf build",
@@ -91,7 +91,7 @@
9191
"patch-package": "^6.1.2",
9292
"pdfmake": "^0.2.5",
9393
"postinstall-postinstall": "^2.0.0",
94-
"query-string": "^6.1.0",
94+
"qs": "6.14.0",
9595
"react": "18.3.1",
9696
"react-dom": "18.3.1",
9797
"react-easy-crop": "^4.0.1",
@@ -159,7 +159,7 @@
159159
"@types/lodash": "^4.14.149",
160160
"@types/node": "^20.12.7",
161161
"@types/qrcode": "^1.5.0",
162-
"@types/query-string": "^6.1.0",
162+
"@types/qs": "^6.14.0",
163163
"@types/react": "18.3.1",
164164
"@types/react-dom": "18.3.0",
165165
"@types/react-stickynode": "^1.4.0",
@@ -193,6 +193,7 @@
193193
"jsonwebtoken": "^9.0.0",
194194
"msw": "^2.7.0",
195195
"opener": "^1.5.1",
196+
"postcss-styled-syntax": "^0.7.1",
196197
"prettier": "3.5.3",
197198
"qrcode": "^1.5.1",
198199
"react-select-event": "^5.5.1",
@@ -202,7 +203,6 @@
202203
"stylelint": "^14.11.0",
203204
"stylelint-config-recommended": "^9.0.0",
204205
"stylelint-config-styled-components": "^0.1.1",
205-
"stylelint-processor-styled-components": "^1.10.0",
206206
"traverse": "^0.6.6",
207207
"ts-node": "^7.0.1",
208208
"typescript": "5.6.3",

packages/client/public/mockServiceWorker.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/* eslint-disable */
2+
/* tslint:disable */
3+
14
/**
25
* Mock Service Worker.
36
* @see https://github.com/mswjs/msw

packages/client/src/components/DateRangePicker.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import {
2424
ChevronRight,
2525
Cross
2626
} from '@opencrvs/components/lib/icons'
27-
import addDays from 'date-fns/addDays'
2827
import addYears from 'date-fns/addYears'
2928
import endOfDay from 'date-fns/endOfDay'
3029
import endOfYear from 'date-fns/endOfYear'

0 commit comments

Comments
 (0)