experiments(dui3): super wip work
This commit is contained in:
@@ -29,7 +29,7 @@ export async function useAccountsSetup() {
|
||||
|
||||
// Matches local accounts coming from the host app to app state.
|
||||
const refreshAccounts = async () => {
|
||||
const accs = JSON.parse(await $bindings.getAccounts()) as Account[]
|
||||
const accs = await $bindings.getAccounts()
|
||||
const newAccs = [] as DUIAccount[]
|
||||
for (const acc of accs) {
|
||||
const existing = accounts.value.find((a) => a.accountInfo.id === acc.id)
|
||||
@@ -53,10 +53,16 @@ export async function useAccountsSetup() {
|
||||
accounts.value = newAccs
|
||||
}
|
||||
|
||||
// Call this one first to initialize the account state
|
||||
await refreshAccounts()
|
||||
|
||||
const defaultAccount = computed(() =>
|
||||
accounts.value.find((acc) => acc.accountInfo.isDefault)
|
||||
)
|
||||
|
||||
const accState = {
|
||||
accounts,
|
||||
defaultAccount,
|
||||
refreshAccounts
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { IWebUiBinding } from '~/types'
|
||||
import { createNanoEvents, Emitter } from 'nanoevents'
|
||||
import { HostAppEvents } from '~/types'
|
||||
|
||||
export class CefSharpBridge {
|
||||
private emitter: Emitter
|
||||
|
||||
constructor(bindingObject: IWebUiBinding) {
|
||||
const hoistTarget = this as unknown as Record<string, unknown>
|
||||
const hoistSource = bindingObject as unknown as Record<string, unknown>
|
||||
|
||||
for (const key in bindingObject) {
|
||||
hoistTarget[key] = hoistSource[key]
|
||||
}
|
||||
|
||||
this.emitter = createNanoEvents<HostAppEvents>()
|
||||
this.emitter.emit('start', 'polo pasta')
|
||||
}
|
||||
|
||||
on<E extends keyof HostAppEvents>(event: E, callback: HostAppEvents[E]) {
|
||||
return this.emitter.on(event, callback)
|
||||
}
|
||||
|
||||
emit(eventName: string, payload: string) {
|
||||
const parsedPayload = JSON.parse(payload) as unknown
|
||||
this.emitter.emit(eventName, parsedPayload)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
// TODO
|
||||
@@ -1,4 +1,6 @@
|
||||
// github.com/johot/WebView2-better-bridge/blob/master/web-ui/src/betterBridge.ts
|
||||
import { createNanoEvents, Emitter } from 'nanoevents'
|
||||
import { HostAppEvents } from '~/types'
|
||||
|
||||
type IWebView2 = {
|
||||
webview: {
|
||||
@@ -17,6 +19,7 @@ declare let chrome: IWebView2
|
||||
|
||||
export class WebView2Bridge {
|
||||
private webViewBridge: IRawBridge
|
||||
private emitter: Emitter
|
||||
|
||||
constructor(bridgeName: string) {
|
||||
this.webViewBridge = chrome.webview.hostObjects[bridgeName]
|
||||
@@ -33,6 +36,8 @@ export class WebView2Bridge {
|
||||
hoistTarget[lowercasedMethodName] = (...args: unknown[]) =>
|
||||
this.runMethod(methodName, args)
|
||||
}
|
||||
|
||||
this.emitter = createNanoEvents<HostAppEvents>()
|
||||
}
|
||||
|
||||
private async runMethod(methodName: string, args: unknown[]): Promise<unknown> {
|
||||
@@ -45,6 +50,15 @@ export class WebView2Bridge {
|
||||
|
||||
return JSON.parse(result) as unknown
|
||||
}
|
||||
|
||||
on<E extends keyof HostAppEvents>(event: E, callback: HostAppEvents[E]) {
|
||||
return this.emitter.on(event, callback)
|
||||
}
|
||||
|
||||
emit(eventName: string, payload: string) {
|
||||
const parsedPayload = JSON.parse(payload) as unknown
|
||||
this.emitter.emit(eventName, parsedPayload)
|
||||
}
|
||||
}
|
||||
|
||||
const lowercaseMethodName = (name: string) =>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { IWebUiBinding } from '~/types'
|
||||
|
||||
export class SketchupBindings implements IWebUiBinding {
|
||||
requestId = 0
|
||||
requests = {} as Record<number, unknown>
|
||||
|
||||
SketchupBindings() {
|
||||
// todo
|
||||
}
|
||||
|
||||
getAccounts() {
|
||||
this.requestId++
|
||||
this.requests[this.requestId] = new Promise((resolve, reject) => resolve('[]'))
|
||||
|
||||
return this.requests[this.requestId] as Promise<string>
|
||||
}
|
||||
|
||||
async sayHi(name: string) {
|
||||
return `Hi ${name} from (sketchup mocked bindings)!`
|
||||
}
|
||||
|
||||
getSourceAppName() {
|
||||
return new Promise((resolve, reject) => resolve('sketchup')) as Promise<string>
|
||||
}
|
||||
|
||||
async openDevTools() {
|
||||
// eslint-disable-next-line no-alert
|
||||
window.alert('Please right click and select show dev tools.')
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@
|
||||
"graphql": "^16.6.0",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nanoevents": "^8.0.0",
|
||||
"portal-vue": "^3.0.0",
|
||||
"subscriptions-transport-ws": "^0.11.0"
|
||||
},
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
{{ acc.accountInfo.serverInfo.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div>Your default account is {{ defaultAccount?.accountInfo }}</div>
|
||||
<div>
|
||||
<div v-for="(res, clientId) in queries" :key="clientId">
|
||||
<strong>{{ clientId }}:</strong>
|
||||
@@ -38,7 +39,7 @@ import { ServerInfoTestQuery } from '~/lib/common/generated/gql/graphql'
|
||||
|
||||
const { $bindings } = useNuxtApp()
|
||||
const appName = await $bindings.getSourceAppName()
|
||||
const { accounts, refreshAccounts } = await useAccountsSetup()
|
||||
const { accounts, refreshAccounts, defaultAccount } = await useAccountsSetup()
|
||||
|
||||
const versionQuery = graphql(`
|
||||
query ServerInfoTest {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IWebUiBinding, MockedBindings } from '~/types'
|
||||
import { WebView2Bridge } from '~/lib/bridge/webview'
|
||||
import { CefSharpBridge } from '~/lib/bridge/cefSharp'
|
||||
|
||||
interface ICefSharp {
|
||||
BindObjectAsync: (arg: string) => Promise<void>
|
||||
@@ -11,10 +12,14 @@ interface IWebView2 {
|
||||
|
||||
declare let CefSharp: ICefSharp
|
||||
declare let chrome: IWebView2
|
||||
declare let sketchup: Record<string, unknown> //
|
||||
declare let sketchup: Record<string, unknown>
|
||||
|
||||
declare let WebUIBinding: IWebUiBinding
|
||||
|
||||
// Tries to find the correct host application binding. The sequence is:
|
||||
// - CEFSharp (.NET)
|
||||
// - WebView2 (.NET)
|
||||
// - Sketchup (Ruby) - NOT IMPLEMENTED
|
||||
export default defineNuxtPlugin(async () => {
|
||||
let bindings: IWebUiBinding | undefined = undefined
|
||||
|
||||
@@ -22,7 +27,7 @@ export default defineNuxtPlugin(async () => {
|
||||
if (!CefSharp) throw new Error('No global CefSharp object found.')
|
||||
await CefSharp.BindObjectAsync('WebUIBinding')
|
||||
console.info('Bound WebUIBinding object for CefSharp.')
|
||||
bindings = WebUIBinding
|
||||
bindings = new CefSharpBridge(WebUIBinding) as unknown as IWebUiBinding
|
||||
} catch (e) {
|
||||
console.warn('Failed to bind CefSharp.')
|
||||
console.warn(e)
|
||||
@@ -32,10 +37,9 @@ export default defineNuxtPlugin(async () => {
|
||||
if (!chrome.webview) throw new Error('No global Webview2 object found.')
|
||||
bindings = new WebView2Bridge('WebUIBinding') as unknown as IWebUiBinding
|
||||
console.info('Bound WebUIBinding object for Webview2.')
|
||||
|
||||
const res = await bindings.sayHi('Test')
|
||||
console.log(res)
|
||||
|
||||
// TODO: Wrap the motherfucking wv2 bindings up
|
||||
} catch (e) {
|
||||
console.warn('Failed to bind Webview2.')
|
||||
console.warn(e)
|
||||
@@ -57,6 +61,10 @@ export default defineNuxtPlugin(async () => {
|
||||
|
||||
;(globalThis as Record<string, unknown>).bindings = bindings
|
||||
|
||||
bindings.on('test', (args) => {
|
||||
console.log(args)
|
||||
})
|
||||
|
||||
return {
|
||||
provide: {
|
||||
bindings
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { createNanoEvents, Emitter } from 'nanoevents'
|
||||
/* eslint-disable @typescript-eslint/require-await */
|
||||
export type Account = {
|
||||
id: string
|
||||
@@ -30,17 +31,46 @@ type ModelCard = {
|
||||
// settings: Record<string,unknown>???
|
||||
// report: Record<string,unknown>???
|
||||
// progress: Record<string,unknown>???
|
||||
status: 'idle' | 'inprogress' | 'error' | 'warning' | 'disabled'
|
||||
}
|
||||
|
||||
export type IWebUiBinding = {
|
||||
type TestData = {
|
||||
foo: number
|
||||
bar: string
|
||||
baz: boolean
|
||||
}
|
||||
|
||||
export interface HostAppEvents {
|
||||
test: (data: TestData) => void
|
||||
documentChanged: () => void
|
||||
selectionChanged: () => void
|
||||
documentClosed: () => void
|
||||
updateModelCardState: () => void
|
||||
displayToastNotification: () => void // bla bla bla
|
||||
}
|
||||
|
||||
export interface IWebUiBinding {
|
||||
sayHi: (name: string) => Promise<string>
|
||||
openDevTools: () => Promise<void>
|
||||
getAccounts: () => Promise<Account[]>
|
||||
getSourceAppName: () => Promise<string>
|
||||
// etc.
|
||||
getFileState: () => Promise<FileState>
|
||||
// getFileState: () => Promise<FileState>
|
||||
// addModelCard(string modelId, string projectId), removeModelCard(...) // etc. etc.
|
||||
/**
|
||||
* Subscribe to messages from the host application.
|
||||
* @param event
|
||||
* @param callback
|
||||
*/
|
||||
on: <E extends keyof HostAppEvents>(event: E, callback: HostAppEvents[E]) => void
|
||||
/**
|
||||
* Used by the host application to notify/send data to the web app. Do not use from the frontend.
|
||||
* @param eventName
|
||||
* @param args
|
||||
*/
|
||||
emit?: (eventName: string, args: Record<string, unknown>) => void
|
||||
}
|
||||
|
||||
const mockedEmitter = createNanoEvents<HostAppEvents>()
|
||||
export const MockedBindings: IWebUiBinding = {
|
||||
async sayHi(name: string) {
|
||||
return `Hi ${name} from (mocked bindings)!`
|
||||
@@ -57,5 +87,8 @@ export const MockedBindings: IWebUiBinding = {
|
||||
},
|
||||
async getFileState() {
|
||||
return { models: [] }
|
||||
},
|
||||
on<E extends keyof HostAppEvents>(event: E, callback: HostAppEvents[E]) {
|
||||
return mockedEmitter.on(event, callback)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user