@operato/dataset 1.0.0-alpha.9 → 1.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +404 -0
  2. package/demo/index.html +8 -90
  3. package/demo/ox-data-entry-form.html +118 -0
  4. package/demo/ox-data-item-spec.html +152 -0
  5. package/demo/ox-data-ooc-view.html +185 -0
  6. package/demo/ox-data-sample-view.html +150 -0
  7. package/demo/ox-grist-editor-data-item-spec.html +476 -0
  8. package/dist/src/grist-editor/index.d.ts +1 -0
  9. package/dist/src/grist-editor/index.js +7 -0
  10. package/dist/src/grist-editor/index.js.map +1 -0
  11. package/dist/src/grist-editor/ox-grist-editor-data-item-spec.d.ts +11 -0
  12. package/dist/src/grist-editor/ox-grist-editor-data-item-spec.js +77 -0
  13. package/dist/src/grist-editor/ox-grist-editor-data-item-spec.js.map +1 -0
  14. package/dist/src/grist-editor/ox-popup-data-item-spec.d.ts +13 -0
  15. package/dist/src/grist-editor/ox-popup-data-item-spec.js +90 -0
  16. package/dist/src/grist-editor/ox-popup-data-item-spec.js.map +1 -0
  17. package/dist/src/index.d.ts +6 -1
  18. package/dist/src/index.js +6 -1
  19. package/dist/src/index.js.map +1 -1
  20. package/dist/src/ox-data-entry-form.d.ts +1 -24
  21. package/dist/src/ox-data-entry-form.js +12 -16
  22. package/dist/src/ox-data-entry-form.js.map +1 -1
  23. package/dist/src/ox-data-item-spec.d.ts +18 -0
  24. package/dist/src/ox-data-item-spec.js +77 -0
  25. package/dist/src/ox-data-item-spec.js.map +1 -0
  26. package/dist/src/ox-data-ooc-view.d.ts +10 -0
  27. package/dist/src/ox-data-ooc-view.js +69 -0
  28. package/dist/src/ox-data-ooc-view.js.map +1 -0
  29. package/dist/src/ox-data-sample-view copy.d.ts +13 -0
  30. package/dist/src/ox-data-sample-view copy.js +214 -0
  31. package/dist/src/ox-data-sample-view copy.js.map +1 -0
  32. package/dist/src/ox-data-sample-view.d.ts +13 -0
  33. package/dist/src/ox-data-sample-view.js +168 -0
  34. package/dist/src/ox-data-sample-view.js.map +1 -0
  35. package/dist/src/ox-data-use-case.d.ts +16 -0
  36. package/dist/src/ox-data-use-case.js +111 -0
  37. package/dist/src/ox-data-use-case.js.map +1 -0
  38. package/dist/src/types.d.ts +78 -0
  39. package/dist/src/types.js +2 -0
  40. package/dist/src/types.js.map +1 -0
  41. package/dist/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +20 -12
  43. package/src/grist-editor/index.ts +10 -0
  44. package/src/grist-editor/ox-grist-editor-data-item-spec.ts +92 -0
  45. package/src/grist-editor/ox-popup-data-item-spec.ts +90 -0
  46. package/src/index.ts +6 -1
  47. package/src/ox-data-entry-form.ts +13 -37
  48. package/src/ox-data-item-spec.ts +74 -0
  49. package/src/ox-data-ooc-view.ts +67 -0
  50. package/src/ox-data-sample-view.ts +175 -0
  51. package/src/ox-data-use-case.ts +147 -0
  52. package/src/types.ts +72 -0
  53. package/themes/grist-theme.css +194 -0
  54. package/themes/oops-theme.css +26 -0
  55. package/themes/report-theme.css +47 -0
  56. package/translations/en.json +1 -0
  57. package/translations/ko.json +1 -0
  58. package/translations/ms.json +1 -0
  59. package/translations/zh.json +1 -0
@@ -1,30 +1,9 @@
1
1
  import '@operato/input/ox-input-file.js'
2
2
 
3
- import { LitElement, css, html } from 'lit'
3
+ import { css, html, LitElement } from 'lit'
4
4
  import { customElement, property } from 'lit/decorators.js'
5
5
 
6
- type SelectOption = { text: string; value: string }
7
- type SelectOptions = SelectOption[]
8
- type TypeOptions = {
9
- options?: SelectOptions
10
- [prop: string]: any
11
- }
12
-
13
- export type DataItem = {
14
- name: string
15
- description: string
16
- sequence: number
17
- tag: string
18
- type: string
19
- options: TypeOptions
20
- quota: number
21
- }
22
-
23
- export type DataSet = {
24
- name: string
25
- description: string
26
- dataItems: DataItem[]
27
- }
6
+ import { DataSet } from './types.js'
28
7
 
29
8
  @customElement('ox-data-entry-form')
30
9
  export class OxDataEntryForm extends LitElement {
@@ -51,6 +30,7 @@ export class OxDataEntryForm extends LitElement {
51
30
  background-color: var(--main-section-background-color);
52
31
  padding: var(--padding-default) 0;
53
32
  }
33
+
54
34
  div[name] {
55
35
  grid-column: span 2 / auto;
56
36
  font: var(--label-font);
@@ -75,6 +55,7 @@ export class OxDataEntryForm extends LitElement {
75
55
  padding: var(--input-field-padding);
76
56
  font: var(--input-field-font);
77
57
  }
58
+
78
59
  @media only screen and (max-width: 460px) {
79
60
  div[name] {
80
61
  grid-column: span 3 / auto;
@@ -93,28 +74,28 @@ export class OxDataEntryForm extends LitElement {
93
74
  }
94
75
 
95
76
  private onChange(e: Event) {
96
- const value = this.buildValue()
77
+ this.value = this.buildValue()
97
78
 
98
79
  this.dispatchEvent(
99
80
  new CustomEvent('change', {
100
81
  bubbles: true,
101
82
  composed: true,
102
- detail: value
83
+ detail: this.value
103
84
  })
104
85
  )
105
86
  }
106
87
 
107
88
  private buildInputs() {
108
- const dataItems = this.dataSet!.dataItems
89
+ const dataItems = this.dataSet!.dataItems.filter(item => item.active)
109
90
 
110
91
  return (dataItems || []).map(dataItem => {
111
- const { name, description, tag, type, quota = 1, options = {} } = dataItem
92
+ const { name, description, tag, type, quota = 1, options = {}, unit } = dataItem
112
93
 
113
94
  const samples = new Array(quota).fill(0)
114
- const value = this.value?.[tag]
95
+ const value = this.value && this.value[tag]
115
96
 
116
97
  const elements = samples.map((_, idx) => {
117
- const v = quota <= 1 ? value : value instanceof Array && value[idx]
98
+ const v = value instanceof Array ? value[idx] : idx === 0 ? value : undefined
118
99
 
119
100
  switch (type) {
120
101
  case 'select':
@@ -150,7 +131,7 @@ export class OxDataEntryForm extends LitElement {
150
131
  })
151
132
 
152
133
  return html` <label .title=${description}>
153
- <div name>${name}</div>
134
+ <div name>${name}${unit ? `(${unit})` : ''}</div>
154
135
  <div elements>${elements}</div>
155
136
  </label>`
156
137
  })
@@ -160,19 +141,14 @@ export class OxDataEntryForm extends LitElement {
160
141
  const dataItems = this.dataSet!.dataItems
161
142
 
162
143
  return (dataItems || []).reduce((sum, dataItem) => {
163
- const { tag, quota, type } = dataItem
144
+ const { tag, type } = dataItem
164
145
 
165
146
  const editors = Array.prototype.slice.call(
166
147
  this.renderRoot.querySelectorAll(`[name=${tag}]`) as NodeListOf<HTMLInputElement>
167
148
  ) as HTMLInputElement[]
168
149
 
169
150
  if (editors.length > 0) {
170
- sum[tag] =
171
- editors.length > 1
172
- ? editors.map(editor => (type === 'boolean' ? editor.checked : editor.value))
173
- : type === 'boolean'
174
- ? editors[0].checked
175
- : editors[0].value
151
+ sum[tag] = editors.map(editor => (type === 'boolean' ? editor.checked : editor.value))
176
152
  }
177
153
 
178
154
  return sum
@@ -0,0 +1,74 @@
1
+ import '@operato/property-editor/ox-properties-dynamic-view.js'
2
+
3
+ import { css, html, LitElement, PropertyValues } from 'lit'
4
+ import { customElement, property, queryAll, state } from 'lit/decorators.js'
5
+
6
+ import { OxDataUseCase } from './ox-data-use-case.js'
7
+ import { DataItem, DataItemSpecSet } from './types.js'
8
+
9
+ @customElement('ox-data-item-spec')
10
+ export class OxDataItemSpec extends LitElement {
11
+ static styles = css`
12
+ :host {
13
+ display: flex;
14
+ flex-direction: row;
15
+ border-bottom: var(--border-dark-color);
16
+ padding: var(--margin-default) 0;
17
+ }
18
+ [specName] {
19
+ font: var(--legend-font);
20
+ color: var(--legend-text-color);
21
+ }
22
+ [description] {
23
+ font: var(--form-sublabel-font);
24
+ opacity: 0.8;
25
+ }
26
+
27
+ form {
28
+ flex: 1;
29
+ }
30
+ `
31
+
32
+ @property({ type: Object }) value?: { [specSetName: string]: any }
33
+ @property({ type: Object }) dataItem?: DataItem
34
+
35
+ @state() dataItemSpecSets: DataItemSpecSet[] = []
36
+
37
+ @queryAll('ox-properties-dynamic-view') specSetViews!: NodeListOf<HTMLElement & { value: any }>
38
+
39
+ render() {
40
+ return html`<form @property-change=${(e: Event) => this.onChange(e)}>
41
+ ${this.dataItemSpecSets.map(
42
+ ({ name, description, specs }) => html` <div specName>${name}</div>
43
+ <div description>${description}</div>
44
+ <ox-properties-dynamic-view data-name=${name} .props=${specs} .value=${this.value?.[name]}>
45
+ </ox-properties-dynamic-view>`
46
+ )}
47
+ </form>`
48
+ }
49
+
50
+ updated(changes: PropertyValues<this>) {
51
+ if (changes.has('dataItem')) {
52
+ this.dataItemSpecSets = OxDataUseCase.getUseCases().map(useCase => useCase.getSpecification(this.dataItem!))
53
+ }
54
+ }
55
+
56
+ private onChange(e: Event) {
57
+ this.value = this.buildValue()
58
+
59
+ this.dispatchEvent(
60
+ new CustomEvent('change', {
61
+ bubbles: true,
62
+ composed: true,
63
+ detail: { ...this.value }
64
+ })
65
+ )
66
+ }
67
+
68
+ private buildValue() {
69
+ var value = {} as any
70
+ this.specSetViews.forEach(view => (value[view.getAttribute('data-name')!] = view.value))
71
+
72
+ return value
73
+ }
74
+ }
@@ -0,0 +1,67 @@
1
+ import '@operato/input/ox-input-file.js'
2
+ import './ox-data-sample-view'
3
+
4
+ import { DataOoc, DataSet } from './types.js'
5
+ import { LitElement, css, html } from 'lit'
6
+ import { customElement, property } from 'lit/decorators.js'
7
+
8
+ @customElement('ox-data-ooc-view')
9
+ export class OxDataOocView extends LitElement {
10
+ static styles = css`
11
+ :host {
12
+ display: flex;
13
+ flex-direction: column;
14
+ background-color: var(--main-section-background-color);
15
+ padding: var(--padding-wide);
16
+
17
+ position: relative;
18
+ }
19
+
20
+ h3 {
21
+ margin: var(--title-margin);
22
+ padding-top: 12px;
23
+ font: var(--title-font);
24
+ color: var(--title-text-color);
25
+ }
26
+
27
+ h3[state] {
28
+ position: absolute;
29
+
30
+ right: 20px;
31
+ top: 25px;
32
+ }
33
+
34
+ [page-description] {
35
+ margin: var(--page-description-margin);
36
+ font: var(--page-description-font);
37
+ color: var(--page-description-color);
38
+ }
39
+ `
40
+
41
+ @property({ type: Object }) dataSet?: DataSet
42
+ @property({ type: Object }) dataOoc?: DataOoc
43
+
44
+ render() {
45
+ const history = this.dataOoc?.history || []
46
+ const formatter = new Intl.DateTimeFormat(navigator.language, { dateStyle: 'full', timeStyle: 'short' })
47
+
48
+ return html`
49
+ <ox-data-sample-view .dataSample=${this.dataOoc} .dataSet=${this.dataSet}></ox-data-sample-view>
50
+
51
+ <h3 state>${this.dataOoc?.state || ''}</h3>
52
+
53
+ <h3>history</h3>
54
+ ${history.map(
55
+ ({ user, state, comment, timestamp }) => html`
56
+ <p page-description>
57
+ ${formatter.format(new Date(timestamp))}
58
+ <br />
59
+ ${state} by ${user.name}
60
+ <br />
61
+ ${comment}
62
+ </p>
63
+ `
64
+ )}
65
+ `
66
+ }
67
+ }
@@ -0,0 +1,175 @@
1
+ import '@operato/input/ox-input-file.js'
2
+
3
+ import { css, html, LitElement } from 'lit'
4
+ import { customElement, property } from 'lit/decorators.js'
5
+
6
+ import { OxDataUseCase } from './ox-data-use-case.js'
7
+ import { DataItem, DataSample, DataSet } from './types.js'
8
+
9
+ @customElement('ox-data-sample-view')
10
+ export class OxDataSampleView extends LitElement {
11
+ static styles = css`
12
+ :host {
13
+ display: flex;
14
+ flex-direction: column;
15
+ background-color: var(--main-section-background-color);
16
+ }
17
+
18
+ form {
19
+ flex: 1;
20
+
21
+ display: flex;
22
+ flex-direction: column;
23
+ }
24
+
25
+ h2 {
26
+ margin: var(--title-margin);
27
+ padding-top: 25px;
28
+ font: var(--title-font);
29
+ color: var(--title-text-color);
30
+ }
31
+ [page-description] {
32
+ margin: var(--page-description-margin);
33
+ font: var(--page-description-font);
34
+ color: var(--page-description-color);
35
+ }
36
+
37
+ table {
38
+ border-collapse: collapse;
39
+ margin-bottom: var(--margin-default);
40
+ }
41
+ th {
42
+ padding: var(--th-padding);
43
+ border-top: var(--th-border-top);
44
+ border-bottom: var(--td-border-bottom);
45
+ text-transform: var(--th-text-transform);
46
+ font: var(--th-font);
47
+ color: var(--th-color);
48
+ text-align: left;
49
+ }
50
+ th[item] {
51
+ min-width: 100px;
52
+ }
53
+ th[value] {
54
+ min-width: 100px;
55
+ }
56
+ tr {
57
+ background-color: var(--tr-background-color);
58
+ }
59
+ tr:nth-child(odd) {
60
+ background-color: var(--tr-background-odd-color);
61
+ }
62
+ tr:hover {
63
+ background-color: var(--tr-background-hover-color);
64
+ }
65
+ tr[ooc],
66
+ tr[oos] {
67
+ background-color: #fefbdf;
68
+ }
69
+ td {
70
+ border-bottom: var(--td-border-bottom);
71
+ padding: var(--td-padding);
72
+ font: var(--td-font);
73
+ color: var(--td-color);
74
+ }
75
+ td[name] {
76
+ font-weight: bold;
77
+ }
78
+ td mwc-icon {
79
+ color: var(--status-danger-color);
80
+ }
81
+
82
+ pre {
83
+ tab-size: 2;
84
+ }
85
+ `
86
+
87
+ @property({ type: Object }) dataSet?: DataSet
88
+ @property({ type: Object }) dataSample?: DataSample
89
+
90
+ render() {
91
+ const dataItems = this.dataSet?.dataItems.filter(item => item.active) || []
92
+ const data = this.dataSample?.data || {}
93
+ const formatter = new Intl.DateTimeFormat(navigator.language, { dateStyle: 'full', timeStyle: 'short' })
94
+
95
+ const { name, description, collectedAt, workDate, workShift } = this.dataSample || {}
96
+
97
+ return html` <h2>${name}</h2>
98
+ <p page-description>
99
+ ${description}<br /><br />
100
+ work date: ${workDate} ${workShift}<br />
101
+ collected at: ${formatter.format(new Date(collectedAt!))}
102
+ </p>
103
+
104
+ <form @change=${(e: Event) => this.onChange(e)}>
105
+ <table>
106
+ <tr>
107
+ <th item>item</th>
108
+ <th>description</th>
109
+ <th>unit</th>
110
+ <th value>value</th>
111
+ <th>specification</th>
112
+ <th>OOC</th>
113
+ <th>OOS</th>
114
+ </tr>
115
+ ${dataItems.map(dataItem => {
116
+ const { ooc, oos } = this.evaluateOOC(dataItem, data?.[dataItem.tag]) || {}
117
+ const { name, description, unit } = dataItem
118
+ return html`
119
+ <tr ?ooc=${ooc} ?oos=${oos}>
120
+ <td name>${name}</td>
121
+ <td>${description}</td>
122
+ <td>${unit}</td>
123
+ <td>${this.buildValue(dataItem)}</td>
124
+ <td><pre>${this.buildSpec(dataItem)}</pre></td>
125
+ <td>${ooc ? html`<mwc-icon>done</mwc-icon>` : ''}</td>
126
+ <td>${oos ? html`<mwc-icon>done</mwc-icon>` : ''}</td>
127
+ </tr>
128
+ `
129
+ })}
130
+ </table>
131
+ </form>`
132
+ }
133
+
134
+ private onChange(e: Event) {}
135
+
136
+ private buildSpec(dataItem: DataItem) {
137
+ return OxDataUseCase.elaborateDataItemSpec(this.dataSet!, dataItem)
138
+ }
139
+
140
+ private buildValue(dataItem: DataItem) {
141
+ const { tag, type } = dataItem
142
+
143
+ if (!this.dataSample) {
144
+ return ''
145
+ }
146
+
147
+ const value = this.dataSample?.data[dataItem.tag]
148
+ if (value === undefined) {
149
+ return ''
150
+ }
151
+ const values = value instanceof Array ? value : [value]
152
+
153
+ const elements = values.map((_: any, idx) => {
154
+ const v = value[idx]
155
+
156
+ switch (type) {
157
+ case 'boolean':
158
+ return html` <input type="checkbox" name=${tag} .checked=${v} disabled />`
159
+ break
160
+
161
+ case 'select':
162
+ case 'number':
163
+ case 'string':
164
+ default:
165
+ return String(v === undefined ? '' : v)
166
+ }
167
+ })
168
+
169
+ return type === 'boolean' ? elements : elements.join(', ')
170
+ }
171
+
172
+ private evaluateOOC(dataItem: DataItem, value: any) {
173
+ return OxDataUseCase.evaluateItem(this.dataSet!, dataItem, value)
174
+ }
175
+ }
@@ -0,0 +1,147 @@
1
+ import { DataItem, DataItemSpecSet, DataSet, EvaluationResult } from './types'
2
+
3
+ export abstract class OxDataUseCase {
4
+ static registry: { [name: string]: OxDataUseCase } = {}
5
+
6
+ public static registerUseCase(name: string, useCase: OxDataUseCase) {
7
+ OxDataUseCase.registry[name] = useCase
8
+ }
9
+
10
+ public static getUseCaseNames() {
11
+ return Object.keys(OxDataUseCase.registry)
12
+ }
13
+
14
+ public static getUseCases(): OxDataUseCase[] {
15
+ return Object.values(OxDataUseCase.registry)
16
+ }
17
+
18
+ public static getUseCase(name: string): OxDataUseCase | undefined {
19
+ return OxDataUseCase.registry[name]
20
+ }
21
+
22
+ public static elaborateDataItemSpec(dataSet: DataSet, dataItem: DataItem): string {
23
+ if (!dataSet.useCase) {
24
+ return ''
25
+ }
26
+
27
+ const useCaseNames = dataSet.useCase.split(',').map(useCaseName => useCaseName.trim())
28
+ const useCases = useCaseNames.map(useCaseName => OxDataUseCase.getUseCase(useCaseName)).filter(useCase => !!useCase)
29
+
30
+ var texts = []
31
+
32
+ for (let j = 0; j < useCases.length; j++) {
33
+ const useCase = useCases[j]
34
+ if (!useCase) {
35
+ continue
36
+ }
37
+
38
+ const specs = dataItem.spec?.[dataSet.useCase]
39
+ if (!specs) {
40
+ continue
41
+ }
42
+
43
+ const result = useCase.elaborateUseCaseSpec(dataItem.spec)
44
+ if (!result) {
45
+ continue
46
+ }
47
+
48
+ texts.push(result)
49
+ }
50
+
51
+ return texts.join('\n')
52
+ }
53
+
54
+ public static evaluate(dataSet: DataSet, dataItems: DataItem[], data: any): EvaluationResult | undefined {
55
+ var ooc = false
56
+ var oos = false
57
+
58
+ if (!dataSet.useCase) {
59
+ return { ooc, oos }
60
+ }
61
+
62
+ const useCaseNames = dataSet.useCase.split(',').map(useCaseName => useCaseName.trim())
63
+ const useCases = useCaseNames.map(useCaseName => OxDataUseCase.getUseCase(useCaseName)).filter(useCase => !!useCase)
64
+
65
+ for (let i = 0; i < dataItems.length; i++) {
66
+ const dataItem = dataItems[i]
67
+ const { active, tag } = dataItem
68
+ if (!active || !tag) {
69
+ continue
70
+ }
71
+
72
+ let values: any | any[] = data[tag]
73
+ if (typeof values === 'undefined') {
74
+ continue // TODO what if in case no value ?
75
+ }
76
+
77
+ if (!(values instanceof Array)) {
78
+ values = [values]
79
+ }
80
+
81
+ for (let j = 0; j < useCases.length; j++) {
82
+ const useCase = useCases[j]
83
+
84
+ const specs = dataItem.spec?.[dataSet.useCase]
85
+ if (!specs) {
86
+ continue
87
+ }
88
+
89
+ const result = useCase?.evaluate(specs, values)
90
+
91
+ if (result) {
92
+ ooc ||= result.ooc
93
+ oos ||= result.oos
94
+ }
95
+ }
96
+ }
97
+
98
+ return { ooc, oos }
99
+ }
100
+
101
+ public static evaluateItem(dataSet: DataSet, dataItem: DataItem, values: any | any[]): EvaluationResult | undefined {
102
+ var ooc = false
103
+ var oos = false
104
+
105
+ if (!dataSet.useCase) {
106
+ return { ooc, oos }
107
+ }
108
+
109
+ const useCaseNames = dataSet.useCase.split(',').map(useCaseName => useCaseName.trim())
110
+ const useCases = useCaseNames.map(useCaseName => OxDataUseCase.getUseCase(useCaseName)).filter(useCase => !!useCase)
111
+
112
+ const { active, tag } = dataItem
113
+ if (!active || !tag) {
114
+ return
115
+ }
116
+
117
+ if (typeof values === 'undefined') {
118
+ return // TODO what if in case no value ?
119
+ }
120
+
121
+ if (!(values instanceof Array)) {
122
+ values = [values]
123
+ }
124
+
125
+ for (let j = 0; j < useCases.length; j++) {
126
+ const useCase = useCases[j]
127
+
128
+ const specs = dataItem.spec?.[dataSet.useCase]
129
+ if (!specs) {
130
+ return
131
+ }
132
+
133
+ const result = useCase?.evaluate(specs, values)
134
+
135
+ if (result) {
136
+ ooc ||= result.ooc
137
+ oos ||= result.oos
138
+ }
139
+ }
140
+
141
+ return { ooc, oos }
142
+ }
143
+
144
+ public abstract evaluate(specs: any, values: any[]): EvaluationResult | undefined
145
+ public abstract elaborateUseCaseSpec(spec: any): string | undefined
146
+ public abstract getSpecification(dataItem: DataItem): DataItemSpecSet
147
+ }
package/src/types.ts ADDED
@@ -0,0 +1,72 @@
1
+ export type SelectOption = { text: string; value: string }
2
+ export type SelectOptions = SelectOption[]
3
+ export type TypeOptions = {
4
+ options?: SelectOptions
5
+ [prop: string]: any
6
+ }
7
+
8
+ export type DataItem = {
9
+ name: string
10
+ description: string
11
+ sequence: number
12
+ tag: string
13
+ type: string
14
+ active: boolean
15
+ options: TypeOptions
16
+ unit: string
17
+ quota: number
18
+ spec: { [useCase: string]: any }
19
+ }
20
+
21
+ export type DataSet = {
22
+ name: string
23
+ description: string
24
+ type: 'manual' | 'automatic'
25
+ useCase: string
26
+ active: boolean
27
+ dataItems: DataItem[]
28
+ spec: { [dataItem: string]: { [useCase: string]: any } }
29
+ }
30
+
31
+ export type DataItemSpec = {
32
+ type: string
33
+ label: string
34
+ name: string
35
+ property?: { [option: string]: any }
36
+ }
37
+
38
+ export type DataItemSpecSet = {
39
+ name: string
40
+ description: string
41
+ help: string
42
+ specs: DataItemSpec[]
43
+ }
44
+
45
+ export type DataSample = {
46
+ name: string
47
+ description: string
48
+ data: any
49
+ spec: any
50
+ quota: number
51
+ workDate: string
52
+ workShift: string
53
+ collectedAt: Date
54
+ }
55
+
56
+ export type DataOocState = 'CREATED' | 'REVIEWED' | 'CORRECTED'
57
+
58
+ export type DataOoc = DataSample & {
59
+ state: DataOocState
60
+ correctiveAction: string
61
+ history: {
62
+ user: {
63
+ id: string
64
+ name: string
65
+ }
66
+ state: DataOocState
67
+ comment: string
68
+ timestamp: number
69
+ }[]
70
+ }
71
+
72
+ export type EvaluationResult = { oos: boolean; ooc: boolean }