Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/silent-ideas-joke.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
'@forgerock/davinci-client': minor
---

Support form agreements with AgreementCollector
Support form agreements with additional `title` property ReadOnlyCollector
2 changes: 1 addition & 1 deletion .changeset/single-checkbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
'@forgerock/davinci-client': minor
---

Adds support for the SINGLE_CHECKBOX field. A new ValidatedBooleanCollector interface was introduced including validation support for required checkboxes and updater support for booleans.
Adds support for the SINGLE_CHECKBOX field. A new ValidatedBooleanCollector interface was introduced including validation support for required checkboxes and updater support for booleans. A BooleanCollector was also added for parity in the case that no validation is required.

**Type improvements**

Expand Down
30 changes: 0 additions & 30 deletions e2e/davinci-app/components/agreement.ts

This file was deleted.

20 changes: 15 additions & 5 deletions e2e/davinci-app/components/boolean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* of the MIT license. See the LICENSE file for details.
*/
import type {
BooleanCollector,
ValidatedBooleanCollector,
Updater,
Validator,
Expand All @@ -14,15 +15,15 @@ import { dotToCamelCase, richContentInterpolation } from '../helper.js';
/**
* Creates a single checkbox and attaches it to the form
* @param {HTMLFormElement} formEl - The form element to attach the checkbox to
* @param {ValidatedBooleanCollector} collector - Contains the configuration
* @param {BoooleanCollector | ValidatedBooleanCollector} collector - Contains the configuration
* @param {Updater} updater - Function to call when selection changes
* @param {Validator} validator - Function to validate the input
*/
export default function booleanComponent(
formEl: HTMLFormElement,
collector: ValidatedBooleanCollector,
updater: Updater<ValidatedBooleanCollector>,
validator: Validator<ValidatedBooleanCollector>,
collector: BooleanCollector | ValidatedBooleanCollector,
updater: Updater<BooleanCollector | ValidatedBooleanCollector>,
validator?: Validator<ValidatedBooleanCollector>,
) {
const collectorKey = dotToCamelCase(collector.output.key);

Expand Down Expand Up @@ -57,7 +58,16 @@ export default function booleanComponent(
// Add event listener to handle single-select behavior
checkbox.addEventListener('change', (event) => {
const checked = (event.target as HTMLInputElement).checked;
const result = validator(checked);

if (collector.type === 'BooleanCollector') {
const updateError = updater(checked);
if (updateError && 'error' in updateError) {
console.error(updateError.error.message);
}
return;
}

const result = validator && validator(checked);
const errorEl = formEl?.querySelector(`.${collectorKey}-error`);

// Validate the input
Expand Down
35 changes: 0 additions & 35 deletions e2e/davinci-app/components/label.ts

This file was deleted.

41 changes: 41 additions & 0 deletions e2e/davinci-app/components/read-only.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2025 - 2026 Ping Identity Corporation. All rights reserved.
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
import type { ReadOnlyCollector, RichTextCollector } from '@forgerock/davinci-client/types';
import { richContentInterpolation } from '../helper.js';

export default function (
formEl: HTMLFormElement,
collector: ReadOnlyCollector | RichTextCollector,
) {
const p = document.createElement('p');
p.style.whiteSpace = 'pre-line';

if (collector.type === 'ReadOnlyCollector') {
// Display agreement title if it exists
if (collector.output.title) {
const titleEl = document.createElement('h3');
titleEl.innerText = collector.output.title;
formEl?.appendChild(titleEl);
}

p.innerText = collector.output.content;
formEl?.appendChild(p);
} else if (collector.type === 'RichTextCollector') {
const { richContent } = collector.output;

if (richContent.replacements.length === 0) {
p.innerText = collector.output.content;
formEl?.appendChild(p);
return;
}

// Interpolate the template by splitting on {{key}} and inserting links
const pRichText = richContentInterpolation(richContent);

formEl?.appendChild(pRichText);
}
}
26 changes: 13 additions & 13 deletions e2e/davinci-app/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { davinci } from '@forgerock/davinci-client';
import { oidc } from '@forgerock/oidc-client';
import type { OidcConfig } from '@forgerock/oidc-client/types';
import type {
Collectors,
CustomLogger,
DaVinciConfig,
DavinciClient,
Expand All @@ -30,11 +31,10 @@ import socialLoginButtonComponent from './components/social-login-button.js';
import { serverConfigs } from './server-configs.js';
import singleValueComponent from './components/single-value.js';
import multiValueComponent from './components/multi-value.js';
import labelComponent from './components/label.js';
import readOnlyComponent from './components/read-only.js';
import objectValueComponent from './components/object-value.js';
import fidoComponent from './components/fido.js';
import qrCodeComponent from './components/qr-code.js';
import agreementComponent from './components/agreement.js';
import pollingComponent from './components/polling.js';
import booleanComponent from './components/boolean.js';

Expand Down Expand Up @@ -206,7 +206,7 @@ const urlParams = new URLSearchParams(window.location.search);

const collectors = davinciClient.getCollectors();

collectors.forEach((collector) => {
collectors.forEach((collector: Collectors) => {
if (collector.type === 'TextCollector' && collector.name === 'protectsdk') {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
collector;
Expand All @@ -226,14 +226,12 @@ const urlParams = new URLSearchParams(window.location.search);
submitForm,
);
} else if (collector.type === 'ReadOnlyCollector' || collector.type === 'RichTextCollector') {
labelComponent(
readOnlyComponent(
formEl, // You can ignore this; it's just for rendering
collector, // This is the plain object of the collector
);
} else if (collector.type === 'QrCodeCollector') {
qrCodeComponent(formEl, collector);
} else if (collector.type === 'AgreementCollector') {
agreementComponent(formEl, collector);
} else if (collector.type === 'TextCollector') {
textComponent(
formEl, // You can ignore this; it's just for rendering
Expand Down Expand Up @@ -288,6 +286,15 @@ const urlParams = new URLSearchParams(window.location.search);
davinciClient.update(collector), // Returns an update function for this collector
submitForm,
);
} else if (collector.type === 'BooleanCollector') {
booleanComponent(formEl, collector, davinciClient.update(collector));
} else if (collector.type === 'ValidatedBooleanCollector') {
booleanComponent(
formEl,
collector,
davinciClient.update(collector),
davinciClient.validate(collector),
);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
} else if (collector.type === 'FlowCollector') {
flowLinkComponent(
formEl, // You can ignore this; it's just for rendering
Expand All @@ -302,13 +309,6 @@ const urlParams = new URLSearchParams(window.location.search);
singleValueComponent(formEl, collector, davinciClient.update(collector));
} else if (collector.type === 'MultiSelectCollector') {
multiValueComponent(formEl, collector, davinciClient.update(collector));
} else if (collector.type === 'ValidatedBooleanCollector') {
booleanComponent(
formEl,
collector,
davinciClient.update(collector),
davinciClient.validate(collector),
);
}
});

Expand Down
Loading
Loading