@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
@@ -0,0 +1,191 @@
|
|
1
|
+
import '@material/web/button/outlined-button.js'
|
2
|
+
|
3
|
+
import { css, html, LitElement } from 'lit'
|
4
|
+
import { customElement, property, state } from 'lit/decorators.js'
|
5
|
+
|
6
|
+
import { i18next } from '@operato/i18n'
|
7
|
+
import { OxPopupList } from '@operato/popup'
|
8
|
+
|
9
|
+
import { FilterConfigObject, FilterPreference, PersonalGristPreference } from '../types.js'
|
10
|
+
|
11
|
+
import { OxFiltersForm } from '../filters/filters-form'
|
12
|
+
|
13
|
+
@customElement('ox-grist-filter-personalizer')
|
14
|
+
export class OxGristFilterPersonalizer extends LitElement {
|
15
|
+
static styles = [
|
16
|
+
css`
|
17
|
+
md-icon {
|
18
|
+
--md-icon-size: 16px;
|
19
|
+
width: 36px;
|
20
|
+
height: 36px;
|
21
|
+
color: var(--md-sys-color-secondary-container);
|
22
|
+
cursor: pointer;
|
23
|
+
|
24
|
+
display: flex;
|
25
|
+
place-content: center;
|
26
|
+
place-items: center;
|
27
|
+
position: relative;
|
28
|
+
|
29
|
+
&:hover {
|
30
|
+
color: var(--md-sys-color-primary-container);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
md-ripple {
|
35
|
+
border-radius: 50%;
|
36
|
+
inset: unset;
|
37
|
+
height: 36px;
|
38
|
+
width: 36px;
|
39
|
+
}
|
40
|
+
`
|
41
|
+
]
|
42
|
+
|
43
|
+
@property({ type: Boolean, attribute: true }) debug: boolean = false
|
44
|
+
|
45
|
+
@state() private preference?: PersonalGristPreference
|
46
|
+
|
47
|
+
render() {
|
48
|
+
return html`
|
49
|
+
<md-icon
|
50
|
+
@click=${async (e: MouseEvent) => {
|
51
|
+
const form = this.closest('ox-filters-form') as OxFiltersForm
|
52
|
+
const { filterColumns, personalFilters = [] } = form
|
53
|
+
const queryFilters = await form.getQueryFilters()
|
54
|
+
|
55
|
+
this.preference = {
|
56
|
+
filters: (
|
57
|
+
personalFilters.map((filter: FilterPreference) => {
|
58
|
+
const originFilterColumn =
|
59
|
+
filter.name == 'search'
|
60
|
+
? { filter: { name: 'search' } }
|
61
|
+
: filterColumns.find(f => f.name == filter.name)
|
62
|
+
|
63
|
+
if (!originFilterColumn) {
|
64
|
+
/* 원래 filters 설정에 있는 것들 만을 유지한다. */
|
65
|
+
return
|
66
|
+
}
|
67
|
+
|
68
|
+
const { value } = originFilterColumn.filter! as FilterConfigObject
|
69
|
+
|
70
|
+
return {
|
71
|
+
name: filter.name,
|
72
|
+
hidden: filter.hidden,
|
73
|
+
/* 만약, filters에 기본값이 이미 설정되어 있다면, 그대로 유지한다. */
|
74
|
+
value: value ?? queryFilters.find(f => f.name == filter.name)?.value
|
75
|
+
}
|
76
|
+
}) || []
|
77
|
+
).filter(Boolean) as FilterPreference[]
|
78
|
+
}
|
79
|
+
|
80
|
+
const template = html`
|
81
|
+
<div class="personalizer-header" slot="header">
|
82
|
+
<md-icon
|
83
|
+
style="margin-left: auto;"
|
84
|
+
@click=${async (e: MouseEvent) => {
|
85
|
+
if (form.personalConfigProvider) {
|
86
|
+
form.personalConfig = await form.personalConfigProvider.save(this.preference)
|
87
|
+
}
|
88
|
+
popup.close()
|
89
|
+
}}
|
90
|
+
title=${String(i18next.t('button.save'))}
|
91
|
+
>keep</md-icon
|
92
|
+
><md-icon
|
93
|
+
@click=${async (e: MouseEvent) => {
|
94
|
+
if (form.personalConfigProvider) {
|
95
|
+
form.personalConfig = this.preference = {}
|
96
|
+
await form.personalConfigProvider.reset()
|
97
|
+
}
|
98
|
+
popup.close()
|
99
|
+
}}
|
100
|
+
title=${String(i18next.t('button.delete'))}
|
101
|
+
>keep_off</md-icon
|
102
|
+
><md-icon @click=${async (e: MouseEvent) => popup.close()} title=${String(i18next.t('button.close'))}
|
103
|
+
>close</md-icon
|
104
|
+
>
|
105
|
+
</div>
|
106
|
+
|
107
|
+
${this.preference?.filters!.map(
|
108
|
+
filter => html`
|
109
|
+
<ox-checkbox label="checkbox" ?checked=${!filter.hidden} value=${filter.name} option
|
110
|
+
>${filter.name}<span style="position: absolute; right: 10px; cursor: move;" handle
|
111
|
+
>☰</span
|
112
|
+
></ox-checkbox
|
113
|
+
>
|
114
|
+
`
|
115
|
+
)}
|
116
|
+
`
|
117
|
+
|
118
|
+
const popup = OxPopupList.open({
|
119
|
+
template,
|
120
|
+
multiple: true,
|
121
|
+
sortable: true,
|
122
|
+
debug: this.debug,
|
123
|
+
attrSelected: 'checked',
|
124
|
+
top: e.pageY,
|
125
|
+
left: e.pageX,
|
126
|
+
styles: css`
|
127
|
+
:host {
|
128
|
+
width: 240px;
|
129
|
+
max-height: 300px;
|
130
|
+
overflow: auto;
|
131
|
+
}
|
132
|
+
|
133
|
+
::slotted(.personalizer-header) {
|
134
|
+
--md-icon-size: 1.4em;
|
135
|
+
|
136
|
+
display: flex;
|
137
|
+
flex-direction: row;
|
138
|
+
align-items: center;
|
139
|
+
text-transform: capitalize;
|
140
|
+
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.3);
|
141
|
+
}
|
142
|
+
|
143
|
+
::slotted([option]) {
|
144
|
+
position: relative;
|
145
|
+
user-select: none;
|
146
|
+
}
|
147
|
+
`
|
148
|
+
})
|
149
|
+
|
150
|
+
popup.onselect = (e: Event) => {
|
151
|
+
const selected = (e as CustomEvent).detail
|
152
|
+
|
153
|
+
const pconfig: PersonalGristPreference = { ...form.personalConfig }
|
154
|
+
const pfilters = this.preference?.filters!
|
155
|
+
|
156
|
+
pconfig.filters = pfilters.map(filter => {
|
157
|
+
return {
|
158
|
+
name: filter.name,
|
159
|
+
hidden: selected.indexOf(filter.name) == -1,
|
160
|
+
value: filter.value
|
161
|
+
}
|
162
|
+
})
|
163
|
+
|
164
|
+
form.personalConfig = this.preference = pconfig
|
165
|
+
|
166
|
+
form.applyUpdatedConfiguration()
|
167
|
+
}
|
168
|
+
|
169
|
+
popup.addEventListener('sorted', (e: Event) => {
|
170
|
+
const sorted = (e as CustomEvent).detail as HTMLElement[]
|
171
|
+
|
172
|
+
const pconfig: PersonalGristPreference = { ...form.personalConfig }
|
173
|
+
const pfilters = this.preference?.filters!
|
174
|
+
|
175
|
+
pconfig.filters = sorted
|
176
|
+
.map(element => {
|
177
|
+
const name = (element as HTMLInputElement).value
|
178
|
+
return pfilters.find(filter => filter.name == name)!
|
179
|
+
})
|
180
|
+
.filter(Boolean)
|
181
|
+
|
182
|
+
form.personalConfig = this.preference = pconfig
|
183
|
+
|
184
|
+
form.applyUpdatedConfiguration()
|
185
|
+
})
|
186
|
+
}}
|
187
|
+
>settings<md-ripple></md-ripple
|
188
|
+
></md-icon>
|
189
|
+
`
|
190
|
+
}
|
191
|
+
}
|
@@ -72,7 +72,13 @@ export class OxGristPersonalizer extends LitElement {
|
|
72
72
|
style="margin-left: auto;"
|
73
73
|
@click=${async (e: MouseEvent) => {
|
74
74
|
if (grist.personalConfigProvider) {
|
75
|
-
|
75
|
+
const { mode, columns, sorters, pagination } = this.preference || {}
|
76
|
+
grist.personalConfig = this.preference = await grist.personalConfigProvider.save({
|
77
|
+
mode,
|
78
|
+
columns,
|
79
|
+
sorters,
|
80
|
+
pagination
|
81
|
+
})
|
76
82
|
}
|
77
83
|
popup.close()
|
78
84
|
}}
|
package/src/types.ts
CHANGED
@@ -106,6 +106,7 @@ export type FilterChangedCallback = (value: any, form: OxFiltersForm) => boolean
|
|
106
106
|
* @property {string} type - The type of the filter condition.
|
107
107
|
* @property {FilterOperator} [operator] - The filter operator used to compare values (optional).
|
108
108
|
* @property {Object} [options] - Additional options or parameters for the filter condition (optional).
|
109
|
+
* @property {boolean|undefined} [hidden] - The hidden flag for the filter condition (optional).
|
109
110
|
* @property {string|number|boolean|string[]|number[]|undefined} [value] - The value to compare with in the filter condition (optional).
|
110
111
|
* @property {string} [label] - The label to display for the filter condition (optional).
|
111
112
|
*/
|
@@ -116,6 +117,7 @@ export type FilterConfigObject = {
|
|
116
117
|
value?: string | number | boolean | string[] | number[] | undefined
|
117
118
|
label?: string
|
118
119
|
boundTo?: string[]
|
120
|
+
hidden?: boolean
|
119
121
|
onchange?: FilterChangedCallback
|
120
122
|
}
|
121
123
|
|
@@ -775,5 +777,15 @@ export type GristSelectFunction = (record: GristRecord) => boolean
|
|
775
777
|
*/
|
776
778
|
export type PersonalGristPreference = {
|
777
779
|
columns?: Partial<ColumnConfig>[]
|
780
|
+
filters?: FilterPreference[]
|
781
|
+
pagination?: PaginationConfig
|
782
|
+
sorters?: SortersConfig
|
783
|
+
mode?: 'GRID' | 'LIST' | 'CARD'
|
778
784
|
[key: string]: any
|
779
785
|
}
|
786
|
+
|
787
|
+
export type FilterPreference = {
|
788
|
+
name: string
|
789
|
+
hidden?: boolean
|
790
|
+
value?: any
|
791
|
+
}
|
@@ -8,6 +8,7 @@ import '../src/filters/filters-form.js'
|
|
8
8
|
import '../src/sorters/sorters-control.js'
|
9
9
|
import '../src/record-view/record-creator.js'
|
10
10
|
import '../src/personalizer/ox-grist-personalizer.js'
|
11
|
+
import '../src/personalizer/ox-grist-filter-personalizer.js'
|
11
12
|
|
12
13
|
import { html, TemplateResult } from 'lit'
|
13
14
|
|
@@ -364,6 +365,17 @@ interface ArgTypes {
|
|
364
365
|
debug: boolean
|
365
366
|
}
|
366
367
|
|
368
|
+
var personalConfig: PersonalGristPreference = {
|
369
|
+
columns: [
|
370
|
+
{ name: 'name', hidden: false, width: 200 },
|
371
|
+
{ name: 'description', hidden: true }
|
372
|
+
],
|
373
|
+
pagination: {
|
374
|
+
pages: [20, 30, 50, 100, 200],
|
375
|
+
limit: 30
|
376
|
+
}
|
377
|
+
}
|
378
|
+
|
367
379
|
const Template: Story<ArgTypes> = ({
|
368
380
|
config,
|
369
381
|
mode = 'GRID',
|
@@ -399,23 +411,19 @@ const Template: Story<ArgTypes> = ({
|
|
399
411
|
.personalConfigProvider=${{
|
400
412
|
async load() {
|
401
413
|
await sleep(1000)
|
402
|
-
return
|
403
|
-
columns: [
|
404
|
-
{ name: 'name', hidden: false, width: 200 },
|
405
|
-
{ name: 'description', hidden: true }
|
406
|
-
],
|
407
|
-
pagination: {
|
408
|
-
pages: [20, 30, 50, 100, 200],
|
409
|
-
limit: 30
|
410
|
-
}
|
411
|
-
}
|
414
|
+
return personalConfig
|
412
415
|
},
|
413
416
|
async save(preference: PersonalGristPreference) {
|
414
417
|
await sleep(1000)
|
415
|
-
|
418
|
+
personalConfig = {
|
419
|
+
...personalConfig,
|
420
|
+
...preference
|
421
|
+
}
|
422
|
+
console.log('saving preference', personalConfig)
|
416
423
|
return preference
|
417
424
|
},
|
418
425
|
async reset() {
|
426
|
+
personalConfig = {}
|
419
427
|
await sleep(1000)
|
420
428
|
}
|
421
429
|
}}
|
@@ -424,24 +432,9 @@ const Template: Story<ArgTypes> = ({
|
|
424
432
|
>
|
425
433
|
<div slot="headroom">
|
426
434
|
<div id="filters">
|
427
|
-
<ox-filters-form autofocus
|
428
|
-
|
429
|
-
|
430
|
-
<div id="sorters">
|
431
|
-
Sort
|
432
|
-
<md-icon
|
433
|
-
@click=${(e: Event) => {
|
434
|
-
const target = e.currentTarget as HTMLElement
|
435
|
-
;(target.closest('#sorters')!.querySelector('#sorter-control') as any).open({
|
436
|
-
right: 0,
|
437
|
-
top: target.offsetTop + target.offsetHeight
|
438
|
-
})
|
439
|
-
}}
|
440
|
-
>expand_more</md-icon
|
441
|
-
>
|
442
|
-
<ox-popup id="sorter-control">
|
443
|
-
<ox-sorters-control> </ox-sorters-control>
|
444
|
-
</ox-popup>
|
435
|
+
<ox-filters-form autofocus>
|
436
|
+
<ox-grist-filter-personalizer slot="setting"></ox-grist-filter-personalizer>
|
437
|
+
</ox-filters-form>
|
445
438
|
</div>
|
446
439
|
|
447
440
|
<div id="modes">
|