@operato/app 8.0.0-alpha.4 → 8.0.0-alpha.41

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@operato/app",
3
3
  "description": "WebApplication production supporting components following open-wc recommendations",
4
4
  "author": "heartyoh",
5
- "version": "8.0.0-alpha.4",
5
+ "version": "8.0.0-alpha.41",
6
6
  "main": "dist/src/index.js",
7
7
  "module": "dist/src/index.js",
8
8
  "exports": {
@@ -29,6 +29,8 @@
29
29
  "./grist-editor/ox-grist-editor-resource-object.js": "./dist/src/grist-editor/ox-grist-editor-resource-object.js",
30
30
  "./grist-editor/ox-grist-editor-resource-object-legacy.js": "./dist/src/grist-editor/ox-grist-editor-resource-object-legacy.js",
31
31
  "./grist-editor/ox-grist-editor-resource-code.js": "./dist/src/grist-editor/ox-grist-editor-resource-code.js",
32
+ "./filters-form/filter-resource-code.js": "./dist/src/filters-form/filter-resource-code.js",
33
+ "./filters-form/filter-resource-object.js": "./dist/src/filters-form/filter-resource-object.js",
32
34
  "./filter-renderer.js": "./dist/src/filter-renderer/index.js",
33
35
  "./filters-form.js": "./dist/src/filters-form/index.js"
34
36
  },
@@ -97,6 +99,15 @@
97
99
  "grist-editor/ox-grist-editor-resource-code.js": [
98
100
  "dist/src/grist-editor/ox-grist-editor-resource-code.d.ts"
99
101
  ],
102
+ "filters-form/filter-resource-code.js": [
103
+ "./dist/src/filters-form/filter-resource-code.d.ts"
104
+ ],
105
+ "filters-form/filter-resource-object.js": [
106
+ "./dist/src/filters-form/filter-resource-object.d.ts"
107
+ ],
108
+ "filters-form.js": [
109
+ "dist/src/filters-form/index.d.ts"
110
+ ],
100
111
  "filter-renderer.js": [
101
112
  "dist/src/filter-renderer/index.d.ts"
102
113
  ]
@@ -136,18 +147,18 @@
136
147
  "@graphql-tools/delegate": "^10.0.1",
137
148
  "@graphql-tools/wrap": "^8.5.0",
138
149
  "@material/web": "^2.0.0",
139
- "@operato/attachment": "^8.0.0-alpha.4",
140
- "@operato/data-grist": "^8.0.0-alpha.4",
141
- "@operato/font": "^8.0.0-alpha.4",
142
- "@operato/form": "^8.0.0-alpha.4",
143
- "@operato/graphql": "^8.0.0-alpha.0",
144
- "@operato/i18n": "^8.0.0-alpha.0",
145
- "@operato/input": "^8.0.0-alpha.4",
146
- "@operato/layout": "^8.0.0-alpha.4",
147
- "@operato/property-editor": "^8.0.0-alpha.4",
148
- "@operato/shell": "^8.0.0-alpha.4",
149
- "@operato/styles": "^8.0.0-alpha.4",
150
- "@operato/utils": "^8.0.0-alpha.0",
150
+ "@operato/attachment": "^8.0.0-alpha.41",
151
+ "@operato/data-grist": "^8.0.0-alpha.41",
152
+ "@operato/font": "^8.0.0-alpha.41",
153
+ "@operato/form": "^8.0.0-alpha.41",
154
+ "@operato/graphql": "^8.0.0-alpha.37",
155
+ "@operato/i18n": "^8.0.0-alpha.37",
156
+ "@operato/input": "^8.0.0-alpha.41",
157
+ "@operato/layout": "^8.0.0-alpha.41",
158
+ "@operato/property-editor": "^8.0.0-alpha.41",
159
+ "@operato/shell": "^8.0.0-alpha.41",
160
+ "@operato/styles": "^8.0.0-alpha.37",
161
+ "@operato/utils": "^8.0.0-alpha.37",
151
162
  "cm6-graphql": "^0.0.14",
152
163
  "codemirror": "^6.0.1",
153
164
  "cronstrue": "^2.2.0",
@@ -157,17 +168,17 @@
157
168
  "lit": "^3.1.2"
158
169
  },
159
170
  "devDependencies": {
160
- "@custom-elements-manifest/analyzer": "^0.9.2",
171
+ "@custom-elements-manifest/analyzer": "^0.10.0",
161
172
  "@hatiolab/prettier-config": "^1.0.0",
162
173
  "@open-wc/eslint-config": "^12.0.3",
163
- "@open-wc/testing": "^3.1.6",
164
- "@typescript-eslint/eslint-plugin": "^7.0.1",
165
- "@typescript-eslint/parser": "^7.0.1",
166
- "@web/dev-server": "^0.3.0",
174
+ "@open-wc/testing": "^4.0.0",
175
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
176
+ "@typescript-eslint/parser": "^8.0.0",
177
+ "@web/dev-server": "^0.4.0",
167
178
  "@web/dev-server-storybook": "^2.0.1",
168
- "@web/test-runner": "^0.18.0",
169
- "concurrently": "^8.0.1",
170
- "eslint": "^8.39.0",
179
+ "@web/test-runner": "^0.19.0",
180
+ "concurrently": "^9.0.0",
181
+ "eslint": "^9.0.0",
171
182
  "eslint-config-prettier": "^9.1.0",
172
183
  "husky": "^9.0.11",
173
184
  "lint-staged": "^15.2.2",
@@ -188,5 +199,5 @@
188
199
  "prettier --write"
189
200
  ]
190
201
  },
191
- "gitHead": "ac097b448ea96721b3418132e92988afdf764519"
202
+ "gitHead": "0c2adcc994cd105055c9355810fa9c7c8196ca41"
192
203
  }
@@ -0,0 +1,11 @@
1
+ import './ox-filter-resource-code.js'
2
+
3
+ import { html } from 'lit-html'
4
+
5
+ import { FilterSelectRenderer } from '@operato/data-grist'
6
+
7
+ export const FilterResourceCode: FilterSelectRenderer = (column, value, owner) => {
8
+ return html`
9
+ <ox-filter-resource-code name=${column?.name} .column=${column} .value=${value}></ox-filter-resource-code>
10
+ `
11
+ }
@@ -0,0 +1,11 @@
1
+ import './ox-filter-resource-object.js'
2
+
3
+ import { html } from 'lit-html'
4
+
5
+ import { FilterSelectRenderer } from '@operato/data-grist'
6
+
7
+ export const FilterResourceObject: FilterSelectRenderer = (column, value, owner) => {
8
+ return html`
9
+ <ox-filter-resource-object name=${column?.name} .column=${column} .value=${value}></ox-filter-resource-object>
10
+ `
11
+ }
@@ -1,6 +1,14 @@
1
1
  import { registerFilterRenderer } from '@operato/form'
2
+ import { registerFilterRenderer as dataGristFilterRenderer } from '@operato/data-grist'
2
3
 
3
4
  import { FilterResourceSelect } from './filter-resource-select.js'
4
5
 
6
+ import { FilterResourceCode } from './filter-resource-code.js'
7
+ import { FilterResourceObject } from './filter-resource-object.js'
8
+
5
9
  registerFilterRenderer('resource-object', [FilterResourceSelect])
6
10
  registerFilterRenderer('resource-id', [FilterResourceSelect])
11
+
12
+ dataGristFilterRenderer('code', [FilterResourceCode])
13
+ dataGristFilterRenderer('object', [FilterResourceObject])
14
+ dataGristFilterRenderer('resource-object', [FilterResourceObject])
@@ -0,0 +1,154 @@
1
+ import '@operato/input/ox-select.js'
2
+
3
+ import gql from 'graphql-tag'
4
+ import { css, html } from 'lit'
5
+ import { customElement, property, state } from 'lit/decorators.js'
6
+
7
+ import { i18next } from '@operato/i18n'
8
+ import { FilterConfigObject } from '@operato/data-grist'
9
+ import { client, gqlContext } from '@operato/graphql'
10
+ import { OxFormField } from '@operato/input'
11
+
12
+ type CommonCodeDetail = {
13
+ name: string
14
+ description: string
15
+ rank: number
16
+ }
17
+
18
+ const FETCH_COMMON_CODE_GQL = (codeName: string) => gql`
19
+ {
20
+ commonCode(name: "${codeName}") {
21
+ details {
22
+ name
23
+ description
24
+ rank
25
+ }
26
+ }
27
+ }
28
+ `
29
+
30
+ @customElement('ox-filter-resource-code')
31
+ export class OxFilterResourceCode extends OxFormField {
32
+ static styles = css`
33
+ :host {
34
+ min-width: 100px;
35
+ }
36
+ `
37
+
38
+ @property({ type: Object }) column: any
39
+ @property({ type: String }) value?: string
40
+
41
+ @state() codes?: CommonCodeDetail[]
42
+
43
+ render() {
44
+ const { name, filter } = this.column
45
+ const operator = (filter as FilterConfigObject).operator
46
+ const { selectDispOpt = 'code-name' } = this.column.record || {}
47
+
48
+ if (!this.codes) {
49
+ return html`<p>Loading...</p>`
50
+ }
51
+
52
+ return operator === 'in'
53
+ ? html`
54
+ <ox-select
55
+ .value=${this.value}
56
+ @change=${(e: CustomEvent) => {
57
+ let val = e.detail
58
+ this.value = val?.length > 0 ? val : undefined
59
+
60
+ this?.dispatchEvent(
61
+ new CustomEvent('change', {
62
+ detail: {
63
+ name,
64
+ operator,
65
+ value: this.value
66
+ }
67
+ })
68
+ )
69
+ }}
70
+ >
71
+ <ox-popup-list multiple attr-selected="checked" with-search align-left>
72
+ <ox-checkbox
73
+ checkAll
74
+ @click=${(e: any) => {
75
+ const checked = e.target.checked
76
+ const val = checked ? this.codes!.map((code: CommonCodeDetail) => code.name) : []
77
+
78
+ e.target?.dispatchEvent(new CustomEvent('select', { bubbles: true, detail: val }))
79
+ }}
80
+ >${i18next.t('label.all')}</ox-checkbox
81
+ >
82
+ ${this.codes
83
+ ?.filter((code: CommonCodeDetail) => !!code.name)
84
+ .map(
85
+ (code: CommonCodeDetail) => html`
86
+ <ox-checkbox
87
+ option
88
+ value=${code.name}
89
+ @change=${(e: any) => {
90
+ const parent = e.target.parentElement
91
+ const checkCnt = e.target.checked ? 1 : -1
92
+ const checkedLen = parent.querySelectorAll('ox-checkbox[option][checked]').length + checkCnt
93
+
94
+ parent.querySelector('ox-checkbox[checkAll]').checked =
95
+ this.codes!.filter((code: CommonCodeDetail) => !!code.name).length === checkedLen
96
+ }}
97
+ >${selectDispOpt.replace('name', code.description).replace('code', code.name)}</ox-checkbox
98
+ >
99
+ `
100
+ )}
101
+ </ox-popup-list>
102
+ </ox-select>
103
+ `
104
+ : html`
105
+ <ox-select
106
+ .value=${this.value}
107
+ @change=${(e: CustomEvent) => {
108
+ this.value = e.detail
109
+ this.dispatchEvent(
110
+ new CustomEvent('change', {
111
+ detail: {
112
+ name,
113
+ operator,
114
+ value: this.value
115
+ }
116
+ })
117
+ )
118
+ }}
119
+ >
120
+ <ox-popup-list with-search>
121
+ <div option value="">&nbsp;</div>
122
+ ${this.codes?.map(
123
+ (code: CommonCodeDetail) => html`
124
+ <div option value=${code.name}>
125
+ ${selectDispOpt.replace('name', code.description).replace('code', code.name)}
126
+ </div>
127
+ `
128
+ )}
129
+ </ox-popup-list>
130
+ </ox-select>
131
+ `
132
+ }
133
+
134
+ async fetchCodes() {
135
+ const { codeName } = this.column.record || {}
136
+
137
+ if (codeName) {
138
+ const response = await client.query({
139
+ query: FETCH_COMMON_CODE_GQL(codeName),
140
+ context: gqlContext()
141
+ })
142
+
143
+ this.codes = response?.data?.commonCode?.details || []
144
+
145
+ this.requestUpdate()
146
+ }
147
+ }
148
+
149
+ connectedCallback() {
150
+ super.connectedCallback()
151
+
152
+ this.fetchCodes()
153
+ }
154
+ }
@@ -0,0 +1,224 @@
1
+ import '../selector/ox-selector-resource-object.js'
2
+
3
+ import { css, html } from 'lit'
4
+ import { customElement, property, state } from 'lit/decorators.js'
5
+
6
+ import { i18next } from '@operato/i18n'
7
+ import { openPopup, PopupHandle } from '@operato/layout'
8
+ import { OxFormField } from '@operato/input'
9
+
10
+ @customElement('ox-filter-resource-object')
11
+ export class OxFilterResourceObject extends OxFormField {
12
+ static styles = [
13
+ css`
14
+ :host {
15
+ display: block;
16
+ position: relative;
17
+ border-bottom: 1px solid rgba(0, 0, 0, 0.15);
18
+ min-width: 100px;
19
+
20
+ --ox-select-padding: var(--spacing-tiny);
21
+ --ox-select-font: var(--input-font);
22
+ --ox-select-color: var(--input-color, var(--md-sys-color-on-surface-variant));
23
+ --ox-select-icon-color: var(--theme-primary-text-color, var(--md-sys-color-on-surface-variant));
24
+ --ox-select-icon-hover-color: var(--md-sys-color-on-primary-container, #3c3938);
25
+ }
26
+
27
+ div {
28
+ width: 100%;
29
+ box-sizing: border-box;
30
+
31
+ display: flex;
32
+ flex-direction: row;
33
+ align-items: center;
34
+ justify-content: center;
35
+ cursor: pointer;
36
+ padding: var(--ox-select-padding);
37
+ font: var(--ox-select-font);
38
+ color: var(--ox-select-color);
39
+ }
40
+
41
+ span {
42
+ flex: 1;
43
+ overflow: hidden;
44
+ text-overflow: ellipsis;
45
+ white-space: nowrap;
46
+ gap: 4px;
47
+ }
48
+
49
+ md-icon {
50
+ --md-icon-size: 16px;
51
+ display: block;
52
+ text-align: right;
53
+ color: var(--ox-select-icon-color);
54
+ opacity: 0.7;
55
+ }
56
+
57
+ div:hover md-icon {
58
+ color: var(--md-sys-color-on-primary-container);
59
+ }
60
+ `
61
+ ]
62
+
63
+ @property({ type: Object }) column: any
64
+ @property({ type: String }) value?: string
65
+
66
+ @state() resourceObject?: any
67
+
68
+ private popup?: PopupHandle
69
+
70
+ render() {
71
+ var { nameField = 'name', descriptionField = 'description' } = this.column.record.options || {}
72
+
73
+ var value = this.resourceObject || {}
74
+ var name, description
75
+
76
+ if (typeof nameField === 'function') {
77
+ name = nameField(value)
78
+ } else {
79
+ name = value[nameField]
80
+ }
81
+
82
+ if (typeof descriptionField === 'function') {
83
+ description = descriptionField(value)
84
+ } else {
85
+ description = value[descriptionField] && `(${value[descriptionField]})`
86
+ }
87
+
88
+ return html`
89
+ <div @click=${this._onclick} @keydown=${this._onkeydown}>
90
+ <span tabindex="0" style="flex:1">${name || ''}${(description && `(${description})`) || ''}</span>
91
+ <md-icon>search</md-icon>
92
+ </div>
93
+ `
94
+ }
95
+
96
+ _onclick(e: Event): void {
97
+ e.stopPropagation()
98
+ this.openSelector()
99
+ }
100
+
101
+ _onkeydown(e: KeyboardEvent): void {
102
+ const key = e.key
103
+ if (key == 'Enter') {
104
+ e.stopPropagation()
105
+ this.openSelector()
106
+ }
107
+ }
108
+
109
+ openSelector() {
110
+ if (this.popup) {
111
+ delete this.popup
112
+ }
113
+
114
+ var {
115
+ title = '',
116
+ idField = 'id',
117
+ nameField = 'name',
118
+ descriptionField = 'description',
119
+ valueField = 'id',
120
+ queryName,
121
+ basicArgs,
122
+ select,
123
+ columns,
124
+ pagination,
125
+ list
126
+ } = this.column.record.options || {}
127
+
128
+ if (!queryName) {
129
+ console.warn('queryName is empty')
130
+ return
131
+ }
132
+
133
+ /* select options is only for compatability, it might be able to be deprecated. */
134
+ columns = columns || select
135
+
136
+ const confirmCallback = (selected?: { [field: string]: any }) => {
137
+ // this.department = selected
138
+ // ? {
139
+ // id: selected.id,
140
+ // controlNo: selected.controlNo,
141
+ // name: selected.name,
142
+ // description: selected.description
143
+ // }
144
+ // : null
145
+
146
+ // this.value = this.department?.name
147
+
148
+ // this.dispatchEvent(
149
+ // new CustomEvent('change', {
150
+ // bubbles: true,
151
+ // composed: true,
152
+ // detail: this.value
153
+ // })
154
+ // )
155
+
156
+ this.resourceObject = selected
157
+ ? {
158
+ ...(columns || [])
159
+ .map((field: any) => field.name)
160
+ .reduce(
161
+ (obj: { [field: string]: any }, fieldName: string) => {
162
+ return (obj = {
163
+ ...obj,
164
+ [fieldName]: selected[fieldName]
165
+ })
166
+ },
167
+ {} as { [field: string]: any }
168
+ ),
169
+ [idField]: selected[idField],
170
+ [nameField]: selected[nameField],
171
+ [descriptionField]: selected[descriptionField]
172
+ }
173
+ : null
174
+
175
+ this.value = this.resourceObject?.[nameField]
176
+
177
+ this.dispatchEvent(
178
+ new CustomEvent('change', {
179
+ detail: this.value
180
+ })
181
+ )
182
+ }
183
+
184
+ var value = this.resourceObject || {}
185
+ var actualValue
186
+ if (typeof valueField === 'function') {
187
+ actualValue = valueField(value)
188
+ } else {
189
+ actualValue = value[valueField]
190
+ }
191
+
192
+ var template = html`
193
+ <ox-selector-resource-object
194
+ .value=${actualValue}
195
+ .confirmCallback=${confirmCallback.bind(this)}
196
+ .queryName=${queryName}
197
+ .columns=${columns}
198
+ .pagination=${pagination}
199
+ .list=${list}
200
+ .basicArgs=${basicArgs}
201
+ .valueField=${valueField}
202
+ ></ox-selector-resource-object>
203
+ `
204
+
205
+ this.popup = openPopup(template, {
206
+ backdrop: true,
207
+ size: 'large',
208
+ search: {
209
+ autofocus: true,
210
+ placeholder: title || i18next.t('title.select_item'),
211
+ handler: (instance: any, value: any) => {
212
+ /* instance: template instance */
213
+ instance.searchText(value)
214
+ }
215
+ },
216
+ filter: {
217
+ handler: (instance: any) => {
218
+ /* instance: template instance */
219
+ instance.toggleFilter()
220
+ }
221
+ }
222
+ })
223
+ }
224
+ }
@@ -11,6 +11,7 @@ import '@operato/property-editor/ox-property-editor-data.js'
11
11
  import '@operato/property-editor/ox-property-editor-date.js'
12
12
  import '@operato/property-editor/ox-property-editor-month.js'
13
13
  import '@operato/property-editor/ox-property-editor-time.js'
14
+ import '@operato/property-editor/ox-property-editor-datetime.js'
14
15
  import '@operato/property-editor/ox-property-editor-checkbox.js'
15
16
  import '@operato/property-editor/ox-property-editor-options.js'
16
17
  import '@operato/property-editor/ox-property-editor-select.js'
@@ -55,6 +56,7 @@ OxPropertyEditor.register({
55
56
  select: 'ox-property-editor-select',
56
57
  date: 'ox-property-editor-date',
57
58
  month: 'ox-property-editor-month',
59
+ datetime: 'ox-property-editor-datetime',
58
60
  time: 'ox-property-editor-time',
59
61
  options: 'ox-property-editor-options',
60
62
  data: 'ox-property-editor-data',