@things-factory/shell 5.0.0-zeta.9 → 5.0.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/shell",
3
- "version": "5.0.0-zeta.9",
3
+ "version": "5.0.0",
4
4
  "description": "Core module for framework",
5
5
  "bin": {
6
6
  "things-factory": "bin/things-factory",
@@ -31,53 +31,57 @@
31
31
  "test": "NODE_ENV=test jest"
32
32
  },
33
33
  "dependencies": {
34
- "@apollo/client": "^3.6.8",
35
- "@graphql-tools/merge": "^8.2.3",
36
- "@graphql-tools/schema": "^8.3.2",
37
- "@graphql-tools/utils": "^8.6.2",
34
+ "@anchan828/typeorm-history": "^1.0.16",
35
+ "@apollo/client": "^3.6.9",
36
+ "@graphql-tools/merge": "^8.3.0",
37
+ "@graphql-tools/schema": "^8.5.0",
38
+ "@graphql-tools/utils": "^8.8.0",
38
39
  "@hatiolab/koa-webpack": "^6.0.0",
39
- "@hatiolab/things-scene": "^3.0.16",
40
- "@koa/cors": "^3.1.0",
41
- "@material/mwc-button": "^0.25.3",
42
- "@material/mwc-fab": "^0.25.3",
43
- "@material/mwc-icon": "^0.25.3",
44
- "@material/mwc-icon-button": "^0.25.3",
45
- "@material/mwc-slider": "^0.25.3",
46
- "@material/mwc-textfield": "^0.25.3",
47
- "@operato/board": "^1.0.0-beta.40",
48
- "@operato/graphql": "^1.0.0-beta.40",
49
- "@operato/help": "^1.0.0-beta.40",
50
- "@operato/layout": "^1.0.0-beta.40",
51
- "@operato/shell": "^1.0.0-beta.40",
52
- "@operato/utils": "^1.0.0-beta.40",
53
- "@things-factory/ejs-remote": "^5.0.0-zeta.9",
54
- "@things-factory/env": "^5.0.0-zeta.9",
55
- "@things-factory/styles": "^5.0.0-zeta.9",
56
- "@things-factory/utils": "^5.0.0-zeta.9",
40
+ "@hatiolab/things-scene": "^3.0.19",
41
+ "@koa/cors": "^3.3.0",
42
+ "@material/mwc-button": "^0.26.1",
43
+ "@material/mwc-fab": "^0.26.1",
44
+ "@material/mwc-icon": "^0.26.1",
45
+ "@material/mwc-icon-button": "^0.26.1",
46
+ "@material/mwc-slider": "^0.26.1",
47
+ "@material/mwc-textfield": "^0.26.1",
48
+ "@operato/board": "^1.0.0",
49
+ "@operato/graphql": "^1.0.0",
50
+ "@operato/help": "^1.0.0",
51
+ "@operato/layout": "^1.0.0",
52
+ "@operato/shell": "^1.0.0",
53
+ "@operato/utils": "^1.0.0",
54
+ "@things-factory/ejs-remote": "^5.0.0",
55
+ "@things-factory/env": "^5.0.0",
56
+ "@things-factory/styles": "^5.0.0",
57
+ "@things-factory/utils": "^5.0.0",
57
58
  "@webcomponents/webcomponentsjs": "^2.6.0",
58
59
  "@webpack-contrib/schema-utils": "^1.0.0-beta.0",
59
- "apollo-server-core": "^3.6.4",
60
- "apollo-server-koa": "^3.6.4",
61
- "apollo-server-types": "^3.5.1",
60
+ "apollo-server-core": "^3.10.0",
61
+ "apollo-server-koa": "^3.10.0",
62
+ "apollo-server-types": "^3.6.2",
62
63
  "apollo-upload-client": "^17.0.0",
63
64
  "args": "^5.0.0",
64
65
  "broadcastchannel-polyfill": "^1.0.1",
65
66
  "chalk": "^4.1.0",
66
67
  "class-validator": "^0.13.2",
67
- "core-js": "^3.16.0",
68
+ "core-js": "^3.23.3",
68
69
  "csvtojson": "^2.0.10",
69
70
  "debug": "^4.1.1",
70
71
  "firebase": "^8.0.1",
71
72
  "fs-extra": "^9.0.1",
72
73
  "glob": "^7.1.6",
73
- "graphql": "^15.7.2",
74
+ "graphql": "^16.5.0",
75
+ "graphql-language-service-interface": "^2.10.2",
76
+ "graphql-language-service-parser": "^1.10.4",
77
+ "graphql-language-service-utils": "^2.7.1",
74
78
  "graphql-mqtt-subscriptions": "^1.2.0",
75
- "graphql-redis-subscriptions": "^2.4.2",
79
+ "graphql-redis-subscriptions": "^2.5.0",
76
80
  "graphql-subscriptions": "^2.0.0",
77
81
  "graphql-tag": "^2.12.6",
78
- "graphql-upload": "^13.0.0",
79
- "graphql-ws": "^5.9.0",
80
- "haunted": "^4.8.2",
82
+ "graphql-upload": "^15.0.2",
83
+ "graphql-ws": "^5.9.1",
84
+ "haunted": "^5.0.0",
81
85
  "html-webpack-plugin": "^5.5.0",
82
86
  "husky": "7.0.1",
83
87
  "imports-loader": "^3.0.0",
@@ -86,21 +90,20 @@
86
90
  "json-stringify-safe": "^5.0.1",
87
91
  "json5": "^2.2.0",
88
92
  "koa": "^2.13.4",
89
- "koa-bodyparser": "^4.2.0",
90
- "koa-ip": "^2.1.0",
93
+ "koa-bodyparser": "^4.3.0",
94
+ "koa-ip": "^2.1.2",
91
95
  "koa-router": "^7.4.0",
92
96
  "koa-send": "^5.0.0",
93
97
  "koa-static": "^5.0.0",
94
- "koa-unless": "^1.0.7",
95
98
  "koa2-connect-history-api-fallback": "^0.1.2",
96
- "lit": "^2.2.1",
99
+ "lit": "^2.2.7",
97
100
  "loader-utils": "^2.0.0",
98
- "lodash": "^4.17.15",
99
- "lodash-es": "^4.17.15",
100
- "mkdirp": "^1.0.3",
101
+ "lodash": "^4.17.21",
102
+ "lodash-es": "^4.17.21",
103
+ "mkdirp": "^1.0.4",
101
104
  "mqtt": "^4.3.4",
102
- "node-fetch": "^2.6.0",
103
- "nodemon": "^2.0.2",
105
+ "node-fetch": "^3.2.6",
106
+ "nodemon": "^2.0.19",
104
107
  "npm-license-crawler": "^0.2.1",
105
108
  "pluralize": "^8.0.0",
106
109
  "promises-all": "^1.0.0",
@@ -111,26 +114,22 @@
111
114
  "reselect": "^4.0.0",
112
115
  "sass": "^1.50.1",
113
116
  "scrollbooster": "^3.0.2",
114
- "subscriptions-transport-ws": "^0.11.0",
115
117
  "sweetalert2": "^10.9.0",
116
- "type-graphql": "^1.2.0-rc.1",
117
- "typeorm": "^0.2.41",
118
+ "type-graphql": "npm:type-graphql-v2-fork@2.0.0-alpha2",
119
+ "typeorm": "^0.2.45",
118
120
  "uuid": "^3.4.0",
119
121
  "web-animations-js": "^2.3.2",
120
- "web-push": "^3.4.5",
122
+ "web-push": "^3.5.0",
121
123
  "webfontloader": "^1.6.28",
122
- "ws": "^8.8.0"
124
+ "ws": "^8.8.1"
123
125
  },
124
126
  "optionalDependencies": {
125
- "better-sqlite3": "^7.1.2",
127
+ "better-sqlite3": "^7.5.3",
126
128
  "mssql": "^8.1.2",
127
129
  "mysql2": "^2.3.3",
128
- "oracledb": "^5.1.0",
129
- "pg": "^8.3.0",
130
- "sqlite3": "^5.0.0"
130
+ "oracledb": "^5.4.0",
131
+ "pg": "^8.7.3",
132
+ "sqlite3": "^5.0.8"
131
133
  },
132
- "resolutions": {
133
- "core-js": "^3.16.0"
134
- },
135
- "gitHead": "af1562aba5cd179a7d10fc252b791e0a78049283"
134
+ "gitHead": "32cb91663e38de9ab1bb7a72af923c3bf8ac187b"
136
135
  }
package/server/schema.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { loader, orderedModuleNames } from '@things-factory/env'
2
-
3
1
  import { GraphQLSchema } from 'graphql'
4
- import { GraphQLUpload } from 'graphql-upload'
2
+ import { GraphQLUpload } from 'graphql-upload/GraphQLUpload.js'
5
3
  import { buildSchema } from 'type-graphql'
6
- import { deepMerge } from '@things-factory/utils'
4
+
7
5
  import { mergeSchemas } from '@graphql-tools/schema'
6
+ import { loader, orderedModuleNames } from '@things-factory/env'
7
+ import { deepMerge } from '@things-factory/utils'
8
8
 
9
9
  export async function schema() {
10
10
  const schemas = orderedModuleNames
@@ -1,24 +1,23 @@
1
- /* following lines should be located in top of the file */
2
- // @prettier-ignore
1
+ // ts-import-sorter: disable
2
+
3
+ /* following 2 lines should be located in top of the file */
3
4
  process.env.NODE_ENV = 'development'
4
5
  process.setMaxListeners(0)
5
6
 
6
- /* following lines should be located in top of the file */
7
- import { ApolloServerPluginLandingPageGraphQLPlayground } from 'apollo-server-core'
7
+ import { ApolloServerPluginDrainHttpServer, ApolloServerPluginLandingPageGraphQLPlayground } from 'apollo-server-core'
8
8
  import { ApolloServer } from 'apollo-server-koa'
9
9
  import bytesFormat from 'bytes'
10
- import co from 'co'
11
- import { execute, subscribe } from 'graphql'
12
- import { graphqlUploadKoa } from 'graphql-upload'
10
+ import graphqlUploadKoa from 'graphql-upload/graphqlUploadKoa.js'
11
+ import { useServer } from 'graphql-ws/lib/use/ws'
13
12
  import { createServer } from 'http'
14
13
  import Koa from 'koa'
15
14
  import koaBodyParser from 'koa-bodyparser'
16
- import compose from 'koa-compose'
17
15
  import ip from 'koa-ip'
18
16
  import koaStatic from 'koa-static'
17
+ import compose from 'koa-compose'
19
18
  import { historyApiFallback } from 'koa2-connect-history-api-fallback'
20
- /** Never move following lines */
21
- import { ConnectionContext, SubscriptionServer } from 'subscriptions-transport-ws'
19
+ import { WebSocketServer } from 'ws'
20
+ import co from 'co'
22
21
 
23
22
  import koaWebpack from '@hatiolab/koa-webpack'
24
23
  import cors from '@koa/cors'
@@ -111,23 +110,29 @@ const bootstrap = async () => {
111
110
  const builtSchema = await schema()
112
111
 
113
112
  const httpServer = createServer(app.callback())
113
+ const websocketServer = new WebSocketServer({
114
+ server: httpServer,
115
+ path: '/graphql'
116
+ })
114
117
 
115
- const subscriptionServer = SubscriptionServer.create(
118
+ // Save the returned server's info so we can shut down this server later
119
+ const serverCleanup = useServer(
116
120
  {
117
121
  schema: builtSchema,
118
- // These are imported from `graphql`.
119
- execute,
120
- subscribe,
121
- async onConnect(connectionParams: Object, webSocket: WebSocket, context: ConnectionContext) {
122
- var { request } = context
122
+ context: async (ctx, msg, args) => {
123
+ return ctx['context']
124
+ },
125
+ onConnect: async ctx => {
126
+ var { extra, connectionParams } = ctx
127
+ var { request } = extra
123
128
 
124
- var url = new URL((connectionParams['headers'] || connectionParams).referer)
129
+ var url = new URL(((connectionParams['headers'] as any) || connectionParams).referer)
125
130
  var accessToken = url.searchParams.get('access_token')
126
131
  connectionParams['headers']['authorization'] = accessToken
127
132
 
128
133
  request.headers = {
129
134
  ...request.headers,
130
- ...(connectionParams['headers'] || connectionParams)
135
+ ...(connectionParams['headers'] || (connectionParams as any))
131
136
  }
132
137
 
133
138
  var koacontext = await app.createContext(request, {} as any)
@@ -139,13 +144,16 @@ const bootstrap = async () => {
139
144
 
140
145
  await fn(koacontext)
141
146
 
142
- return koacontext
147
+ return (ctx['context'] = koacontext)
148
+ },
149
+ onDisconnect(ctx, code, reason) {
150
+ console.log('Disconnected!')
151
+ },
152
+ onError(ctx, msg, errors) {
153
+ console.error(msg, errors)
143
154
  }
144
155
  },
145
- {
146
- server: httpServer,
147
- path: '/subscriptions'
148
- }
156
+ websocketServer
149
157
  )
150
158
 
151
159
  const server = new ApolloServer({
@@ -155,7 +163,6 @@ const bootstrap = async () => {
155
163
  return error
156
164
  },
157
165
  formatResponse: response => {
158
- // logger.info('response %s', JSON.stringify(response, null, 2))
159
166
  return response
160
167
  },
161
168
  context: async ({ connection, ctx }) => {
@@ -171,19 +178,21 @@ const bootstrap = async () => {
171
178
  'request.credentials': 'same-origin'
172
179
  }
173
180
  }),
181
+ ApolloServerPluginDrainHttpServer({ httpServer }),
174
182
  {
175
183
  async serverWillStart() {
176
184
  return {
177
185
  async drainServer() {
178
- subscriptionServer.close()
186
+ await serverCleanup.dispose()
179
187
  }
180
188
  }
181
189
  }
182
190
  }
183
- ]
191
+ ],
192
+ cache: 'bounded'
184
193
  })
185
194
 
186
- server.start()
195
+ await server.start()
187
196
 
188
197
  GraphqlLocalClient.init(builtSchema, app)
189
198
 
@@ -241,7 +250,7 @@ const bootstrap = async () => {
241
250
  .use(domainPrivateRouter.routes())
242
251
  .use(domainPrivateRouter.allowedMethods())
243
252
 
244
- /* should be history-fallback => webpack-middleware => koaStatic */
253
+ /* should follow this order : history-fallback => webpack-middleware => koaStatic */
245
254
  app.use(historyApiFallback({ whiteList: [] }))
246
255
 
247
256
  app.use(middleware)
@@ -254,7 +263,7 @@ const bootstrap = async () => {
254
263
 
255
264
  httpServer.listen({ port: PORT }, () => {
256
265
  logger.info(`🚀 Server ready at http://0.0.0.0:${PORT}${server.graphqlPath}`)
257
- logger.info(`🚀 Subscriptions ready at ws://0.0.0.0:${PORT}${'/subscriptions'}`)
266
+ logger.info(`🚀 Subscriptions ready at ws://0.0.0.0:${PORT}${server.graphqlPath}`)
258
267
 
259
268
  process.emit('bootstrap-module-start' as any, { app, config, builtSchema, httpServer } as any)
260
269
  })
package/server/server.ts CHANGED
@@ -1,20 +1,23 @@
1
- // @prettier-ignore
1
+ // ts-import-sorter: disable
2
+
3
+ /* following 2 lines should be located in top of the file */
2
4
  process.env.NODE_ENV = 'production'
3
5
  process.setMaxListeners(0)
4
6
 
7
+ import { ApolloServerPluginDrainHttpServer, ApolloServerPluginLandingPageGraphQLPlayground } from 'apollo-server-core'
5
8
  import { ApolloServer } from 'apollo-server-koa'
6
9
  import bytesFormat from 'bytes'
7
- import co from 'co'
8
- import { execute, subscribe } from 'graphql'
9
- import { graphqlUploadKoa } from 'graphql-upload'
10
+ import graphqlUploadKoa from 'graphql-upload/graphqlUploadKoa.js'
11
+ import { useServer } from 'graphql-ws/lib/use/ws'
10
12
  import { createServer } from 'http'
11
13
  import Koa from 'koa'
12
14
  import koaBodyParser from 'koa-bodyparser'
13
- import compose from 'koa-compose'
14
15
  import ip from 'koa-ip'
15
16
  import koaStatic from 'koa-static'
17
+ import compose from 'koa-compose'
16
18
  import { historyApiFallback } from 'koa2-connect-history-api-fallback'
17
- import { ConnectionContext, SubscriptionServer } from 'subscriptions-transport-ws'
19
+ import { WebSocketServer } from 'ws'
20
+ import co from 'co'
18
21
 
19
22
  import cors from '@koa/cors'
20
23
  import { config, loader, logger, orderedModuleNames } from '@things-factory/env'
@@ -53,6 +56,7 @@ const fileUploadOption = {
53
56
  maxFileSize: bytesFormat.parse(fileUpload.maxFileSize) || bytesFormat.parse('10mb'),
54
57
  maxFiles: fileUpload.maxFiles || 10
55
58
  }
59
+
56
60
  /* bootstrap */
57
61
  const bootstrap = async () => {
58
62
  await databaseInitializer()
@@ -93,41 +97,50 @@ const bootstrap = async () => {
93
97
  const builtSchema = await schema()
94
98
 
95
99
  const httpServer = createServer(app.callback())
100
+ const websocketServer = new WebSocketServer({
101
+ server: httpServer,
102
+ path: '/graphql'
103
+ })
96
104
 
97
- const subscriptionServer = SubscriptionServer.create(
105
+ // Save the returned server's info so we can shut down this server later
106
+ const serverCleanup = useServer(
98
107
  {
99
108
  schema: builtSchema,
100
- // These are imported from `graphql`.
101
- execute,
102
- subscribe,
103
- async onConnect(connectionParams: Object, webSocket: WebSocket, context: ConnectionContext) {
104
- var { request } = context
109
+ context: async (ctx, msg, args) => {
110
+ return ctx['context']
111
+ },
112
+ onConnect: async ctx => {
113
+ var { extra, connectionParams } = ctx
114
+ var { request } = extra
105
115
 
106
- var url = new URL((connectionParams['headers'] || connectionParams).referer)
116
+ var url = new URL(((connectionParams['headers'] as any) || connectionParams).referer)
107
117
  var accessToken = url.searchParams.get('access_token')
108
118
  connectionParams['headers']['authorization'] = accessToken
109
119
 
110
120
  request.headers = {
111
121
  ...request.headers,
112
- ...(connectionParams['headers'] || connectionParams)
122
+ ...(connectionParams['headers'] || (connectionParams as any))
113
123
  }
114
124
 
115
- /* in case connect error(like a authentication error) just throw exception */
116
125
  var koacontext = await app.createContext(request, {} as any)
117
126
  koacontext['state'] = {}
118
127
 
128
+ /* in case connect error(like a authentication error) just throw exception */
119
129
  var middlewares = [...subscriptionMiddleware]
120
130
  const fn = co.wrap(compose(middlewares))
121
131
 
122
132
  await fn(koacontext)
123
133
 
124
- return koacontext
134
+ return (ctx['context'] = koacontext)
135
+ },
136
+ onDisconnect(ctx, code, reason) {
137
+ console.log('Disconnected!')
138
+ },
139
+ onError(ctx, msg, errors) {
140
+ console.error(msg, errors)
125
141
  }
126
142
  },
127
- {
128
- server: httpServer,
129
- path: '/subscriptions'
130
- }
143
+ websocketServer
131
144
  )
132
145
 
133
146
  const server = new ApolloServer({
@@ -149,16 +162,18 @@ const bootstrap = async () => {
149
162
  }
150
163
  },
151
164
  plugins: [
165
+ ApolloServerPluginDrainHttpServer({ httpServer }),
152
166
  {
153
167
  async serverWillStart() {
154
168
  return {
155
169
  async drainServer() {
156
- subscriptionServer.close()
170
+ await serverCleanup.dispose()
157
171
  }
158
172
  }
159
173
  }
160
174
  }
161
- ]
175
+ ],
176
+ cache: 'bounded'
162
177
  })
163
178
 
164
179
  await server.start()
@@ -205,7 +220,7 @@ const bootstrap = async () => {
205
220
  .use(domainPrivateRouter.routes())
206
221
  .use(domainPrivateRouter.allowedMethods())
207
222
 
208
- /* should be history-fallback => koaStatic */
223
+ /* should follow this order : history-fallback => koaStatic */
209
224
  app.use(historyApiFallback({ whiteList: [] }))
210
225
 
211
226
  app.use(
@@ -216,7 +231,7 @@ const bootstrap = async () => {
216
231
 
217
232
  httpServer.listen({ port: PORT }, () => {
218
233
  logger.info(`🚀 Server ready at http://0.0.0.0:${PORT}${server.graphqlPath}`)
219
- logger.info(`🚀 Subscriptions ready at ws://0.0.0.0:${PORT}${'/subscriptions'}`)
234
+ logger.info(`🚀 Subscriptions ready at ws://0.0.0.0:${PORT}${server.graphqlPath}`)
220
235
 
221
236
  process.emit('bootstrap-module-start' as any, { app, config, builtSchema, httpServer } as any)
222
237
  })
@@ -11,7 +11,7 @@ export const ScalarDate = new GraphQLScalarType({
11
11
  * Note: Allow value to be date only like "2021-01-31" to be serialize before passing data to clientside for TypeGraphql.
12
12
  * Usage: When database column datatype is "date" and data do not contain any time component.
13
13
  */
14
- return new Date(value).getTime() // value sent to the client
14
+ return new Date(value as any).getTime() // value sent to the client
15
15
  },
16
16
  parseLiteral(ast) {
17
17
  if (ast.kind === Kind.INT) {
@@ -1,7 +1,8 @@
1
- import { GraphQLSchema, defaultFieldResolver } from 'graphql'
2
- import { gql } from 'graphql-tag'
1
+ import { defaultFieldResolver, GraphQLSchema } from 'graphql'
2
+ import gql from 'graphql-tag'
3
3
  import { getConnection } from 'typeorm'
4
- import { mapSchema, getDirective, MapperKind } from '@graphql-tools/utils'
4
+
5
+ import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils'
5
6
 
6
7
  const debug = require('debug')('things-factory:shell:directive-transaction')
7
8
 
@@ -1,6 +1,6 @@
1
- import { Filter, ListParam } from 'server/service'
2
1
  import { Brackets, EntityMetadata, Repository, SelectQueryBuilder, WhereExpressionBuilder } from 'typeorm'
3
2
 
3
+ import { Filter, ListParam } from '../service/common-types/list-param'
4
4
  import { Domain } from '../service/domain/domain'
5
5
 
6
6
  const debug = require('debug')('things-factory:shell:get-query-builder-from-list-params')
@@ -3,10 +3,6 @@ import route from './client/route'
3
3
  export default {
4
4
  route,
5
5
  routes: [
6
- {
7
- tagname: 'ox-help-home',
8
- page: 'help'
9
- },
10
6
  {
11
7
  tagname: 'page-404',
12
8
  page: 'page404'
@@ -1,69 +0,0 @@
1
- import { css } from 'lit'
2
-
3
- export const AppStyle = css`
4
- :host {
5
- display: grid;
6
-
7
- grid-template-rows: var(--app-grid-template-rows, auto 1fr auto);
8
- grid-template-columns: var(--app-grid-template-columns, auto 1fr auto);
9
- grid-template-areas: var(--app-grid-template-area, 'header header header' 'nav main aside' 'nav footer aside');
10
- grid-gap: var(--app-grid-gap, 0em);
11
-
12
- max-width: 100vw;
13
- width: 100vw;
14
- height: 100vh;
15
- }
16
-
17
- ox-header-bar {
18
- grid-area: header;
19
- }
20
-
21
- ox-nav-bar {
22
- grid-area: nav;
23
- }
24
-
25
- main {
26
- grid-area: main;
27
-
28
- overflow: hidden;
29
-
30
- display: flex;
31
- flex-direction: row;
32
- }
33
-
34
- ox-aside-bar {
35
- grid-area: aside;
36
- }
37
-
38
- ox-footer-bar {
39
- grid-area: footer;
40
- }
41
-
42
- main * {
43
- flex: 1;
44
- }
45
-
46
- main *:not([active]) {
47
- display: none;
48
- }
49
-
50
- [hidden] {
51
- display: none;
52
- }
53
-
54
- ox-snack-bar {
55
- z-index: 1000;
56
- }
57
-
58
- /* Wide layout */
59
- @media (min-width: 460px) {
60
- }
61
-
62
- @media print {
63
- :host {
64
- width: 100%;
65
- height: 100%;
66
- min-height: 100vh;
67
- }
68
- }
69
- `