-
Notifications
You must be signed in to change notification settings - Fork 3
feat(davinci-client): rich-text-collector #568
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
613e21a
099321c
d8d7997
08a8bcd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| --- | ||
| '@forgerock/davinci-client': minor | ||
| --- | ||
|
|
||
| **Breaking change**: `ReadOnlyCollector.output.content` now returns a plain `string` (the label text) instead of `ContentPart[]`. | ||
|
|
||
| A new `ReadOnlyCollector.output.richContent` property is always present and contains the structured link data when a LABEL field includes `richContent`. Its shape is `CollectorRichContent` — a template string with `{{key}}` placeholders (`content`) and a validated `replacements` array (`ValidatedReplacement[]`). When no `richContent` is present, `replacements` is an empty array. | ||
|
|
||
| **Removed type exports**: `ContentPart`, `TextContentPart`, `LinkContentPart` | ||
|
|
||
| **New type exports**: `RichContentLink`, `ValidatedReplacement`, `CollectorRichContent` | ||
|
|
||
| Includes href protocol validation that rejects unsafe URI schemes (e.g. `javascript:`, `data:`). | ||
|
Comment on lines
+1
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make this changeset a major bump. The note explicitly documents a breaking API change ( Suggested fix- '@forgerock/davinci-client': minor
+ '@forgerock/davinci-client': major🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| .opensource/ |
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this file? Do we want to include it? |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,9 +7,43 @@ | |
| import type { ReadOnlyCollector } from '@forgerock/davinci-client/types'; | ||
|
|
||
| export default function (formEl: HTMLFormElement, collector: ReadOnlyCollector) { | ||
| // create paragraph element with text of "Loading ... " | ||
| const p = document.createElement('p'); | ||
| p.style.whiteSpace = 'pre-line'; | ||
| 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 segments = richContent.content.split(/\{\{(\w+)\}\}/); | ||
| const replacementMap = new Map(richContent.replacements.map((r) => [r.key, r])); | ||
|
|
||
| for (let i = 0; i < segments.length; i++) { | ||
| if (i % 2 === 0) { | ||
| // Text segment | ||
| if (segments[i]) { | ||
| p.appendChild(document.createTextNode(segments[i])); | ||
| } | ||
| } else { | ||
| // Replacement key | ||
| const replacement = replacementMap.get(segments[i]); | ||
| if (replacement?.type === 'link') { | ||
| const a = document.createElement('a'); | ||
| a.href = replacement.href; | ||
| a.textContent = replacement.value; | ||
| if (replacement.target) { | ||
| a.target = replacement.target; | ||
| if (replacement.target === '_blank') { | ||
| a.rel = 'noopener noreferrer'; | ||
| } | ||
| } | ||
| p.appendChild(a); | ||
| } | ||
| } | ||
|
Comment on lines
+20
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Preserve unmatched placeholders instead of dropping them. The loop currently skips any token without a matching link replacement, so a typo or unsupported placeholder silently disappears from the rendered label. The ♻️ Suggested fix const replacement = replacementMap.get(segments[i]);
if (replacement?.type === 'link') {
const a = document.createElement('a');
a.href = replacement.href;
a.textContent = replacement.value;
if (replacement.target) {
a.target = replacement.target;
if (replacement.target === '_blank') {
a.rel = 'noopener noreferrer';
}
}
p.appendChild(a);
+ } else {
+ p.appendChild(document.createTextNode(`{{${segments[i]}}}`));
}🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| p.innerText = collector.output.label; | ||
| formEl?.appendChild(p); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the language is a little off in this comment. There was never a
contentproperty on the collector.contentwas on the DaVinci field. I also don't think we have an interface calledContentPart.That said, should we consider a new type of collector
RichTextCollectorto avoid this breaking change and a major bump?