@operato/data-grist 2.0.0-alpha.98 → 2.0.0-beta.0
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 +441 -0
- package/demo/data-grist-test.html +1 -1
- package/demo/index.html +1 -1
- package/dist/src/data-card/data-card-field.js +2 -2
- package/dist/src/data-card/data-card-field.js.map +1 -1
- package/dist/src/data-card/data-card-gutter-menu.js +5 -5
- package/dist/src/data-card/data-card-gutter-menu.js.map +1 -1
- package/dist/src/data-card/data-card-gutter.js +6 -6
- package/dist/src/data-card/data-card-gutter.js.map +1 -1
- package/dist/src/data-card/data-card.js +7 -9
- package/dist/src/data-card/data-card.js.map +1 -1
- package/dist/src/data-card/record-card.js +9 -10
- package/dist/src/data-card/record-card.js.map +1 -1
- package/dist/src/data-grid/data-grid-accum-field.js +12 -5
- package/dist/src/data-grid/data-grid-accum-field.js.map +1 -1
- package/dist/src/data-grid/data-grid-body-style.js +12 -0
- package/dist/src/data-grid/data-grid-body-style.js.map +1 -1
- package/dist/src/data-grid/data-grid-body.d.ts +0 -1
- package/dist/src/data-grid/data-grid-body.js +14 -21
- package/dist/src/data-grid/data-grid-body.js.map +1 -1
- package/dist/src/data-grid/data-grid-field.js +8 -2
- package/dist/src/data-grid/data-grid-field.js.map +1 -1
- package/dist/src/data-grid/data-grid-footer.js +4 -2
- package/dist/src/data-grid/data-grid-footer.js.map +1 -1
- package/dist/src/data-grid/data-grid-header.js +9 -6
- package/dist/src/data-grid/data-grid-header.js.map +1 -1
- package/dist/src/data-grid/data-grid.js +23 -1
- package/dist/src/data-grid/data-grid.js.map +1 -1
- package/dist/src/data-grid/event-handlers/data-grid-body-click-handler.js +3 -0
- package/dist/src/data-grid/event-handlers/data-grid-body-click-handler.js.map +1 -1
- package/dist/src/data-grist.d.ts +10 -2
- package/dist/src/data-grist.js +71 -8
- package/dist/src/data-grist.js.map +1 -1
- package/dist/src/data-list/data-list-field.js +5 -5
- package/dist/src/data-list/data-list-field.js.map +1 -1
- package/dist/src/data-list/data-list-gutter.js +3 -3
- package/dist/src/data-list/data-list-gutter.js.map +1 -1
- package/dist/src/data-list/data-list.js +4 -4
- package/dist/src/data-list/data-list.js.map +1 -1
- package/dist/src/data-list/record-partial.js +9 -10
- package/dist/src/data-list/record-partial.js.map +1 -1
- package/dist/src/data-manipulator.d.ts +1 -1
- package/dist/src/data-manipulator.js +5 -5
- package/dist/src/data-manipulator.js.map +1 -1
- package/dist/src/data-report/data-report-field.js +2 -1
- package/dist/src/data-report/data-report-field.js.map +1 -1
- package/dist/src/data-report/data-report-header.js +2 -2
- package/dist/src/data-report/data-report-header.js.map +1 -1
- 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/editors/ox-input-tree.js +8 -8
- package/dist/src/editors/ox-input-tree.js.map +1 -1
- package/dist/src/filters/filter-input-barcode.js +1 -0
- package/dist/src/filters/filter-input-barcode.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/filter-styles.js +46 -31
- package/dist/src/filters/filter-styles.js.map +1 -1
- package/dist/src/filters/filters-form.d.ts +15 -4
- package/dist/src/filters/filters-form.js +205 -70
- package/dist/src/filters/filters-form.js.map +1 -1
- package/dist/src/gutters/gutter-dirty.js +2 -2
- package/dist/src/gutters/gutter-dirty.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/personalizer/index.d.ts +1 -0
- package/dist/src/personalizer/index.js +2 -0
- package/dist/src/personalizer/index.js.map +1 -0
- 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.d.ts +8 -0
- package/dist/src/personalizer/ox-grist-personalizer.js +178 -0
- package/dist/src/personalizer/ox-grist-personalizer.js.map +1 -0
- package/dist/src/record-view/record-creator.js +2 -2
- package/dist/src/record-view/record-creator.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/renderers/ox-grist-renderer-tree.js +8 -8
- package/dist/src/renderers/ox-grist-renderer-tree.js.map +1 -1
- package/dist/src/sorters/sorters-control.js +3 -3
- package/dist/src/sorters/sorters-control.js.map +1 -1
- package/dist/src/types.d.ts +41 -2
- package/dist/src/types.js.map +1 -1
- package/dist/stories/{accumulator.stories.d.ts → accumulator-format.stories.d.ts} +9 -0
- package/dist/stories/{accumulator.stories.js → accumulator-format.stories.js} +24 -12
- package/dist/stories/accumulator-format.stories.js.map +1 -0
- package/dist/stories/barcode-input-filter.stories.d.ts +5 -0
- package/dist/stories/barcode-input-filter.stories.js +29 -5
- package/dist/stories/barcode-input-filter.stories.js.map +1 -1
- package/dist/stories/bounded-select-filters.stories.d.ts +30 -0
- package/dist/stories/bounded-select-filters.stories.js +288 -0
- package/dist/stories/bounded-select-filters.stories.js.map +1 -0
- package/dist/stories/bounded-select-record.stories.d.ts +30 -0
- package/dist/stories/bounded-select-record.stories.js +291 -0
- package/dist/stories/bounded-select-record.stories.js.map +1 -0
- package/dist/stories/click-event.stories.d.ts +41 -0
- package/dist/stories/click-event.stories.js +234 -0
- package/dist/stories/click-event.stories.js.map +1 -0
- package/dist/stories/creatable-only-column.stories.d.ts +5 -0
- package/dist/stories/creatable-only-column.stories.js +46 -21
- package/dist/stories/creatable-only-column.stories.js.map +1 -1
- package/dist/stories/default-filters.stories.d.ts +5 -0
- package/dist/stories/default-filters.stories.js +84 -17
- package/dist/stories/default-filters.stories.js.map +1 -1
- package/dist/stories/dynamic-editable.stories.d.ts +5 -0
- package/dist/stories/dynamic-editable.stories.js +44 -21
- package/dist/stories/dynamic-editable.stories.js.map +1 -1
- package/dist/stories/empty-sorters.stories.d.ts +7 -1
- package/dist/stories/empty-sorters.stories.js +41 -17
- package/dist/stories/empty-sorters.stories.js.map +1 -1
- package/dist/stories/explicit-fetch.stories.d.ts +5 -0
- package/dist/stories/explicit-fetch.stories.js +40 -17
- package/dist/stories/explicit-fetch.stories.js.map +1 -1
- package/dist/stories/fixed-column.stories.d.ts +5 -0
- package/dist/stories/fixed-column.stories.js +53 -30
- package/dist/stories/fixed-column.stories.js.map +1 -1
- package/dist/stories/grid-setting.stories.d.ts +20 -4
- package/dist/stories/grid-setting.stories.js +96 -51
- package/dist/stories/grid-setting.stories.js.map +1 -1
- package/dist/stories/grist-modes.stories.d.ts +8 -2
- package/dist/stories/grist-modes.stories.js +58 -35
- package/dist/stories/grist-modes.stories.js.map +1 -1
- package/dist/stories/group-header.stories.d.ts +5 -0
- package/dist/stories/group-header.stories.js +53 -30
- package/dist/stories/group-header.stories.js.map +1 -1
- package/dist/stories/textarea.stories.d.ts +8 -2
- package/dist/stories/textarea.stories.js +37 -13
- package/dist/stories/textarea.stories.js.map +1 -1
- package/dist/stories/tree-column-with-checkbox.stories.d.ts +5 -0
- package/dist/stories/tree-column-with-checkbox.stories.js +44 -21
- package/dist/stories/tree-column-with-checkbox.stories.js.map +1 -1
- package/dist/stories/tree-column.stories.d.ts +5 -0
- package/dist/stories/tree-column.stories.js +44 -21
- package/dist/stories/tree-column.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 +15 -10
- package/src/data-card/data-card-field.ts +2 -2
- package/src/data-card/data-card-gutter-menu.ts +5 -5
- package/src/data-card/data-card-gutter.ts +6 -6
- package/src/data-card/data-card.ts +7 -9
- package/src/data-card/record-card.ts +9 -10
- package/src/data-grid/data-grid-accum-field.ts +11 -5
- package/src/data-grid/data-grid-body-style.ts +12 -0
- package/src/data-grid/data-grid-body.ts +16 -29
- package/src/data-grid/data-grid-field.ts +7 -2
- package/src/data-grid/data-grid-footer.ts +4 -2
- package/src/data-grid/data-grid-header.ts +8 -6
- package/src/data-grid/data-grid.ts +23 -1
- package/src/data-grid/event-handlers/data-grid-body-click-handler.ts +4 -0
- package/src/data-grist.ts +88 -8
- package/src/data-list/data-list-field.ts +5 -5
- package/src/data-list/data-list-gutter.ts +3 -3
- package/src/data-list/data-list.ts +4 -4
- package/src/data-list/record-partial.ts +9 -10
- package/src/data-manipulator.ts +5 -5
- package/src/data-report/data-report-field.ts +2 -1
- package/src/data-report/data-report-header.ts +2 -2
- package/src/editors/ox-grist-editor-select.ts +41 -28
- package/src/editors/ox-input-tree.ts +8 -8
- package/src/filters/filter-input-barcode.ts +1 -0
- package/src/filters/filter-select.ts +41 -28
- package/src/filters/filter-styles.ts +46 -31
- package/src/filters/filters-form.ts +273 -119
- package/src/gutters/gutter-dirty.ts +2 -2
- package/src/index.ts +1 -0
- package/src/personalizer/index.ts +1 -0
- package/src/personalizer/ox-grist-filter-personalizer.ts +191 -0
- package/src/personalizer/ox-grist-personalizer.ts +192 -0
- package/src/record-view/record-creator.ts +2 -2
- package/src/renderers/ox-grist-renderer-select.ts +41 -6
- package/src/renderers/ox-grist-renderer-tree.ts +8 -8
- package/src/sorters/sorters-control.ts +3 -3
- package/src/types.ts +53 -2
- package/stories/{accumulator.stories.ts → accumulator-format.stories.ts} +33 -12
- package/stories/barcode-input-filter.stories.ts +31 -6
- package/stories/bounded-select-filters.stories.ts +339 -0
- package/stories/bounded-select-record.stories.ts +342 -0
- package/stories/click-event.stories.ts +269 -0
- package/stories/creatable-only-column.stories.ts +54 -28
- package/stories/default-filters.stories.ts +92 -24
- package/stories/dynamic-editable.stories.ts +52 -28
- package/stories/empty-sorters.stories.ts +51 -25
- package/stories/explicit-fetch.stories.ts +48 -24
- package/stories/fixed-column.stories.ts +62 -39
- package/stories/grid-setting.stories.ts +120 -63
- package/stories/grist-modes.stories.ts +74 -46
- package/stories/group-header.stories.ts +61 -39
- package/stories/textarea.stories.ts +49 -17
- package/stories/tree-column-with-checkbox.stories.ts +52 -28
- package/stories/tree-column.stories.ts +52 -28
- package/themes/dark-hc.css +151 -0
- package/themes/dark-mc.css +151 -0
- package/themes/dark.css +151 -0
- package/themes/grist-theme.css +103 -100
- package/themes/light-hc.css +151 -0
- package/themes/light-mc.css +151 -0
- package/themes/light.css +151 -0
- package/themes/md-typescale-styles.css +100 -0
- package/themes/spacing.css +43 -0
- package/themes/state-color.css +6 -0
- package/dist/stories/accumulator.stories.js.map +0 -1
- package/themes/app-theme.css +0 -145
- package/themes/form-theme.css +0 -75
- package/themes/oops-theme.css +0 -26
- package/themes/report-theme.css +0 -47
@@ -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
|
+
}
|
@@ -0,0 +1,192 @@
|
|
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
|
+
import { OxCheckbox } from '@operato/input'
|
9
|
+
|
10
|
+
import { ColumnConfig, PersonalGristPreference } from '../types'
|
11
|
+
import { DataGrist } from '../data-grist'
|
12
|
+
|
13
|
+
@customElement('ox-grist-personalizer')
|
14
|
+
export class OxGristPersonalizer extends LitElement {
|
15
|
+
static styles = [
|
16
|
+
css`
|
17
|
+
md-icon {
|
18
|
+
--md-icon-size: 14px;
|
19
|
+
width: 16px;
|
20
|
+
height: 16px;
|
21
|
+
color: var(--ox-grist-p13n-color, var(--md-sys-color-on-primary));
|
22
|
+
background-color: var(--ox-grist-p13n-background-color, var(--md-sys-color-primary));
|
23
|
+
border-radius: 0px 0px 7px 7px;
|
24
|
+
cursor: pointer;
|
25
|
+
|
26
|
+
&:hover {
|
27
|
+
color: var(--ox-grist-p13n-hover-color, var(--md-sys-color-primary));
|
28
|
+
background-color: var(--ox-grist-p13n-hover-background-color, var(--md-sys-color-on-primary));
|
29
|
+
}
|
30
|
+
}
|
31
|
+
`
|
32
|
+
]
|
33
|
+
|
34
|
+
@property({ type: Boolean, attribute: true }) debug: boolean = false
|
35
|
+
|
36
|
+
@state() private preference?: PersonalGristPreference
|
37
|
+
|
38
|
+
render() {
|
39
|
+
return html`
|
40
|
+
<md-icon
|
41
|
+
@click=${(e: MouseEvent) => {
|
42
|
+
const grist = this.closest('ox-grist') as DataGrist
|
43
|
+
|
44
|
+
const { config, compiledConfig, sorters, pagination, mode } = grist
|
45
|
+
const { columns: compiledColumns } = compiledConfig
|
46
|
+
|
47
|
+
const columns = compiledColumns
|
48
|
+
.filter(ccolumn => {
|
49
|
+
const column = config.columns.find((column: Partial<ColumnConfig>) => column.name == ccolumn.name)
|
50
|
+
return column && column.name && column.type !== 'gutter' && !column.hidden && !column.unusable
|
51
|
+
})
|
52
|
+
.map(column => compiledColumns.find(compiledColumn => compiledColumn.name == column.name)!)
|
53
|
+
|
54
|
+
this.preference = {
|
55
|
+
columns: columns.map(column => {
|
56
|
+
return {
|
57
|
+
name: column.name,
|
58
|
+
hidden: column.hidden,
|
59
|
+
width: column.width
|
60
|
+
}
|
61
|
+
}),
|
62
|
+
sorters,
|
63
|
+
pagination: {
|
64
|
+
...pagination,
|
65
|
+
limit: grist.getCurrentLimit()
|
66
|
+
},
|
67
|
+
mode
|
68
|
+
}
|
69
|
+
|
70
|
+
const template = html`
|
71
|
+
<div class="personalizer-header" slot="header">
|
72
|
+
<md-icon
|
73
|
+
style="margin-left: auto;"
|
74
|
+
@click=${async (e: MouseEvent) => {
|
75
|
+
if (grist.personalConfigProvider) {
|
76
|
+
const { mode, columns, sorters, pagination } = this.preference || {}
|
77
|
+
grist.personalConfig = this.preference = await grist.personalConfigProvider.save({
|
78
|
+
mode,
|
79
|
+
columns,
|
80
|
+
sorters,
|
81
|
+
pagination
|
82
|
+
})
|
83
|
+
}
|
84
|
+
popup.close()
|
85
|
+
}}
|
86
|
+
title=${String(i18next.t('button.save'))}
|
87
|
+
>keep</md-icon
|
88
|
+
><md-icon
|
89
|
+
@click=${async (e: MouseEvent) => {
|
90
|
+
if (grist.personalConfigProvider) {
|
91
|
+
grist.personalConfig = this.preference = {}
|
92
|
+
await grist.personalConfigProvider.reset()
|
93
|
+
}
|
94
|
+
popup.close()
|
95
|
+
}}
|
96
|
+
title=${String(i18next.t('button.delete'))}
|
97
|
+
>keep_off</md-icon
|
98
|
+
><md-icon @click=${async (e: MouseEvent) => popup.close()} title=${String(i18next.t('button.close'))}
|
99
|
+
>close</md-icon
|
100
|
+
>
|
101
|
+
</div>
|
102
|
+
|
103
|
+
${columns.map(
|
104
|
+
column => html`
|
105
|
+
<ox-checkbox label="checkbox" ?checked=${!column.hidden} value=${column.name} option
|
106
|
+
>${column.header.renderer(column)}<span style="position: absolute; right: 10px; cursor: move;" handle
|
107
|
+
>☰</span
|
108
|
+
></ox-checkbox
|
109
|
+
>
|
110
|
+
`
|
111
|
+
)}
|
112
|
+
`
|
113
|
+
|
114
|
+
const popup = OxPopupList.open({
|
115
|
+
template,
|
116
|
+
multiple: true,
|
117
|
+
sortable: true,
|
118
|
+
debug: this.debug,
|
119
|
+
attrSelected: 'checked',
|
120
|
+
top: e.pageY,
|
121
|
+
left: e.pageX,
|
122
|
+
styles: css`
|
123
|
+
:host {
|
124
|
+
width: 240px;
|
125
|
+
max-height: 300px;
|
126
|
+
overflow: auto;
|
127
|
+
}
|
128
|
+
|
129
|
+
::slotted(.personalizer-header) {
|
130
|
+
--md-icon-size: 1.4em;
|
131
|
+
|
132
|
+
display: flex;
|
133
|
+
flex-direction: row;
|
134
|
+
align-items: center;
|
135
|
+
text-transform: capitalize;
|
136
|
+
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.3);
|
137
|
+
}
|
138
|
+
|
139
|
+
::slotted([option]) {
|
140
|
+
position: relative;
|
141
|
+
user-select: none;
|
142
|
+
}
|
143
|
+
`
|
144
|
+
})
|
145
|
+
|
146
|
+
popup.onselect = (e: Event) => {
|
147
|
+
const selected = (e as CustomEvent).detail
|
148
|
+
|
149
|
+
const pconfig: PersonalGristPreference = grist.personalConfig || {}
|
150
|
+
const pcolumns = this.preference?.columns || columns
|
151
|
+
|
152
|
+
pconfig.columns = pcolumns.map(column => {
|
153
|
+
return {
|
154
|
+
name: column.name,
|
155
|
+
hidden: selected.indexOf(column.name) == -1,
|
156
|
+
width: column.width
|
157
|
+
}
|
158
|
+
})
|
159
|
+
|
160
|
+
this.preference = pconfig
|
161
|
+
|
162
|
+
grist.personalConfig = this.preference
|
163
|
+
|
164
|
+
grist.applyUpdatedConfiguration()
|
165
|
+
}
|
166
|
+
|
167
|
+
popup.addEventListener('sorted', (e: Event) => {
|
168
|
+
const sorted = (e as CustomEvent).detail as HTMLElement[]
|
169
|
+
|
170
|
+
const pconfig: PersonalGristPreference = grist.personalConfig || {}
|
171
|
+
|
172
|
+
pconfig.columns = sorted.map(element => {
|
173
|
+
const name = (element as OxCheckbox).value
|
174
|
+
return {
|
175
|
+
name,
|
176
|
+
hidden: !element.hasAttribute('checked'),
|
177
|
+
width: columns.find(column => column.name == name)?.width
|
178
|
+
}
|
179
|
+
})
|
180
|
+
|
181
|
+
this.preference = pconfig
|
182
|
+
|
183
|
+
grist.personalConfig = this.preference
|
184
|
+
|
185
|
+
grist.applyUpdatedConfiguration()
|
186
|
+
})
|
187
|
+
}}
|
188
|
+
>settings</md-icon
|
189
|
+
>
|
190
|
+
`
|
191
|
+
}
|
192
|
+
}
|
@@ -145,7 +145,7 @@ export class RecordCreator extends LitElement {
|
|
145
145
|
}
|
146
146
|
})
|
147
147
|
|
148
|
-
recordView.addEventListener('field-change', (e: Event) => {
|
148
|
+
recordView.addEventListener('field-change', async (e: Event) => {
|
149
149
|
const view = e.currentTarget as RecordView
|
150
150
|
|
151
151
|
var { after, before, column, record, row } = (e as CustomEvent).detail as {
|
@@ -158,7 +158,7 @@ export class RecordCreator extends LitElement {
|
|
158
158
|
|
159
159
|
var validation = column.validation
|
160
160
|
if (validation && typeof validation == 'function') {
|
161
|
-
if (!validation.call(this, after, before, record, column)) {
|
161
|
+
if (!(await validation.call(this, after, before, record, column))) {
|
162
162
|
return
|
163
163
|
}
|
164
164
|
}
|
@@ -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
|
}
|
@@ -38,7 +38,7 @@ export class OxGristRendererTree extends OxGristRenderer {
|
|
38
38
|
transform: translate(-25%, -50%) rotate(-90deg);
|
39
39
|
content: ' ';
|
40
40
|
border: 5px solid transparent;
|
41
|
-
border-top: 5px solid var(--primary-
|
41
|
+
border-top: 5px solid var(--md-sys-color-on-primary-container, #1890ff);
|
42
42
|
}
|
43
43
|
|
44
44
|
span[expander][expanded]::before {
|
@@ -48,7 +48,7 @@ export class OxGristRendererTree extends OxGristRenderer {
|
|
48
48
|
transform: translate(-50%, -25%);
|
49
49
|
content: ' ';
|
50
50
|
border: 5px solid transparent;
|
51
|
-
border-top: 5px solid var(--primary-
|
51
|
+
border-top: 5px solid var(--md-sys-color-on-primary-container, #1890ff);
|
52
52
|
}
|
53
53
|
|
54
54
|
span[checkbox] {
|
@@ -70,7 +70,7 @@ export class OxGristRendererTree extends OxGristRenderer {
|
|
70
70
|
display: block;
|
71
71
|
width: 10px;
|
72
72
|
height: 10px;
|
73
|
-
border: 1px solid var(--primary-
|
73
|
+
border: 1px solid var(--md-sys-color-on-primary-container, #1890ff);
|
74
74
|
border-radius: 2px;
|
75
75
|
}
|
76
76
|
|
@@ -79,8 +79,8 @@ export class OxGristRendererTree extends OxGristRenderer {
|
|
79
79
|
}
|
80
80
|
|
81
81
|
span[checkbox][checked='checked']::before {
|
82
|
-
background-color: var(--primary-
|
83
|
-
border-color: var(--primary-
|
82
|
+
background-color: var(--md-sys-color-on-primary-container, #1890ff);
|
83
|
+
border-color: var(--md-sys-color-on-primary-container, #1890ff);
|
84
84
|
}
|
85
85
|
|
86
86
|
span[checkbox][checked='checked']::after {
|
@@ -100,8 +100,8 @@ export class OxGristRendererTree extends OxGristRenderer {
|
|
100
100
|
}
|
101
101
|
|
102
102
|
span[checkbox][checked='half-checked']::before {
|
103
|
-
background-color: var(--primary-
|
104
|
-
border-color: var(--primary-
|
103
|
+
background-color: var(--md-sys-color-on-primary-container, #1890ff);
|
104
|
+
border-color: var(--md-sys-color-on-primary-container, #1890ff);
|
105
105
|
}
|
106
106
|
|
107
107
|
span[checkbox][checked='half-checked']::after {
|
@@ -113,7 +113,7 @@ export class OxGristRendererTree extends OxGristRenderer {
|
|
113
113
|
transform: translate(-50%, -50%);
|
114
114
|
width: 10px;
|
115
115
|
height: 2px;
|
116
|
-
background-color:
|
116
|
+
background-color: var(--md-sys-color-surface);
|
117
117
|
}
|
118
118
|
`
|
119
119
|
|
@@ -30,12 +30,12 @@ export class SortersControl extends LitElement {
|
|
30
30
|
user-select: none;
|
31
31
|
}
|
32
32
|
[option] md-icon {
|
33
|
-
margin-left: var(--
|
33
|
+
margin-left: var(--spacing-medium);
|
34
34
|
--md-icon-size: var(--fontsize-large);
|
35
|
-
color: var(--primary-
|
35
|
+
color: var(--md-sys-color-on-primary-container);
|
36
36
|
}
|
37
37
|
[option] sub {
|
38
|
-
color: var(--primary-
|
38
|
+
color: var(--md-sys-color-on-primary-container);
|
39
39
|
}
|
40
40
|
`
|
41
41
|
]
|
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
|
*
|
@@ -90,6 +106,7 @@ export type FilterOperator =
|
|
90
106
|
* @property {string} type - The type of the filter condition.
|
91
107
|
* @property {FilterOperator} [operator] - The filter operator used to compare values (optional).
|
92
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).
|
93
110
|
* @property {string|number|boolean|string[]|number[]|undefined} [value] - The value to compare with in the filter condition (optional).
|
94
111
|
* @property {string} [label] - The label to display for the filter condition (optional).
|
95
112
|
*/
|
@@ -99,6 +116,9 @@ export type FilterConfigObject = {
|
|
99
116
|
options?: { [key: string]: any }
|
100
117
|
value?: string | number | boolean | string[] | number[] | undefined
|
101
118
|
label?: string
|
119
|
+
boundTo?: string[]
|
120
|
+
hidden?: boolean
|
121
|
+
onchange?: FilterChangedCallback
|
102
122
|
}
|
103
123
|
|
104
124
|
/**
|
@@ -341,6 +361,8 @@ export type ColumnConfig = {
|
|
341
361
|
imex?: ImexConfig | boolean
|
342
362
|
multiple?: boolean
|
343
363
|
rowCount?: boolean
|
364
|
+
/** 특정 도구에 의해서 사용되는 옵션으로, 일반적인 용도로 사용되지 않음을 표현할 수 있다. */
|
365
|
+
unusable?: boolean
|
344
366
|
}
|
345
367
|
|
346
368
|
/**
|
@@ -355,7 +377,12 @@ export type ColumnConfig = {
|
|
355
377
|
* @param {ColumnConfig} column - The configuration of the column being edited.
|
356
378
|
* @returns {boolean} - Returns `true` if the value is valid, `false` otherwise.
|
357
379
|
*/
|
358
|
-
export type ValidationCallback = (
|
380
|
+
export type ValidationCallback = (
|
381
|
+
after: any,
|
382
|
+
before: any,
|
383
|
+
record: GristRecord,
|
384
|
+
column: ColumnConfig
|
385
|
+
) => boolean | Promise<boolean>
|
359
386
|
|
360
387
|
/**
|
361
388
|
* Configuration options for column labels.
|
@@ -743,3 +770,27 @@ export type GristData = {
|
|
743
770
|
* @returns {boolean} - `true` if the record should be selected, `false` otherwise.
|
744
771
|
*/
|
745
772
|
export type GristSelectFunction = (record: GristRecord) => boolean
|
773
|
+
|
774
|
+
/**
|
775
|
+
* Defines a type for personalized grid settings. It includes individual column settings and additional configurations specific to a user's grid view.
|
776
|
+
*
|
777
|
+
* @typedef {Object} PersonalGristPreference
|
778
|
+
* @property {Partial<ColumnConfig>[]} [columns] - Partially defines the configuration for each column in the grid.
|
779
|
+
* Each element can include only some properties of the `ColumnConfig`, used for optionally overriding column settings.
|
780
|
+
* @property {any} [key] - Allows for storing additional user-defined properties with dynamic keys.
|
781
|
+
* This property can include various custom settings beyond the grid configuration, and the keys can be freely defined.
|
782
|
+
*/
|
783
|
+
export type PersonalGristPreference = {
|
784
|
+
columns?: Partial<ColumnConfig>[]
|
785
|
+
filters?: FilterPreference[]
|
786
|
+
pagination?: PaginationConfig
|
787
|
+
sorters?: SortersConfig
|
788
|
+
mode?: 'GRID' | 'LIST' | 'CARD'
|
789
|
+
[key: string]: any
|
790
|
+
}
|
791
|
+
|
792
|
+
export type FilterPreference = {
|
793
|
+
name: string
|
794
|
+
hidden?: boolean
|
795
|
+
value?: any
|
796
|
+
}
|