@operato/data-grist 2.0.0-alpha.102 → 2.0.0-alpha.104
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/dist/src/editors/ox-grist-editor-select.js +37 -25
- package/dist/src/editors/ox-grist-editor-select.js.map +1 -1
- package/dist/src/filters/filter-select.js +30 -16
- package/dist/src/filters/filter-select.js.map +1 -1
- package/dist/src/filters/filters-form.d.ts +6 -2
- package/dist/src/filters/filters-form.js +74 -21
- package/dist/src/filters/filters-form.js.map +1 -1
- package/dist/src/renderers/ox-grist-renderer-select.js +34 -4
- package/dist/src/renderers/ox-grist-renderer-select.js.map +1 -1
- package/dist/src/types.d.ts +14 -1
- package/dist/src/types.js.map +1 -1
- package/dist/stories/bounded-select-filters.stories.d.ts +25 -0
- package/dist/stories/bounded-select-filters.stories.js +264 -0
- package/dist/stories/bounded-select-filters.stories.js.map +1 -0
- package/dist/stories/bounded-select-record.stories.d.ts +25 -0
- package/dist/stories/bounded-select-record.stories.js +267 -0
- package/dist/stories/bounded-select-record.stories.js.map +1 -0
- package/dist/stories/default-filters.stories.js +43 -0
- package/dist/stories/default-filters.stories.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/default-value/value-generator/date-generator.md +29 -0
- package/docs/default-value/value-generator/hour-time-generator.md +33 -0
- package/docs/default-value/value-generator/minute-time-generator.md +33 -0
- package/docs/default-value/value-generator/month-date-generator.md +2 -0
- package/docs/default-value/value-generator/now-generator.md +29 -0
- package/docs/default-value/value-generator/time-generator.md +31 -0
- package/docs/default-value/value-generator/today-generator.md +29 -0
- package/docs/default-value/value-generator/week-date-generator.md +31 -0
- package/docs/default-value/value-generator/year-date-generator.md +31 -0
- package/package.json +3 -3
- package/src/editors/ox-grist-editor-select.ts +41 -28
- package/src/filters/filter-select.ts +41 -28
- package/src/filters/filters-form.ts +74 -10
- package/src/renderers/ox-grist-renderer-select.ts +41 -6
- package/src/types.ts +19 -1
- package/stories/bounded-select-filters.stories.ts +313 -0
- package/stories/bounded-select-record.stories.ts +316 -0
- package/stories/default-filters.stories.ts +43 -0
- package/yarn-error.log +0 -16971
@@ -1,11 +1,41 @@
|
|
1
1
|
import { html } from 'lit'
|
2
|
+
import { until } from 'lit/directives/until.js'
|
2
3
|
|
3
|
-
import { FieldRenderer } from '../types'
|
4
|
+
import { FieldRenderer, SelectOption, SelectOptionObject } from '../types'
|
5
|
+
|
6
|
+
function buildOptions(options: SelectOption[], value: any) {
|
7
|
+
const selectOptionObjects = options.map(option => {
|
8
|
+
switch (typeof option) {
|
9
|
+
case 'string':
|
10
|
+
return {
|
11
|
+
display: option,
|
12
|
+
value: option
|
13
|
+
}
|
14
|
+
case 'object':
|
15
|
+
return {
|
16
|
+
display: option.display || option.name,
|
17
|
+
value: option.value
|
18
|
+
}
|
19
|
+
default:
|
20
|
+
return option
|
21
|
+
}
|
22
|
+
}) as SelectOptionObject[]
|
23
|
+
|
24
|
+
var res = selectOptionObjects
|
25
|
+
? selectOptionObjects.filter((option: any) => option.value == String(value == null ? '' : value))
|
26
|
+
: []
|
27
|
+
|
28
|
+
if (res.length) {
|
29
|
+
return html`<span>${res[0].display || res[0].name || ''}</span>`
|
30
|
+
}
|
31
|
+
return html`<span>${value}</span>`
|
32
|
+
}
|
4
33
|
|
5
34
|
export const OxGristRendererSelect: FieldRenderer = (value, column, record, rowIndex, field) => {
|
6
35
|
if (value == null) {
|
7
36
|
return ''
|
8
37
|
}
|
38
|
+
|
9
39
|
var rowOptionField = column.record.rowOptionField && record[column.record.rowOptionField]
|
10
40
|
var options = rowOptionField?.options ? rowOptionField.options : column.record.options
|
11
41
|
|
@@ -13,11 +43,16 @@ export const OxGristRendererSelect: FieldRenderer = (value, column, record, rowI
|
|
13
43
|
console.error(`options value for select '${column.name}' column is mandatory.`)
|
14
44
|
} else if (typeof options == 'function') {
|
15
45
|
options = options.call(null, value, column, record, rowIndex, field)
|
16
|
-
}
|
17
46
|
|
18
|
-
|
19
|
-
|
20
|
-
|
47
|
+
if (options instanceof Promise) {
|
48
|
+
return html`${until(
|
49
|
+
options.then(options => buildOptions(options, value)),
|
50
|
+
value
|
51
|
+
)}`
|
52
|
+
} else {
|
53
|
+
return buildOptions((options || []) as SelectOption[], value)
|
54
|
+
}
|
55
|
+
} else {
|
56
|
+
return buildOptions((options || []) as SelectOption[], value)
|
21
57
|
}
|
22
|
-
return html`<span>${value}</span>`
|
23
58
|
}
|
package/src/types.ts
CHANGED
@@ -9,7 +9,7 @@ import { DataListGutter } from './data-list/data-list-gutter'
|
|
9
9
|
import { RecordPartial } from './data-list/record-partial'
|
10
10
|
import { DataReportField } from './data-report/data-report-field'
|
11
11
|
import { OxGristEditor } from './editors'
|
12
|
-
import { QueryFilter } from './filters'
|
12
|
+
import { QueryFilter, OxFiltersForm } from './filters'
|
13
13
|
import { OxGristRenderer } from './renderers/ox-grist-renderer'
|
14
14
|
|
15
15
|
/**
|
@@ -83,6 +83,22 @@ export type FilterOperator =
|
|
83
83
|
| 'i_nlike'
|
84
84
|
| 'nlike'
|
85
85
|
|
86
|
+
export type SelectOptionObject =
|
87
|
+
| {
|
88
|
+
name: string
|
89
|
+
display?: never
|
90
|
+
value: string
|
91
|
+
}
|
92
|
+
| {
|
93
|
+
display: string
|
94
|
+
name?: never
|
95
|
+
value: string
|
96
|
+
}
|
97
|
+
|
98
|
+
export type SelectOption = SelectOptionObject | string
|
99
|
+
|
100
|
+
export type FilterChangedCallback = (value: any, form: OxFiltersForm) => boolean
|
101
|
+
|
86
102
|
/**
|
87
103
|
* Configuration object for specifying filter conditions.
|
88
104
|
*
|
@@ -99,6 +115,8 @@ export type FilterConfigObject = {
|
|
99
115
|
options?: { [key: string]: any }
|
100
116
|
value?: string | number | boolean | string[] | number[] | undefined
|
101
117
|
label?: string
|
118
|
+
boundTo?: string[]
|
119
|
+
onchange?: FilterChangedCallback
|
102
120
|
}
|
103
121
|
|
104
122
|
/**
|
@@ -0,0 +1,313 @@
|
|
1
|
+
import '../src/index.js'
|
2
|
+
import '../src/filters/filters-form.js'
|
3
|
+
import '../src/sorters/sorters-control.js'
|
4
|
+
import '@operato/popup/ox-popup-list.js'
|
5
|
+
import '@material/web/icon/icon.js'
|
6
|
+
|
7
|
+
import { html, TemplateResult } from 'lit'
|
8
|
+
import { sleep } from '@operato/utils'
|
9
|
+
|
10
|
+
import { ColumnConfig, FetchHandler, GristRecord, SelectOption } from '../src/types.js'
|
11
|
+
|
12
|
+
import { CommonHeaderStyles, CommonGristStyles } from '@operato/styles'
|
13
|
+
import { DataGridField } from '../src/data-grid/data-grid-field.js'
|
14
|
+
|
15
|
+
const fetchHandler: FetchHandler = async ({ sorters = [], filters, page, limit }) => {
|
16
|
+
var total = 120993
|
17
|
+
var start = (page! - 1) * limit!
|
18
|
+
|
19
|
+
await new Promise(resolve => setTimeout(resolve, 500))
|
20
|
+
|
21
|
+
return {
|
22
|
+
total,
|
23
|
+
records: Array(limit! * page! > total ? total % limit! : limit)
|
24
|
+
.fill('')
|
25
|
+
.map((item, idx) => {
|
26
|
+
const warehouse = idx % 2 ? '01' : '02'
|
27
|
+
const zone = idx % 2 ? 'Z001' : 'Z002'
|
28
|
+
|
29
|
+
return {
|
30
|
+
id: String(idx),
|
31
|
+
name: idx % 2 ? `shnam-${start + idx + 1}` : `heartyoh-${start + idx + 1}`,
|
32
|
+
description: idx % 2 ? `hatiolabmanager${start + idx + 1}1234567890` : `hatiosea manager-${start + idx + 1}`,
|
33
|
+
warehouse,
|
34
|
+
zone,
|
35
|
+
location: `L${warehouse}-${zone}-0${(idx % 5) + 1}`,
|
36
|
+
createdAt: Date.now(),
|
37
|
+
updatedAt: Date.now()
|
38
|
+
}
|
39
|
+
})
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
function buildConfig({ headerFilter }: { headerFilter: boolean }) {
|
44
|
+
return {
|
45
|
+
list: {
|
46
|
+
fields: ['name', 'description'],
|
47
|
+
details: ['updatedAt', 'createdAt']
|
48
|
+
},
|
49
|
+
columns: [
|
50
|
+
{
|
51
|
+
type: 'gutter',
|
52
|
+
gutterName: 'sequence'
|
53
|
+
},
|
54
|
+
{
|
55
|
+
type: 'string',
|
56
|
+
name: 'id',
|
57
|
+
hidden: true
|
58
|
+
},
|
59
|
+
{
|
60
|
+
type: 'string',
|
61
|
+
name: 'name',
|
62
|
+
label: true,
|
63
|
+
header: 'name',
|
64
|
+
filter: {
|
65
|
+
operator: 'eq',
|
66
|
+
value: 'shnam'
|
67
|
+
},
|
68
|
+
sortable: true,
|
69
|
+
width: 120
|
70
|
+
},
|
71
|
+
{
|
72
|
+
type: 'string',
|
73
|
+
name: 'description',
|
74
|
+
header: 'description',
|
75
|
+
record: {
|
76
|
+
align: 'left'
|
77
|
+
},
|
78
|
+
width: 200
|
79
|
+
},
|
80
|
+
{
|
81
|
+
type: 'select',
|
82
|
+
name: 'warehouse',
|
83
|
+
header: 'warehouse',
|
84
|
+
filter: {
|
85
|
+
operator: 'eq'
|
86
|
+
},
|
87
|
+
record: {
|
88
|
+
align: 'left',
|
89
|
+
options: async (
|
90
|
+
value: any,
|
91
|
+
column: ColumnConfig,
|
92
|
+
record: GristRecord,
|
93
|
+
rowIndex: number,
|
94
|
+
field: DataGridField
|
95
|
+
): Promise<SelectOption[]> => {
|
96
|
+
await sleep(1000) // 테스트를 위해서 강제로 1초 쉬기
|
97
|
+
return [
|
98
|
+
{
|
99
|
+
display: '',
|
100
|
+
value: ''
|
101
|
+
}
|
102
|
+
].concat(
|
103
|
+
WAREHOUSE.map(w => {
|
104
|
+
return {
|
105
|
+
display: w.name,
|
106
|
+
value: w.id
|
107
|
+
}
|
108
|
+
})
|
109
|
+
)
|
110
|
+
}
|
111
|
+
},
|
112
|
+
width: 200
|
113
|
+
},
|
114
|
+
{
|
115
|
+
type: 'select',
|
116
|
+
name: 'zone',
|
117
|
+
header: 'zone',
|
118
|
+
filter: {
|
119
|
+
operator: 'eq',
|
120
|
+
boundTo: ['warehouse'],
|
121
|
+
onchange: () => {
|
122
|
+
console.log('warehousde filter value changed.')
|
123
|
+
}
|
124
|
+
},
|
125
|
+
record: {
|
126
|
+
align: 'left',
|
127
|
+
options: async (
|
128
|
+
value: any,
|
129
|
+
column: ColumnConfig,
|
130
|
+
record: GristRecord,
|
131
|
+
rowIndex: number,
|
132
|
+
field: DataGridField
|
133
|
+
): Promise<SelectOption[]> => {
|
134
|
+
console.log('arguments', arguments)
|
135
|
+
await sleep(1000) // 테스트를 위해서 강제로 1초 쉬기
|
136
|
+
const warehouse = record.warehouse
|
137
|
+
console.log('warehouse', warehouse)
|
138
|
+
|
139
|
+
const targetWH = warehouse && WAREHOUSE.find(w => w.id == warehouse)
|
140
|
+
const zones = targetWH
|
141
|
+
? targetWH.zones
|
142
|
+
: WAREHOUSE.reduce((sum, warehouse) => {
|
143
|
+
sum = sum.concat(warehouse.zones)
|
144
|
+
return sum
|
145
|
+
}, [] as any[])
|
146
|
+
|
147
|
+
return [
|
148
|
+
{
|
149
|
+
display: '',
|
150
|
+
value: ''
|
151
|
+
}
|
152
|
+
].concat(
|
153
|
+
zones.map((z: any) => {
|
154
|
+
return {
|
155
|
+
display: z.name,
|
156
|
+
value: z.id
|
157
|
+
}
|
158
|
+
})
|
159
|
+
)
|
160
|
+
}
|
161
|
+
},
|
162
|
+
width: 200
|
163
|
+
},
|
164
|
+
{
|
165
|
+
type: 'select',
|
166
|
+
name: 'location',
|
167
|
+
header: 'location',
|
168
|
+
filter: {
|
169
|
+
operator: 'eq',
|
170
|
+
boundTo: ['warehouse', 'zone']
|
171
|
+
},
|
172
|
+
record: {
|
173
|
+
align: 'left',
|
174
|
+
options: async (
|
175
|
+
value: any,
|
176
|
+
column: ColumnConfig,
|
177
|
+
record: GristRecord,
|
178
|
+
rowIndex: number,
|
179
|
+
field: DataGridField
|
180
|
+
): Promise<SelectOption[]> => {
|
181
|
+
await sleep(1000) // 테스트를 위해서 강제로 1초 쉬기
|
182
|
+
const warehouse = record.warehouse
|
183
|
+
const zone = record.zone
|
184
|
+
console.log('warehouse, zone', warehouse, zone)
|
185
|
+
|
186
|
+
const targetWH = (warehouse && WAREHOUSE.find(w => w.id == warehouse)) || null
|
187
|
+
const targetZone = zone && targetWH?.zones.find((z: any) => z.id == zone)
|
188
|
+
return targetZone ? ['', ...targetZone.locations] : []
|
189
|
+
}
|
190
|
+
},
|
191
|
+
width: 200
|
192
|
+
},
|
193
|
+
{
|
194
|
+
type: 'datetime',
|
195
|
+
name: 'updatedAt',
|
196
|
+
header: 'updated at',
|
197
|
+
width: 180
|
198
|
+
},
|
199
|
+
{
|
200
|
+
type: 'datetime',
|
201
|
+
name: 'createdAt',
|
202
|
+
header: 'created at',
|
203
|
+
width: 180
|
204
|
+
}
|
205
|
+
],
|
206
|
+
rows: {},
|
207
|
+
sorters: [
|
208
|
+
{
|
209
|
+
name: 'name',
|
210
|
+
desc: true
|
211
|
+
}
|
212
|
+
],
|
213
|
+
filters: {
|
214
|
+
header: headerFilter
|
215
|
+
},
|
216
|
+
pagination: {
|
217
|
+
pages: [30, 50, 100, 200]
|
218
|
+
}
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
const WAREHOUSE = [
|
223
|
+
{
|
224
|
+
id: '01',
|
225
|
+
name: '제 1 창고',
|
226
|
+
zones: [
|
227
|
+
{
|
228
|
+
id: 'Z001',
|
229
|
+
name: 'Zone 01-001',
|
230
|
+
locations: ['L01-001-01', 'L01-001-02', 'L01-001-03', 'L01-001-04', 'L01-001-05']
|
231
|
+
},
|
232
|
+
{
|
233
|
+
id: 'Z002',
|
234
|
+
name: 'Zone 01-002',
|
235
|
+
locations: ['L01-002-01', 'L01-002-02', 'L01-002-03', 'L01-002-04', 'L01-002-05']
|
236
|
+
}
|
237
|
+
]
|
238
|
+
},
|
239
|
+
{
|
240
|
+
id: '02',
|
241
|
+
name: '제 2 창고',
|
242
|
+
zones: [
|
243
|
+
{
|
244
|
+
id: 'Z001',
|
245
|
+
name: 'Zone 02-001',
|
246
|
+
locations: ['L02-001-01', 'L02-001-02', 'L02-001-03', 'L02-001-04', 'L02-001-05']
|
247
|
+
},
|
248
|
+
{
|
249
|
+
id: 'Z002',
|
250
|
+
name: 'Zone 02-002',
|
251
|
+
locations: ['L02-002-01', 'L02-002-02', 'L02-002-03', 'L02-002-04', 'L02-002-05']
|
252
|
+
}
|
253
|
+
]
|
254
|
+
}
|
255
|
+
]
|
256
|
+
|
257
|
+
export default {
|
258
|
+
title: 'bounded select filters for ox-grist',
|
259
|
+
component: 'ox-grist',
|
260
|
+
argTypes: {
|
261
|
+
headerFilter: { control: 'boolean' }
|
262
|
+
}
|
263
|
+
}
|
264
|
+
|
265
|
+
interface Story<T> {
|
266
|
+
(args: T): TemplateResult
|
267
|
+
args?: Partial<T>
|
268
|
+
argTypes?: Record<string, unknown>
|
269
|
+
}
|
270
|
+
|
271
|
+
interface ArgTypes {
|
272
|
+
headerFilter: boolean
|
273
|
+
}
|
274
|
+
|
275
|
+
const Template: Story<ArgTypes> = ({ headerFilter }: ArgTypes) =>
|
276
|
+
html` <link
|
277
|
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL@20..48,100..700,0..1"
|
278
|
+
rel="stylesheet"
|
279
|
+
/>
|
280
|
+
<link
|
281
|
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL@20..48,100..700,0..1"
|
282
|
+
rel="stylesheet"
|
283
|
+
/>
|
284
|
+
<link
|
285
|
+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL@20..48,100..700,0..1"
|
286
|
+
rel="stylesheet"
|
287
|
+
/>
|
288
|
+
<link href="/themes/app-theme.css" rel="stylesheet" />
|
289
|
+
<link href="/themes/oops-theme.css" rel="stylesheet" />
|
290
|
+
<link href="/themes/grist-theme.css" rel="stylesheet" />
|
291
|
+
|
292
|
+
<style>
|
293
|
+
${CommonGristStyles.cssText}
|
294
|
+
${CommonHeaderStyles.cssText}
|
295
|
+
</style>
|
296
|
+
|
297
|
+
<ox-grist
|
298
|
+
.config=${buildConfig({ headerFilter })}
|
299
|
+
mode="GRID"
|
300
|
+
.fetchHandler=${fetchHandler}
|
301
|
+
@filters-change=${(e: Event) => console.log('filters', (e.target as any).filters)}
|
302
|
+
>
|
303
|
+
<div slot="headroom">
|
304
|
+
<div id="filters">
|
305
|
+
<ox-filters-form></ox-filters-form>
|
306
|
+
</div>
|
307
|
+
</div>
|
308
|
+
</ox-grist>`
|
309
|
+
|
310
|
+
export const Regular = Template.bind({})
|
311
|
+
Regular.args = {
|
312
|
+
headerFilter: true
|
313
|
+
}
|