@operato/dataset 1.5.32 → 1.5.34

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/dataset",
3
3
  "description": "WebApplication dataset supporting components following open-wc recommendations",
4
4
  "author": "heartyoh",
5
- "version": "1.5.32",
5
+ "version": "1.5.34",
6
6
  "main": "dist/src/index.js",
7
7
  "module": "dist/src/index.js",
8
8
  "exports": {
@@ -93,13 +93,13 @@
93
93
  "@material/mwc-button": "^0.27.0",
94
94
  "@material/mwc-icon": "^0.27.0",
95
95
  "@material/mwc-icon-button": "^0.27.0",
96
- "@operato/data-grist": "^1.5.32",
96
+ "@operato/data-grist": "^1.5.34",
97
97
  "@operato/graphql": "^1.4.76",
98
- "@operato/grist-editor": "^1.5.32",
98
+ "@operato/grist-editor": "^1.5.34",
99
99
  "@operato/i18n": "^1.5.14",
100
- "@operato/input": "^1.5.28",
100
+ "@operato/input": "^1.5.34",
101
101
  "@operato/popup": "^1.5.28",
102
- "@operato/property-editor": "^1.5.32",
102
+ "@operato/property-editor": "^1.5.34",
103
103
  "@operato/shell": "^1.5.28",
104
104
  "@operato/styles": "^1.5.28",
105
105
  "@operato/utils": "^1.4.64",
@@ -137,5 +137,5 @@
137
137
  "prettier --write"
138
138
  ]
139
139
  },
140
- "gitHead": "cc7c19babfdb76202f12efaff1f28317608789cf"
140
+ "gitHead": "d094996e18a31bc0d4610924002dbb2719aa2cb2"
141
141
  }
@@ -3,17 +3,24 @@ import '@operato/input/ox-input-file.js'
3
3
  import { css, html, LitElement } from 'lit'
4
4
  import { customElement, property } from 'lit/decorators.js'
5
5
 
6
- import { DataSet } from './types.js'
6
+ import { i18next } from '@operato/i18n'
7
+
8
+ import { DataSet, DataSpecLimitSet } from './types.js'
9
+ import { OxDataUseCase } from './usecase/ox-data-use-case.js'
7
10
 
8
11
  @customElement('ox-data-entry-view')
9
12
  export class OxDataEntryView extends LitElement {
10
13
  static styles = css`
11
14
  :host {
12
15
  display: flex;
13
- flex-direction: row;
16
+ flex-direction: column;
17
+ }
18
+
19
+ form {
20
+ flex: 1;
14
21
 
15
- --item-description-font: normal 0.8rem/1rem var(--theme-font);
16
- --item-description-color: var(--page-description-color);
22
+ display: flex;
23
+ flex-direction: column;
17
24
  }
18
25
 
19
26
  h2 {
@@ -21,108 +28,77 @@ export class OxDataEntryView extends LitElement {
21
28
  font: var(--title-font);
22
29
  color: var(--title-text-color);
23
30
  text-transform: capitalize;
24
- text-align: center;
25
31
  }
26
- h3 {
32
+ [page-description] {
27
33
  margin: var(--page-description-margin);
34
+ opacity: 0.7;
28
35
  font: var(--page-description-font);
29
- color: var(--page-description-color);
36
+ color: var(--secondary-color);
30
37
  text-transform: capitalize;
31
- text-align: center;
32
38
  }
33
-
34
- form {
35
- flex: 1;
36
-
37
- display: flex;
38
- flex-direction: column;
39
+ [page-description] * {
40
+ vertical-align: middle;
41
+ }
42
+ [page-description] mwc-icon {
43
+ margin-top: -2px;
44
+ font-size: 0.9rem;
45
+ color: var(--page-description-color);
39
46
  }
40
47
 
41
- label {
42
- display: grid;
43
-
44
- grid-template-rows: auto 1fr;
45
- grid-template-columns: 1fr 5fr;
46
- grid-template-areas: 'name description' 'empty inputs';
47
-
48
- grid-gap: 9px;
49
- align-items: center;
48
+ table {
49
+ border-collapse: collapse;
50
50
  margin-bottom: var(--margin-default);
51
51
  }
52
-
53
- label:nth-child(odd) {
54
- background-color: var(--main-section-background-color);
55
- padding: var(--padding-default) 0;
52
+ th {
53
+ padding: var(--th-padding);
54
+ border-top: var(--th-border-top);
55
+ border-bottom: var(--td-border-bottom);
56
+ text-transform: var(--th-text-transform);
57
+ font: var(--th-font);
58
+ color: var(--th-color);
59
+ text-align: left;
56
60
  }
57
-
58
- div[name] {
59
- grid-area: name;
60
- font: var(--label-font);
61
- color: var(--label-color);
62
- text-align: right;
61
+ th[item] {
62
+ min-width: 100px;
63
63
  }
64
-
65
- div[description] {
66
- grid-area: description;
67
- opacity: 0.7;
68
- font: var(--item-description-font);
69
- color: var(--item-description-color);
70
- text-align: left;
64
+ th[value] {
65
+ min-width: 100px;
71
66
  }
72
-
73
- div[description] * {
74
- vertical-align: middle;
67
+ tr {
68
+ background-color: var(--tr-background-color);
75
69
  }
76
-
77
- div[description] mwc-icon {
78
- margin-top: -3px;
79
- font-size: 0.9rem;
70
+ tr:nth-child(odd) {
71
+ background-color: var(--tr-background-odd-color);
80
72
  }
81
-
82
- div[elements] {
83
- grid-area: inputs;
84
- display: flex;
85
- flex-direction: row;
86
- flex-wrap: wrap;
87
- gap: 10px;
88
- padding-right: var(--padding-default);
73
+ tr:hover {
74
+ background-color: var(--tr-background-hover-color);
89
75
  }
90
-
91
- div[elements] * {
92
- flex: 1;
76
+ tr[ooc],
77
+ tr[oos] {
78
+ background-color: #fefbdf;
93
79
  }
94
-
95
- div[elements] input,
96
- div[elements] select {
97
- border: var(--input-field-border);
98
- border-radius: var(--input-field-border-radius);
99
- padding: var(--input-field-padding);
100
- font: var(--input-field-font);
80
+ td {
81
+ border-bottom: var(--td-border-bottom);
82
+ padding: var(--td-padding);
83
+ font: var(--td-font);
84
+ color: var(--td-color);
85
+ }
86
+ td[name] {
87
+ font-weight: bold;
88
+ }
89
+ td mwc-icon {
90
+ color: var(--status-danger-color);
101
91
  }
102
92
 
103
- @media only screen and (max-width: 460px) {
104
- label {
105
- display: grid;
106
-
107
- grid-template-rows: auto auto 1fr;
108
- grid-template-columns: 1fr;
109
- grid-template-areas: 'name' 'description' 'inputs';
110
-
111
- grid-gap: 9px;
112
- align-items: center;
113
- margin-bottom: var(--margin-default);
114
- }
115
-
116
- div[name] {
117
- text-align: left;
118
- }
93
+ pre {
94
+ tab-size: 2;
119
95
  }
120
96
  `
121
97
 
122
98
  @property({ type: Object }) dataSet?: DataSet
123
99
  @property({ type: Object }) value?: { [tag: string]: any }
124
100
 
125
- render() {
101
+ __render() {
126
102
  return html`<form>
127
103
  <h2>${this.dataSet?.name || ''}</h2>
128
104
  <h3>${this.dataSet?.description || ''}</h3>
@@ -183,4 +159,90 @@ export class OxDataEntryView extends LitElement {
183
159
  </label>`
184
160
  })
185
161
  }
162
+
163
+ render() {
164
+ const { name, description, useCase, dataItems = [] } = this.dataSet!
165
+
166
+ const data = this.value || {}
167
+ const useCaseNames = useCase?.split(',').filter(useCase => useCase.trim()) || []
168
+
169
+ return html` <h2>${name}</h2>
170
+ <p page-description><mwc-icon>info_outline</mwc-icon> ${description}<br /></p>
171
+
172
+ <form>
173
+ <table>
174
+ <tr>
175
+ <th item>${i18next.t('field.item')}</th>
176
+ <th>${i18next.t('field.description')}</th>
177
+ <th>${i18next.t('field.stat-function')}</th>
178
+ <th>${i18next.t('field.unit')}</th>
179
+ <th value>${i18next.t('field.value')}</th>
180
+ <th>${i18next.t('field.spec')}</th>
181
+ <th>${i18next.t('field.ooc')}</th>
182
+ <th>${i18next.t('field.oos')}</th>
183
+ </tr>
184
+ ${dataItems.map(dataItem => {
185
+ const { name = '', tag = '', description = '', stat, unit = '', spec = {}, type } = dataItem
186
+ const value = data[tag]
187
+ const { ooc, oos } = OxDataUseCase.evaluateTag(this.dataSet!, dataItems, data, tag) || {}
188
+
189
+ return html`
190
+ <tr ?ooc=${ooc} ?oos=${oos}>
191
+ <td name>${name}</td>
192
+ <td>${description}</td>
193
+ <td>${stat}</td>
194
+ <td>${unit}</td>
195
+ <td>${this.buildValue(type, value)}</td>
196
+ <td><pre>${this.buildSpec(useCaseNames, spec)}</pre></td>
197
+ <td>${ooc ? html`<mwc-icon>done</mwc-icon>` : ''}</td>
198
+ <td>${oos ? html`<mwc-icon>done</mwc-icon>` : ''}</td>
199
+ </tr>
200
+ `
201
+ })}
202
+ </table>
203
+ </form>`
204
+ }
205
+
206
+ private buildSpec(useCaseNames: string[], spec: DataSpecLimitSet): string {
207
+ return OxDataUseCase.elaborateDataItemSpec(useCaseNames, spec)
208
+ }
209
+
210
+ private download(file: { mimetype: string; name: string; fullpath: string }) {
211
+ const element = document.createElement('a')
212
+ element.setAttribute('href', file.fullpath)
213
+ element.setAttribute('download', file.name!)
214
+ document.body.appendChild(element)
215
+ element.click()
216
+ }
217
+
218
+ private buildValue(type: string, value: any | any[]) {
219
+ if (value === undefined) {
220
+ return ''
221
+ }
222
+ const values = value instanceof Array ? value : [value]
223
+
224
+ if (type == 'file') {
225
+ const files = values.flat() as { mimetype: string; name: string; fullpath: string }[]
226
+
227
+ return files.map(file => html`<a @click=${() => this.download(file)}>${file.name}</a></br>`)
228
+ }
229
+
230
+ const elements = values.map((v: any, idx) => {
231
+ switch (typeof v) {
232
+ case 'boolean':
233
+ return html` <input type="checkbox" .checked=${v} disabled />`
234
+ break
235
+
236
+ default:
237
+ if (type == 'date') {
238
+ return new Date(v).toLocaleDateString()
239
+ } else if (type == 'datetime') {
240
+ return new Date(v).toLocaleString()
241
+ }
242
+ return v ?? ''
243
+ }
244
+ })
245
+
246
+ return typeof values[0] === 'boolean' ? elements : elements.join(', ')
247
+ }
186
248
  }
@@ -105,7 +105,6 @@ export class OxDataOocBriefView extends LitElement {
105
105
  }
106
106
  `
107
107
 
108
- @property({ type: Object }) dataSet?: DataSet
109
108
  @property({ type: Object }) dataOoc?: DataOoc
110
109
 
111
110
  render() {
@@ -92,6 +92,51 @@ export abstract class OxDataUseCase {
92
92
  return { ooc, oos }
93
93
  }
94
94
 
95
+ public static evaluateTag(dataSet: DataSet, dataItems: DataItem[], data: any, tag: string): EvaluationResult {
96
+ var ooc = false
97
+ var oos = false
98
+
99
+ if (!dataSet.useCase) {
100
+ return { ooc, oos }
101
+ }
102
+
103
+ const useCaseNames = dataSet.useCase.split(',').map(useCaseName => useCaseName.trim())
104
+ const useCases = useCaseNames.map(useCaseName => OxDataUseCase.getUseCase(useCaseName)).filter(useCase => !!useCase)
105
+
106
+ const dataItem = dataItems.find(i => i.tag == tag && i.active)
107
+
108
+ if (!dataItem) {
109
+ return { ooc, oos } // TODO what if in case no value ?
110
+ }
111
+
112
+ let values: any | any[] = data[tag]
113
+ if (typeof values === 'undefined') {
114
+ return { ooc, oos } // TODO what if in case no value ?
115
+ }
116
+
117
+ if (!(values instanceof Array)) {
118
+ values = [values]
119
+ }
120
+
121
+ for (let j = 0; j < useCases.length; j++) {
122
+ const useCase = useCases[j]
123
+
124
+ const specs = dataItem.spec?.[dataSet.useCase]
125
+ if (!specs) {
126
+ continue
127
+ }
128
+
129
+ const result = useCase!.evaluate(specs, values)
130
+
131
+ if (result) {
132
+ ooc ||= result.ooc
133
+ oos ||= result.oos
134
+ }
135
+ }
136
+
137
+ return { ooc, oos }
138
+ }
139
+
95
140
  public static evaluateItem(spec: DataSpecLimitSet, values: any | any[]): EvaluationResult | undefined {
96
141
  var ooc = false
97
142
  var oos = false