@operato/dataset 1.0.0-alpha.4 → 1.0.0-alpha.40

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 (61) hide show
  1. package/CHANGELOG.md +330 -0
  2. package/demo/index.html +11 -95
  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 +473 -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 +58 -17
  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 +165 -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 +76 -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 +19 -11
  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 +59 -38
  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 +171 -0
  51. package/src/ox-data-use-case.ts +147 -0
  52. package/src/types.ts +70 -0
  53. package/themes/app-theme.css +142 -0
  54. package/themes/form-theme.css +75 -0
  55. package/themes/grist-theme.css +194 -0
  56. package/themes/oops-theme.css +26 -0
  57. package/themes/report-theme.css +47 -0
  58. package/translations/en.json +1 -0
  59. package/translations/ko.json +1 -0
  60. package/translations/ms.json +1 -0
  61. 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 {
@@ -35,9 +14,56 @@ export class OxDataEntryForm extends LitElement {
35
14
  }
36
15
 
37
16
  form {
17
+ flex: 1;
18
+
38
19
  display: flex;
39
20
  flex-direction: column;
40
21
  }
22
+ label {
23
+ display: grid;
24
+ grid-template-columns: repeat(12, 1fr);
25
+ gap: 9px;
26
+ align-items: center;
27
+ margin-bottom: var(--margin-default);
28
+ }
29
+ label:nth-child(even) {
30
+ background-color: var(--main-section-background-color);
31
+ padding: var(--padding-default) 0;
32
+ }
33
+
34
+ div[name] {
35
+ grid-column: span 2 / auto;
36
+ font: var(--label-font);
37
+ color: var(--label-color);
38
+ text-align: right;
39
+ }
40
+ div[elements] {
41
+ grid-column: span 10 / auto;
42
+ display: flex;
43
+ flex-direction: row;
44
+ flex-wrap: wrap;
45
+ gap: 10px;
46
+ padding-right: var(--padding-default);
47
+ }
48
+ div[elements] * {
49
+ flex: 1;
50
+ }
51
+ div[elements] input,
52
+ div[elements] select {
53
+ border: var(--input-field-border);
54
+ border-radius: var(--input-field-border-radius);
55
+ padding: var(--input-field-padding);
56
+ font: var(--input-field-font);
57
+ }
58
+
59
+ @media only screen and (max-width: 460px) {
60
+ div[name] {
61
+ grid-column: span 3 / auto;
62
+ }
63
+ div[elements] {
64
+ grid-column: span 9 / auto;
65
+ }
66
+ }
41
67
  `
42
68
 
43
69
  @property({ type: Object }) dataSet?: DataSet
@@ -48,28 +74,28 @@ export class OxDataEntryForm extends LitElement {
48
74
  }
49
75
 
50
76
  private onChange(e: Event) {
51
- const value = this.buildValue()
77
+ this.value = this.buildValue()
52
78
 
53
79
  this.dispatchEvent(
54
80
  new CustomEvent('change', {
55
81
  bubbles: true,
56
82
  composed: true,
57
- detail: value
83
+ detail: this.value
58
84
  })
59
85
  )
60
86
  }
61
87
 
62
88
  private buildInputs() {
63
- const dataItems = this.dataSet!.dataItems
89
+ const dataItems = this.dataSet!.dataItems.filter(item => item.active)
64
90
 
65
91
  return (dataItems || []).map(dataItem => {
66
- const { name, description, tag, type, quota = 1, options = {} } = dataItem
92
+ const { name, description, tag, type, quota = 1, options = {}, unit } = dataItem
67
93
 
68
94
  const samples = new Array(quota).fill(0)
69
- const value = this.value?.[tag]
95
+ const value = this.value && this.value[tag]
70
96
 
71
97
  const elements = samples.map((_, idx) => {
72
- const v = quota <= 1 ? value : value instanceof Array && value[idx]
98
+ const v = value instanceof Array ? value[idx] : idx === 0 ? value : undefined
73
99
 
74
100
  switch (type) {
75
101
  case 'select':
@@ -105,8 +131,8 @@ export class OxDataEntryForm extends LitElement {
105
131
  })
106
132
 
107
133
  return html` <label .title=${description}>
108
- <div>${name}</div>
109
- <div>${elements}</div>
134
+ <div name>${name}${unit ? `(${unit})` : ''}</div>
135
+ <div elements>${elements}</div>
110
136
  </label>`
111
137
  })
112
138
  }
@@ -115,19 +141,14 @@ export class OxDataEntryForm extends LitElement {
115
141
  const dataItems = this.dataSet!.dataItems
116
142
 
117
143
  return (dataItems || []).reduce((sum, dataItem) => {
118
- const { tag, quota, type } = dataItem
144
+ const { tag, type } = dataItem
119
145
 
120
146
  const editors = Array.prototype.slice.call(
121
147
  this.renderRoot.querySelectorAll(`[name=${tag}]`) as NodeListOf<HTMLInputElement>
122
148
  ) as HTMLInputElement[]
123
149
 
124
150
  if (editors.length > 0) {
125
- sum[tag] =
126
- editors.length > 1
127
- ? editors.map(editor => (type === 'boolean' ? editor.checked : editor.value))
128
- : type === 'boolean'
129
- ? editors[0].checked
130
- : editors[0].value
151
+ sum[tag] = editors.map(editor => (type === 'boolean' ? editor.checked : editor.value))
131
152
  }
132
153
 
133
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,171 @@
1
+ import '@operato/input/ox-input-file.js'
2
+
3
+ import { DataItem, DataSample, DataSet } from './types.js'
4
+ import { LitElement, css, html } from 'lit'
5
+ import { customElement, property } from 'lit/decorators.js'
6
+
7
+ import { OxDataUseCase } from './ox-data-use-case.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
+ return html` <h2>${this.dataSample?.name}</h2>
96
+ <p page-description>
97
+ ${this.dataSample?.description}<br /><br />
98
+ collected at: ${this.dataSample && formatter.format(new Date(this.dataSample?.collectedAt!))}
99
+ </p>
100
+
101
+ <form @change=${(e: Event) => this.onChange(e)}>
102
+ <table>
103
+ <tr>
104
+ <th item>item</th>
105
+ <th>description</th>
106
+ <th>unit</th>
107
+ <th value>value</th>
108
+ <th>specification</th>
109
+ <th>OOC</th>
110
+ <th>OOS</th>
111
+ </tr>
112
+ ${dataItems.map(dataItem => {
113
+ const { ooc, oos } = this.evaluateOOC(dataItem, data?.[dataItem.tag]) || {}
114
+ return html`
115
+ <tr ?ooc=${ooc} ?oos=${oos}>
116
+ <td name>${dataItem.name}</td>
117
+ <td>${dataItem.description}</td>
118
+ <td>${dataItem.unit}</td>
119
+ <td>${this.buildValue(dataItem)}</td>
120
+ <td><pre>${this.buildSpec(dataItem)}</pre></td>
121
+ <td>${ooc ? html`<mwc-icon>done</mwc-icon>` : ''}</td>
122
+ <td>${oos ? html`<mwc-icon>done</mwc-icon>` : ''}</td>
123
+ </tr>
124
+ `
125
+ })}
126
+ </table>
127
+ </form>`
128
+ }
129
+
130
+ private onChange(e: Event) {}
131
+
132
+ private buildSpec(dataItem: DataItem) {
133
+ return OxDataUseCase.elaborateDataItemSpec(this.dataSet!, dataItem)
134
+ }
135
+
136
+ private buildValue(dataItem: DataItem) {
137
+ const { tag, type } = dataItem
138
+
139
+ if (!this.dataSample) {
140
+ return ''
141
+ }
142
+
143
+ const value = this.dataSample?.data[dataItem.tag]
144
+ if (value === undefined) {
145
+ return ''
146
+ }
147
+ const values = value instanceof Array ? value : [value]
148
+
149
+ const elements = values.map((_: any, idx) => {
150
+ const v = value[idx]
151
+
152
+ switch (type) {
153
+ case 'boolean':
154
+ return html` <input type="checkbox" name=${tag} .checked=${v} disabled />`
155
+ break
156
+
157
+ case 'select':
158
+ case 'number':
159
+ case 'string':
160
+ default:
161
+ return String(v === undefined ? '' : v)
162
+ }
163
+ })
164
+
165
+ return type === 'boolean' ? elements : elements.join(', ')
166
+ }
167
+
168
+ private evaluateOOC(dataItem: DataItem, value: any) {
169
+ return OxDataUseCase.evaluateItem(this.dataSet!, dataItem, value)
170
+ }
171
+ }
@@ -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,70 @@
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
+ collectedAt: Date
52
+ }
53
+
54
+ export type DataOocState = 'CREATED' | 'REVIEWED' | 'CORRECTED'
55
+
56
+ export type DataOoc = DataSample & {
57
+ state: DataOocState
58
+ correctiveAction: string
59
+ history: {
60
+ user: {
61
+ id: string
62
+ name: string
63
+ }
64
+ state: DataOocState
65
+ comment: string
66
+ timestamp: number
67
+ }[]
68
+ }
69
+
70
+ export type EvaluationResult = { oos: boolean; ooc: boolean }