Skip to content

Commit b4ea9c5

Browse files
Dan select component (#1048)
1 parent 7d6d99c commit b4ea9c5

File tree

29 files changed

+478
-73
lines changed

29 files changed

+478
-73
lines changed

pgml-dashboard/content/blog/how-to-improve-search-results-with-machine-learning.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ This is considered a Supervised Learning problem, because we have a labeled data
216216

217217
### Training Data
218218

219-
First things first, we need to record some user clicks on our search results. We'll create a new table to store our training data, which are the observed inputs and output of our new relevance function. In a real system, we'd probably have separate tables to record **sessions**, **searches**, **results**, **clicks** and other events, but for simplicity in this example, we'll just record the exact information we need to train our model in a single table. Everytime we perform a search, we'll record the `ts_rank` for the both the **title** and **body**, and whether the user **clicked** on the result.
219+
First things first, we need to record some user clicks on our search results. We'll create a new table to store our training data, which are the observed inputs and output of our new relevance function. In a real system, we'd probably have separate tables to record **sessions**, **searches**, **results**, **clicks** and other events, but for simplicity in this example, we'll just record the exact information we need to train our model in a single table. Everytime we perform a search, we'll record the `ts_rank` for both the **title** and **body**, and whether the user **clicked** on the result.
220220

221221
!!! generic
222222

pgml-dashboard/src/components/dropdown/dropdown.scss

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
display: flex;
4040
justify-content: space-between;
4141
font-weight: $font-weight-normal;
42+
padding: 16px 20px;
4243

4344
--bs-btn-border-color: transparent;
4445
--bs-btn-border-width: 1px;
@@ -48,6 +49,10 @@
4849
--bs-btn-active-color: #{$gray-100};
4950
--bs-btn-hover-color: #{$gray-100};
5051

52+
&.error {
53+
border-color: #{$error};
54+
}
55+
5156
.material-symbols-outlined {
5257
color: #{$neon-shade-100};
5358
}
@@ -73,7 +78,7 @@
7378
}
7479

7580
.menu-item {
76-
a {
81+
a, div {
7782
padding: 8px 12px;
7883
overflow: hidden;
7984
text-overflow: ellipsis;

pgml-dashboard/src/components/dropdown/mod.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::components::navigation::dropdown_link::DropdownLink;
2+
use crate::components::stimulus::stimulus_target::StimulusTarget;
13
use pgml_components::component;
24
use pgml_components::Component;
35
use sailfish::TemplateOnce;
@@ -21,35 +23,57 @@ pub struct Dropdown {
2123
/// The currently selected value.
2224
value: DropdownValue,
2325

24-
/// The list of dropdown links to render.
25-
links: Vec<StaticNavLink>,
26+
/// The list of dropdown items to render.
27+
items: Vec<Component>,
2628

2729
/// Position of the dropdown menu.
2830
offset: String,
2931

30-
/// Whether or not the dropdown is collapsble.
32+
/// Whether or not the dropdown is collapsable.
3133
collapsable: bool,
3234
offset_collapsed: String,
3335

3436
/// Where the dropdown menu should appear
3537
menu_position: String,
3638
expandable: bool,
39+
40+
/// target to control value
41+
value_target: StimulusTarget,
3742
}
3843

3944
impl Dropdown {
40-
pub fn new(links: Vec<StaticNavLink>) -> Self {
45+
pub fn new() -> Self {
46+
Dropdown {
47+
items: Vec::new(),
48+
value: DropdownValue::Text("Dropdown".to_owned().into()),
49+
offset: "0, 10".to_owned(),
50+
offset_collapsed: "68, -44".to_owned(),
51+
menu_position: "".to_owned(),
52+
..Default::default()
53+
}
54+
}
55+
56+
pub fn nav(links: Vec<StaticNavLink>) -> Self {
4157
let binding = links
4258
.iter()
4359
.filter(|link| link.active)
4460
.collect::<Vec<&StaticNavLink>>();
61+
4562
let active = binding.first();
4663
let value = if let Some(active) = active {
4764
active.name.to_owned()
4865
} else {
49-
"Menu".to_owned()
66+
"Dropdown Nav".to_owned()
5067
};
68+
69+
let mut items = Vec::new();
70+
for link in links {
71+
let item = DropdownLink::new(link);
72+
items.push(item.into());
73+
}
74+
5175
Dropdown {
52-
links,
76+
items,
5377
value: DropdownValue::Text(value.into()),
5478
offset: "0, 10".to_owned(),
5579
offset_collapsed: "68, -44".to_owned(),
@@ -58,6 +82,11 @@ impl Dropdown {
5882
}
5983
}
6084

85+
pub fn items(mut self, items: Vec<Component>) -> Self {
86+
self.items = items;
87+
self
88+
}
89+
6190
pub fn text(mut self, value: Component) -> Self {
6291
self.value = DropdownValue::Text(value);
6392
self
@@ -97,6 +126,11 @@ impl Dropdown {
97126
self.expandable = true;
98127
self
99128
}
129+
130+
pub fn value_target(mut self, value_target: StimulusTarget) -> Self {
131+
self.value_target = value_target;
132+
self
133+
}
100134
}
101135

102136
component!(Dropdown);

pgml-dashboard/src/components/dropdown/template.html

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
data-bs-toggle="dropdown"
2121
data-bs-offset="<%= offset %>"
2222
aria-expanded="false">
23-
<span class="btn-dropdown-text"><%+ text %></span>
23+
<span class="btn-dropdown-text" <%- value_target %>><%+ text %></span>
2424
<span class="material-symbols-outlined">
2525
expand_more
2626
</span>
@@ -41,15 +41,9 @@
4141
</div>
4242
<% } %>
4343

44-
<ul class="dropdown-menu <%= menu_position %>">
45-
<% for link in links { %>
46-
<li class="menu-item d-flex align-items-center <% if link.disabled { %>disabled<% } %>">
47-
<% if link.disabled { %>
48-
<a type="button" class="dropdown-item" disabled href="#"><%= link.name %></a>
49-
<% } else { %>
50-
<a type="button" class="dropdown-item" href="<%- link.href %>"><%= link.name %></a>
51-
<% } %>
52-
</li>
44+
<ul class="dropdown-menu overflow-auto <%= menu_position %>">
45+
<% for item in items { %>
46+
<%+ item %>
5347
<% } %>
5448
</ul>
5549
</div>

pgml-dashboard/src/components/inputs/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,9 @@
55
pub mod range_group;
66
pub use range_group::RangeGroup;
77

8+
// src/components/inputs/select
9+
pub mod select;
10+
pub use select::Select;
11+
812
// src/components/inputs/text
913
pub mod text;
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use crate::components::stimulus::stimulus_action::{StimulusAction, StimulusEvents};
2+
use pgml_components::component;
3+
use pgml_components::Component;
4+
use sailfish::TemplateOnce;
5+
6+
#[derive(TemplateOnce, Default)]
7+
#[template(path = "inputs/select/template.html")]
8+
pub struct Select {
9+
options: Vec<Component>,
10+
value: String,
11+
offset: String,
12+
collapsable: bool,
13+
offset_collapsed: String,
14+
menu_position: String,
15+
expandable: bool,
16+
name: String,
17+
}
18+
19+
impl Select {
20+
pub fn new() -> Select {
21+
Select {
22+
options: Vec::new(),
23+
value: "Select".to_owned(),
24+
offset: "0, 10".to_owned(),
25+
offset_collapsed: "68, -44".to_owned(),
26+
menu_position: "".to_owned(),
27+
name: "input_name".to_owned(),
28+
..Default::default()
29+
}
30+
.options(vec![
31+
"option1".to_owned(),
32+
"option2".to_owned(),
33+
"option3".to_owned(),
34+
])
35+
}
36+
37+
pub fn options(mut self, values: Vec<String>) -> Self {
38+
let mut options = Vec::new();
39+
self.value = values.first().unwrap().to_owned();
40+
41+
for value in values {
42+
let item = Option::new(
43+
value,
44+
StimulusAction::new()
45+
.controller("inputs-select")
46+
.method("choose")
47+
.action(StimulusEvents::Click),
48+
);
49+
options.push(item.into());
50+
}
51+
52+
self.options = options;
53+
self
54+
}
55+
56+
pub fn name(mut self, name: &str) -> Self {
57+
self.name = name.to_owned();
58+
self
59+
}
60+
61+
pub fn text(mut self, value: String) -> Self {
62+
self.value = value;
63+
self
64+
}
65+
66+
pub fn collapsable(mut self) -> Self {
67+
self.collapsable = true;
68+
self
69+
}
70+
71+
pub fn menu_end(mut self) -> Self {
72+
self.menu_position = "dropdown-menu-end".to_owned();
73+
self
74+
}
75+
76+
pub fn menu_start(mut self) -> Self {
77+
self.menu_position = "dropdown-menu-start".to_owned();
78+
self
79+
}
80+
81+
pub fn offset(mut self, offset: &str) -> Self {
82+
self.offset = offset.to_owned();
83+
self
84+
}
85+
86+
pub fn offset_collapsed(mut self, offset: &str) -> Self {
87+
self.offset_collapsed = offset.to_owned();
88+
self
89+
}
90+
91+
pub fn expandable(mut self) -> Self {
92+
self.expandable = true;
93+
self
94+
}
95+
}
96+
97+
#[derive(TemplateOnce)]
98+
#[template(path = "inputs/select/option.html")]
99+
pub struct Option {
100+
value: String,
101+
action: StimulusAction,
102+
}
103+
104+
impl Option {
105+
pub fn new(value: String, action: StimulusAction) -> Self {
106+
Option { value, action }
107+
}
108+
}
109+
110+
component!(Option);
111+
component!(Select);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
<li class="menu-item d-flex align-items-center">
3+
<button type="button" class="dropdown-item" data-action="<%- action %>"><%= value %></button>
4+
</li>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
div[data-controller="inputs-select"] {
2+
3+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Controller } from '@hotwired/stimulus'
2+
3+
export default class extends Controller {
4+
static targets = ["input", "value"]
5+
6+
choose(e) {
7+
this.inputTarget.value = e.target.innerHTML
8+
this.valueTarget.innerHTML = e.target.innerHTML
9+
}
10+
11+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<%
2+
use crate::components::dropdown::Dropdown;
3+
use crate::components::stimulus::stimulus_target::StimulusTarget;
4+
%>
5+
<div data-controller="inputs-select">
6+
7+
<% let mut dropdown = Dropdown::new()
8+
.items(options)
9+
.offset(&offset)
10+
.offset_collapsed(&offset_collapsed)
11+
.text(value.clone().into());
12+
13+
if menu_position == "dropdown-menu-end" {
14+
dropdown = dropdown.menu_end();
15+
} else if menu_position == "dropdown-menu-start" {
16+
dropdown = dropdown.menu_start();
17+
}
18+
19+
if collapsable {
20+
dropdown = dropdown.collapsable();
21+
}
22+
23+
if expandable {
24+
dropdown = dropdown.expandable();
25+
}
26+
27+
dropdown = dropdown.value_target(StimulusTarget::new().controller("inputs-select").name("value"));
28+
%>
29+
30+
<%+ dropdown %>
31+
32+
<input type="hidden" name="<%= name %>" value="<%= value %>" data-inputs-select-target="input">
33+
</div>

0 commit comments

Comments
 (0)