-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathPersonListView.kt
163 lines (152 loc) · 7.23 KB
/
PersonListView.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package example.crudflow.person
import com.github.mvysny.karibudsl.v10.*
import com.github.mvysny.kaributools.*
import com.github.vokorm.db
import com.github.vokorm.exp
import com.gitlab.mvysny.jdbiorm.condition.Condition
import com.gitlab.mvysny.jdbiorm.vaadin.filter.BooleanFilterField
import com.gitlab.mvysny.jdbiorm.vaadin.filter.DateRangePopup
import com.gitlab.mvysny.jdbiorm.vaadin.filter.FilterTextField
import com.gitlab.mvysny.jdbiorm.vaadin.filter.NumberRangePopup
import com.vaadin.flow.component.Key.KEY_G
import com.vaadin.flow.component.button.Button
import com.vaadin.flow.component.button.ButtonVariant
import com.vaadin.flow.component.grid.ColumnTextAlign
import com.vaadin.flow.component.grid.Grid
import com.vaadin.flow.component.grid.contextmenu.GridContextMenu
import com.vaadin.flow.component.icon.IconFactory
import com.vaadin.flow.component.icon.VaadinIcon
import com.vaadin.flow.data.renderer.ComponentRenderer
import com.vaadin.flow.router.Route
import eu.vaadinonkotlin.toDate
import eu.vaadinonkotlin.vaadin.*
import eu.vaadinonkotlin.vaadin.vokdb.dataProvider
import eu.vaadinonkotlin.vaadin.vokdb.enumFilterField
import example.crudflow.MainLayout
import java.time.LocalDate
/**
* The main view contains a button and a template element.
*/
@Route("", layout = MainLayout::class)
class PersonListView : KComposite() {
private lateinit var personGrid: Grid<Person>
lateinit var gridContextMenu: GridContextMenu<Person>
private val nameFilter = FilterTextField()
private val ageFilter = NumberRangePopup()
private val aliveFilter = BooleanFilterField()
private val dateOfBirthFilter = DateRangePopup()
private val maritalStatusFilter = enumFilterField<MaritalStatus>()
private val dataProvider = Person.dataProvider
private val createdFilter = DateRangePopup()
private val root = ui {
verticalLayout {
setSizeFull()
h4("Person list")
button("Generate testing data (Alt+G)") {
onClick {
generateTestingData()
}
addClickShortcut(Alt + KEY_G)
}
personGrid = grid<Person>(dataProvider) {
flexGrow = 1.0
appendHeaderRow() // because of https://github.com/vaadin/vaadin-grid/issues/1870
val filterBar = appendHeaderRow()
addButtonColumn(VaadinIcon.EYE, "view", { person: Person -> navigateTo(PersonView::class, person.id!!) }) {}
addButtonColumn(VaadinIcon.EDIT, "edit", { person: Person -> createOrEditPerson(person) }) {}
addButtonColumn(VaadinIcon.TRASH, "delete", { person: Person -> person.delete(); refresh() }) {}
columnFor(Person::id, sortable = false) {
width = "90px"; isExpand = false
}
val nameColumn = columnFor(Person::name) {
setSortProperty(Person::name.exp)
nameFilter.addValueChangeListener { updateFilter() }
filterBar.getCell(this).component = nameFilter
}
columnFor(Person::age) {
width = "120px"; isExpand = false; textAlign = ColumnTextAlign.CENTER
setSortProperty(Person::age.exp)
ageFilter.addValueChangeListener { updateFilter() }
filterBar.getCell(this).component = ageFilter
}
columnFor(Person::alive) {
width = "130px"; isExpand = false
setSortProperty(Person::alive.exp)
aliveFilter.addValueChangeListener { updateFilter() }
filterBar.getCell(this).component = aliveFilter
}
columnFor(Person::dateOfBirth, converter = { it?.toString() }) {
setSortProperty(Person::dateOfBirth.exp)
dateOfBirthFilter.addValueChangeListener { updateFilter() }
filterBar.getCell(this).component = dateOfBirthFilter
}
columnFor(Person::maritalStatus) {
width = "160px"; isExpand = false
setSortProperty(Person::maritalStatus.exp)
maritalStatusFilter.addValueChangeListener { updateFilter() }
filterBar.getCell(this).component = maritalStatusFilter
}
columnFor(Person::created, converter = { it!!.toInstant().toString() }) {
setSortProperty(Person::created.exp)
createdFilter.addValueChangeListener { updateFilter() }
filterBar.getCell(this).component = createdFilter
}
gridContextMenu = gridContextMenu {
item("view", { person: Person? -> if (person != null) navigateTo(PersonView::class, person.id!!) })
item("edit", { person: Person? -> if (person != null) createOrEditPerson(person) })
item("delete", { person: Person? -> if (person != null) { person.delete(); refresh() } })
}
sort(nameColumn.asc)
}
}
}
private fun updateFilter() {
var c: Condition = Condition.NO_CONDITION
if (!nameFilter.value.isBlank()) {
c = c.and(Person::name.exp.startsWithIgnoreCase(nameFilter.value))
}
c = c.and(ageFilter.value.asIntegerInterval().contains(Person::age.exp))
if (!aliveFilter.isEmpty) {
c = c.and(Person::alive.exp.`is`(aliveFilter.value))
}
c = c.and(dateOfBirthFilter.value.contains(Person::dateOfBirth.exp, BrowserTimeZone.get))
if (!maritalStatusFilter.isAllOrNothingSelected) {
c = c.and(Person::maritalStatus.exp.`in`(maritalStatusFilter.value))
}
c = c.and(createdFilter.value.contains(Person::created.exp, BrowserTimeZone.get))
dataProvider.filter = c
}
private fun createOrEditPerson(person: Person) {
CreateEditPerson(person).apply {
onSaveOrCreateListener = { personGrid.refresh() }
}.open()
}
private fun generateTestingData() {
db {
(0..85).forEach {
Person(name = "generated$it", age = it + 15, maritalStatus = MaritalStatus.Single, alive = true,
dateOfBirth = LocalDate.of(1990, 1, 1).plusDays(it.toLong()),
created = LocalDate.of(2011, 1, 1).plusDays(it.toLong()).atStartOfDay(BrowserTimeZone.get).toInstant().toDate).save()
}
}
personGrid.dataProvider.refreshAll()
}
}
/**
* Utility method which adds a column housing one small icon button with given [icon] and [clickListener].
*/
fun <T> Grid<T>.addButtonColumn(icon: IconFactory, key: String, clickListener: (T) -> Unit, block: Grid.Column<T>.()->Unit): Grid.Column<T> {
val renderer = ComponentRenderer<Button, T> { row: T ->
val button = Button(icon.create())
button.addThemeVariants(ButtonVariant.LUMO_ICON, ButtonVariant.LUMO_TERTIARY, ButtonVariant.LUMO_SMALL)
button.addClickListener { clickListener(row) }
button
}
val column: Grid.Column<T> = addColumn(renderer).apply {
setKey(key)
setWidth("50px")
isExpand = false
block()
}
return column
}