@things-factory/shell 4.0.37 → 4.0.41

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.
@@ -1 +1 @@
1
- {"version":3,"file":"list-query-builder.js","sourceRoot":"","sources":["../../server/utils/list-query-builder.ts"],"names":[],"mappings":";;;AAAA,2DAAoD;AAE7C,MAAM,UAAU,GAAG,UAAU,YAAiB,EAAE,MAAW,EAAE,OAAY,EAAE,YAAqB,IAAI;IACzG,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;IAC9B,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAA;IACpC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAA;IAChC,MAAM,QAAQ,GAAG,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAA;IAE3E,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;QACjC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;YACvB,MAAM,SAAS,GAAG,IAAA,kCAAc,EAC9B,YAAY,CAAC,KAAK,EAClB,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,KAAK,EACZ,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC,CAAC,MAAM,CACjD,CAAA;YAED,IAAI,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,MAAM;gBAAE,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;YAC9D,IAAI,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,UAAU;gBAAE,YAAY,CAAC,aAAa,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;QAC7E,CAAC,CAAC,CAAA;KACH;IAED,IAAI,SAAS,EAAE;QACb,YAAY,CAAC,QAAQ,CAAC,GAAG,YAAY,CAAC,KAAK,qBAAqB,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAA;KAChF;IAED,IAAI,UAAU,IAAI,UAAU,CAAC,IAAI,GAAG,CAAC,IAAI,UAAU,CAAC,KAAK,GAAG,CAAC,EAAE;QAC7D,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAA;QAC3D,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;KACpC;IAED,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;QACnC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;YAClC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,EAAE,CAAA;YAC7G,IAAI,KAAK,KAAK,CAAC,EAAE;gBACf,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;aAC/D;iBAAM;gBACL,YAAY,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;aAClE;QACH,CAAC,CAAC,CAAA;KACH;AACH,CAAC,CAAA;AAzCY,QAAA,UAAU,cAyCtB"}
1
+ {"version":3,"file":"list-query-builder.js","sourceRoot":"","sources":["../../server/utils/list-query-builder.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/shell",
3
- "version": "4.0.37",
3
+ "version": "4.0.41",
4
4
  "description": "Core module for framework",
5
5
  "bin": {
6
6
  "things-factory": "bin/things-factory",
@@ -36,7 +36,7 @@
36
36
  "@graphql-tools/schema": "^8.2.0",
37
37
  "@graphql-tools/utils": "^8.3.0",
38
38
  "@hatiolab/koa-webpack": "^6.0.0",
39
- "@hatiolab/things-scene": "^2.7.31",
39
+ "@hatiolab/things-scene": "^2.7.33",
40
40
  "@koa/cors": "^3.1.0",
41
41
  "@material/mwc-button": "^0.25.3",
42
42
  "@material/mwc-fab": "^0.25.3",
@@ -44,13 +44,14 @@
44
44
  "@material/mwc-icon-button": "^0.25.3",
45
45
  "@material/mwc-slider": "^0.25.3",
46
46
  "@material/mwc-textfield": "^0.25.3",
47
- "@operato/board": "^0.3.17",
48
- "@operato/graphql": "^0.3.17",
49
- "@operato/utils": "^0.3.17",
50
- "@things-factory/ejs-remote": "^4.0.37",
51
- "@things-factory/env": "^4.0.37",
52
- "@things-factory/styles": "^4.0.37",
53
- "@things-factory/utils": "^4.0.37",
47
+ "@operato/board": "^0.3.21",
48
+ "@operato/graphql": "^0.3.21",
49
+ "@operato/shell": "^0.3.21",
50
+ "@operato/utils": "^0.3.21",
51
+ "@things-factory/ejs-remote": "^4.0.41",
52
+ "@things-factory/env": "^4.0.41",
53
+ "@things-factory/styles": "^4.0.41",
54
+ "@things-factory/utils": "^4.0.41",
54
55
  "@webcomponents/webcomponentsjs": "^2.6.0",
55
56
  "@webpack-contrib/schema-utils": "^1.0.0-beta.0",
56
57
  "apollo-server-core": "^3.5.0",
@@ -68,6 +69,7 @@
68
69
  "fs-extra": "^9.0.1",
69
70
  "glob": "^7.1.6",
70
71
  "graphql": "^15.7.2",
72
+ "graphql-kafka-subscriptions": "^0.4.0",
71
73
  "graphql-mqtt-subscriptions": "^1.2.0",
72
74
  "graphql-redis-subscriptions": "^2.4.2",
73
75
  "graphql-subscriptions": "^2.0.0",
@@ -93,7 +95,7 @@
93
95
  "loader-utils": "^2.0.0",
94
96
  "lodash": "^4.17.15",
95
97
  "mkdirp": "^1.0.3",
96
- "mqtt": "^4.2.6",
98
+ "mqtt": "^4.3.4",
97
99
  "node-fetch": "^2.6.0",
98
100
  "node-sass": "^6.0.1",
99
101
  "nodemon": "^2.0.2",
@@ -124,5 +126,5 @@
124
126
  "resolutions": {
125
127
  "core-js": "^3.16.0"
126
128
  },
127
- "gitHead": "7abd5ee06f7329c7fbb0c305f7b075a990bc2c18"
129
+ "gitHead": "1dd445b5b5e5b9e37291dc274886131199d7bf6a"
128
130
  }
package/server/pubsub.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { KafkaPubSub } from 'graphql-kafka-subscriptions'
1
2
  import { MQTTPubSub } from 'graphql-mqtt-subscriptions'
2
3
  import { RedisPubSub } from 'graphql-redis-subscriptions'
3
4
  import { PubSub } from 'graphql-subscriptions'
@@ -6,7 +7,7 @@ import { connect } from 'mqtt'
6
7
 
7
8
  import { config } from '@things-factory/env'
8
9
 
9
- const { middleware, host, port, nodes, options } = config.get('pubsub', {})
10
+ const { middleware, host, port, nodes, topic, options } = config.get('pubsub', {})
10
11
 
11
12
  const debug = require('debug')('things-factory:shell')
12
13
 
@@ -43,9 +44,50 @@ switch (middleware) {
43
44
  subscriber: cluster
44
45
  })
45
46
  break
47
+ case 'kafka':
48
+ // globalConfig: {} // options passed directly to the consumer and producer
49
+ pubsub = new KafkaPubSub({
50
+ topic,
51
+ host,
52
+ port,
53
+ ...options
54
+ })
55
+ break
46
56
  default:
47
57
  pubsub = new PubSub()
48
58
  break
49
59
  }
50
60
 
61
+ debug(middleware || 'default', 'pubsub initialized.')
62
+
63
+ // kafka pubsub keeps connection and app port with 'ctrl+c' termination.
64
+ const exitHandler = async (evt) => {
65
+ if (pubsub.close) {
66
+ try {
67
+ await pubsub.close()
68
+ } catch (err) {
69
+ console.error(err)
70
+ }
71
+ }
72
+ debug('exit on', evt.name)
73
+ if (evt.exit) process.exit()
74
+ }
75
+
76
+ /*
77
+ * exit events hint from https://stackoverflow.com/a/14032965/14539284
78
+ */
79
+
80
+ //do something when app is closing
81
+ process.on('exit', exitHandler.bind(null, { name: 'exit', exit: true } ))
82
+
83
+ //catches ctrl+c event
84
+ process.on('SIGINT', exitHandler.bind(null, { name: 'SIGINT', exit: true } ))
85
+
86
+ // catches "kill pid" (for example: nodemon restart)
87
+ process.on('SIGUSR1', exitHandler.bind(null, { name: 'SIGUSR1', exit: true } ))
88
+ process.on('SIGUSR2', exitHandler.bind(null, { name: 'SIGUSR2', exit: true } ))
89
+
90
+ //catches uncaught exceptions
91
+ process.on('uncaughtException', exitHandler.bind(null, { name: 'uncaughtException', exit: true } ))
92
+
51
93
  export { pubsub }
@@ -24,6 +24,7 @@ import koaBodyParser from 'koa-bodyparser'
24
24
  import koaStatic from 'koa-static'
25
25
  import koaWebpack from '@hatiolab/koa-webpack'
26
26
  import { schema } from './schema'
27
+ import bytesFormat from 'bytes'
27
28
 
28
29
  const debug = require('debug')('things-factory:shell:server-dev')
29
30
 
@@ -47,12 +48,21 @@ const compiler = webpack(webpackConfig)
47
48
 
48
49
  const PORT = (process.env.PORT = flags.port)
49
50
 
51
+ const requestBody = config.get('requestBody')||{}
52
+
50
53
  const bodyParserOption = {
51
- formLimit: '10mb',
52
- jsonLimit: '10mb',
53
- textLimit: '10mb'
54
+ formLimit: requestBody.formLimit||'10mb',
55
+ jsonLimit: requestBody.jsonLimit||'10mb',
56
+ textLimit: requestBody.textLimit||'10mb'
57
+ }
58
+
59
+ const fileUpload = config.get('fileUpload')||{}
60
+ const fileUploadOption = {
61
+ maxFileSize: bytesFormat.parse(fileUpload.maxFileSize)||bytesFormat.parse('10mb'),
62
+ maxFiles: fileUpload.maxFiles||10
54
63
  }
55
64
 
65
+
56
66
  /* bootstrap */
57
67
  const bootstrap = async () => {
58
68
  await databaseInitializer()
@@ -199,7 +209,7 @@ const bootstrap = async () => {
199
209
  })
200
210
 
201
211
  app.use(koaBodyParser(bodyParserOption))
202
- app.use(graphqlUploadKoa({ maxFileSize: 10000000, maxFiles: 10 }))
212
+ app.use(graphqlUploadKoa(fileUploadOption))
203
213
 
204
214
  app.use(
205
215
  server.getMiddleware({
package/server/server.ts CHANGED
@@ -20,6 +20,7 @@ import ip from 'koa-ip'
20
20
  import koaBodyParser from 'koa-bodyparser'
21
21
  import koaStatic from 'koa-static'
22
22
  import { schema } from './schema'
23
+ import bytesFormat from 'bytes'
23
24
 
24
25
  const args = require('args')
25
26
 
@@ -31,12 +32,19 @@ const path = require('path')
31
32
 
32
33
  const PORT = (process.env.PORT = flags.port)
33
34
 
35
+ const requestBody = config.get('requestBody')||{}
36
+
34
37
  const bodyParserOption = {
35
- formLimit: '10mb',
36
- jsonLimit: '10mb',
37
- textLimit: '10mb'
38
+ formLimit: requestBody.formLimit||'10mb',
39
+ jsonLimit: requestBody.jsonLimit||'10mb',
40
+ textLimit: requestBody.textLimit||'10mb'
38
41
  }
39
42
 
43
+ const fileUpload = config.get('fileUpload')||{}
44
+ const fileUploadOption = {
45
+ maxFileSize: bytesFormat.parse(fileUpload.maxFileSize)||bytesFormat.parse('10mb'),
46
+ maxFiles: fileUpload.maxFiles||10
47
+ }
40
48
  /* bootstrap */
41
49
  const bootstrap = async () => {
42
50
  await databaseInitializer()
@@ -165,7 +173,7 @@ const bootstrap = async () => {
165
173
  })
166
174
 
167
175
  app.use(koaBodyParser(bodyParserOption))
168
- app.use(graphqlUploadKoa({ maxFileSize: 10000000, maxFiles: 10 }))
176
+ app.use(graphqlUploadKoa(fileUploadOption))
169
177
 
170
178
  app.use(
171
179
  server.getMiddleware({
@@ -25,6 +25,7 @@ export const buildCondition = function (
25
25
  parameters: { [`args${seq}`]: `${value}` }
26
26
  }
27
27
 
28
+ case 'search':
28
29
  case 'i_like':
29
30
  return {
30
31
  clause: `LOWER(${alias}.${fieldName}) LIKE :args${seq}`,
@@ -1,13 +1,15 @@
1
- import { Equal, Not, Like, Raw, In, IsNull, Between } from 'typeorm'
1
+ import { Between, Equal, ILike, In, IsNull, Like, Not, Raw } from 'typeorm'
2
+
2
3
  import { ListParam } from '../service/common-types'
3
4
 
4
5
  const OPERATION_FUNCTION_MAP = {
6
+ search: value => ILike(value),
5
7
  eq: value => Equal(value),
6
8
  noteq: value => Not(Equal(value)),
7
9
  like: value => Like(value),
8
- i_like: value => Raw(alias => `LOWER(${alias}) LIKE '${String(value).toLowerCase()}'`),
10
+ i_like: value => ILike(value),
9
11
  nlike: value => Not(Like(value)),
10
- i_nlike: value => Raw(alias => `LOWER(${alias}) NOT LIKE '${String(value).toLowerCase()}'`),
12
+ i_nlike: value => Not(ILike(value)),
11
13
  lt: value => Raw(alias => `${alias} < ${typeof value === 'string' ? "'" + value + "'" : value}`),
12
14
  gt: value => Raw(alias => `${alias} > ${typeof value === 'string' ? "'" + value + "'" : value}`),
13
15
  lte: value => Raw(alias => `${alias} <= ${typeof value === 'string' ? "'" + value + "'" : value}`),
@@ -25,51 +27,6 @@ const OPERATION_FUNCTION_MAP = {
25
27
  between: value => Between(value[0], value[1])
26
28
  }
27
29
 
28
- // function getOperatorFunction({ operator, name, value, dataType }) {
29
- // switch (operator) {
30
- // case 'eq':
31
- // return Equal(value)
32
- // case 'noteq':
33
- // return Not(Equal(value))
34
- // case 'like':
35
- // return Like(value)
36
- // case 'nlike':
37
- // return Not(Like(value))
38
- // case 'lt':
39
- // return Raw(alias => `${alias} < ${value}`)
40
- // case 'gt':
41
- // return Raw(alias => `${alias} > ${value}`)
42
- // case 'lte':
43
- // return Raw(alias => `${alias} <= ${value}`)
44
- // case 'gte':
45
- // return Raw(alias => `${alias} >= ${value}`)
46
- // case 'in':
47
- // return In(value)
48
- // case 'notin':
49
- // return Not(In(value))
50
- // case 'is_null':
51
- // return IsNull()
52
- // case 'is_not_null':
53
- // return Not(IsNull())
54
- // case 'is_false':
55
- // return Raw(alias => `${alias} IS FALSE`)
56
- // case 'is_true':
57
- // return Raw(alias => `${alias} IS TRUE`)
58
- // case 'is_not_false':
59
- // return Raw(alias => `${alias} IS NOT FALSE`)
60
- // case 'is_not_true':
61
- // return Raw(alias => `${alias} IS NOT TRUE`)
62
- // case 'is_present':
63
- // return Raw(alias => `${alias} IS PRESENT`)
64
- // case 'is_blank':
65
- // return Raw(alias => `${alias} IS BLANK`)
66
- // case 'is_empty_num_id':
67
- // return Raw(alias => `${alias} IS EMPTY NUMERIC ID`)
68
- // case 'between':
69
- // return Between(value[0], value[1])
70
- // }
71
- // }
72
-
73
30
  function getOperatorFunction({ operator, name, value, dataType }) {
74
31
  return OPERATION_FUNCTION_MAP[operator](value)
75
32
  }
@@ -111,17 +68,31 @@ function makeSortingParams(sortings) {
111
68
  }
112
69
 
113
70
  function makeFilterParams(filters) {
114
- var jsonParams = {}
115
- if (filters) {
116
- var where = {}
117
- filters.forEach(f => {
118
- var operationFunc = getOperatorFunction(f)
119
- where[f.name] = operationFunc
120
- })
121
- Object.assign(jsonParams, { where })
71
+ /* for where AND clauses */
72
+ const columnFilters = filters.filter(filter => filter.operator !== 'search')
73
+ const columnWhere = columnFilters.reduce((where, f) => {
74
+ where[f.name] = getOperatorFunction(f)
75
+ return where
76
+ }, {})
77
+
78
+ const searchFilters = filters.filter(filter => filter.operator === 'search')
79
+ if (searchFilters.length === 0) {
80
+ return {
81
+ where: columnWhere
82
+ }
122
83
  }
123
84
 
124
- return jsonParams
85
+ /* for fulltext searching ... OR-AND composition */
86
+ const searchWheres = searchFilters.map(f => {
87
+ return {
88
+ [f.name]: getOperatorFunction(f),
89
+ ...columnWhere
90
+ }
91
+ })
92
+
93
+ return {
94
+ where: searchWheres
95
+ }
125
96
  }
126
97
 
127
98
  export function convertListParams(params: typeof ListParam, domain?: String) {
@@ -1,13 +1,16 @@
1
+ import { Brackets } from 'typeorm'
2
+
1
3
  import { buildCondition } from './condition-builder'
2
4
 
3
5
  export const buildQuery = function (queryBuilder: any, params: any, context: any, domainRef: Boolean = true) {
4
- const filters = params.filters
6
+ const columnFilters = params.filters?.filter(filter => filter.operator !== 'search') || []
7
+ const searchFilters = params.filters?.filter(filter => filter.operator === 'search') || []
5
8
  const pagination = params.pagination
6
9
  const sortings = params.sortings
7
10
  const domainId = context && context.state.domain && context.state.domain.id
8
11
 
9
- if (filters && filters.length > 0) {
10
- filters.forEach(filter => {
12
+ if (columnFilters && columnFilters.length > 0) {
13
+ columnFilters.forEach(filter => {
11
14
  const condition = buildCondition(
12
15
  queryBuilder.alias,
13
16
  filter.name,
@@ -22,6 +25,19 @@ export const buildQuery = function (queryBuilder: any, params: any, context: any
22
25
  })
23
26
  }
24
27
 
28
+ if (searchFilters.length > 0) {
29
+ queryBuilder.andWhere(
30
+ new Brackets(qb => {
31
+ searchFilters.forEach((filter, index) => {
32
+ const clause = `${queryBuilder.alias}.${filter.name} LIKE :${filter.name}`
33
+ const parameters = { [filter.name]: filter.value }
34
+
35
+ index === 0 ? qb.where(clause, parameters) : qb.orWhere(clause, parameters)
36
+ })
37
+ })
38
+ )
39
+ }
40
+
25
41
  if (domainRef) {
26
42
  queryBuilder.andWhere(`${queryBuilder.alias}.domain = :domainId`, { domainId })
27
43
  }
@@ -1,12 +0,0 @@
1
- export const UPDATE_MODULES = 'UPDATE_MODULES'
2
- export const UPDATE_BASE_URL = 'UPDATE_BASE_URL'
3
- export const UPDATE_CONTEXT_PATH = 'UPDATE_CONTEXT_PATH'
4
- export const SET_DOMAINS = 'SET-DOMAINS'
5
-
6
- export const updateDomains = (domains, domain) => (dispatch, getState) => {
7
- dispatch({
8
- type: SET_DOMAINS,
9
- domains,
10
- domain
11
- })
12
- }
@@ -1,2 +0,0 @@
1
- export * from './app'
2
- export * from './route'
@@ -1,101 +0,0 @@
1
- import { store } from '../store'
2
- import { getPathInfo } from '@things-factory/utils'
3
-
4
- export const UPDATE_PAGE = 'UPDATE_PAGE'
5
- export const UPDATE_CONTEXT = 'UPDATE_CONTEXT'
6
- export const UPDATE_ACTIVE_PAGE = 'UPDATE_ACTIVE_PAGE'
7
-
8
- export const REGISTER_NAVIGATION_CALLBACK = 'REGISTER_NAVIGATION_CALLBACK'
9
- export const UNREGISTER_NAVIGATION_CALLBACK = 'UNREGISTER_NAVIGATION_CALLBACK'
10
-
11
- export const HOMEPAGE = ''
12
-
13
- /**
14
- * 페이지를 이동하는 방법으로는 다음 두가지가 있다.
15
- * 1. page link를 사용하는 방법 <a href='page'>goto page</a>
16
- * 이 방법은 route(page)와 동일하다.
17
- * 2. navigate('page')를 사용하는 방법
18
- *
19
- * @param string page
20
- */
21
- export const navigate = (location, replace) => {
22
- if (replace) history.replaceState(history.state, '', location)
23
- else history.pushState({}, '', location)
24
-
25
- window.dispatchEvent(new Event('popstate'))
26
- }
27
-
28
- export const navigateWithSilence = ({ pathname: path, search }) => dispatch => {
29
- const { path: pathname } = getPathInfo(path)
30
-
31
- const reg = /\/([^\/]+)\/*([^\/]*)/
32
- const decodePath = decodeURIComponent(pathname)
33
- const matchReturn = decodePath.match(reg) || []
34
- const page = matchReturn[1] || HOMEPAGE
35
- const id = matchReturn[2]
36
- const searchParams = new URLSearchParams(search)
37
-
38
- var params = {}
39
- searchParams.forEach((value, key) => {
40
- params[key] = value
41
- })
42
-
43
- // Any other info you might want to extract from the path (like page type),
44
- // you can do here
45
- dispatch(loadPage(page, id, params))
46
- }
47
-
48
- const _preLoadPage = page => {
49
- /*
50
- * _preLoadPage 에서는 page를 load하기 전처리를 수행한다.
51
- * 예를 들면, page dynamic import 또는 page re-routing
52
- */
53
- var state = store.getState()
54
-
55
- /* override 기능을 위해서 dependency 관계의 역순으로 route를 실행한다. */
56
- var modules = state.app.modules
57
- if (modules) {
58
- for (let i = modules.length - 1; i >= 0; i--) {
59
- let factoryModule = modules[i]
60
- let _page = factoryModule.route && factoryModule.route(page)
61
- if (_page) {
62
- return _page
63
- }
64
- }
65
- }
66
- }
67
-
68
- export const loadPage = (page, id, params) => dispatch => {
69
- var newPage = _preLoadPage(page)
70
-
71
- if (page !== newPage && (newPage.indexOf('/') == 0)) {
72
- dispatch(
73
- navigateWithSilence({
74
- pathname: newPage,
75
- params
76
- })
77
- )
78
- return
79
- }
80
-
81
- dispatch({
82
- type: UPDATE_PAGE,
83
- page: newPage,
84
- resourceId: id,
85
- params
86
- })
87
- }
88
-
89
- export const route = url => {
90
- /*
91
- * Caution : This function works normally in a desktop environment,
92
- * but it is not guaranteed in a mobile environment, so be sure to check it.
93
- */
94
- const link = document.createElement('a')
95
-
96
- link.setAttribute('href', url)
97
-
98
- document.body.appendChild(link)
99
- link.click()
100
- document.body.removeChild(link)
101
- }
@@ -1,144 +0,0 @@
1
- import { LitElement, html } from 'lit-element'
2
-
3
- import { store } from '../../store'
4
- import { UPDATE_CONTEXT } from '../../actions/route'
5
-
6
- import isEqual from 'lodash/isEqual'
7
-
8
- function diff(after, before) {
9
- var changed = false
10
- var changes = {}
11
-
12
- Object.getOwnPropertyNames(after).forEach(function(key) {
13
- let before_val = before[key]
14
- let after_val = after[key]
15
-
16
- if (!isEqual(before_val, after_val)) {
17
- changes[key] = after_val
18
- changed = true
19
- }
20
- })
21
-
22
- return changed && changes
23
- }
24
-
25
- export class PageView extends LitElement {
26
- // Only render this page if it's actually visible.
27
- shouldUpdate(changes) {
28
- var active = String(this.active) == 'true'
29
- var { active: oldActive = false } = this._oldLifecycleInfo$ || {}
30
-
31
- /*
32
- * page lifecycle
33
- * case 1. page가 새로 activate 되었다.
34
- * case 2. page가 active 상태에서 lifecycle 정보가 바뀌었다.
35
- **/
36
- if (active) {
37
- this.pageUpdate({
38
- active
39
- })
40
- } else if (oldActive) {
41
- this.pageUpdate({
42
- active
43
- })
44
- }
45
-
46
- return active
47
- }
48
-
49
- static get properties() {
50
- return {
51
- active: Boolean,
52
- lifecycle: Object,
53
- contextPath: { attribute: 'context-path' }
54
- }
55
- }
56
-
57
- /* lifecycle */
58
- async pageUpdate(changes = {}, force = false) {
59
- var before = this._oldLifecycleInfo$ || {}
60
-
61
- var after = {
62
- ...before,
63
- ...this.lifecycle,
64
- contextPath: this.contextPath,
65
- ...changes
66
- }
67
-
68
- if (!('initialized' in changes) && after.active && !before.initialized) {
69
- after.initialized = true
70
- }
71
-
72
- if (force) {
73
- after.updated = Date.now()
74
- }
75
-
76
- var changed = diff(after, before)
77
- if (!changed) {
78
- return
79
- }
80
-
81
- this._oldLifecycleInfo$ = after
82
-
83
- /* page의 이미 초기화된 상태에서 contextPath가 바뀐다면, 무조건 page가 리셋되어야 한다. */
84
- if (before.initialized && changed.contextPath) {
85
- await this.pageReset()
86
- return
87
- }
88
-
89
- if (changed.initialized) {
90
- await this.pageInitialized(after)
91
- }
92
-
93
- if ('initialized' in changed) {
94
- if (changed.initialized) {
95
- /*
96
- * 방금 초기화된 경우라면, 엘리먼트들이 만들어지지 않았을 가능성이 있으므로,
97
- * 다음 animationFrame에서 pageUpdated 콜백을 호출한다.
98
- */
99
- requestAnimationFrame(async () => {
100
- await this.pageUpdated(changed, after, before)
101
- /* active page인 경우에는, page Context 갱신도 필요할 것이다. */
102
- after.active && this.updateContext()
103
- })
104
- } else {
105
- await this.pageDisposed(after)
106
- }
107
- } else {
108
- await this.pageUpdated(changed, after, before)
109
- /* active page인 경우에는, page Context 갱신도 필요할 것이다. */
110
- after.active && this.updateContext()
111
- }
112
- }
113
-
114
- async pageReset() {
115
- var { initialized } = this._oldLifecycleInfo$ || {}
116
-
117
- if (initialized) {
118
- await this.pageDispose()
119
- await this.pageUpdate({}, true)
120
- }
121
- }
122
-
123
- async pageDispose() {
124
- await this.pageUpdate({
125
- initialized: false
126
- })
127
- }
128
-
129
- pageInitialized(pageInfo) {}
130
- pageUpdated(changes, after, before) {}
131
- pageDisposed(pageInfo) {}
132
-
133
- /* context */
134
- updateContext(override) {
135
- store.dispatch({
136
- type: UPDATE_CONTEXT,
137
- context: override ? { ...this.context, ...override } : this.context
138
- })
139
- }
140
-
141
- get context() {
142
- return {}
143
- }
144
- }
@@ -1,40 +0,0 @@
1
- import { UPDATE_MODULES, UPDATE_BASE_URL, UPDATE_CONTEXT_PATH, SET_DOMAINS } from '../actions/app.js'
2
- import { getPathInfo } from '@things-factory/utils'
3
-
4
- const INITIAL_STATE = {
5
- baseUrl: location.origin,
6
- contextPath: getPathInfo(location.pathname).contextPath,
7
- domains: []
8
- }
9
-
10
- const app = (state = INITIAL_STATE, action) => {
11
- switch (action.type) {
12
- case UPDATE_MODULES:
13
- return {
14
- ...state,
15
- modules: action.modules
16
- }
17
- case UPDATE_BASE_URL:
18
- return {
19
- ...state,
20
- baseUrl: action.baseUrl
21
- }
22
- case UPDATE_CONTEXT_PATH:
23
- return {
24
- ...state,
25
- contextPath: action.contextPath
26
- }
27
-
28
- case SET_DOMAINS:
29
- return {
30
- ...state,
31
- domains: action.domains,
32
- domain: action.domain
33
- }
34
-
35
- default:
36
- return state
37
- }
38
- }
39
-
40
- export default app