Skip to content

Commit

Permalink
Iframe: add widget api
Browse files Browse the repository at this point in the history
  • Loading branch information
Williangalvani committed Dec 12, 2024
1 parent b85a1bd commit 08b8def
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 6 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"serve": "vite preview",
"test:ci": "vitest --coverage --run",
"test:unit": "vitest",
"typecheck": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false"
"typecheck": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
"build:lib": "BUILD_MODE=library vite build"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.4.0",
Expand Down
22 changes: 20 additions & 2 deletions src/components/widgets/IFrame.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<teleport to=".widgets-view">
<iframe
v-show="iframe_loaded"
ref="iframe"
:src="widget.options.source"
:style="iframeStyle"
frameborder="0"
Expand Down Expand Up @@ -60,12 +61,15 @@ import { defaultBlueOsAddress } from '@/assets/defaults'
import Snackbar from '@/components/Snackbar.vue'
import { isValidURL } from '@/libs/utils'
import { useAppInterfaceStore } from '@/stores/appInterface'
import { useMainVehicleStore } from '@/stores/mainVehicle'
import { useWidgetManagerStore } from '@/stores/widgetManager'
import type { Widget } from '@/types/widgets'
import { listenCockpitActionVariable } from '@/libs/actions/data-lake'
const interfaceStore = useAppInterfaceStore()
const widgetStore = useWidgetManagerStore()
const iframe = ref()
const props = defineProps<{
/**
* Widget reference
Expand Down Expand Up @@ -97,10 +101,24 @@ const updateURL = (): void => {
}
onBeforeMount(() => {
window.addEventListener(
'message',
(event) => {
if (event.data.type !== 'cockpit:listenToDatalakeVariables') {
return
}
const { variable } = event.data
console.log('asked to listen to ', variable)
listenCockpitActionVariable(variable, (value) => {
iframe.value.contentWindow.postMessage({ type: 'cockpit:datalakeVariable', variable, value }, '*')
})
},
false
)
if (Object.keys(widget.value.options).length !== 0) {
return
}
widget.value.options = {
source: defaultBlueOsAddress,
}
Expand Down
2 changes: 1 addition & 1 deletion src/libs/actions/data-lake.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const createCockpitActionVariable = (
initialValue?: string | number | boolean
): void => {
if (cockpitActionVariableInfo[variable.id]) {
throw new Error(`Cockpit action variable with id '${variable.id}' already exists. Update it instead.`)
console.warn(`Cockpit action variable with id '${variable.id}' already exists. Update it instead.`)
}
cockpitActionVariableInfo[variable.id] = variable
cockpitActionVariableData[variable.id] = initialValue
Expand Down
19 changes: 19 additions & 0 deletions src/libs/external-api/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const COCKPIT_WIDGET_API_VERSION = '0.0.0'

export function listenToDatalakeVariable(variable: string, callback: (data: any) => void, maxRateHz: number = 10) {
const message = {
type: "cockpit:listenToDatalakeVariables",
variable: variable,
maxRateHz: maxRateHz
};
window.postMessage(message, window.parent.location.origin);

window.addEventListener('message', function handler(event) {
if (event.data.type === "cockpit:datalakeVariableUpdate" && event.data.variable === variable) {
callback(event.data);
}
});
}


export default listenToDatalakeVariable
3 changes: 3 additions & 0 deletions src/libs/vehicle/ardupilot/ardupilot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { type MissionLoadingCallback, type Waypoint, defaultLoadingCallback } fr

import * as Vehicle from '../vehicle'
import { defaultMessageFrequency } from './defaults'
import { CockpitActionVariable, createCockpitActionVariable, setCockpitActionVariableData, updateCockpitActionVariableInfo } from '@/libs/actions/data-lake'

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ArduPilot = ArduPilotVehicle<any>
Expand Down Expand Up @@ -408,6 +409,8 @@ export abstract class ArduPilotVehicle<Modes> extends Vehicle.AbstractVehicle<Mo
this._attitude.roll = attitude.roll
this._attitude.pitch = attitude.pitch
this._attitude.yaw = attitude.yaw
createCockpitActionVariable(new CockpitActionVariable('mainvehicle.attitude.yaw', 'mainvehicle.attitude.yaw', 'number'), attitude.yaw)
setCockpitActionVariableData('mainvehicle.attitude.yaw', attitude.yaw)
this.onAttitude.emit()
break
}
Expand Down
37 changes: 37 additions & 0 deletions test/test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
background-color: white;
}
</style>
</head>
<body>
<h1>Datalake consumption test</h1>
<div id="messageDisplay"></div>

<script>
function listenToDatalakeVariable(variable, callback, maxRateHz) {
const message = {
type: "cockpit:listenToDatalakeVariables",
variable: variable,
maxRateHz: 10,
};
window.parent.postMessage(message, '*');

window.addEventListener('message', function handler(event) {
if (event.data.type === "cockpit:datalakeVariable" && event.data.variable === variable) {
callback(event.data.value);
}
});
}

listenToDatalakeVariable('mainvehicle.attitude.yaw', function(data) {
document.getElementById('messageDisplay').innerText = 'Yaw: ' + data;
});
</script>
</body>
</html>
42 changes: 40 additions & 2 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import { getVersion } from './src/libs/non-browser-utils'
// Check if we're running in Electron mode or building the application
const isElectron = process.env.ELECTRON === 'true'
const isBuilding = process.argv.includes('build')
const isLibrary = process.env.BUILD_MODE === 'library'

export default defineConfig({
// Base configuration that will be merged
const baseConfig = {
plugins: [
(isElectron || isBuilding) &&
electron([
Expand Down Expand Up @@ -70,4 +72,40 @@ export default defineConfig({
server: {
host: '0.0.0.0',
},
})
}

// Library-specific configuration
const libraryConfig = {
build: {
lib: {
entry: path.resolve(__dirname, 'src/libs/external-api/api.ts'), // Change this to your library file
name: 'YourLibrary', // Change this to your library name
formats: ['es', 'umd'],
fileName: (format: string) => `cockpit-external-api.${format}.js`
},
rollupOptions: {
external: ['vue', 'vuetify'], // Add your external dependencies
output: {
globals: {
vue: 'Vue',
vuetify: 'Vuetify'
}
}
},
outDir: 'dist/lib', // Separate output directory for library builds
minify: false, // Disable minification for now
}
}

export default defineConfig((_configEnv) => {
if (isLibrary) {
// For library builds, merge the base config with library-specific settings
return {
...baseConfig,
...libraryConfig
}
}

// For regular builds, return the base config as-is
return baseConfig
})

0 comments on commit 08b8def

Please sign in to comment.