Skip to content

Conversation

@sheikhuzairhussain
Copy link
Contributor

@sheikhuzairhussain sheikhuzairhussain commented Nov 20, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Template field selection now uses a dropdown menu with asynchronous loading
    • Dropdown menus now support placeholder options with distinct styling
    • Page selection provides predefined page key options for easier navigation
  • Bug Fixes

    • Improved selection validation to automatically ensure valid default choices when required

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 20, 2025

Walkthrough

This change introduces comprehensive placeholder support for dropdown and select components across the UI layer, integrating asynchronous select dropdowns into the builder's text field editor. It adds placeholder value injection logic, styling, and backend metadata to support predefined page keys as dropdown options.

Changes

Cohort / File(s) Summary
WDS Component Enhancements
src/ui/src/wds/WdsDropdownMenu.vue, src/ui/src/wds/WdsDropdownMenuItem.vue, src/ui/src/wds/WdsSelect.vue
Added placeholder support with optional isPlaceholder field, placeholder styling classes, placeholder injection logic, and strengthened selection handling with validation and fallback mechanisms. Introduced required prop and computed selectOptions for automatic placeholder option rendering.
Builder Integration
src/ui/src/builder/settings/BuilderFieldsText.vue
Integrated async WdsSelect dropdown with conditional rendering based on shouldUseDropdown. Added computed bindings for options, selectOptions, selectValue, and pageKeys helper in predefinedOptionFns. Dropdown renders when field type is "template" with available options.
Backend Template Metadata
src/writer/blocks/changepage.py
Extended pageKey field metadata with predefined pageKeys options reference.

Sequence Diagram

sequenceDiagram
    participant BuilderFieldsText
    participant WdsSelect
    participant Option Storage
    
    Note over BuilderFieldsText,WdsSelect: Initialization Phase
    BuilderFieldsText->>BuilderFieldsText: Compute options (Record<string, string>)
    BuilderFieldsText->>BuilderFieldsText: Derive selectOptions (array of {value, label})
    BuilderFieldsText->>BuilderFieldsText: Evaluate shouldUseDropdown
    
    alt shouldUseDropdown = true
        BuilderFieldsText->>WdsSelect: Mount async component<br/>(options passed as prop)
        WdsSelect->>WdsSelect: Normalize options to selectOptions
        WdsSelect->>WdsSelect: Compute shouldInjectPlaceholder
        WdsSelect->>WdsSelect: Prepend PLACEHOLDER_VALUE if needed
    else shouldUseDropdown = false
        BuilderFieldsText->>BuilderFieldsText: Render BuilderTemplateInput
    end
    
    Note over BuilderFieldsText,WdsSelect: User Selection Phase
    User->>WdsSelect: Select option or placeholder
    WdsSelect->>WdsSelect: Update currentValueArray
    WdsSelect->>WdsSelect: Compute selectedOptions & currentLabel
    WdsSelect->>WdsSelect: Apply isPlaceholderSelected styling
    WdsSelect->>BuilderFieldsText: Emit selection (via selectValue setter)
    BuilderFieldsText->>BuilderFieldsText: Update fieldViewModel.content
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • WdsSelect.vue requires careful review of the placeholder injection logic, selection validation with ensureValidSelection, and the distinction between required/non-required behavior
  • selectValue binding in BuilderFieldsText.vue with its getter/setter mapping to inputValue and fieldViewModel updates
  • Async component loading and conditional template rendering logic based on shouldUseDropdown state
  • Type consistency across Record<string, string> options and Option[] selectOptions transformations

Possibly related PRs

Suggested reviewers

  • madeindjs

Poem

🐰 A dropdown blooms with placeholder grace,
Where options dance in their chosen place,
The builder now selects with async delight,
Each page key mapped to render just right,
Placeholders styled in softest gray light ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main change: converting a pageKey field from text input to a dropdown in the Change Page block.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/page-key-dropdown

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sheikhuzairhussain sheikhuzairhussain changed the title Convert pageKey field to dropdown in Change Page block 🚧 Convert pageKey field to dropdown in Change Page block Nov 20, 2025
Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HackerOne Code Security Review

🟢 Scan Complete: 1 Issue(s)

Here's how the code changes were interpreted and info about the tools used for scanning.

📖 Summary of Changes The changes focus on enhancing dropdown and select components across the UI, introducing new placeholder styling, and improving page key selection functionality. Modifications include adding WdsSelect component, refining dropdown menu items, and extending template configuration to support predefined page key options. The updates aim to improve user interface interactions and form field management.
File Summary
src/ui/src/builder/settings/BuilderFieldsText.vue Added WdsSelect component for dropdown functionality, introduced new predefined option function for page keys, and implemented computed properties for select options and dropdown visibility based on template type and available options.
src/ui/src/wds/WdsDropdownMenu.vue The changes include adding an optional isPlaceholder property to the WdsDropdownMenuOption type and adding a border to the .WdsDropdownMenu class in the CSS. The hasNoResults section was also removed from the template.
src/ui/src/wds/WdsDropdownMenuItem.vue Added a new CSS class 'WdsDropdownMenuItem--placeholder' to the template and style section, introducing styling for placeholder menu items with specific color variations for label and detail text.
src/ui/src/wds/WdsSelect.vue The changes include adding a new required prop, enhancing placeholder handling, improving option selection logic, and adding a new CSS class for placeholder styling with more robust option management and validation.
src/writer/blocks/changepage.py Added "options": "pageKeys" to the "pageKey" field in the AbstractTemplate's writer configuration, which suggests providing a predefined list of page key options for the field.
ℹ️ Issues Detected

NOTE: These may not require action!

Below are unvalidated results from the Analysis Tools that ran during the latest scan for transparency. We investigate each of these for accuracy and relevance before surfacing them as a potential problem.

How will I know if something is a problem?
When validation completes, any concerns that warrant attention prior to merge will be posted as inline comments. These will show up in 2 ways:

  • Expert review (most cases): Issues will be posted by experts who manually reviewed and validated them. These are real HackerOne engineers (not bots) reviewing through an integrated IDE-like tool. You can communicate with them like any other reviewer. They'll stay assigned and get notified with commit & comment updates.
  • Automatically: In cases where our validation checks have highest confidence the problem is legitimate and urgent. These will include a description of contextual reasoning why & actionable next steps.
File & Line Issue
src/ui/src/builder/settings/BuilderFieldsText.vue Line 177 The code introduces a new dropdown feature for page keys without proper validation. The selectValue computed property allows setting any value, including potentially malicious ones, directly into the component's field value. The transformation function doesn't sanitize or validate this input before using it.
🧰 Analysis tools

⏱️ Latest scan covered changes up to commit 2a1791e (latest)

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Jim K reviewed all the included code changes and associated automation findings and determined that there were no immediately actionable security flaws. Note that they will continue to be notified of any new commits or comments and follow up as needed throughout the duration of this pull request's lifecycle.

Image of Jim K Jim K


Reviewed with ❤️ by PullRequest

…pdown support and placeholder options

- Added WdsSelect component with dropdown functionality and placeholder handling.
- Updated BuilderFieldsText to conditionally render WdsSelect based on input type.
- Introduced isPlaceholder property in WdsDropdownMenu for better UI representation.
- Enhanced styling for placeholder items in WdsDropdownMenuItem.
- Updated changepage.py to include pageKeys as options for the target page key.
@sheikhuzairhussain sheikhuzairhussain changed the title 🚧 Convert pageKey field to dropdown in Change Page block Convert pageKey field to dropdown in Change Page block Nov 21, 2025
@sheikhuzairhussain sheikhuzairhussain self-assigned this Nov 21, 2025
@sheikhuzairhussain sheikhuzairhussain marked this pull request as ready for review November 21, 2025 14:32
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (6)
src/ui/src/wds/WdsDropdownMenuItem.vue (1)

48-53: Placeholder styling on dropdown items is coherent; minor variant interaction

The new WdsDropdownMenuItem--placeholder class and corresponding muted colors make placeholder entries clearly distinct, and the option.isPlaceholder hook lines up with the updated option type.

One nuance: if an option were ever marked both variant: 'danger' and isPlaceholder, the placeholder text color (defined later) would override the danger color. If that combination is not expected, this is fine; otherwise you might want a more specific rule for that case.

Also applies to: 157-162

src/ui/src/wds/WdsSelect.vue (2)

108-109: Placeholder injection via selectOptions is reasonable; watch for custom placeholder edge cases

Using PLACEHOLDER_VALUE = "" plus shouldInjectPlaceholder to prepend an auto-generated placeholder option (with isPlaceholder: true) only for non-required, single-select cases is a good default.

One edge case to be aware of: if a caller passes an option with isPlaceholder: true but a non-empty value, your injection logic will remove that option (filter((option) => !option.isPlaceholder)) when adding the empty-string placeholder. If you ever want to support custom-valued placeholders, you may want to instead treat any option.isPlaceholder or option.value === PLACEHOLDER_VALUE as “a placeholder already exists” and skip adding a new one, without filtering those options out.

Also applies to: 136-172


174-179: Unknown-option handling is solid; minor naming nit

The flow from currentValueArrayfindOptionselectedOptions and hasUnknowOptionSelected looks robust:

  • Unknown values are preserved as synthetic options { value, label: String(value) }, so the user still sees what’s in the model.
  • currentLabel falls back to raw model values when unknowns are present, which makes the state debuggable instead of silently blank.

Only nit: hasUnknowOptionSelected is slightly misspelled; if you touch this code again, consider renaming to hasUnknownOptionSelected for clarity.

Also applies to: 181-193, 196-214

src/ui/src/builder/settings/BuilderFieldsText.vue (3)

4-11: Conditional WdsSelect usage for text fields is wired correctly; consider hiding icons explicitly

The switch to render WdsSelect when shouldUseDropdown is true and fall back to BuilderTemplateInput otherwise looks clean, and passing :options="selectOptions" plus :placeholder="defaultValue" matches the new option/placeholder semantics in WdsSelect.

You’re currently passing default-icon="" without setting hide-icons. Because WdsSelect uses ?? when choosing the icon, this will result in an empty string being forwarded to WdsIcon rather than suppressing the icon entirely. If you don’t want any icon for this builder control, it would be clearer to pass :hide-icons="true" instead of an empty default-icon.

Also applies to: 13-24


50-55: pageKeys helper correctly backs the new ChangePage dropdown; consider typing the accumulator

The new async WdsSelect import and the pageKeys helper together complete the loop from the Python metadata "options": "pageKeys" to concrete dropdown entries:

  • pageKeys walks root-level components of type "page", pulls their content.key as the option value, and chooses a human-friendly label via titlenamekeyid.
  • This gives a stable mapping of page keys to labels for the Change Page block.

For TypeScript friendliness, you might want to explicitly type the reducer accumulator as Record<string, string> (similar to the options computed) instead of relying on {} inference:

-		return pages.reduce((acc, page) => {
+		return pages.reduce((acc: Record<string, string>, page) => {
 			// ...
 			return acc;
-		}, {});
+		}, {} as Record<string, string>);

This would avoid any implicit any/indexing issues on acc.

Also applies to: 96-113


137-150: options computed is clearer now; a small guard could make it more robust

Typing options as computed<Record<string, string>> and delegating through field.options (function, string key, or object) is a good cleanup.

If field.options is ever a string that doesn’t correspond to a key in predefinedOptionFns, predefinedOptionFns?.[field.options](...) will throw at runtime. You could harden this slightly by guarding the lookup:

-	if (typeof field.options === "string") {
-		return predefinedOptionFns?.[field.options](wf, props.componentId);
-	}
+	if (typeof field.options === "string") {
+		const fn = predefinedOptionFns?.[field.options as keyof typeof predefinedOptionFns];
+		return fn ? fn(wf, props.componentId) : {};
+	}

This would fail closed (empty options) instead of crashing if someone mistypes the options key.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1dcd956 and 2a1791e.

📒 Files selected for processing (5)
  • src/ui/src/builder/settings/BuilderFieldsText.vue (5 hunks)
  • src/ui/src/wds/WdsDropdownMenu.vue (1 hunks)
  • src/ui/src/wds/WdsDropdownMenuItem.vue (2 hunks)
  • src/ui/src/wds/WdsSelect.vue (8 hunks)
  • src/writer/blocks/changepage.py (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-28T14:01:53.761Z
Learnt from: sheikhuzairhussain
Repo: writer/writer-framework PR: 1147
File: src/ui/src/components/core/input/CoreSelectInput.vue:170-172
Timestamp: 2025-10-28T14:01:53.761Z
Learning: In CoreSelectInput.vue (src/ui/src/components/core/input/CoreSelectInput.vue), the watcher on fields.allowMultiSelect intentionally resets formValue to defaultValue when the multi-select mode toggles, rather than preserving the user's current selection.

Applied to files:

  • src/ui/src/builder/settings/BuilderFieldsText.vue
  • src/ui/src/wds/WdsSelect.vue
🔇 Additional comments (5)
src/writer/blocks/changepage.py (1)

19-24: Hooking pageKey up to pageKeys options looks correct

Wiring "options": "pageKeys" into the ChangePage metadata matches the new predefinedOptionFns.pageKeys helper in BuilderFieldsText.vue, so the builder can render a dropdown for valid page keys without affecting runtime behavior in run(). I don’t see issues here.

src/ui/src/wds/WdsDropdownMenu.vue (1)

87-101: Extending WdsDropdownMenuOption with isPlaceholder is safe

Adding the optional isPlaceholder?: boolean flag cleanly extends the option contract and aligns with the new styling in WdsDropdownMenuItem.vue. Existing callers remain valid because the field is optional.

src/ui/src/wds/WdsSelect.vue (2)

5-8: Trigger placeholder behavior is consistent across single and multi select

The trigger’s placeholder handling (WdsSelect__trigger--placeholder, multi-select placeholder text, and currentLabel ?? placeholderLabel for single-select) is internally consistent and lines up with the computed placeholderLabel and isPlaceholderSelected. This should give a clear, uniform UX for “no selection yet” states.

Also applies to: 40-44, 52-53, 341-343


226-265: ensureValidSelection eagerly normalizes invalid values; verify that’s desirable for all callers

The watch([...], ensureValidSelection, { immediate: true }) plus ensureValidSelection logic ensures:

  • For single-select + required, an invalid or empty current value is coerced to the first available option.
  • For single-select + non-required, any value not present in selectOptions is coerced to PLACEHOLDER_VALUE (the injected placeholder).

This is a sensible default for most form-style selects, but it does mean the component will mutate the bound v-model on mount or when options change if the current value is not in the options (e.g., stale config, removed page, etc.).

If some usages need to preserve unknown values until the user consciously changes them, you may want to gate this behavior (e.g. behind a prop) or narrow it to “no value provided” cases only.

src/ui/src/builder/settings/BuilderFieldsText.vue (1)

152-162: Select options / value mapping is sound; be aware of how unknown values are normalized

The pipeline

  • options: computed<Record<string, string>>
  • selectOptions: computed<Option[]> from Object.entries
  • shouldUseDropdown gating on type === "template" && selectOptions.length > 0
  • selectValue as the v-model bridge between WdsSelect and fieldViewModel

is well-structured and typed.

One behavioral detail: selectValue’s getter returns undefined whenever inputValue isn’t one of the current selectOptions. Combined with WdsSelect’s ensureValidSelection, this means that opening the editor while the underlying field holds a value that’s no longer in the options (e.g. a deleted page key) will cause the model to be normalized to the placeholder (or first option, if required is set on WdsSelect). If that’s the intended behavior for stale configs, you’re good; otherwise you may want to preserve and surface unknown values instead of normalizing them.

Also applies to: 169-179

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PullRequest reviewed the updates made to #1196 up until the latest commit (2a1791e). No further issues were found.

Reviewed by:

Image of Jim K Jim K

@pullrequest
Copy link

pullrequest bot commented Dec 6, 2025

Due to inactivity, PullRequest has cancelled this review job. You can reactivate the code review job from the PullRequest dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants