@things-factory/dataset 5.0.0-alpha.14 → 5.0.0-alpha.18

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 (38) hide show
  1. package/client/pages/data-item-list.js +1 -1
  2. package/client/pages/data-ooc.js +35 -3
  3. package/client/pages/data-set.js +2 -2
  4. package/dist-server/controllers/create-data-sample.js +103 -0
  5. package/dist-server/controllers/create-data-sample.js.map +1 -0
  6. package/dist-server/controllers/data-use-case.js +3 -3
  7. package/dist-server/controllers/data-use-case.js.map +1 -1
  8. package/dist-server/routes.js +9 -24
  9. package/dist-server/routes.js.map +1 -1
  10. package/dist-server/service/data-ooc/data-ooc-query.js +27 -1
  11. package/dist-server/service/data-ooc/data-ooc-query.js.map +1 -1
  12. package/dist-server/service/data-ooc/data-ooc-subscription.js +65 -0
  13. package/dist-server/service/data-ooc/data-ooc-subscription.js.map +1 -0
  14. package/dist-server/service/data-ooc/index.js +2 -1
  15. package/dist-server/service/data-ooc/index.js.map +1 -1
  16. package/dist-server/service/data-sample/data-sample-mutation.js +2 -80
  17. package/dist-server/service/data-sample/data-sample-mutation.js.map +1 -1
  18. package/dist-server/service/data-sample/data-sample.js +3 -3
  19. package/dist-server/service/data-sample/data-sample.js.map +1 -1
  20. package/dist-server/service/data-set/data-set-query.js +12 -0
  21. package/dist-server/service/data-set/data-set-query.js.map +1 -1
  22. package/dist-server/service/data-set/data-set.js +3 -3
  23. package/dist-server/service/data-set/data-set.js.map +1 -1
  24. package/package.json +14 -14
  25. package/server/controllers/create-data-sample.ts +142 -0
  26. package/server/controllers/data-use-case.ts +3 -3
  27. package/server/routes.ts +18 -32
  28. package/server/service/data-ooc/data-ooc-query.ts +20 -2
  29. package/server/service/data-ooc/data-ooc-subscription.ts +51 -0
  30. package/server/service/data-ooc/index.ts +2 -1
  31. package/server/service/data-sample/data-sample-mutation.ts +2 -105
  32. package/server/service/data-sample/data-sample.ts +4 -3
  33. package/server/service/data-set/data-set-query.ts +8 -1
  34. package/server/service/data-set/data-set.ts +4 -3
  35. package/translations/en.json +2 -1
  36. package/translations/ko.json +2 -1
  37. package/translations/ms.json +2 -1
  38. package/translations/zh.json +2 -1
@@ -11,10 +11,10 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  var _a, _b, _c, _d, _e;
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.DataSet = void 0;
14
- const typeorm_1 = require("typeorm");
15
- const shell_1 = require("@things-factory/shell");
16
14
  const type_graphql_1 = require("type-graphql");
15
+ const typeorm_1 = require("typeorm");
17
16
  const auth_base_1 = require("@things-factory/auth-base");
17
+ const shell_1 = require("@things-factory/shell");
18
18
  const data_item_1 = require("../data-item/data-item");
19
19
  let DataSet = class DataSet {
20
20
  };
@@ -55,7 +55,7 @@ __decorate([
55
55
  (0, typeorm_1.ManyToOne)(type => auth_base_1.Role, {
56
56
  nullable: true
57
57
  }),
58
- (0, type_graphql_1.Field)({ nullable: true }),
58
+ (0, type_graphql_1.Field)(type => auth_base_1.Role, { nullable: true }),
59
59
  __metadata("design:type", typeof (_b = typeof auth_base_1.Role !== "undefined" && auth_base_1.Role) === "function" ? _b : Object)
60
60
  ], DataSet.prototype, "supervisoryRole", void 0);
61
61
  __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"data-set.js","sourceRoot":"","sources":["../../../server/service/data-set/data-set.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data-set.js","sourceRoot":"","sources":["../../../server/service/data-set/data-set.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/dataset",
3
- "version": "5.0.0-alpha.14",
3
+ "version": "5.0.0-alpha.18",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "client/index.js",
6
6
  "things-factory": true,
@@ -24,19 +24,19 @@
24
24
  "migration:create": "node ../../node_modules/typeorm/cli.js migration:create -d ./server/migrations"
25
25
  },
26
26
  "dependencies": {
27
- "@operato/app": "1.0.0-alpha.34",
28
- "@operato/data-grist": "1.0.0-alpha.34",
29
- "@operato/dataset": "1.0.0-alpha.34",
30
- "@operato/graphql": "1.0.0-alpha.34",
31
- "@operato/i18n": "1.0.0-alpha.34",
32
- "@operato/layout": "1.0.0-alpha.34",
33
- "@operato/shell": "1.0.0-alpha.34",
34
- "@operato/styles": "1.0.0-alpha.34",
35
- "@operato/utils": "1.0.0-alpha.34",
36
- "@things-factory/auth-base": "^5.0.0-alpha.14",
37
- "@things-factory/env": "^5.0.0-alpha.14",
38
- "@things-factory/shell": "^5.0.0-alpha.14",
27
+ "@operato/app": "1.0.0-alpha.37",
28
+ "@operato/data-grist": "1.0.0-alpha.37",
29
+ "@operato/dataset": "1.0.0-alpha.37",
30
+ "@operato/graphql": "1.0.0-alpha.37",
31
+ "@operato/i18n": "1.0.0-alpha.37",
32
+ "@operato/layout": "1.0.0-alpha.37",
33
+ "@operato/shell": "1.0.0-alpha.37",
34
+ "@operato/styles": "1.0.0-alpha.37",
35
+ "@operato/utils": "1.0.0-alpha.37",
36
+ "@things-factory/auth-base": "^5.0.0-alpha.18",
37
+ "@things-factory/env": "^5.0.0-alpha.18",
38
+ "@things-factory/shell": "^5.0.0-alpha.18",
39
39
  "moment": "^2.29.1"
40
40
  },
41
- "gitHead": "e64e66b147eca1d3219fed7d9764fe2a221a5569"
41
+ "gitHead": "724366d140177b67a583e21d43a4bc6e25ada3e8"
42
42
  }
@@ -0,0 +1,142 @@
1
+ import moment from 'moment'
2
+ import { EntityManager } from 'typeorm'
3
+
4
+ import { User } from '@things-factory/auth-base'
5
+ import { Domain, getRedirectSubdomainPath, pubsub } from '@things-factory/shell'
6
+
7
+ import { DataItem } from '../service/data-item/data-item'
8
+ import { DataOoc, DataOocStatus } from '../service/data-ooc/data-ooc'
9
+ import { DataSample } from '../service/data-sample/data-sample'
10
+ import { NewDataSample } from '../service/data-sample/data-sample-type'
11
+ import { DataSet } from '../service/data-set/data-set'
12
+ import { DataUseCase } from './data-use-case'
13
+
14
+ const debug = require('debug')('things-factory:dataset:controller/save-data-sample')
15
+
16
+ // parse variable javascript string pattern
17
+ const replaceVariables = (keys, dic) => {
18
+ for (const k in keys) {
19
+ const matches = keys[k].match(/\$\{\w*\}/g)
20
+ matches &&
21
+ matches.forEach(m => {
22
+ keys[k] = keys[k].replace(m, dic[m.slice(2, -1)])
23
+ })
24
+ }
25
+ return keys
26
+ }
27
+
28
+ // It is required UTC date for Partitioning File System like AWS S3 from Athena.
29
+ // ex) %YYYY, %MM, %DD
30
+ const formatDate = (keys, _moment) => {
31
+ for (const k in keys) {
32
+ const matches = keys[k].match(/%\w*/g)
33
+ matches &&
34
+ matches.forEach(m => {
35
+ keys[k] = keys[k].replace(m, _moment.format(m.substr(1)))
36
+ })
37
+ }
38
+ return keys
39
+ }
40
+
41
+ export async function createDataSample(
42
+ dataSample: NewDataSample,
43
+ context: {
44
+ state: {
45
+ domain: Domain
46
+ user: User
47
+ tx: EntityManager
48
+ }
49
+ }
50
+ ): Promise<DataSample> {
51
+ const { domain, user, tx } = context.state
52
+
53
+ const dataSet = await tx.getRepository(DataSet).findOne({
54
+ where: { id: dataSample.dataSet.id }
55
+ })
56
+
57
+ const dataItems = await tx.getRepository(DataItem).find({
58
+ where: {
59
+ domain,
60
+ dataSet
61
+ },
62
+ order: {
63
+ sequence: 'DESC'
64
+ }
65
+ })
66
+
67
+ const spec = dataItems.reduce((spec, dataItem) => {
68
+ spec[dataItem.tag] = {
69
+ ...dataItem.spec,
70
+ name: dataItem.name /* do we need ? */
71
+ }
72
+
73
+ return spec
74
+ }, {})
75
+
76
+ var partitionKeys = {
77
+ ...dataSet.partitionKeys
78
+ }
79
+
80
+ const collectedAt = dataSample.collectedAt || new Date()
81
+ partitionKeys = formatDate(partitionKeys, moment(collectedAt).utc())
82
+ partitionKeys = replaceVariables(partitionKeys, {
83
+ domain: domain.subdomain,
84
+ dataSetId: dataSample.dataSet.id,
85
+ ...dataSample.data
86
+ })
87
+
88
+ const { ooc, oos } = DataUseCase.evaluate(dataSet, dataItems, dataSample.data) || {}
89
+
90
+ const result = await tx.getRepository(DataSample).save({
91
+ name: dataSet.name,
92
+ description: dataSet.description,
93
+ ...dataSample,
94
+ domain,
95
+ partitionKeys,
96
+ spec,
97
+ ooc,
98
+ oos,
99
+ collectedAt,
100
+ creator: user,
101
+ updater: user
102
+ })
103
+
104
+ if (ooc || oos) {
105
+ const dataOoc = await tx.getRepository(DataOoc).save({
106
+ name: dataSet.name,
107
+ description: dataSet.description,
108
+ dataSet,
109
+ dataSample: result,
110
+ data: dataSample.data,
111
+ domain,
112
+ partitionKeys,
113
+ spec,
114
+ ooc,
115
+ oos,
116
+ state: DataOocStatus.CREATED,
117
+ collectedAt,
118
+ creator: user,
119
+ updater: user
120
+ })
121
+
122
+ debug('dataOoc is about to publish...', dataOoc)
123
+
124
+ pubsub.publish('data-ooc', {
125
+ dataOoc,
126
+ supervisoryRoleId: dataSet.supervisoryRoleId
127
+ })
128
+
129
+ pubsub.publish('notification', {
130
+ notification: {
131
+ domain,
132
+ type: 'error',
133
+ title: `Data OOC occurred on '${dataSet.name}'`,
134
+ body: `Data OOC occurred on '${dataSet.name}'`,
135
+ url: getRedirectSubdomainPath(context, domain.subdomain, `/data-ooc/${dataOoc.id}`),
136
+ timestamp: collectedAt
137
+ }
138
+ })
139
+ }
140
+
141
+ return result
142
+ }
@@ -43,12 +43,12 @@ export abstract class DataUseCase {
43
43
 
44
44
  for (let i = 0; i < dataItems.length; i++) {
45
45
  const dataItem = dataItems[i]
46
- const { name, active } = dataItem
47
- if (!active) {
46
+ const { active, tag } = dataItem
47
+ if (!active || !tag) {
48
48
  continue
49
49
  }
50
50
 
51
- let values: any | any[] = data[name]
51
+ let values: any | any[] = data[tag]
52
52
  if (typeof values === 'undefined') {
53
53
  continue // TODO what if in case no value ?
54
54
  }
package/server/routes.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { getConnection } from 'typeorm'
1
+ import { getConnection, getRepository } from 'typeorm'
2
2
 
3
- import { DataSample } from './service'
4
- import { DataItem } from './service/data-item/data-item'
3
+ import { User } from '@things-factory/auth-base'
4
+
5
+ import { createDataSample } from './controllers/create-data-sample'
5
6
  import { DataSensor } from './service/data-sensor/data-sensor'
6
7
 
7
8
  const debug = require('debug')('things-factory:dataset:routes')
@@ -47,41 +48,26 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
47
48
 
48
49
  const domain = sensor.domain
49
50
  const dataSet = sensor.dataSet
50
- const user = sensor.appliance
51
-
52
- const dataItems = await tx.getRepository(DataItem).find({
51
+ const user: User = await getRepository(User).findOne({
53
52
  where: {
54
- domain,
55
- dataSet
56
- },
57
- order: {
58
- sequence: 'DESC'
53
+ reference: sensor.appliance.id,
54
+ userType: 'appliance'
59
55
  }
60
56
  })
61
57
 
62
- var spec = {} as any
63
-
64
- dataItems.forEach(dataItem => {
65
- spec[dataItem.name] = dataItem.spec
66
- })
67
-
68
- await tx.getRepository(DataSample).save({
69
- domain,
70
- name: dataSet.name,
71
- description: dataSet.description,
72
- partitionKeys: dataSet.partitionKeys,
73
- dataSet,
74
- data,
75
- rawData,
76
- spec,
77
- source: deviceId,
78
- collectedAt: new Date(timestamp),
79
- creator: user,
80
- updater: user
81
- })
58
+ return await createDataSample(
59
+ {
60
+ dataSet,
61
+ data,
62
+ rawData,
63
+ source: deviceId,
64
+ collectedAt: new Date(timestamp)
65
+ },
66
+ { state: { domain, user, tx } }
67
+ )
82
68
  })
83
69
 
84
- return 'OK'
70
+ context.status = 200
85
71
  })
86
72
  })
87
73
 
@@ -1,7 +1,11 @@
1
- import { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive } from 'type-graphql'
1
+ import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'
2
2
  import { getRepository } from 'typeorm'
3
- import { Domain, ListParam, convertListParams } from '@things-factory/shell'
3
+
4
4
  import { User } from '@things-factory/auth-base'
5
+ import { convertListParams, Domain, ListParam } from '@things-factory/shell'
6
+
7
+ import { DataSample } from '../data-sample/data-sample'
8
+ import { DataSet } from '../data-set/data-set'
5
9
  import { DataOoc } from './data-ooc'
6
10
  import { DataOocList } from './data-ooc-type'
7
11
 
@@ -28,6 +32,20 @@ export class DataOocQuery {
28
32
  return { items, total }
29
33
  }
30
34
 
35
+ @FieldResolver(type => DataSet)
36
+ async dataSet(@Root() dataOoc: DataOoc): Promise<DataSet> {
37
+ return await getRepository(DataSet).findOne({
38
+ id: dataOoc.dataSetId
39
+ })
40
+ }
41
+
42
+ @FieldResolver(type => DataSample)
43
+ async dataSample(@Root() dataOoc: DataOoc): Promise<DataSample> {
44
+ return await getRepository(DataSample).findOne({
45
+ id: dataOoc.dataSampleId
46
+ })
47
+ }
48
+
31
49
  @FieldResolver(type => Domain)
32
50
  async domain(@Root() dataOoc: DataOoc): Promise<Domain> {
33
51
  return await getRepository(Domain).findOne(dataOoc.domainId)
@@ -0,0 +1,51 @@
1
+ import { Resolver, Subscription, Root } from 'type-graphql'
2
+ import { withFilter } from 'graphql-subscriptions'
3
+ import { pubsub } from '@things-factory/shell'
4
+ import { User } from '@things-factory/auth-base'
5
+ import { DataOoc } from './data-ooc'
6
+ import { getRepository } from 'typeorm'
7
+
8
+ const debug = require('debug')('things-factory:dataset:data-ooc-subscription')
9
+
10
+ @Resolver(DataOoc)
11
+ export class DataOocSubscription {
12
+ @Subscription({
13
+ subscribe: (_, args, context, info) => {
14
+ const { domain, user } = context.state
15
+ const subdomain = domain?.subdomain
16
+
17
+ debug('subscribe', subdomain)
18
+
19
+ if (!domain) {
20
+ throw new Error('domain required')
21
+ }
22
+
23
+ if (!user.domains?.find(d => d.subdomain === subdomain)) {
24
+ throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)
25
+ }
26
+
27
+ return withFilter(
28
+ () => pubsub.asyncIterator('data-ooc'),
29
+ async (payload, variables, context, info) => {
30
+ const { dataOoc, supervisoryRoleId } = payload
31
+ const { domain } = dataOoc
32
+
33
+ if (subdomain !== domain?.subdomain) {
34
+ return false
35
+ }
36
+
37
+ // check if the user has that role
38
+ const userWithRoles: User = await getRepository(User).findOne({
39
+ where: { id: user.id },
40
+ relations: ['roles']
41
+ })
42
+
43
+ return userWithRoles.roles.find(role => role.id === supervisoryRoleId)
44
+ }
45
+ )(_, args, context, info)
46
+ }
47
+ })
48
+ dataOoc(@Root() payload: { dataOoc: DataOoc; supervisoryRoleId: string }): DataOoc {
49
+ return payload.dataOoc
50
+ }
51
+ }
@@ -1,6 +1,7 @@
1
1
  import { DataOoc } from './data-ooc'
2
2
  import { DataOocMutation } from './data-ooc-mutation'
3
3
  import { DataOocQuery } from './data-ooc-query'
4
+ import { DataOocSubscription } from './data-ooc-subscription'
4
5
 
5
6
  export const entities = [DataOoc]
6
- export const resolvers = [DataOocQuery, DataOocMutation]
7
+ export const resolvers = [DataOocQuery, DataOocMutation, DataOocSubscription]
@@ -1,121 +1,18 @@
1
1
  import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
2
2
 
3
- import { DataItem } from '../data-item/data-item'
4
- import { DataSet } from '../data-set/data-set'
5
3
  import { DataSample } from './data-sample'
6
4
  import { NewDataSample } from './data-sample-type'
7
5
 
8
- import moment from 'moment'
9
- import { DataUseCase } from '../../controllers'
10
- import { DataOoc, DataOocStatus } from '../data-ooc/data-ooc'
6
+ import { createDataSample } from '../../controllers/create-data-sample'
11
7
 
12
8
  const debug = require('debug')('things-factory:dataset:data-sample:data-sample-mutation')
13
9
 
14
- // parse variable javascript string pattern
15
- const replaceVariables = (keys, dic) => {
16
- for (const k in keys) {
17
- const matches = keys[k].match(/\$\{\w*\}/g)
18
- matches &&
19
- matches.forEach(m => {
20
- keys[k] = keys[k].replace(m, dic[m.slice(2, -1)])
21
- })
22
- }
23
- return keys
24
- }
25
-
26
- // It is required UTC date for Partitioning File System like AWS S3 from Athena.
27
- // ex) %YYYY, %MM, %DD
28
- const formatDate = (keys, _moment) => {
29
- for (const k in keys) {
30
- const matches = keys[k].match(/%\w*/g)
31
- matches &&
32
- matches.forEach(m => {
33
- keys[k] = keys[k].replace(m, _moment.format(m.substr(1)))
34
- })
35
- }
36
- return keys
37
- }
38
-
39
10
  @Resolver(DataSample)
40
11
  export class DataSampleMutation {
41
12
  @Directive('@privilege(category: "data-sample", privilege: "mutation", domainOwnerGranted: true)')
42
13
  @Directive('@transaction')
43
14
  @Mutation(returns => DataSample, { description: 'To create new data sample' })
44
15
  async createDataSample(@Arg('dataSample') dataSample: NewDataSample, @Ctx() context: any): Promise<DataSample> {
45
- const { domain, user, tx } = context.state
46
-
47
- const dataSet = await tx.getRepository(DataSet).findOne({
48
- where: { id: dataSample.dataSet.id }
49
- })
50
- const dataItems = await tx.getRepository(DataItem).find({
51
- where: {
52
- domain,
53
- dataSet
54
- },
55
- order: {
56
- sequence: 'DESC'
57
- }
58
- })
59
-
60
- const spec = dataItems.reduce((spec, dataItem) => {
61
- spec[dataItem.tag] = {
62
- ...dataItem.spec,
63
- name: dataItem.name /* do we need ? */
64
- }
65
-
66
- return spec
67
- }, {})
68
-
69
- // appending spec to data for reporting and optimizing AWS Athena search
70
- dataSample.data = { ...dataSample.data, _spec: JSON.stringify(spec) }
71
-
72
- var partitionKeys = {
73
- ...dataSet.partitionKeys
74
- }
75
-
76
- const collectedAt = dataSample.collectedAt || new Date()
77
- partitionKeys = formatDate(partitionKeys, moment(collectedAt).utc())
78
- partitionKeys = replaceVariables(partitionKeys, {
79
- domain: domain.subdomain,
80
- dataSetId: dataSample.dataSet.id,
81
- ...dataSample.data
82
- })
83
-
84
- const { ooc, oos } = DataUseCase.evaluate(dataSet, dataItems, dataSample.data) || {}
85
-
86
- const result = await tx.getRepository(DataSample).save({
87
- name: dataSet.name,
88
- description: dataSet.description,
89
- ...dataSample,
90
- domain,
91
- partitionKeys,
92
- spec,
93
- ooc,
94
- oos,
95
- collectedAt,
96
- creator: user,
97
- updater: user
98
- })
99
-
100
- if (ooc || oos) {
101
- await tx.getRepository(DataOoc).save({
102
- name: dataSet.name,
103
- description: dataSet.description,
104
- dataSet,
105
- dataSample: result,
106
- data: dataSample.data,
107
- domain,
108
- partitionKeys,
109
- spec,
110
- ooc,
111
- oos,
112
- state: DataOocStatus.CREATED,
113
- collectedAt,
114
- creator: user,
115
- updater: user
116
- })
117
- }
118
-
119
- return result
16
+ return await createDataSample(dataSample, context)
120
17
  }
121
18
  }
@@ -1,3 +1,4 @@
1
+ import { Field, ID, ObjectType } from 'type-graphql'
1
2
  import {
2
3
  Column,
3
4
  CreateDateColumn,
@@ -8,12 +9,12 @@ import {
8
9
  RelationId,
9
10
  UpdateDateColumn
10
11
  } from 'typeorm'
11
- import { Domain, ScalarObject } from '@things-factory/shell'
12
- import { Field, ID, ObjectType } from 'type-graphql'
13
12
 
14
- import { DataSet } from '../data-set/data-set'
15
13
  import { User } from '@things-factory/auth-base'
16
14
  import { config } from '@things-factory/env'
15
+ import { Domain, ScalarObject } from '@things-factory/shell'
16
+
17
+ import { DataSet } from '../data-set/data-set'
17
18
 
18
19
  const ORMCONFIG = config.get('ormconfig', {})
19
20
  const DATABASE_TYPE = ORMCONFIG.type
@@ -1,7 +1,7 @@
1
1
  import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'
2
2
  import { getRepository } from 'typeorm'
3
3
 
4
- import { User } from '@things-factory/auth-base'
4
+ import { Role, User } from '@things-factory/auth-base'
5
5
  import { convertListParams, Domain, ListParam } from '@things-factory/shell'
6
6
 
7
7
  import { DataItem } from '../data-item/data-item'
@@ -38,6 +38,13 @@ export class DataSetQuery {
38
38
  })
39
39
  }
40
40
 
41
+ @FieldResolver(type => Role)
42
+ async supervisoryRole(@Root() dataSet: DataSet): Promise<Role> {
43
+ return await getRepository(Role).findOne({
44
+ id: dataSet.supervisoryRoleId
45
+ })
46
+ }
47
+
41
48
  @FieldResolver(type => Domain)
42
49
  async domain(@Root() dataSet: DataSet): Promise<Domain> {
43
50
  return await getRepository(Domain).findOne(dataSet.domainId)
@@ -1,3 +1,4 @@
1
+ import { Field, ID, ObjectType } from 'type-graphql'
1
2
  import {
2
3
  Column,
3
4
  CreateDateColumn,
@@ -9,9 +10,9 @@ import {
9
10
  RelationId,
10
11
  UpdateDateColumn
11
12
  } from 'typeorm'
12
- import { Domain, ScalarObject } from '@things-factory/shell'
13
- import { Field, ID, ObjectType } from 'type-graphql'
13
+
14
14
  import { Role, User } from '@things-factory/auth-base'
15
+ import { Domain, ScalarObject } from '@things-factory/shell'
15
16
 
16
17
  import { DataItem } from '../data-item/data-item'
17
18
 
@@ -49,7 +50,7 @@ export class DataSet {
49
50
  @ManyToOne(type => Role, {
50
51
  nullable: true
51
52
  })
52
- @Field({ nullable: true })
53
+ @Field(type => Role, { nullable: true })
53
54
  supervisoryRole?: Role
54
55
 
55
56
  @RelationId((dataSet: DataSet) => dataSet.supervisoryRole)
@@ -26,7 +26,8 @@
26
26
  "text.data sample created successfully": "a data sample created successfully",
27
27
  "title.data-entry-form": "data entry form",
28
28
  "title.data-item list": "data item list",
29
+ "title.data-ooc list": "data OOC list",
29
30
  "title.data-sample list": "data sample list",
30
31
  "title.data-sensor list": "data sensor list",
31
32
  "title.data-set list": "data set list"
32
- }
33
+ }
@@ -26,7 +26,8 @@
26
26
  "text.data sample created successfully": "데이타 샘플이 성공적으로 생성되었습니다",
27
27
  "title.data-entry-form": "데이타 입력",
28
28
  "title.data-item list": "데이타 아이템 조회",
29
+ "title.data-ooc list": "데이타 이탈점 조회",
29
30
  "title.data-sample list": "데이타 샘플 조회",
30
31
  "title.data-sensor list": "데이타 센서 조회",
31
32
  "title.data-set list": "데이타 셋 조회"
32
- }
33
+ }
@@ -18,7 +18,7 @@
18
18
  "field.ref-by": "ref. by",
19
19
  "field.serial-no": "serial #",
20
20
  "field.spec": "spec",
21
- "field.state": "state",
21
+ "field.state": "keadaan",
22
22
  "field.supervisory-role": "supervisory role",
23
23
  "field.tag": "tag name",
24
24
  "field.unit": "unit",
@@ -26,6 +26,7 @@
26
26
  "text.data sample created successfully": "a data sample created successfully",
27
27
  "title.data-entry-form": "data entry form",
28
28
  "title.data-item list": "data item list",
29
+ "title.data-ooc list": "data OOC list",
29
30
  "title.data-sample list": "data sample list",
30
31
  "title.data-sensor list": "data sensor list",
31
32
  "title.data-set list": "data set list"
@@ -18,7 +18,7 @@
18
18
  "field.ref-by": "ref. by",
19
19
  "field.serial-no": "serial #",
20
20
  "field.spec": "spec",
21
- "field.state": "state",
21
+ "field.state": "状态",
22
22
  "field.supervisory-role": "supervisory role",
23
23
  "field.tag": "tag name",
24
24
  "field.unit": "unit",
@@ -26,6 +26,7 @@
26
26
  "text.data sample created successfully": "a data sample created successfully",
27
27
  "title.data-entry-form": "data entry form",
28
28
  "title.data-item list": "data item list",
29
+ "title.data-ooc list": "data OOC list",
29
30
  "title.data-sample list": "data sample list",
30
31
  "title.data-sensor list": "data sensor list",
31
32
  "title.data-set list": "data set list"