@things-factory/dataset 6.0.73 → 6.0.75

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 (55) hide show
  1. package/client/pages/data-archive/data-archive-list-page.ts +0 -2
  2. package/client/pages/data-report/data-report-samples-page.ts +4 -2
  3. package/client/pages/data-sample/data-sample-list-page.ts +4 -2
  4. package/client/pages/data-sample/data-sample-search-page.ts +27 -22
  5. package/client/pages/data-sample/data-sample-view.ts +1 -0
  6. package/client/pages/data-set/data-item-list.ts +25 -0
  7. package/client/pages/data-set/data-set-list-page.ts +1 -0
  8. package/client/pages/data-summary/data-summary-list-page.ts +62 -6
  9. package/client/pages/data-summary/data-summary-search-page.ts +131 -62
  10. package/client/pages/data-summary/data-summary-view.ts +15 -2
  11. package/dist-client/pages/data-archive/data-archive-list-page.js +0 -1
  12. package/dist-client/pages/data-archive/data-archive-list-page.js.map +1 -1
  13. package/dist-client/pages/data-report/data-report-samples-page.js +4 -2
  14. package/dist-client/pages/data-report/data-report-samples-page.js.map +1 -1
  15. package/dist-client/pages/data-sample/data-sample-list-page.js +4 -2
  16. package/dist-client/pages/data-sample/data-sample-list-page.js.map +1 -1
  17. package/dist-client/pages/data-sample/data-sample-search-page.d.ts +2 -1
  18. package/dist-client/pages/data-sample/data-sample-search-page.js +29 -22
  19. package/dist-client/pages/data-sample/data-sample-search-page.js.map +1 -1
  20. package/dist-client/pages/data-sample/data-sample-view.js +1 -0
  21. package/dist-client/pages/data-sample/data-sample-view.js.map +1 -1
  22. package/dist-client/pages/data-set/data-item-list.js +23 -0
  23. package/dist-client/pages/data-set/data-item-list.js.map +1 -1
  24. package/dist-client/pages/data-set/data-set-list-page.js +1 -0
  25. package/dist-client/pages/data-set/data-set-list-page.js.map +1 -1
  26. package/dist-client/pages/data-summary/data-summary-list-page.js +62 -5
  27. package/dist-client/pages/data-summary/data-summary-list-page.js.map +1 -1
  28. package/dist-client/pages/data-summary/data-summary-search-page.d.ts +15 -2
  29. package/dist-client/pages/data-summary/data-summary-search-page.js +131 -62
  30. package/dist-client/pages/data-summary/data-summary-search-page.js.map +1 -1
  31. package/dist-client/pages/data-summary/data-summary-view.d.ts +1 -1
  32. package/dist-client/pages/data-summary/data-summary-view.js +15 -2
  33. package/dist-client/pages/data-summary/data-summary-view.js.map +1 -1
  34. package/dist-client/tsconfig.tsbuildinfo +1 -1
  35. package/dist-server/controllers/generate-data-summary.js +52 -2
  36. package/dist-server/controllers/generate-data-summary.js.map +1 -1
  37. package/dist-server/service/data-sample/data-sample-query.js +36 -2
  38. package/dist-server/service/data-sample/data-sample-query.js.map +1 -1
  39. package/dist-server/service/data-set/data-item-type.js +28 -20
  40. package/dist-server/service/data-set/data-item-type.js.map +1 -1
  41. package/dist-server/service/data-summary/data-summary-query.js +39 -7
  42. package/dist-server/service/data-summary/data-summary-query.js.map +1 -1
  43. package/dist-server/service/data-summary/data-summary.js +25 -0
  44. package/dist-server/service/data-summary/data-summary.js.map +1 -1
  45. package/dist-server/tsconfig.tsbuildinfo +1 -1
  46. package/package.json +13 -11
  47. package/server/controllers/generate-data-summary.ts +68 -1
  48. package/server/service/data-sample/data-sample-query.ts +38 -2
  49. package/server/service/data-set/data-item-type.ts +17 -10
  50. package/server/service/data-summary/data-summary-query.ts +42 -6
  51. package/server/service/data-summary/data-summary.ts +20 -0
  52. package/translations/en.json +6 -0
  53. package/translations/ko.json +13 -7
  54. package/translations/ms.json +6 -0
  55. package/translations/zh.json +6 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/dataset",
3
- "version": "6.0.73",
3
+ "version": "6.0.75",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/index.js",
6
6
  "things-factory": true,
@@ -35,17 +35,19 @@
35
35
  "@operato/shell": "^1.0.1",
36
36
  "@operato/styles": "^1.0.0",
37
37
  "@operato/utils": "^1.0.1",
38
- "@things-factory/auth-base": "^6.0.73",
39
- "@things-factory/aws-base": "^6.0.73",
40
- "@things-factory/board-service": "^6.0.73",
38
+ "@things-factory/auth-base": "^6.0.75",
39
+ "@things-factory/aws-base": "^6.0.75",
40
+ "@things-factory/board-service": "^6.0.75",
41
41
  "@things-factory/env": "^6.0.71",
42
- "@things-factory/organization": "^6.0.73",
43
- "@things-factory/scheduler-client": "^6.0.73",
44
- "@things-factory/shell": "^6.0.73",
45
- "@things-factory/work-shift": "^6.0.73",
46
- "@things-factory/worklist": "^6.0.73",
42
+ "@things-factory/organization": "^6.0.75",
43
+ "@things-factory/scheduler-client": "^6.0.75",
44
+ "@things-factory/shell": "^6.0.75",
45
+ "@things-factory/work-shift": "^6.0.75",
46
+ "@things-factory/worklist": "^6.0.75",
47
47
  "cron-parser": "^4.3.0",
48
- "moment-timezone": "^0.5.40"
48
+ "moment-timezone": "^0.5.40",
49
+ "simple-statistics": "^7.8.3",
50
+ "statistics": "^3.3.0"
49
51
  },
50
- "gitHead": "cf00adc3f06bebbe492c63f0f743eb874155f9b5"
52
+ "gitHead": "f7ca179a7fabfc129a9981a7bd734380a3ac64f0"
51
53
  }
@@ -1,3 +1,6 @@
1
+ const statistics = require('simple-statistics')
2
+ const deepClone = require('lodash/cloneDeep')
3
+
1
4
  import { Sorting, getQueryBuilderFromListParams } from '@things-factory/shell'
2
5
  import { logger } from '@things-factory/env'
3
6
 
@@ -7,6 +10,20 @@ import { DataSet } from '../service/data-set/data-set'
7
10
  import { DataSummary } from '../service/data-summary/data-summary'
8
11
  import { DataKeyItem } from '../service/data-key-set/data-key-item-type'
9
12
 
13
+ import { DataItem } from 'service'
14
+
15
+ const STAT_FUNCTION_MAP = {
16
+ sum: 'sum',
17
+ mean: 'mean',
18
+ stddev: 'standardDeviation',
19
+ variance: 'variance',
20
+ min: 'min',
21
+ max: 'max',
22
+ range: 'range',
23
+ median: 'median',
24
+ mode: 'mode'
25
+ }
26
+
10
27
  const compareKeys = (dataKeyItems: DataKeyItem[], summary: Partial<DataSummary>, sample: DataSample): boolean => {
11
28
  return dataKeyItems.every((item, index) => {
12
29
  const prop = `key0${index + 1}`
@@ -31,6 +48,42 @@ const buildKeySortingList = (dataKeyItems: DataKeyItem[]): Sorting[] => {
31
48
  }, [])
32
49
  }
33
50
 
51
+ const calculateSummary = (dataItems: DataItem[], base: { [tag: string]: any[] }) => {
52
+ return dataItems.reduce((summary, item) => {
53
+ const tag = item.tag
54
+
55
+ const data = base[tag]
56
+ .flat(Infinity)
57
+ .map(Number)
58
+ .filter(item => !isNaN(item))
59
+
60
+ switch (item.stat) {
61
+ case 'range':
62
+ summary[tag] = statistics.max(data) - statistics.min(data)
63
+ break
64
+
65
+ default:
66
+ const functionName = STAT_FUNCTION_MAP[item.stat]
67
+ summary[tag] = (functionName && statistics[functionName](data)) || ''
68
+ }
69
+
70
+ return summary
71
+ }, {})
72
+ }
73
+
74
+ const fillSummaryResult = (
75
+ dataSummary: Partial<DataSummary>,
76
+ dataItems: DataItem[],
77
+ base: { [tag: string]: any[] }
78
+ ): void => {
79
+ const summary = calculateSummary(dataItems, base)
80
+
81
+ dataSummary.summary = summary
82
+ dataItems.slice(0, 4).forEach((dataItem, idx) => {
83
+ dataSummary[`data0${idx + 1}`] = summary[dataItem.tag]
84
+ })
85
+ }
86
+
34
87
  export async function generateDataSummary(
35
88
  dataSetId: string,
36
89
  workDate: string,
@@ -46,6 +99,11 @@ export async function generateDataSummary(
46
99
  })
47
100
 
48
101
  const dataKeyItems = dataSet.dataKeySet?.dataKeyItems || []
102
+ const dataItems = dataSet.dataItems.filter(item => item.stat)
103
+ const initialSummary = dataItems.reduce((sum, item) => {
104
+ sum[item.tag] = []
105
+ return sum
106
+ }, {})
49
107
 
50
108
  const limit = 100
51
109
  var page = 1
@@ -71,6 +129,7 @@ export async function generateDataSummary(
71
129
  for (const sample of samples) {
72
130
  if (!summary || !compareKeys(dataKeyItems, summary, sample)) {
73
131
  if (summary) {
132
+ fillSummaryResult(summary, dataItems, summary.summary)
74
133
  summaries.push(summary)
75
134
  }
76
135
 
@@ -85,6 +144,7 @@ export async function generateDataSummary(
85
144
  count: 0,
86
145
  countOoc: 0,
87
146
  countOos: 0,
147
+ summary: deepClone(initialSummary),
88
148
  updater: user,
89
149
  creator: user
90
150
  }
@@ -93,10 +153,17 @@ export async function generateDataSummary(
93
153
  summary.count++
94
154
  sample.ooc && summary.countOoc++
95
155
  sample.oos && summary.countOos++
156
+
157
+ dataItems.forEach(item => {
158
+ summary.summary[item.tag].push(sample.data[item.tag])
159
+ })
96
160
  }
97
161
 
98
162
  if (samples.length < limit) {
99
- summary && summaries.push(summary)
163
+ if (summary) {
164
+ fillSummaryResult(summary, dataItems, summary.summary)
165
+ summaries.push(summary)
166
+ }
100
167
  break
101
168
  }
102
169
 
@@ -39,6 +39,42 @@ export class DataSampleQuery {
39
39
  return { items, total }
40
40
  }
41
41
 
42
+ @Directive('@privilege(category: "data-sample", privilege: "query", domainOwnerGranted: true)')
43
+ @Query(returns => DataSampleList, { description: 'To fetch multiple data samples by data set' })
44
+ async dataSamplesByDataSet(
45
+ @Arg('dataSetId') dataSetId: string,
46
+ @Args() params: ListParam,
47
+ @Ctx() context: ResolverContext
48
+ ): Promise<DataSampleList> {
49
+ const { domain } = context.state
50
+
51
+ const dataSet = await getRepository(DataSet).findOne({
52
+ where: { domain: { id: domain.id }, id: dataSetId },
53
+ relations: ['dataKeySet']
54
+ })
55
+
56
+ if (!dataSet) {
57
+ throw new Error(`dataSet not found by the given dataSetId(${dataSetId})`)
58
+ }
59
+
60
+ const dataKeyItems = dataSet.dataKeySet?.dataKeyItems || []
61
+ const searchables = dataKeyItems.map((item, index) => `key0${index + 1}`)
62
+
63
+ const queryBuilder = getQueryBuilderFromListParams({
64
+ repository: getRepository(DataSample),
65
+ params,
66
+ domain,
67
+ alias: 'sample',
68
+ searchables: ['name', 'description'].concat(searchables)
69
+ }).innerJoin('sample.dataSet', 'ds', 'ds.id = :dataSetId', {
70
+ dataSetId
71
+ })
72
+
73
+ const [items, total] = await queryBuilder.getManyAndCount()
74
+
75
+ return { items, total }
76
+ }
77
+
42
78
  @Directive('@privilege(category: "data-sample", privilege: "query", domainOwnerGranted: true)')
43
79
  @Query(returns => DataSampleList, { description: 'To fetch multiple data samples by data key set' })
44
80
  async dataSamplesByDataKeySet(
@@ -56,9 +92,9 @@ export class DataSampleQuery {
56
92
  repository: getRepository(DataSample),
57
93
  params,
58
94
  domain,
59
- alias: 'dks',
95
+ alias: 'sample',
60
96
  searchables: ['name', 'description'].concat(searchables)
61
- }).innerJoin('dks.dataSet', 'ds', 'ds.dataKeySet = :dataKeySetId', {
97
+ }).innerJoin('sample.dataSet', 'ds', 'ds.dataKeySet = :dataKeySetId', {
62
98
  dataKeySetId
63
99
  })
64
100
 
@@ -17,23 +17,21 @@ registerEnumType(DataItemType, {
17
17
  description: 'type enumeration of a data-item'
18
18
  })
19
19
 
20
- export enum DataItemReducerType {
20
+ export enum DataItemStatType {
21
21
  sum = 'sum',
22
22
  mean = 'mean',
23
23
  stddev = 'stddev',
24
- var = 'var',
24
+ variance = 'variance',
25
25
  min = 'min',
26
26
  max = 'max',
27
27
  range = 'range',
28
28
  median = 'median',
29
- mode = 'mode',
30
- percentile = 'percentile',
31
- histogram = 'histogram'
29
+ mode = 'mode'
32
30
  }
33
31
 
34
- registerEnumType(DataItemReducerType, {
35
- name: 'DataItemReducerType',
36
- description: 'reducer type enumeration of a data-item'
32
+ registerEnumType(DataItemStatType, {
33
+ name: 'DataItemStatType',
34
+ description: 'stat type enumeration of a data-item'
37
35
  })
38
36
 
39
37
  @ObjectType({ description: 'Entity for DataItem' })
@@ -59,8 +57,11 @@ export class DataItem {
59
57
  @Field(type => ScalarObject, { nullable: true })
60
58
  options?: { [option: string]: any }
61
59
 
62
- @Field({ nullable: true })
63
- reducer?: DataItemReducerType
60
+ @Field({
61
+ nullable: true,
62
+ description: 'The grouping logic for data summarization in the given field during periodic task deadlines.'
63
+ })
64
+ stat?: DataItemStatType
64
65
 
65
66
  @Field({ nullable: true })
66
67
  unit?: string
@@ -89,6 +90,12 @@ export class DataItemPatch {
89
90
  @Field(type => ScalarObject, { nullable: true })
90
91
  options?: { [option: string]: any }
91
92
 
93
+ @Field({
94
+ nullable: true,
95
+ description: 'The grouping logic for data summarization in the given field during periodic task deadlines.'
96
+ })
97
+ stat?: DataItemStatType
98
+
92
99
  @Field({ nullable: true })
93
100
  unit?: string
94
101
 
@@ -35,6 +35,42 @@ export class DataSummaryQuery {
35
35
  return { items, total }
36
36
  }
37
37
 
38
+ @Directive('@privilege(category: "data-summary", privilege: "query", domainOwnerGranted: true)')
39
+ @Query(returns => DataSummaryList, { description: 'To fetch multiple data summaries by data set' })
40
+ async dataSummariesByDataSet(
41
+ @Arg('dataSetId') dataSetId: string,
42
+ @Args() params: ListParam,
43
+ @Ctx() context: ResolverContext
44
+ ): Promise<DataSummaryList> {
45
+ const { domain } = context.state
46
+
47
+ const dataSet = await getRepository(DataSet).findOne({
48
+ where: { domain: { id: domain.id }, id: dataSetId },
49
+ relations: ['dataKeySet']
50
+ })
51
+
52
+ if (!dataSet) {
53
+ throw new Error(`dataSet not found by the given dataSetId(${dataSetId})`)
54
+ }
55
+
56
+ const dataKeyItems = dataSet.dataKeySet?.dataKeyItems || []
57
+ const searchables = dataKeyItems.map((item, index) => `key0${index + 1}`)
58
+
59
+ const queryBuilder = getQueryBuilderFromListParams({
60
+ repository: getRepository(DataSummary),
61
+ params,
62
+ domain,
63
+ alias: 'summary',
64
+ searchables: ['name', 'description'].concat(searchables)
65
+ }).innerJoin('summary.dataSet', 'ds', 'ds.id = :dataSetId', {
66
+ dataSetId
67
+ })
68
+
69
+ const [items, total] = await queryBuilder.getManyAndCount()
70
+
71
+ return { items, total }
72
+ }
73
+
38
74
  @Directive('@privilege(category: "data-summary", privilege: "query", domainOwnerGranted: true)')
39
75
  @Query(returns => DataSummaryList, { description: 'To fetch multiple data summaries by data key set' })
40
76
  async dataSummariesByDataKeySet(
@@ -52,9 +88,9 @@ export class DataSummaryQuery {
52
88
  repository: getRepository(DataSummary),
53
89
  params,
54
90
  domain,
55
- alias: 'dks',
91
+ alias: 'summary',
56
92
  searchables: ['name', 'description'].concat(searchables)
57
- }).innerJoin('dks.dataSet', 'ds', 'ds.dataKeySet = :dataKeySetId', {
93
+ }).innerJoin('summary.dataSet', 'ds', 'ds.dataKeySet = :dataKeySetId', {
58
94
  dataKeySetId
59
95
  })
60
96
 
@@ -65,13 +101,13 @@ export class DataSummaryQuery {
65
101
 
66
102
  @FieldResolver(type => [DataItem])
67
103
  async dataItems(@Root() dataSummary: DataSummary): Promise<DataItem[]> {
68
- const dataSetHistory: DataSetHistory = await getRepository(DataSetHistory).findOne({
104
+ const dataSet = await getRepository(DataSet).findOne({
69
105
  where: {
70
- originalId: dataSummary.dataSetId,
71
- version: dataSummary.dataSetVersion
106
+ id: dataSummary.dataSetId
72
107
  }
73
108
  })
74
- return dataSetHistory?.dataItems || []
109
+
110
+ return dataSet?.dataItems || []
75
111
  }
76
112
 
77
113
  @FieldResolver(type => DataSet)
@@ -141,6 +141,26 @@ export class DataSummary {
141
141
  @Field({ nullable: true })
142
142
  key05?: string = ''
143
143
 
144
+ @Column({ type: 'real', nullable: true })
145
+ @Field({ nullable: true })
146
+ data01?: number
147
+
148
+ @Column({ type: 'real', nullable: true })
149
+ @Field({ nullable: true })
150
+ data02?: number
151
+
152
+ @Column({ type: 'real', nullable: true })
153
+ @Field({ nullable: true })
154
+ data03?: number
155
+
156
+ @Column({ type: 'real', nullable: true })
157
+ @Field({ nullable: true })
158
+ data04?: number
159
+
160
+ @Column({ type: 'real', nullable: true })
161
+ @Field({ nullable: true })
162
+ data05?: number
163
+
144
164
  @CreateDateColumn()
145
165
  @Field({ nullable: true })
146
166
  createdAt?: Date
@@ -26,6 +26,11 @@
26
26
  "field.key-03": "key 3",
27
27
  "field.key-04": "key 4",
28
28
  "field.key-05": "key 5",
29
+ "field.data-01": "data 1",
30
+ "field.data-02": "data 2",
31
+ "field.data-03": "data 3",
32
+ "field.data-04": "data 4",
33
+ "field.data-05": "data 5",
29
34
  "field.latest-collected-at": "latest collected at",
30
35
  "field.monitor-type": "monitor type",
31
36
  "field.monitor-view": "monitor view",
@@ -34,6 +39,7 @@
34
39
  "field.oos": "out of critical limit",
35
40
  "field.ooc": "out of control limit",
36
41
  "field.summary": "summary",
42
+ "field.stat-function": "stat func.",
37
43
  "field.count": "count",
38
44
  "field.count-oos": "oos count",
39
45
  "field.count-ooc": "oos count",
@@ -21,11 +21,16 @@
21
21
  "field.entry-view": "입력용 화면",
22
22
  "field.hidden": "숨기기",
23
23
  "field.item": "항목",
24
- "field.key-01": "데이타키 1",
25
- "field.key-02": "데이타키 2",
26
- "field.key-03": "데이타키 3",
27
- "field.key-04": "데이타키 4",
28
- "field.key-05": "데이타키 5",
24
+ "field.key-01": " 1",
25
+ "field.key-02": " 2",
26
+ "field.key-03": " 3",
27
+ "field.key-04": " 4",
28
+ "field.key-05": " 5",
29
+ "field.data-01": "데이타 1",
30
+ "field.data-02": "데이타 2",
31
+ "field.data-03": "데이타 3",
32
+ "field.data-04": "데이타 4",
33
+ "field.data-05": "데이타 5",
29
34
  "field.latest-collected-at": "최근 수집 시간",
30
35
  "field.monitor-type": "모니터용 화면종류",
31
36
  "field.monitor-view": "모니터용 화면",
@@ -34,9 +39,10 @@
34
39
  "field.ooc": "관리한계 이탈여부",
35
40
  "field.oos": "허용한계 이탈여부",
36
41
  "field.summary": "마감 자료",
42
+ "field.stat-function": "통계함수",
37
43
  "field.count": "건수",
38
- "field.count-oos": "oos 건수",
39
- "field.count-ooc": "oos 건수",
44
+ "field.count-oos": "허용한계이탈 건수",
45
+ "field.count-ooc": "관리한계이탈 건수",
40
46
  "field.options": "선택옵션",
41
47
  "field.partition-keys": "파티션 키",
42
48
  "field.prev-schedule": "이전 수집계획",
@@ -25,6 +25,11 @@
25
25
  "field.key-03": "key 3",
26
26
  "field.key-04": "key 4",
27
27
  "field.key-05": "key 5",
28
+ "field.data-01": "data 1",
29
+ "field.data-02": "data 2",
30
+ "field.data-03": "data 3",
31
+ "field.data-04": "data 4",
32
+ "field.data-05": "data 5",
28
33
  "field.latest-collected-at": "latest collected at",
29
34
  "field.monitor-type": "monitor type",
30
35
  "field.monitor-view": "monitor view",
@@ -33,6 +38,7 @@
33
38
  "field.oos": "out of critical limit",
34
39
  "field.ooc": "out of control limit",
35
40
  "field.summary": "summary",
41
+ "field.stat-function": "stat func.",
36
42
  "field.count": "count",
37
43
  "field.count-oos": "oos count",
38
44
  "field.count-ooc": "oos count",
@@ -25,6 +25,11 @@
25
25
  "field.key-03": "key 3",
26
26
  "field.key-04": "key 4",
27
27
  "field.key-05": "key 5",
28
+ "field.data-01": "data 1",
29
+ "field.data-02": "data 2",
30
+ "field.data-03": "data 3",
31
+ "field.data-04": "data 4",
32
+ "field.data-05": "data 5",
28
33
  "field.latest-collected-at": "latest collected at",
29
34
  "field.monitor-type": "monitor type",
30
35
  "field.monitor-view": "monitor view",
@@ -33,6 +38,7 @@
33
38
  "field.oos": "out of critical limit",
34
39
  "field.ooc": "out of control limit",
35
40
  "field.summary": "summary",
41
+ "field.stat-function": "stat func.",
36
42
  "field.count": "count",
37
43
  "field.count-oos": "oos count",
38
44
  "field.count-ooc": "oos count",