@hopara/iframe 2.4.57 → 2.4.58
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/build/client.js +1 -1
- package/build/service-worker.js +1 -1
- package/build/types/src/client/index.d.ts +43 -0
- package/build/types/src/demo/Demo.d.ts +5 -0
- package/build/types/src/demo/index.d.ts +1 -0
- package/build/types/src/events/EventEmitter.d.ts +15 -0
- package/build/types/src/events/EventReceiver.d.ts +5 -0
- package/build/types/src/events/Events.d.ts +69 -0
- package/build/types/src/index.d.ts +1 -0
- package/build/types/src/service-worker.d.ts +1 -0
- package/build/types/src/view/Provider.d.ts +73 -0
- package/build/types/src/view/Router.d.ts +1 -0
- package/build/types/src/view/View.d.ts +24 -0
- package/build/types/src/view/index.d.ts +1 -0
- package/package.json +8 -8
- package/src/client/index.ts +256 -0
- package/src/demo/Demo.tsx +119 -0
- package/src/demo/index.tsx +7 -0
- package/src/demo/resources/assets-data.json +20552 -0
- package/src/demo/resources/buildings-data.json +56 -0
- package/src/demo/resources/sensors-data.json +830 -0
- package/src/events/EventEmitter.ts +90 -0
- package/src/events/EventReceiver.ts +24 -0
- package/src/events/Events.ts +86 -0
- package/src/index.ts +2 -0
- package/src/react-app-env.d.ts +9 -0
- package/src/service-worker.ts +1 -0
- package/src/view/Provider.tsx +258 -0
- package/src/view/Router.tsx +35 -0
- package/src/view/View.tsx +159 -0
- package/src/view/index.tsx +20 -0
- package/tasks/preprocessHTML.js +0 -74
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hopara/iframe",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.58",
|
|
4
4
|
"main": "build/client.js",
|
|
5
5
|
"types": "build/types/src/client/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -34,13 +34,13 @@
|
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@babel/register": "^7.15.3",
|
|
37
|
-
"@hopara/components": "2.4.
|
|
38
|
-
"@hopara/config": "2.4.
|
|
39
|
-
"@hopara/design-system": "2.4.
|
|
40
|
-
"@hopara/internals": "2.4.
|
|
41
|
-
"@hopara/rum": "2.4.
|
|
42
|
-
"@hopara/service-worker": "2.4.
|
|
43
|
-
"@hopara/system-test": "2.4.
|
|
37
|
+
"@hopara/components": "2.4.58",
|
|
38
|
+
"@hopara/config": "2.4.58",
|
|
39
|
+
"@hopara/design-system": "2.4.58",
|
|
40
|
+
"@hopara/internals": "2.4.58",
|
|
41
|
+
"@hopara/rum": "2.4.58",
|
|
42
|
+
"@hopara/service-worker": "2.4.58",
|
|
43
|
+
"@hopara/system-test": "2.4.58",
|
|
44
44
|
"babel-loader": "8.1.0",
|
|
45
45
|
"customize-cra": "^1.0.0",
|
|
46
46
|
"lodash": "~4.17.21",
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { EventEmitter } from '../events/EventEmitter'
|
|
2
|
+
import { EventReceiver } from '../events/EventReceiver'
|
|
3
|
+
import { CallbackFunctionData, InitData, LoadDataRequestData, PostMessageEvent, isCallbackFunctionEvent, isLoadDataEvent, isReadyEvent } from '../events/Events'
|
|
4
|
+
import packageJSON from '../../package.json'
|
|
5
|
+
import { DataLoader } from '@hopara/dataset'
|
|
6
|
+
import { Logger } from '@hopara/internals'
|
|
7
|
+
|
|
8
|
+
interface CallbackAction {
|
|
9
|
+
name: string
|
|
10
|
+
callback: (data: any) => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface HoparaIframeConfig extends InitData {
|
|
14
|
+
targetElementId?: string
|
|
15
|
+
targetElement?: HTMLElement | null
|
|
16
|
+
version?: string
|
|
17
|
+
debug?: boolean
|
|
18
|
+
embeddedUrl?: string
|
|
19
|
+
callbacks?: CallbackAction[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const embeddedEnvUrl = {
|
|
23
|
+
'test': 'https://statics.test.hopara.app/embedded',
|
|
24
|
+
'production': 'https://statics.hopara.app/embedded',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class Hopara {
|
|
28
|
+
private static _version = packageJSON.version
|
|
29
|
+
config: HoparaIframeConfig
|
|
30
|
+
private iframe?: HTMLIFrameElement
|
|
31
|
+
private readyEventTimeoutId?: number
|
|
32
|
+
private readonly readyEventTimeoutMs = 5000
|
|
33
|
+
|
|
34
|
+
constructor(config: HoparaIframeConfig) {
|
|
35
|
+
this.config = config
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private getIframeSrc() {
|
|
39
|
+
const envUrl = embeddedEnvUrl[this.config.env ?? 'production'] ?? embeddedEnvUrl.production
|
|
40
|
+
const url = this.config.embeddedUrl ? this.config.embeddedUrl : `${envUrl}/${this.config.version ? this.config.version : 'latest'}`
|
|
41
|
+
return `${url}?v=${Date.now()}${this.config.debug ? '&debug=true' : ''}`
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private getIframeStyle() {
|
|
45
|
+
return 'background-color: transparent; border: 0px none transparent; padding: 0px; overflow: hidden; width: 100%; height: 100%;'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private createIframe(): HTMLIFrameElement {
|
|
49
|
+
const iframe = document.createElement('iframe')
|
|
50
|
+
|
|
51
|
+
iframe.setAttribute('src', this.getIframeSrc())
|
|
52
|
+
iframe.setAttribute('allow', 'geolocation; fullscreen')
|
|
53
|
+
iframe.setAttribute('style', this.getIframeStyle())
|
|
54
|
+
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-presentation allow-modals allow-downloads allow-top-navigation')
|
|
55
|
+
|
|
56
|
+
return iframe
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private getEventData(): InitData {
|
|
60
|
+
const eventData = {
|
|
61
|
+
...this.config,
|
|
62
|
+
visualizationId: this.config.visualizationId ?? (this.config as any).visualization ?? (this.config as any).app,
|
|
63
|
+
dataLoaders: this.config.dataLoaders?.map((dataLoader) => {
|
|
64
|
+
return {
|
|
65
|
+
query: dataLoader.query ?? (dataLoader as any).name,
|
|
66
|
+
source: dataLoader.source,
|
|
67
|
+
cache: dataLoader.cache,
|
|
68
|
+
} as DataLoader
|
|
69
|
+
}),
|
|
70
|
+
callbackNames: this.config.callbacks?.map((callback) => callback.name),
|
|
71
|
+
|
|
72
|
+
// remove uneccessary properties from the event data to prevent postMessage errors and reduce the payload size
|
|
73
|
+
callbacks: undefined,
|
|
74
|
+
targetElementId: undefined,
|
|
75
|
+
targetElement: undefined,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return eventData
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private handleReadyEvent(targetWindow: Window | MessageEventSource) {
|
|
82
|
+
return EventEmitter.init(this.getEventData(), targetWindow as Window)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private handleLoadDataEvent(event: PostMessageEvent<LoadDataRequestData>, targetWindow: Window | MessageEventSource) {
|
|
86
|
+
const dataLoader = this.config.dataLoaders?.find((dataLoader) => {
|
|
87
|
+
return (dataLoader.query === event.data.data.query || (dataLoader as any).name === event.data.data.query) &&
|
|
88
|
+
dataLoader.source === event.data.data.source
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
return dataLoader?.loader(event.data.filterSet)
|
|
92
|
+
.then((data) => EventEmitter.loadDataResponse(
|
|
93
|
+
this.getEventData(),
|
|
94
|
+
dataLoader,
|
|
95
|
+
data,
|
|
96
|
+
undefined,
|
|
97
|
+
targetWindow as Window,
|
|
98
|
+
))
|
|
99
|
+
.catch((error) => EventEmitter.loadDataResponse(
|
|
100
|
+
this.getEventData(),
|
|
101
|
+
dataLoader,
|
|
102
|
+
[],
|
|
103
|
+
error,
|
|
104
|
+
targetWindow as Window,
|
|
105
|
+
))
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
handleCallbackFunctionEvent(event: PostMessageEvent<CallbackFunctionData>) {
|
|
109
|
+
const callbackFunc = this.config.callbacks?.find((callback) => callback.name === event.data.name)
|
|
110
|
+
if (!callbackFunc) return
|
|
111
|
+
return callbackFunc.callback(event.data.row)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
listenerFunction(event: PostMessageEvent<any>) {
|
|
115
|
+
const targetWindow = this.iframe?.contentWindow ?? event.source
|
|
116
|
+
if (!targetWindow && EventReceiver.isHoparaMessage(event)) {
|
|
117
|
+
throw new Error('Hopara: targetWindow is not available')
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (isReadyEvent(event)) {
|
|
121
|
+
this.clearReadyEventTimeout()
|
|
122
|
+
return this.handleReadyEvent(targetWindow!)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (isLoadDataEvent(event)) {
|
|
126
|
+
return this.handleLoadDataEvent(event, targetWindow!)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (isCallbackFunctionEvent(event)) {
|
|
130
|
+
return this.handleCallbackFunctionEvent(event)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private cachedListenerFunction
|
|
135
|
+
|
|
136
|
+
private createListeners() {
|
|
137
|
+
this.cachedListenerFunction = this.listenerFunction.bind(this)
|
|
138
|
+
window.addEventListener('message', this.cachedListenerFunction, true)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private removeListeners() {
|
|
142
|
+
window.removeEventListener('message', this.cachedListenerFunction, true)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private scheduleReadyEventTimeout(targetWindow?: Window | MessageEventSource | null) {
|
|
146
|
+
if (typeof window === 'undefined') return
|
|
147
|
+
|
|
148
|
+
const windowToWatch = targetWindow ?? this.iframe?.contentWindow ?? null
|
|
149
|
+
if (!windowToWatch) return
|
|
150
|
+
|
|
151
|
+
this.clearReadyEventTimeout()
|
|
152
|
+
this.readyEventTimeoutId = window.setTimeout(() => {
|
|
153
|
+
Logger.warn('Hopara: ready event not received within 5s, reloading target window')
|
|
154
|
+
this.readyEventTimeoutId = undefined
|
|
155
|
+
this.reloadTargetWindow(windowToWatch)
|
|
156
|
+
}, this.readyEventTimeoutMs)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private clearReadyEventTimeout() {
|
|
160
|
+
if (!this.readyEventTimeoutId) return
|
|
161
|
+
|
|
162
|
+
clearTimeout(this.readyEventTimeoutId)
|
|
163
|
+
this.readyEventTimeoutId = undefined
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private reloadTargetWindow(targetWindow?: Window | MessageEventSource | null) {
|
|
167
|
+
const windowToReload = targetWindow ?? this.iframe?.contentWindow ?? null
|
|
168
|
+
if (!windowToReload && !this.iframe) return
|
|
169
|
+
|
|
170
|
+
let reloaded = false
|
|
171
|
+
|
|
172
|
+
if (windowToReload) {
|
|
173
|
+
try {
|
|
174
|
+
const location = (windowToReload as Window).location
|
|
175
|
+
if (location && typeof location.reload === 'function') {
|
|
176
|
+
location.reload()
|
|
177
|
+
reloaded = true
|
|
178
|
+
}
|
|
179
|
+
} catch (error) {
|
|
180
|
+
Logger.warn('Hopara: unable to reload target window directly', error as Error)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (!reloaded && this.iframe) {
|
|
185
|
+
this.iframe.setAttribute('src', this.getIframeSrc())
|
|
186
|
+
reloaded = true
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (reloaded) {
|
|
190
|
+
this.scheduleReadyEventTimeout()
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private doInit = () => {
|
|
195
|
+
const targetElement = this.config.targetElementId ? document.getElementById(this.config.targetElementId) : this.config.targetElement
|
|
196
|
+
if (!targetElement) {
|
|
197
|
+
Logger.warn('Hopara: targetElement not found')
|
|
198
|
+
return this
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const iframe = this.createIframe()
|
|
202
|
+
targetElement.appendChild(iframe)
|
|
203
|
+
this.iframe = iframe
|
|
204
|
+
|
|
205
|
+
this.createListeners()
|
|
206
|
+
this.scheduleReadyEventTimeout()
|
|
207
|
+
return this
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
refresh(): void {
|
|
211
|
+
if (!this.iframe) throw new Error('Hopara: iframe is not available')
|
|
212
|
+
|
|
213
|
+
if (this.iframe.contentWindow) {
|
|
214
|
+
EventEmitter.refresh(this.getEventData(), this.iframe.contentWindow)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
update(config: Partial<HoparaIframeConfig>): void {
|
|
219
|
+
this.config = Object.assign({}, this.config, config)
|
|
220
|
+
|
|
221
|
+
if (this.iframe?.contentWindow) {
|
|
222
|
+
EventEmitter.update(this.getEventData(), this.iframe.contentWindow)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
destroy(): void {
|
|
227
|
+
if (!this.iframe) throw new Error('Hopara: iframe is not available')
|
|
228
|
+
|
|
229
|
+
this.iframe.remove()
|
|
230
|
+
this.iframe = undefined
|
|
231
|
+
this.clearReadyEventTimeout()
|
|
232
|
+
this.removeListeners()
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
static init(config: HoparaIframeConfig) {
|
|
236
|
+
if (!config) {
|
|
237
|
+
Logger.warn('Hopara: init config not present'); return
|
|
238
|
+
}
|
|
239
|
+
if ((!window || !window.document)) {
|
|
240
|
+
Logger.warn('Hopara: window is not available'); return
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const client = new Hopara(config)
|
|
244
|
+
return client.doInit()
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
static moduleVersion(): string {
|
|
248
|
+
return this._version
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
moduleVersion(): string {
|
|
252
|
+
return Hopara._version
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export default Hopara
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import Hopara from '../client'
|
|
3
|
+
import buildingsData from './resources/buildings-data.json'
|
|
4
|
+
import sensorsData from './resources/sensors-data.json'
|
|
5
|
+
import assetsData from './resources/assets-data.json'
|
|
6
|
+
import { PureComponent } from '@hopara/design-system'
|
|
7
|
+
|
|
8
|
+
export class DemoPage extends PureComponent<any> {
|
|
9
|
+
componentDidMount(): void {
|
|
10
|
+
const hopara = Hopara.init({
|
|
11
|
+
debug: true,
|
|
12
|
+
visualizationId: '',
|
|
13
|
+
fallbackVisualizationId: '',
|
|
14
|
+
tenant: '',
|
|
15
|
+
accessToken: '',
|
|
16
|
+
// refreshToken: '',
|
|
17
|
+
targetElementId: 'embedded-target-element',
|
|
18
|
+
darkMode: true,
|
|
19
|
+
// filters: [{
|
|
20
|
+
// field: 'type',
|
|
21
|
+
// values: ['REFRIGERATOR', 'FREEZER'],
|
|
22
|
+
// }],
|
|
23
|
+
// initialRow: {
|
|
24
|
+
// layerId: 'hopara-floors',
|
|
25
|
+
// rowId: '1',
|
|
26
|
+
// },
|
|
27
|
+
embeddedUrl: 'http://localhost:3000/',
|
|
28
|
+
dataLoaders: [
|
|
29
|
+
// ...ibbxMockLoaders,
|
|
30
|
+
{
|
|
31
|
+
query: 'labs_floorplans',
|
|
32
|
+
source: 'sample',
|
|
33
|
+
loader: async () => {
|
|
34
|
+
return buildingsData
|
|
35
|
+
},
|
|
36
|
+
} as any,
|
|
37
|
+
{
|
|
38
|
+
query: 'sensors',
|
|
39
|
+
source: 'sample',
|
|
40
|
+
loader: async () => {
|
|
41
|
+
return sensorsData
|
|
42
|
+
},
|
|
43
|
+
} as any,
|
|
44
|
+
{
|
|
45
|
+
query: 'labs_assets',
|
|
46
|
+
source: 'sample',
|
|
47
|
+
loader: async () => {
|
|
48
|
+
return assetsData
|
|
49
|
+
},
|
|
50
|
+
} as any,
|
|
51
|
+
],
|
|
52
|
+
callbacks: [
|
|
53
|
+
{
|
|
54
|
+
name: 'CALLBACK_TEST',
|
|
55
|
+
callback: (data) => {
|
|
56
|
+
alert(`CALLBACK_TEST 4: ${data._id}`)
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'goTo3D',
|
|
61
|
+
callback: () => {
|
|
62
|
+
hopara?.update({
|
|
63
|
+
visualizationId: '78-ativo-3d-2',
|
|
64
|
+
fallbackVisualizationId: 'ativo-3d-2',
|
|
65
|
+
})
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'goTo2D',
|
|
70
|
+
callback: () => {
|
|
71
|
+
hopara?.update({
|
|
72
|
+
visualizationId: '78-ativo-2d-2',
|
|
73
|
+
fallbackVisualizationId: 'ativo-2d-2',
|
|
74
|
+
})
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
// setInterval(() => {
|
|
81
|
+
// hopara?.update({
|
|
82
|
+
// visualizationId: '78-ativo-3d-2',
|
|
83
|
+
// fallbackVisualizationId: 'ativo-3d-2',
|
|
84
|
+
// })
|
|
85
|
+
// }, 10000)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
render() {
|
|
89
|
+
return (
|
|
90
|
+
<div style={{
|
|
91
|
+
display: 'grid',
|
|
92
|
+
gridTemplateRows: '70px 1fr',
|
|
93
|
+
width: '100vw',
|
|
94
|
+
height: '100vh',
|
|
95
|
+
overflow: 'hidden',
|
|
96
|
+
}}>
|
|
97
|
+
<h1 style={{
|
|
98
|
+
alignItems: 'center',
|
|
99
|
+
background: '#efefef',
|
|
100
|
+
display: 'flex',
|
|
101
|
+
font: '22px sans-serif',
|
|
102
|
+
justifyContent: 'center',
|
|
103
|
+
margin: 0,
|
|
104
|
+
padding: '0.5em',
|
|
105
|
+
textAlign: 'center',
|
|
106
|
+
}}>
|
|
107
|
+
Hopara embedded demo page!
|
|
108
|
+
</h1>
|
|
109
|
+
<div
|
|
110
|
+
id="embedded-target-element"
|
|
111
|
+
style={{
|
|
112
|
+
width: '100%',
|
|
113
|
+
height: '100%',
|
|
114
|
+
background: '#fefefe',
|
|
115
|
+
}}></div>
|
|
116
|
+
</div>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
}
|