Skip to content

Commit 0e863ae

Browse files
feat: Add MultiSelect, RadioGroup and Checkbox input widget types (#2472)
### Summary This PR addresses issue #1858 by introducing several new UI input widgets to Chainlit, including `MultiSelect`, `Checkbox`, and `RadioGroup`. These new components provide more flexibility for creating interactive and user-friendly chat settings. ### Changes - **Frontend:** - Created a new `MultiSelectInput` component with a modern, tag-based design. - Added a new `CheckboxInput` component with a simplified UI and improved tooltip handling. - Added a new `RadioButtonGroup` component. - Integrated the new components into the main form in `FormInput.tsx`. - Internationalized the `MultiSelectInput` component with a new translation key. - Updated every `.json` translation file to include this new key. - **Backend:** - Added `Checkbox`, `RadioGroup`, and `MultiSelect` classes to `input_widget.py`. - Updated the `__init__.py` file to expose the new `RadioGroup` class. ### How the New Widgets Work - **MultiSelect:** The `MultiSelect` component allows users to select multiple options from a dropdown list. Selected items are displayed as tags, and can be removed by clicking the "x" button. The dropdown also includes a search input to quickly filter through a long list of options. - **Checkbox:** The `Checkbox` component has been simplified to remove the redundant title. The `label` is now displayed next to the checkbox, and the `tooltip` is displayed when the user hovers over the label. ### Testing Honestly, I tried updating the `chat_setting` test but I wasn't able to set it properly. I'm a bit of a nooby with Cypress. ### Preview <img width="523" height="726" alt="image" src="https://github.com/user-attachments/assets/ffabc0ca-758f-41a7-b71b-e23c70048906" /> --- <img width="481" height="133" alt="image" src="https://github.com/user-attachments/assets/0a11534e-9860-4356-87fc-90262f8c5b3d" /> --- <img width="454" height="102" alt="image" src="https://github.com/user-attachments/assets/24a05854-b338-4ae0-8264-47f70402e3c7" />
1 parent 1c3a01a commit 0e863ae

26 files changed

+869
-5
lines changed

backend/chainlit/input_widget.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,113 @@ def to_dict(self) -> Dict[str, Any]:
180180
"tooltip": self.tooltip,
181181
"description": self.description,
182182
}
183+
184+
185+
@dataclass
186+
class MultiSelect(InputWidget):
187+
"""Useful to create a multi-select input."""
188+
189+
type: InputWidgetType = "multiselect"
190+
initial: List[str] = Field(default_factory=list)
191+
values: List[str] = Field(default_factory=list)
192+
items: Dict[str, str] = Field(default_factory=dict)
193+
194+
def __post_init__(
195+
self,
196+
) -> None:
197+
super().__post_init__()
198+
199+
if not self.values and not self.items:
200+
raise ValueError("Must provide values or items to create a MultiSelect")
201+
202+
if self.values and self.items:
203+
raise ValueError(
204+
"You can only provide either values or items to create a MultiSelect"
205+
)
206+
207+
if self.values:
208+
self.items = {value: value for value in self.values}
209+
210+
def to_dict(self) -> Dict[str, Any]:
211+
return {
212+
"type": self.type,
213+
"id": self.id,
214+
"label": self.label,
215+
"initial": self.initial,
216+
"items": [
217+
{"label": id, "value": value} for id, value in self.items.items()
218+
],
219+
"tooltip": self.tooltip,
220+
"description": self.description,
221+
}
222+
223+
224+
@dataclass
225+
class Checkbox(InputWidget):
226+
"""Useful to create a checkbox input."""
227+
228+
type: InputWidgetType = "checkbox"
229+
initial: bool = False
230+
231+
def to_dict(self) -> Dict[str, Any]:
232+
return {
233+
"type": self.type,
234+
"id": self.id,
235+
"label": self.label,
236+
"initial": self.initial,
237+
"tooltip": self.tooltip,
238+
"description": self.description,
239+
}
240+
241+
242+
@dataclass
243+
class RadioGroup(InputWidget):
244+
"""Useful to create a radio button input."""
245+
246+
type: InputWidgetType = "radio"
247+
initial: Optional[str] = None
248+
initial_index: Optional[int] = None
249+
initial_value: Optional[str] = None
250+
values: List[str] = Field(default_factory=list)
251+
items: Dict[str, str] = Field(default_factory=dict)
252+
253+
def __post_init__(
254+
self,
255+
) -> None:
256+
super().__post_init__()
257+
258+
if not self.values and not self.items:
259+
raise ValueError("Must provide values or items to create a RadioButton")
260+
261+
if self.values and self.items:
262+
raise ValueError(
263+
"You can only provide either values or items to create a RadioButton"
264+
)
265+
266+
if not self.values and self.initial_index is not None:
267+
raise ValueError(
268+
"Initial_index can only be used in combination with values to create a RadioButton"
269+
)
270+
271+
if self.items:
272+
self.initial = self.initial_value
273+
elif self.values:
274+
self.items = {value: value for value in self.values}
275+
self.initial = (
276+
self.values[self.initial_index]
277+
if self.initial_index is not None
278+
else self.initial_value
279+
)
280+
281+
def to_dict(self) -> Dict[str, Any]:
282+
return {
283+
"type": self.type,
284+
"id": self.id,
285+
"label": self.label,
286+
"initial": self.initial,
287+
"items": [
288+
{"label": id, "value": value} for id, value in self.items.items()
289+
],
290+
"tooltip": self.tooltip,
291+
"description": self.description,
292+
}

backend/chainlit/translations/bn.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,10 @@
222222
"security": "Security",
223223
"beta": "Beta",
224224
"best-practice": "Best Practice"
225+
},
226+
"components": {
227+
"MultiSelectInput": {
228+
"placeholder": "বেছে নিন..."
229+
}
225230
}
226231
}

backend/chainlit/translations/el-GR.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,10 @@
222222
"security": "Ασφάλεια",
223223
"beta": "Beta",
224224
"best-practice": "Βέλτιστη Πρακτική"
225+
},
226+
"components": {
227+
"MultiSelectInput": {
228+
"placeholder": "Επιλέξτε..."
229+
}
225230
}
226231
}

backend/chainlit/translations/en-US.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,10 @@
222222
"security": "Security",
223223
"beta": "Beta",
224224
"best-practice": "Best Practice"
225+
},
226+
"components": {
227+
"MultiSelectInput": {
228+
"placeholder": "Select..."
229+
}
225230
}
226231
}

backend/chainlit/translations/es.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,10 @@
222222
"security": "Seguridad",
223223
"beta": "Beta",
224224
"best-practice": "Mejor práctica"
225+
},
226+
"components": {
227+
"MultiSelectInput": {
228+
"placeholder": "Seleccionar..."
229+
}
225230
}
226231
}

backend/chainlit/translations/fr-FR.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,10 @@
222222
"security": "Sécurité",
223223
"beta": "Bêta",
224224
"best-practice": "Meilleure pratique"
225+
},
226+
"components": {
227+
"MultiSelectInput": {
228+
"placeholder": "Sélectionner..."
229+
}
225230
}
226231
}

backend/chainlit/translations/gu.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,10 @@
222222
"security": "Security",
223223
"beta": "Beta",
224224
"best-practice": "Best Practice"
225+
},
226+
"components": {
227+
"MultiSelectInput": {
228+
"placeholder": "બેંચી લો..."
229+
}
225230
}
226231
}

backend/chainlit/translations/he-IL.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,10 @@
222222
"security": "Security",
223223
"beta": "Beta",
224224
"best-practice": "Best Practice"
225+
},
226+
"components": {
227+
"MultiSelectInput": {
228+
"placeholder": "בחר..."
229+
}
225230
}
226231
}

backend/chainlit/translations/hi.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,10 @@
222222
"security": "Security",
223223
"beta": "Beta",
224224
"best-practice": "Best Practice"
225+
},
226+
"components": {
227+
"MultiSelectInput": {
228+
"placeholder": "चुनें..."
229+
}
225230
}
226231
}

backend/chainlit/translations/ja.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,5 +221,10 @@
221221
"security": "Security",
222222
"beta": "Beta",
223223
"best-practice": "Best Practice"
224+
},
225+
"components": {
226+
"MultiSelectInput": {
227+
"placeholder": "選択..."
228+
}
224229
}
225-
}
230+
}

0 commit comments

Comments
 (0)