@operato/data-grist 2.0.0-alpha.133 → 2.0.0-alpha.134
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 +11 -0
- package/dist/src/data-grid/data-grid-header.js +1 -1
- package/dist/src/data-grid/data-grid-header.js.map +1 -1
- package/dist/src/data-grist.js +34 -36
- package/dist/src/data-grist.js.map +1 -1
- package/dist/src/filters/filter-styles.js +21 -11
- package/dist/src/filters/filter-styles.js.map +1 -1
- package/dist/src/filters/filters-form.d.ts +8 -2
- package/dist/src/filters/filters-form.js +128 -62
- package/dist/src/filters/filters-form.js.map +1 -1
- package/dist/src/personalizer/ox-grist-filter-personalizer.d.ts +8 -0
- package/dist/src/personalizer/ox-grist-filter-personalizer.js +177 -0
- package/dist/src/personalizer/ox-grist-filter-personalizer.js.map +1 -0
- package/dist/src/personalizer/ox-grist-personalizer.js +7 -1
- package/dist/src/personalizer/ox-grist-personalizer.js.map +1 -1
- package/dist/src/types.d.ts +11 -0
- package/dist/src/types.js.map +1 -1
- package/dist/stories/grid-setting.stories.d.ts +1 -0
- package/dist/stories/grid-setting.stories.js +21 -29
- package/dist/stories/grid-setting.stories.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/src/data-grid/data-grid-header.ts +1 -1
- package/src/data-grist.ts +36 -38
- package/src/filters/filter-styles.ts +21 -11
- package/src/filters/filters-form.ts +196 -125
- package/src/personalizer/ox-grist-filter-personalizer.ts +191 -0
- package/src/personalizer/ox-grist-personalizer.ts +7 -1
- package/src/types.ts +12 -0
- package/stories/grid-setting.stories.ts +22 -29
package/src/data-grist.ts
CHANGED
@@ -176,7 +176,7 @@ export class DataGrist extends LitElement implements DataConsumer {
|
|
176
176
|
load: () => {
|
177
177
|
return {}
|
178
178
|
},
|
179
|
-
save: preference => preference,
|
179
|
+
save: (preference: any) => preference,
|
180
180
|
reset: () => {}
|
181
181
|
}
|
182
182
|
|
@@ -326,51 +326,49 @@ export class DataGrist extends LitElement implements DataConsumer {
|
|
326
326
|
const config = { ...this.config }
|
327
327
|
const columns: Partial<ColumnConfig>[] = config.columns
|
328
328
|
|
329
|
-
|
330
|
-
const { columns: personalColumns, sorters, pagination, mode } = this.personalConfig
|
329
|
+
const { columns: personalColumns, sorters, pagination, mode } = this.personalConfig
|
331
330
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
function reorderList(a: { name: string }[], b: { name: string }[]): { name: string }[] {
|
339
|
-
// 결과 배열 초기화, a 배열 길이만큼 undefined로 채움
|
340
|
-
const result = new Array(a.length)
|
331
|
+
if (personalColumns) {
|
332
|
+
const xcolumns = columns.map((column: Partial<ColumnConfig>) => {
|
333
|
+
const personalColumn = personalColumns.find(pcolumn => pcolumn.name == column.name)
|
334
|
+
return personalColumn ? { ...column, ...personalColumn } : column
|
335
|
+
})
|
341
336
|
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
result[index] = item
|
346
|
-
}
|
347
|
-
})
|
337
|
+
function reorderList(a: { name: string }[], b: { name: string }[]): { name: string }[] {
|
338
|
+
// 결과 배열 초기화, a 배열 길이만큼 undefined로 채움
|
339
|
+
const result = new Array(a.length)
|
348
340
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
341
|
+
// b 배열에 없는 아이템은 원래 위치로 채움
|
342
|
+
a.forEach((item, index) => {
|
343
|
+
if (!item.name || !b.find(bi => bi.name == item.name)) {
|
344
|
+
result[index] = item
|
345
|
+
}
|
346
|
+
})
|
355
347
|
|
356
|
-
|
357
|
-
|
348
|
+
b.forEach(item => {
|
349
|
+
const ai = a.find(ai => ai.name == item.name)
|
350
|
+
if (ai) {
|
351
|
+
result[result.findIndex(slot => slot === undefined)] = ai
|
352
|
+
}
|
353
|
+
})
|
358
354
|
|
359
|
-
|
360
|
-
config.columns = reorderList(xcolumns as any, personalColumns as any)
|
355
|
+
return result
|
361
356
|
}
|
362
357
|
|
363
|
-
|
364
|
-
|
365
|
-
|
358
|
+
// 배열 재정렬 실행
|
359
|
+
config.columns = reorderList(xcolumns as any, personalColumns as any)
|
360
|
+
}
|
366
361
|
|
367
|
-
|
368
|
-
|
369
|
-
|
362
|
+
if (pagination) {
|
363
|
+
config.pagination = pagination
|
364
|
+
}
|
370
365
|
|
371
|
-
|
372
|
-
|
373
|
-
|
366
|
+
if (sorters) {
|
367
|
+
config.sorters = sorters
|
368
|
+
}
|
369
|
+
|
370
|
+
if (mode) {
|
371
|
+
this.mode = mode
|
374
372
|
}
|
375
373
|
|
376
374
|
this._config = buildConfig({
|
@@ -611,7 +609,7 @@ export class DataGrist extends LitElement implements DataConsumer {
|
|
611
609
|
|
612
610
|
if (changes.has('personalConfigProvider')) {
|
613
611
|
this.personalConfig = await this.personalConfigProvider.load()
|
614
|
-
} else if (changes.has('personalConfig')) {
|
612
|
+
} else if (changes.has('config') || changes.has('personalConfig')) {
|
615
613
|
this.applyUpdatedConfiguration()
|
616
614
|
}
|
617
615
|
|
@@ -47,10 +47,6 @@ export const FilterStyles = css`
|
|
47
47
|
background-color: var(--ox-filters-input-background-color, transparent);
|
48
48
|
}
|
49
49
|
|
50
|
-
label > span + * {
|
51
|
-
min-width: 120px;
|
52
|
-
}
|
53
|
-
|
54
50
|
ox-select:focus,
|
55
51
|
input:focus {
|
56
52
|
outline: none;
|
@@ -88,15 +84,29 @@ export const FilterStyles = css`
|
|
88
84
|
--ox-filters-input-font: normal 16px var(--theme-font);
|
89
85
|
}
|
90
86
|
|
91
|
-
input
|
92
|
-
|
93
|
-
|
87
|
+
ox-input-barcode {
|
88
|
+
max-width: unset;
|
89
|
+
flex: 1;
|
90
|
+
}
|
91
|
+
|
92
|
+
ox-input-search {
|
93
|
+
max-width: unset;
|
94
|
+
}
|
95
|
+
|
96
|
+
ox-select {
|
97
|
+
max-width: unset;
|
98
|
+
}
|
99
|
+
|
100
|
+
ox-checkbox {
|
101
|
+
max-width: unset;
|
102
|
+
}
|
103
|
+
|
104
|
+
input[type='number'] {
|
105
|
+
max-width: unset;
|
94
106
|
}
|
95
107
|
|
96
|
-
input
|
97
|
-
|
98
|
-
padding-right: var(--padding-narrow);
|
99
|
-
min-width: 91%;
|
108
|
+
input {
|
109
|
+
flex: 1;
|
100
110
|
}
|
101
111
|
}
|
102
112
|
`
|
@@ -6,11 +6,12 @@ import '@operato/input/ox-input-search.js'
|
|
6
6
|
import { css, html, LitElement, PropertyValues, TemplateResult, nothing } from 'lit'
|
7
7
|
import { customElement, property, queryAsync, state } from 'lit/decorators.js'
|
8
8
|
|
9
|
+
import { PagePreferenceProvider } from '@operato/p13n'
|
9
10
|
import { getDefaultValue } from '@operato/time-calculator'
|
10
11
|
|
11
|
-
import { FilterConfigObject } from '
|
12
|
+
import { FilterConfigObject, FilterPreference } from '../types.js'
|
12
13
|
import { DataGrist } from '../data-grist'
|
13
|
-
import { ColumnConfig, FilterOperator, FilterValue, GristConfig } from '../types'
|
14
|
+
import { ColumnConfig, FilterOperator, FilterValue, GristConfig, PersonalGristPreference } from '../types'
|
14
15
|
import { FilterStyles } from './filter-styles'
|
15
16
|
import { getFilterRenderer } from './registry'
|
16
17
|
|
@@ -50,8 +51,9 @@ export class OxFiltersForm extends LitElement {
|
|
50
51
|
}
|
51
52
|
|
52
53
|
@media only screen and (max-width: 460px) {
|
53
|
-
|
54
|
-
|
54
|
+
form {
|
55
|
+
flex-direction: column;
|
56
|
+
flex-flow: column;
|
55
57
|
}
|
56
58
|
}
|
57
59
|
`
|
@@ -62,6 +64,10 @@ export class OxFiltersForm extends LitElement {
|
|
62
64
|
@property({ type: Boolean, attribute: 'autofocus' }) autofocus: boolean = true
|
63
65
|
@property({ type: Boolean, attribute: 'empty', reflect: true }) empty: boolean = true
|
64
66
|
|
67
|
+
@state() personalConfigProvider?: PagePreferenceProvider
|
68
|
+
@state() personalConfig?: PersonalGristPreference
|
69
|
+
@state() personalFilters?: FilterPreference[]
|
70
|
+
|
65
71
|
@state() config!: GristConfig
|
66
72
|
@state() filterColumns: ColumnConfig[] = []
|
67
73
|
@state() searchColumns: ColumnConfig[] = []
|
@@ -78,6 +84,7 @@ export class OxFiltersForm extends LitElement {
|
|
78
84
|
|
79
85
|
if (grist) {
|
80
86
|
this.config = grist.compiledConfig
|
87
|
+
this.personalConfigProvider = grist.personalConfigProvider
|
81
88
|
|
82
89
|
grist.addEventListener('config-change', (e: Event) => {
|
83
90
|
this.config = (e as CustomEvent).detail
|
@@ -139,44 +146,11 @@ export class OxFiltersForm extends LitElement {
|
|
139
146
|
}
|
140
147
|
}
|
141
148
|
|
142
|
-
updated(changes: PropertyValues<this>) {
|
143
|
-
if (changes.has('
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
return filter!.operator !== 'search'
|
148
|
-
})
|
149
|
-
this.searchColumns = filters.filter(columnConfig => {
|
150
|
-
const filter = columnConfig.filter as FilterConfigObject
|
151
|
-
return filter!.operator === 'search'
|
152
|
-
})
|
153
|
-
|
154
|
-
const grist = this.closest('ox-grist') as DataGrist
|
155
|
-
|
156
|
-
this.value = (grist?.filters || []).map(filter => {
|
157
|
-
return {
|
158
|
-
...filter,
|
159
|
-
value: this.buildDefaultValue(filter!.operator, filter!.value)
|
160
|
-
}
|
161
|
-
})
|
162
|
-
|
163
|
-
this.empty = (this.searchColumns.length === 0 || this.withoutSearch) && this.filterColumns.length === 0
|
164
|
-
|
165
|
-
this.autoUpdateTargetsOnChange = {}
|
166
|
-
this.filterColumns
|
167
|
-
?.filter(({ filter }) => {
|
168
|
-
return typeof filter == 'object' && filter.boundTo && filter.boundTo.length > 0
|
169
|
-
})
|
170
|
-
.map(({ name, filter }) => {
|
171
|
-
const boundTo = (filter as FilterConfigObject).boundTo
|
172
|
-
|
173
|
-
boundTo!.forEach(to => {
|
174
|
-
const origin = this.autoUpdateTargetsOnChange[to] || []
|
175
|
-
if (name && !origin.includes(name)) {
|
176
|
-
this.autoUpdateTargetsOnChange[to] = [...origin, name]
|
177
|
-
}
|
178
|
-
})
|
179
|
-
})
|
149
|
+
async updated(changes: PropertyValues<this>) {
|
150
|
+
if (changes.has('personalConfigProvider') && this.personalConfigProvider) {
|
151
|
+
this.personalConfig = await this.personalConfigProvider.load()
|
152
|
+
} else if (changes.has('config') || changes.has('personalConfig')) {
|
153
|
+
this.applyUpdatedConfiguration()
|
180
154
|
}
|
181
155
|
}
|
182
156
|
|
@@ -197,93 +171,189 @@ export class OxFiltersForm extends LitElement {
|
|
197
171
|
grist && grist.fetch()
|
198
172
|
}}
|
199
173
|
>
|
200
|
-
${this.
|
201
|
-
|
202
|
-
:
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
: type !== 'select' &&
|
240
|
-
?
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
174
|
+
${this.filterColumns
|
175
|
+
.filter(column => !(column.filter as FilterConfigObject).hidden)
|
176
|
+
.map((column: ColumnConfig) => {
|
177
|
+
const { name, header, label, filter } = column
|
178
|
+
|
179
|
+
const type = (filter as FilterConfigObject).type
|
180
|
+
|
181
|
+
if (type == 'search') {
|
182
|
+
return html`
|
183
|
+
<ox-input-search name="search" .value=${searchValue} ?autofocus=${this.autofocus}></ox-input-search>
|
184
|
+
`
|
185
|
+
}
|
186
|
+
|
187
|
+
const operator = (filter as FilterConfigObject).operator
|
188
|
+
const filterLabel = (filter as FilterConfigObject).label
|
189
|
+
|
190
|
+
const labelText =
|
191
|
+
filterLabel !== undefined
|
192
|
+
? filterLabel
|
193
|
+
: typeof label === 'object' && label.renderer
|
194
|
+
? label.renderer(column)
|
195
|
+
: header.renderer(column) || name
|
196
|
+
|
197
|
+
const idx = operator === 'between' ? 1 : 0
|
198
|
+
const renderer = getFilterRenderer(
|
199
|
+
operator === 'like' || operator === 'i_like' || operator === 'i_nlike' || operator === 'nlike'
|
200
|
+
? 'text'
|
201
|
+
: type
|
202
|
+
)[idx]
|
203
|
+
const value =
|
204
|
+
this.value?.find(filter => filter.name == name)?.value ??
|
205
|
+
this.buildDefaultValue(operator!, (filter as FilterConfigObject)?.value)
|
206
|
+
|
207
|
+
if (!renderer) {
|
208
|
+
return html``
|
209
|
+
}
|
210
|
+
|
211
|
+
return type === 'boolean' || type === 'checkbox'
|
212
|
+
? renderer(column, value, this)
|
213
|
+
: type !== 'select' && labelText
|
214
|
+
? html`<label filter-title ?between=${operator === 'between'}
|
215
|
+
><span>${labelText}</span> ${renderer(column, value, this)}
|
216
|
+
</label> `
|
217
|
+
: type !== 'select' && !labelText
|
218
|
+
? renderer(column, value, this)
|
219
|
+
: operator === 'in'
|
220
|
+
? html`
|
221
|
+
<ox-select
|
222
|
+
name=${name}
|
223
|
+
placeholder=${labelText}
|
224
|
+
.value=${value}
|
225
|
+
@change=${(e: CustomEvent) =>
|
226
|
+
e.target?.dispatchEvent(
|
227
|
+
new CustomEvent('filter-change', {
|
228
|
+
detail: {
|
229
|
+
name,
|
230
|
+
operator,
|
231
|
+
value: e.detail
|
232
|
+
}
|
233
|
+
})
|
234
|
+
)}
|
235
|
+
>
|
236
|
+
<ox-popup-list multiple attr-selected="checked" with-search>
|
237
|
+
${renderer(column, value, this)}
|
238
|
+
</ox-popup-list>
|
239
|
+
</ox-select>
|
240
|
+
`
|
241
|
+
: html`
|
242
|
+
<ox-select
|
243
|
+
name=${name}
|
244
|
+
placeholder=${labelText}
|
245
|
+
.value=${value}
|
246
|
+
@change=${(e: CustomEvent) =>
|
247
|
+
e.target?.dispatchEvent(
|
248
|
+
new CustomEvent('filter-change', {
|
249
|
+
detail: {
|
250
|
+
name,
|
251
|
+
operator,
|
252
|
+
value: e.detail
|
253
|
+
}
|
254
|
+
})
|
255
|
+
)}
|
256
|
+
>
|
257
|
+
<ox-popup-list with-search> ${renderer(column, value, this)} </ox-popup-list>
|
258
|
+
</ox-select>
|
259
|
+
`
|
260
|
+
})}
|
283
261
|
</form>
|
262
|
+
<slot name="setting"></slot>
|
284
263
|
`
|
285
264
|
}
|
286
265
|
|
266
|
+
applyUpdatedConfiguration() {
|
267
|
+
const filters = this.config.columns.filter(columnConfig => !!columnConfig.filter)
|
268
|
+
this.filterColumns = filters.filter((columnConfig: ColumnConfig) => {
|
269
|
+
const filter = columnConfig.filter as FilterConfigObject
|
270
|
+
return filter!.operator !== 'search'
|
271
|
+
})
|
272
|
+
this.searchColumns = filters.filter(columnConfig => {
|
273
|
+
const filter = columnConfig.filter as FilterConfigObject
|
274
|
+
return filter!.operator === 'search'
|
275
|
+
})
|
276
|
+
|
277
|
+
if (this.searchColumns.length > 0) {
|
278
|
+
this.filterColumns.unshift({ name: 'search', filter: { type: 'search' } } as any)
|
279
|
+
}
|
280
|
+
|
281
|
+
if (!this.personalConfig) {
|
282
|
+
this.personalFilters = this.filterColumns.map(column => {
|
283
|
+
return { name: column.name }
|
284
|
+
})
|
285
|
+
} else {
|
286
|
+
const { filters: personalFilters = [] } = this.personalConfig
|
287
|
+
|
288
|
+
if (personalFilters) {
|
289
|
+
const xfilters = this.filterColumns.map(column => {
|
290
|
+
return personalFilters.find(pFilter => pFilter.name == column.name) || { name: column.name }
|
291
|
+
})
|
292
|
+
|
293
|
+
function reorderList(a: FilterPreference[], b: FilterPreference[]): FilterPreference[] {
|
294
|
+
// 결과 배열 초기화, a 배열 길이만큼 undefined로 채움
|
295
|
+
const result = new Array(a.length)
|
296
|
+
|
297
|
+
// b 배열에 없는 아이템은 원래 위치로 채움
|
298
|
+
a.forEach((item, index) => {
|
299
|
+
if (!item.name || !b.find(bi => bi.name == item.name)) {
|
300
|
+
result[index] = item
|
301
|
+
}
|
302
|
+
})
|
303
|
+
|
304
|
+
b.forEach(item => {
|
305
|
+
const ai = a.find(ai => ai.name == item.name)
|
306
|
+
if (ai) {
|
307
|
+
result[result.findIndex(slot => slot === undefined)] = ai
|
308
|
+
}
|
309
|
+
})
|
310
|
+
|
311
|
+
return result
|
312
|
+
}
|
313
|
+
|
314
|
+
// 배열 재정렬 실행
|
315
|
+
this.personalFilters = reorderList(xfilters as any, personalFilters as any) as FilterPreference[]
|
316
|
+
|
317
|
+
this.filterColumns = this.personalFilters
|
318
|
+
.map(filter => {
|
319
|
+
const column = this.filterColumns.find(column => column.name == filter.name)
|
320
|
+
if (column?.filter) {
|
321
|
+
;(column.filter as FilterConfigObject)!.hidden = filter.hidden
|
322
|
+
}
|
323
|
+
return column
|
324
|
+
})
|
325
|
+
.filter(Boolean) as ColumnConfig[]
|
326
|
+
}
|
327
|
+
}
|
328
|
+
|
329
|
+
const grist = this.closest('ox-grist') as DataGrist
|
330
|
+
|
331
|
+
this.value = (grist?.filters || []).map(filter => {
|
332
|
+
return {
|
333
|
+
...filter,
|
334
|
+
value: this.buildDefaultValue(filter!.operator, filter!.value)
|
335
|
+
}
|
336
|
+
})
|
337
|
+
|
338
|
+
this.empty = (this.searchColumns.length === 0 || this.withoutSearch) && this.filterColumns.length === 0
|
339
|
+
|
340
|
+
this.autoUpdateTargetsOnChange = {}
|
341
|
+
this.filterColumns
|
342
|
+
?.filter(({ filter }) => {
|
343
|
+
return typeof filter == 'object' && filter.boundTo && filter.boundTo.length > 0
|
344
|
+
})
|
345
|
+
.map(({ name, filter }) => {
|
346
|
+
const boundTo = (filter as FilterConfigObject).boundTo
|
347
|
+
|
348
|
+
boundTo!.forEach(to => {
|
349
|
+
const origin = this.autoUpdateTargetsOnChange[to] || []
|
350
|
+
if (name && !origin.includes(name)) {
|
351
|
+
this.autoUpdateTargetsOnChange[to] = [...origin, name]
|
352
|
+
}
|
353
|
+
})
|
354
|
+
})
|
355
|
+
}
|
356
|
+
|
287
357
|
async getQueryFilters(): Promise<QueryFilter[]> {
|
288
358
|
const form = await this.form
|
289
359
|
if (!form) return []
|
@@ -292,6 +362,7 @@ export class OxFiltersForm extends LitElement {
|
|
292
362
|
const search: string | undefined = formData.get('search')?.toString()
|
293
363
|
|
294
364
|
var filters = this.filterColumns
|
365
|
+
.filter(column => column.name !== 'search' && !(column.filter as FilterConfigObject)!.hidden)
|
295
366
|
.map((column: ColumnConfig) => {
|
296
367
|
const { name, type, filter } = column
|
297
368
|
const operator = (filter as FilterConfigObject).operator
|