@things-factory/reference-app 5.0.0-zeta.8 → 5.0.1

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 (67) hide show
  1. package/client/bootstrap.js +21 -11
  2. package/client/components/ocr-viewpart.js +1 -1
  3. package/client/editors/id-editor.js +1 -1
  4. package/client/editors/id-selector.js +1 -1
  5. package/client/menu.js +10 -5
  6. package/client/pages/data-entry/data-entry-form.js +117 -0
  7. package/client/pages/data-entry/data-entry-generator-popup.js +110 -0
  8. package/client/pages/data-set/data-item-list.js +277 -0
  9. package/client/pages/data-set/data-set-importer.js +103 -0
  10. package/client/pages/data-set/data-set-list-page.js +738 -0
  11. package/client/pages/ocr-page.js +1 -1
  12. package/client/pages/operation/operation-api.js +85 -0
  13. package/client/pages/operation/operation-master.js +432 -0
  14. package/client/pages/pending-job-page.js +1 -1
  15. package/client/pages/product/product-api.js +150 -0
  16. package/client/pages/product/product-master.js +888 -0
  17. package/client/pages/product-combination-settings-popup.js +395 -0
  18. package/client/pages/product-combinations-popup.js +372 -0
  19. package/client/pages/product-details-popup.js +744 -0
  20. package/client/pages/upload-page.js +1 -1
  21. package/client/route.js +12 -0
  22. package/config/config.development.js +1 -1
  23. package/config.development.js +21 -0
  24. package/db.sqlite +0 -0
  25. package/dist-server/constants/index.js +18 -0
  26. package/dist-server/constants/index.js.map +1 -0
  27. package/dist-server/constants/type-constants.js +26 -0
  28. package/dist-server/constants/type-constants.js.map +1 -0
  29. package/dist-server/controllers/create-data-sample-mockup.js +236 -0
  30. package/dist-server/controllers/create-data-sample-mockup.js.map +1 -0
  31. package/dist-server/controllers/index.js +17 -0
  32. package/dist-server/controllers/index.js.map +1 -1
  33. package/dist-server/service/data-sample-mockup/data-sample-mockup-mutation.js +40 -0
  34. package/dist-server/service/data-sample-mockup/data-sample-mockup-mutation.js.map +1 -0
  35. package/dist-server/service/data-sample-mockup/data-sample-mockup-type.js +28 -0
  36. package/dist-server/service/data-sample-mockup/data-sample-mockup-type.js.map +1 -0
  37. package/dist-server/service/data-sample-mockup/index.js +7 -0
  38. package/dist-server/service/data-sample-mockup/index.js.map +1 -0
  39. package/dist-server/service/index.js +5 -2
  40. package/dist-server/service/index.js.map +1 -1
  41. package/dist-server/service/reference/reference-mutation.js +6 -3
  42. package/dist-server/service/reference/reference-mutation.js.map +1 -1
  43. package/dist-server/service/reference/reference-query.js +7 -4
  44. package/dist-server/service/reference/reference-query.js.map +1 -1
  45. package/logs/.08636eb59927f12972f6774f5947c8507b3564c2-audit.json +4 -14
  46. package/logs/.5e5d741d8b7784a2fbad65eedc0fd46946aaf6f2-audit.json +19 -69
  47. package/logs/application-2022-07-22-10.log +26 -0
  48. package/logs/connections-2022-07-12-00.log +0 -0
  49. package/logs/connections-2022-07-14-14.log +0 -0
  50. package/logs/connections-2022-07-14-15.log +0 -0
  51. package/logs/connections-2022-07-14-16.log +0 -0
  52. package/logs/connections-2022-07-14-17.log +0 -0
  53. package/logs/connections-2022-07-22-10.log +0 -0
  54. package/package.json +58 -56
  55. package/server/constants/index.ts +1 -0
  56. package/server/constants/type-constants.ts +24 -0
  57. package/server/controllers/create-data-sample-mockup.ts +268 -0
  58. package/server/controllers/index.ts +1 -0
  59. package/server/service/data-sample-mockup/data-sample-mockup-mutation.ts +18 -0
  60. package/server/service/data-sample-mockup/data-sample-mockup-type.ts +10 -0
  61. package/server/service/data-sample-mockup/index.ts +4 -0
  62. package/server/service/index.ts +5 -2
  63. package/server/service/reference/reference-mutation.ts +5 -3
  64. package/server/service/reference/reference-query.ts +8 -7
  65. package/things-factory.config.js +8 -0
  66. package/translations/en.json +6 -1
  67. package/translations/ko.json +7 -1
@@ -2,17 +2,22 @@ import '@things-factory/auth-ui' /* for domain-switch */
2
2
  import '@things-factory/barcode-base' /* for <default-label-printer-setting-let> */
3
3
  import '@things-factory/notification' /* for notification-badge */
4
4
  import './components/ocr-viewpart'
5
+ import '@operato/dataset/usecase/ccp'
6
+ import '@operato/dataset/usecase/qc'
7
+ import '@operato/dataset/ox-property-editor-ccp-limits.js'
8
+ import '@operato/dataset/ox-property-editor-qc-limits.js'
5
9
 
6
10
  import { html } from 'lit-html'
7
11
 
8
12
  import { OxGristEditorResourceId } from '@operato/app/grist-editor/ox-grist-editor-resource-id.js'
9
13
  import { registerDefaultGroups } from '@operato/board/register-default-groups.js'
10
14
  import { getEditor, registerEditor, registerRenderer } from '@operato/data-grist'
15
+ import { appendViewpart, toggleOverlay, TOOL_POSITION, VIEWPART_POSITION } from '@operato/layout'
16
+ import { OxPropertyEditor } from '@operato/property-editor'
11
17
  import { isMobileDevice } from '@operato/utils'
12
18
  import { APPEND_APP_TOOL } from '@things-factory/apptool-base'
13
19
  import { auth } from '@things-factory/auth-base'
14
20
  import { setAuthManagementMenus } from '@things-factory/auth-ui'
15
- import { appendViewpart, toggleOverlay, TOOL_POSITION, VIEWPART_POSITION } from '@things-factory/layout-base'
16
21
  import { setupMenuPart, updateMenuTemplate } from '@things-factory/lite-menu'
17
22
  import { ADD_MORENDA } from '@things-factory/more-base'
18
23
  import { ADD_SETTING } from '@things-factory/setting-base'
@@ -39,6 +44,11 @@ export default function bootstrap() {
39
44
  registerEditor('id', OxGristEditorResourceId)
40
45
  registerEditor('barcode', getEditor('string'))
41
46
 
47
+ OxPropertyEditor.register({
48
+ 'ccp-limits': 'ox-property-editor-ccp-limits',
49
+ 'qc-limits': 'ox-property-editor-qc-limits'
50
+ })
51
+
42
52
  /* set board-modeller group and default templates */
43
53
  registerDefaultGroups()
44
54
 
@@ -131,16 +141,16 @@ export default function bootstrap() {
131
141
  }
132
142
  })
133
143
 
134
- store.dispatch({
135
- type: ADD_MORENDA,
136
- morenda: {
137
- icon: html` <mwc-icon>help</mwc-icon> `,
138
- name: html` <i18n-msg msgid="text.help"></i18n-msg> `,
139
- action: () => {
140
- navigate('help')
141
- }
142
- }
143
- })
144
+ // store.dispatch({
145
+ // type: ADD_MORENDA,
146
+ // morenda: {
147
+ // icon: html` <mwc-icon>help</mwc-icon> `,
148
+ // name: html` <i18n-msg msgid="text.help"></i18n-msg> `,
149
+ // action: () => {
150
+ // navigate('help')
151
+ // }
152
+ // }
153
+ // })
144
154
 
145
155
  store.dispatch({
146
156
  type: ADD_SETTING,
@@ -2,7 +2,7 @@ import './camera-capturer'
2
2
  import '@material/mwc-button'
3
3
  import '@operato/ocr/ox-ocr-helper.js'
4
4
 
5
- import { gql } from 'graphql-tag'
5
+ import gql from 'graphql-tag'
6
6
  import { css, html, LitElement } from 'lit'
7
7
 
8
8
  import { client } from '@things-factory/shell'
@@ -3,7 +3,7 @@ import './id-selector'
3
3
 
4
4
  import { css, html, LitElement } from 'lit'
5
5
 
6
- import { openPopup } from '@things-factory/layout-base'
6
+ import { openPopup } from '@operato/layout'
7
7
 
8
8
  export class IdEditor extends LitElement {
9
9
  static get properties() {
@@ -70,7 +70,7 @@ export class IdSelector extends LitElement {
70
70
  .selectedRecords=${this.selectedRecords}
71
71
  >
72
72
  <div id="filters" slot="headroom">
73
- <ox-filters-form></ox-filters-form>
73
+ <ox-filters-form autofocus></ox-filters-form>
74
74
  </div>
75
75
  </ox-grist>
76
76
 
package/client/menu.js CHANGED
@@ -140,6 +140,16 @@ export function getMenuTemplate() {
140
140
  icon: 'settings',
141
141
  description: '데이타 수집을 위한 개념과 기능들을 소개합니다.',
142
142
  menus: [
143
+ {
144
+ name: 'Operation',
145
+ icon: 'schema',
146
+ path: 'operation_master'
147
+ },
148
+ {
149
+ name: 'Product',
150
+ icon: 'inventory',
151
+ path: 'product_master'
152
+ },
143
153
  {
144
154
  icon: 'display_settings',
145
155
  name: 'Data Set Master',
@@ -169,11 +179,6 @@ export function getMenuTemplate() {
169
179
  icon: 'newspaper',
170
180
  name: 'Data Report',
171
181
  path: 'data-report-list'
172
- },
173
- {
174
- icon: 'newspaper',
175
- name: 'Jasper Data Report',
176
- path: 'jasper-report-dev-samples'
177
182
  }
178
183
  ]
179
184
  }
@@ -0,0 +1,117 @@
1
+ import '@operato/dataset/ox-data-entry-form.js'
2
+
3
+ import gql from 'graphql-tag'
4
+ import { css, html, LitElement } from 'lit'
5
+
6
+ import { openPopup } from '@operato/layout'
7
+ import { client } from '@operato/graphql'
8
+ import { i18next, localize } from '@operato/i18n'
9
+ import { ScrollbarStyles } from '@operato/styles'
10
+
11
+ import './data-entry-generator-popup'
12
+
13
+ class DataEntryForm extends localize(i18next)(LitElement) {
14
+ static get properties() {
15
+ return {
16
+ dataSet: Object
17
+ }
18
+ }
19
+
20
+ static get styles() {
21
+ return [
22
+ ScrollbarStyles,
23
+ css`
24
+ :host {
25
+ display: flex;
26
+ flex-direction: column;
27
+
28
+ background-color: #fff;
29
+ }
30
+
31
+ ox-data-entry-form {
32
+ flex: 1;
33
+ padding: 10px;
34
+ overflow: auto;
35
+ }
36
+
37
+ .button-container {
38
+ display: flex;
39
+ margin-left: auto;
40
+ padding: var(--padding-default);
41
+ }
42
+
43
+ mwc-button {
44
+ margin-left: var(--margin-default);
45
+ }
46
+ `
47
+ ]
48
+ }
49
+
50
+ get entryForm() {
51
+ return this.renderRoot.querySelector('ox-data-entry-form')
52
+ }
53
+
54
+ render() {
55
+ return html`
56
+ <ox-data-entry-form .dataSet=${this.dataSet}></ox-data-entry-form>
57
+ <div class="button-container">
58
+ ${process.env.NODE_ENV == 'development'
59
+ ? html`<mwc-button raised @click=${this._generateMockupData.bind(this)}>${i18next.t('button.generate_mockup')}</mwc-button>`
60
+ : html``
61
+ }
62
+ <mwc-button raised @click=${this._updateDataItems.bind(this)}>${i18next.t('button.save')}</mwc-button>
63
+ </div>
64
+ `
65
+ }
66
+
67
+ async _generateMockupData() {
68
+ this.popup = openPopup(
69
+ html`
70
+ <data-entry-generator-popup
71
+ .dataSetId="${this.dataSet.id}"
72
+ @created="${e => {
73
+ this.popup && this.popup.close()
74
+ }}"
75
+ ></data-entry-generator-popup>
76
+ `,
77
+ {
78
+ backdrop: true,
79
+ escapable: false,
80
+ size: 'small',
81
+ title: `${i18next.t('title.generate_mockup')}`
82
+ }
83
+ )
84
+ }
85
+
86
+ async _updateDataItems() {
87
+ const data = this.entryForm.buildValue()
88
+ const dataSample = {
89
+ dataSet: {
90
+ id: this.dataSet.id
91
+ },
92
+ data
93
+ }
94
+
95
+ const response = await client.mutate({
96
+ mutation: gql`
97
+ mutation ($dataSample: NewDataSample!) {
98
+ createDataSample(dataSample: $dataSample) {
99
+ id
100
+ collectedAt
101
+ }
102
+ }
103
+ `,
104
+ variables: {
105
+ dataSample
106
+ }
107
+ })
108
+
109
+ if (!response.errors) {
110
+ document.dispatchEvent(
111
+ new CustomEvent('notify', { detail: { message: i18next.t('text.data sample created successfully') } })
112
+ )
113
+ }
114
+ }
115
+ }
116
+
117
+ window.customElements.define('data-entry-form', DataEntryForm)
@@ -0,0 +1,110 @@
1
+ import { SingleColumnFormStyles } from '@things-factory/form-ui'
2
+ import '@things-factory/grist-ui'
3
+ import { i18next, localize } from '@things-factory/i18n-base'
4
+ import { client } from '@things-factory/shell'
5
+ import { gqlBuilder } from '@things-factory/utils'
6
+ import gql from 'graphql-tag'
7
+ import { css, html, LitElement } from 'lit-element'
8
+ import { notify } from '@things-factory/layout-base'
9
+
10
+ class DataEntryGeneratorPopup extends localize(i18next)(LitElement) {
11
+ static get properties() {
12
+ return {
13
+ dataSetId: String,
14
+ numSamples: Number
15
+ }
16
+ }
17
+
18
+ static get styles() {
19
+ return [
20
+ SingleColumnFormStyles,
21
+ css`
22
+ :host {
23
+ padding: 10px;
24
+ display: flex;
25
+ flex-direction: column;
26
+ overflow-x: overlay;
27
+ background-color: var(--main-section-background-color);
28
+ }
29
+ .button-container {
30
+ padding: var(--button-container-padding);
31
+ margin: var(--button-container-margin);
32
+ text-align: var(--button-container-align);
33
+ background-color: var(--button-container-background);
34
+ height: var(--button-container-height);
35
+ }
36
+ `
37
+ ]
38
+ }
39
+
40
+ render() {
41
+ return html`
42
+ <form id="input-form" name="generation" class="single-column-form" @submit=${e => this.onSubmit(e)}>
43
+ <fieldset>
44
+ <label>${i18next.t('label.num_samples')}</label>
45
+ <input type="number" .value=${this.numSamples} min="1" name="num_samples" required/>
46
+ </fieldset>
47
+ </form>
48
+
49
+ <div class="button-container">
50
+ <mwc-button raised @click="${this.generateMockupData}" label="${i18next.t('button.submit')}"></mwc-button>
51
+ </div>
52
+ `
53
+ }
54
+
55
+ async firstUpdated() {
56
+
57
+ }
58
+
59
+ async onSubmit(e) {
60
+ e.preventDefault()
61
+ this.generateMockupData()
62
+ }
63
+
64
+
65
+ serializeFormData() {
66
+ let obj = {}
67
+
68
+ Array.from(this.shadowRoot.querySelectorAll('form#input-form input')).forEach(field => {
69
+ if (!field.hasAttribute('hidden') && field.value) {
70
+ obj[field.name] = field.type === 'checkbox' ? field.checked : field.value
71
+ }
72
+ })
73
+
74
+ return obj
75
+ }
76
+
77
+ async generateMockupData() {
78
+ const params = this.serializeFormData()
79
+
80
+ const response = await client.mutate({
81
+ mutation: gql`
82
+ mutation ($params: DataSampleMockupInfo!) {
83
+ generateMockupData(params: $params)
84
+ }
85
+ `,
86
+ variables: {
87
+ params: {
88
+ dataSetId: this.dataSetId,
89
+ numSamples: parseInt(params['num_samples'])
90
+ }
91
+ }
92
+ })
93
+
94
+ if (!response.errors) {
95
+ this.dispatchEvent(new CustomEvent('created', {}))
96
+
97
+ document.dispatchEvent(
98
+ new CustomEvent('notify', { detail: { message: i18next.t('text.mockup data created successfully') } })
99
+ )
100
+
101
+ }
102
+ }
103
+
104
+ constructor() {
105
+ super()
106
+ this.numSamples = 1
107
+ }
108
+ }
109
+
110
+ window.customElements.define('data-entry-generator-popup', DataEntryGeneratorPopup)
@@ -0,0 +1,277 @@
1
+ import gql from 'graphql-tag'
2
+ import { css, html, LitElement } from 'lit'
3
+
4
+ import { client } from '@operato/graphql'
5
+ import { i18next, localize } from '@operato/i18n'
6
+ import { isMobileDevice } from '@operato/utils'
7
+
8
+ class DataItemList extends localize(i18next)(LitElement) {
9
+ static get properties() {
10
+ return {
11
+ dataSet: Object,
12
+ gristConfig: Object
13
+ }
14
+ }
15
+
16
+ static get styles() {
17
+ return [
18
+ css`
19
+ :host {
20
+ display: flex;
21
+ flex-direction: column;
22
+
23
+ background-color: #fff;
24
+ }
25
+
26
+ ox-grist {
27
+ flex: 1;
28
+ }
29
+
30
+ .button-container {
31
+ display: flex;
32
+ margin-left: auto;
33
+ padding: var(--padding-default);
34
+ }
35
+
36
+ [danger] {
37
+ --mdc-theme-primary: var(--mdc-danger-button-primary-color);
38
+ }
39
+ mwc-button {
40
+ margin-left: var(--margin-default);
41
+ }
42
+ `
43
+ ]
44
+ }
45
+
46
+ get grist() {
47
+ return this.renderRoot.querySelector('ox-grist')
48
+ }
49
+
50
+ render() {
51
+ return html`
52
+ <ox-grist
53
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
54
+ .config=${this.gristConfig}
55
+ .fetchHandler=${this.fetchHandler.bind(this)}
56
+ ></ox-grist>
57
+ <div class="button-container">
58
+ <mwc-button raised danger @click=${this._deleteDataItems.bind(this)}>${i18next.t('button.delete')}</mwc-button>
59
+ <mwc-button raised @click=${this._updateDataItems.bind(this)}>${i18next.t('button.save')}</mwc-button>
60
+ </div>
61
+ `
62
+ }
63
+
64
+ async firstUpdated() {
65
+ this.gristConfig = {
66
+ list: { fields: ['name', 'description', 'active'] },
67
+ columns: [
68
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
69
+ {
70
+ type: 'gutter',
71
+ gutterName: 'button',
72
+ icon: 'add',
73
+ handlers: {
74
+ click: 'record-copy'
75
+ }
76
+ },
77
+ { type: 'gutter', gutterName: 'sequence' },
78
+ {
79
+ type: 'gutter',
80
+ gutterName: 'button',
81
+ icon: 'arrow_upward',
82
+ handlers: {
83
+ click: 'move-up'
84
+ }
85
+ },
86
+ {
87
+ type: 'gutter',
88
+ gutterName: 'button',
89
+ icon: 'arrow_downward',
90
+ handlers: {
91
+ click: 'move-down'
92
+ }
93
+ },
94
+ {
95
+ type: 'string',
96
+ name: 'name',
97
+ header: i18next.t('field.name'),
98
+ record: {
99
+ editable: true
100
+ },
101
+ width: 140
102
+ },
103
+ {
104
+ type: 'string',
105
+ name: 'description',
106
+ header: i18next.t('field.description'),
107
+ record: {
108
+ editable: true
109
+ },
110
+ width: 180
111
+ },
112
+ {
113
+ type: 'checkbox',
114
+ name: 'active',
115
+ label: true,
116
+ header: i18next.t('field.active'),
117
+ record: {
118
+ editable: true
119
+ },
120
+ sortable: true,
121
+ width: 60
122
+ },
123
+ {
124
+ type: 'checkbox',
125
+ name: 'hidden',
126
+ label: true,
127
+ header: i18next.t('field.hidden'),
128
+ record: {
129
+ editable: true
130
+ },
131
+ sortable: true,
132
+ width: 60
133
+ },
134
+ {
135
+ type: 'string',
136
+ name: 'tag',
137
+ header: i18next.t('field.tag'),
138
+ record: {
139
+ editable: true
140
+ },
141
+ width: 180
142
+ },
143
+ {
144
+ type: 'select',
145
+ name: 'type',
146
+ header: i18next.t('field.type'),
147
+ record: {
148
+ options: ['', 'number', 'text', 'select', 'boolean', 'file'],
149
+ editable: true
150
+ },
151
+ width: 120
152
+ },
153
+ {
154
+ type: 'parameters',
155
+ name: 'options',
156
+ header: i18next.t('field.options'),
157
+ record: {
158
+ editable: true,
159
+ renderer: 'json5',
160
+ options: async (value, column, record, row, field) => {
161
+ return {
162
+ name: record.type,
163
+ help: '',
164
+ spec:
165
+ record.type === 'select'
166
+ ? [
167
+ {
168
+ type: 'options' /* property-editor type */,
169
+ name: 'options',
170
+ label: 'options'
171
+ }
172
+ ]
173
+ : [],
174
+ context: this.grist,
175
+ objectified: true
176
+ }
177
+ }
178
+ },
179
+ width: 120
180
+ },
181
+ {
182
+ type: 'string',
183
+ name: 'unit',
184
+ header: i18next.t('field.unit'),
185
+ record: {
186
+ editable: true
187
+ },
188
+ width: 120
189
+ },
190
+ {
191
+ type: 'number',
192
+ name: 'quota',
193
+ header: i18next.t('field.quota'),
194
+ record: {
195
+ editable: true
196
+ },
197
+ width: 60
198
+ },
199
+ {
200
+ type: 'data-item-spec',
201
+ name: 'spec',
202
+ header: i18next.t('field.spec'),
203
+ record: {
204
+ editable: true,
205
+ options: {
206
+ name: '',
207
+ help: '',
208
+ objectified: true /* prevent from stringifying */
209
+ }
210
+ },
211
+ width: 200
212
+ }
213
+ ],
214
+ rows: {
215
+ selectable: {
216
+ multiple: true
217
+ }
218
+ },
219
+ pagination: {
220
+ infinite: true
221
+ },
222
+ sorters: []
223
+ }
224
+ }
225
+
226
+ async fetchHandler({ filters, page, limit, sortings = [] }) {
227
+ const dataItems = this.dataSet.dataItems || []
228
+
229
+ return {
230
+ total: dataItems.length,
231
+ records: dataItems
232
+ }
233
+ }
234
+
235
+ async _updateDataItems() {
236
+ this.grist.commit()
237
+
238
+ const response = await client.mutate({
239
+ mutation: gql`
240
+ mutation ($id: String!, $patch: DataSetPatch!) {
241
+ updateDataSet(id: $id, patch: $patch) {
242
+ name
243
+ }
244
+ }
245
+ `,
246
+ variables: {
247
+ id: this.dataSet.id,
248
+ patch: {
249
+ dataItems: this.grist.data.records,
250
+ cuFlag: 'M'
251
+ }
252
+ }
253
+ })
254
+
255
+ if (!response.errors) {
256
+ await document.dispatchEvent(
257
+ new CustomEvent('notify', {
258
+ detail: {
259
+ message: i18next.t('text.info_x_successfully', {
260
+ x: i18next.t('button.save')
261
+ })
262
+ }
263
+ })
264
+ )
265
+ }
266
+ }
267
+
268
+ async _deleteDataItems() {
269
+ if (!confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
270
+ return
271
+ }
272
+
273
+ this.grist.deleteSelectedRecords(false)
274
+ }
275
+ }
276
+
277
+ window.customElements.define('data-item-list', DataItemList)