Skip to content

Commit 9f93d5e

Browse files
authored
Merge pull request #629 from ForgeRock/SDKS-4926-single-checkbox
feat(davinci-client): support single checkbox component
2 parents 62dc8ad + 913b98b commit 9f93d5e

21 files changed

Lines changed: 4611 additions & 5251 deletions

.changeset/single-checkbox.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@forgerock/davinci-client': minor
3+
---
4+
5+
Adds support for the SINGLE_CHECKBOX field. A new ValidatedBooleanCollector type was introduced including validation support for required checkboxes and updater support for booleans.
6+
7+
**Type improvements**
8+
9+
- `SingleValueCollectorWithValue<T, V>` and `ValidatedSingleValueCollectorWithValue<T, V>` are now generic over their value type (`V`, defaults to `string`), replacing the loose `string | number | boolean` union
10+
11+
- `Validator` is now generic over collector type `T`, replacing the hardcoded `string` input with `CollectorValueType<T>` — so validators receive the value type that matches their collector (e.g. `boolean` for `ValidatedBooleanCollector`, `string` for text collectors) rather than always `string`

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ GEMINI.md
9494

9595
.claude/worktrees
9696
.claude/settings.local.json
97+
.claude/skills
98+
.claude/CLAUDE.md
9799
.opensource
98100

99101
# Polaris
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2026 Ping Identity Corporation. All rights reserved.
3+
*
4+
* This software may be modified and distributed under the terms
5+
* of the MIT license. See the LICENSE file for details.
6+
*/
7+
import type { ValidatedBooleanCollector, Updater } from '@forgerock/davinci-client/types';
8+
9+
/**
10+
* Creates a single checkbox and attaches it to the form
11+
* @param {HTMLFormElement} formEl - The form element to attach the checkboxes to
12+
* @param {ValidatedBooleanCollector} collector - Contains the configuration
13+
* @param {Updater} updater - Function to call when selection changes
14+
*/
15+
export default function booleanComponent(
16+
formEl: HTMLFormElement,
17+
collector: ValidatedBooleanCollector,
18+
updater: Updater<ValidatedBooleanCollector>,
19+
) {
20+
// Create a container for the checkboxes
21+
const containerDiv = document.createElement('div');
22+
containerDiv.className = 'single-checkbox-container';
23+
24+
// Create a heading/label for the checkbox group
25+
const groupLabel = document.createElement('div');
26+
groupLabel.textContent = collector.output.label || 'Single Checkbox';
27+
groupLabel.className = 'single-checkbox-label';
28+
containerDiv.appendChild(groupLabel);
29+
30+
// Create checkboxes for each option
31+
const wrapper = document.createElement('div');
32+
wrapper.className = 'checkbox-wrapper';
33+
34+
const checkbox = document.createElement('input');
35+
checkbox.type = 'checkbox';
36+
checkbox.id = collector.output.key;
37+
checkbox.name = collector.output.key || 'single-checkbox-field';
38+
checkbox.checked = collector.output.value;
39+
checkbox.value = 'checked';
40+
41+
const label = document.createElement('label');
42+
label.htmlFor = checkbox.id;
43+
label.textContent = collector.output.label;
44+
45+
// Add event listener to handle single-select behavior
46+
checkbox.addEventListener('change', (event) => {
47+
const target = event.target as HTMLInputElement;
48+
updater(target.checked);
49+
});
50+
51+
wrapper.appendChild(checkbox);
52+
wrapper.appendChild(label);
53+
containerDiv.appendChild(wrapper);
54+
55+
// Append the container to the form
56+
formEl.appendChild(containerDiv);
57+
}

e2e/davinci-app/main.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import fidoComponent from './components/fido.js';
3535
import qrCodeComponent from './components/qr-code.js';
3636
import agreementComponent from './components/agreement.js';
3737
import pollingComponent from './components/polling.js';
38+
import booleanComponent from './components/boolean.js';
3839

3940
const loggerFn = {
4041
error: () => {
@@ -298,6 +299,8 @@ const urlParams = new URLSearchParams(window.location.search);
298299
singleValueComponent(formEl, collector, davinciClient.update(collector));
299300
} else if (collector.type === 'MultiSelectCollector') {
300301
multiValueComponent(formEl, collector, davinciClient.update(collector));
302+
} else if (collector.type === 'ValidatedBooleanCollector') {
303+
booleanComponent(formEl, collector, davinciClient.update(collector));
301304
}
302305
});
303306

e2e/davinci-suites/src/form-fields.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ test('Should render form fields', async ({ page }) => {
5353
'checkbox-field-key': ['option1 value', 'option2 value'],
5454
'dropdown-field-key': 'dropdown-option2-value',
5555
'radio-group-key': 'option2 value',
56+
'single-checkbox-field': false,
5657
'combobox-field-key': ['option1 value', 'option3 value'],
5758
'phone-field': {
5859
phoneNumber: '1234567890',

package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
},
1414
"author": "ForgeRock",
1515
"scripts": {
16+
"api-report": "pnpm nx run-many -t api-report -p journey-client oidc-client device-client davinci-client",
17+
"api-report:fix": "for pkg in packages/journey-client packages/oidc-client packages/device-client packages/davinci-client; do pnpm tsx tools/api-report/src/main.ts $pkg --fix; done && pnpm api-report",
1618
"build": "nx sync && nx affected --target=build",
1719
"changeset": "changeset",
1820
"ci:release": "pnpm nx run-many -t build --no-agents --skip-nx-cache && pnpm publish -r --no-git-checks && changeset tag",
@@ -24,15 +26,13 @@
2426
"create-package": "nx g @nx/js:library",
2527
"format": "pnpm nx format:write",
2628
"generate-docs": "typedoc",
29+
"preinstall": "npx only-allow pnpm",
30+
"postinstall": "ts-patch install",
2731
"lint": "nx affected --target=lint",
28-
"api-report": "pnpm nx run-many -t api-report -p journey-client oidc-client device-client davinci-client",
29-
"api-report:fix": "for pkg in packages/journey-client packages/oidc-client packages/device-client packages/davinci-client; do pnpm tsx tools/api-report/src/main.ts $pkg --fix; done && pnpm api-report",
30-
"mapping:validate": "pnpm tsx tools/interface-mapping-validator/src/main.ts",
31-
"mapping:generate": "pnpm tsx tools/interface-mapping-validator/src/main.ts --generate",
3232
"local-release": "pnpm ts-node tools/release/release.ts",
33+
"mapping:generate": "pnpm tsx tools/interface-mapping-validator/src/main.ts --generate",
34+
"mapping:validate": "pnpm tsx tools/interface-mapping-validator/src/main.ts",
3335
"nx": "nx",
34-
"postinstall": "ts-patch install",
35-
"preinstall": "npx only-allow pnpm",
3636
"prepare": "lefthook install",
3737
"serve": "nx serve",
3838
"test": "CI=true nx affected:test",
@@ -55,6 +55,7 @@
5555
"@effect/cli": "catalog:effect",
5656
"@eslint/eslintrc": "^3.0.0",
5757
"@eslint/js": "~9.39.0",
58+
"@evilmartians/lefthook": "^2.1.4",
5859
"@nx/devkit": "22.6.5",
5960
"@nx/eslint": "22.6.5",
6061
"@nx/eslint-plugin": "22.6.5",
@@ -92,7 +93,6 @@
9293
"eslint-plugin-playwright": "^2.0.0",
9394
"eslint-plugin-prettier": "^5.2.3",
9495
"fast-check": "^4.0.0",
95-
"@evilmartians/lefthook": "^2.1.4",
9696
"jiti": "2.6.1",
9797
"jsdom": "27.4.0",
9898
"jsonc-eslint-parser": "^2.1.0",
@@ -104,9 +104,9 @@
104104
"shx": "^0.4.0",
105105
"swc-loader": "0.2.7",
106106
"ts-node": "10.9.2",
107-
"tsx": "^4.20.0",
108107
"ts-patch": "3.3.0",
109108
"tslib": "^2.5.0",
109+
"tsx": "^4.20.0",
110110
"typedoc": "^0.27.4",
111111
"typedoc-github-theme": "0.2.1",
112112
"typedoc-plugin-rename-defaults": "^0.7.2",

0 commit comments

Comments
 (0)