diff --git a/packages/dui3/components/header/NavBar.vue b/packages/dui3/components/header/NavBar.vue index f7412309c..bd5f0ac92 100644 --- a/packages/dui3/components/header/NavBar.vue +++ b/packages/dui3/components/header/NavBar.vue @@ -7,12 +7,12 @@
-
diff --git a/packages/dui3/lib/accounts/composables/setup.ts b/packages/dui3/lib/accounts/composables/setup.ts new file mode 100644 index 000000000..275dc4757 --- /dev/null +++ b/packages/dui3/lib/accounts/composables/setup.ts @@ -0,0 +1,69 @@ +import { ApolloClient } from '@apollo/client/core' +import { ApolloClients } from '@vue/apollo-composable' +import { ShallowRef } from 'vue' +import { resolveClientConfig } from '~/lib/core/configs/apollo' +import { Account } from '~/types' + +export type DUIAccount = { + accountInfo: Account + client: ApolloClient +} + +export type DUIAccountsState = { + accounts: ShallowRef + refreshAccounts: () => Promise +} + +const AccountsInjectionKey = 'DUI_ACCOUNTS_STATE' + +export async function useAccountsSetup() { + const app = useNuxtApp() + const $bindings = app.$bindings + + // Using a shallow ref as we don't need inner values reactive + const accounts = shallowRef([] as DUIAccount[]) + + const apolloClients = {} as Record> + + // Matches local accounts coming from the host app to app state. + const refreshAccounts = async () => { + const accs = JSON.parse(await $bindings.getAccounts()) as Account[] + const newAccs = [] as DUIAccount[] + for (const acc of accs) { + const existing = accounts.value.find((a) => a.accountInfo.id === acc.id) + if (existing) { + newAccs.push(existing) + continue + } + + const client = new ApolloClient( + resolveClientConfig({ + httpEndpoint: new URL('/graphql', acc.serverInfo.url).href, + authToken: () => acc.token + }) + ) + apolloClients[acc.id] = client + newAccs.push({ + accountInfo: acc, + client + }) + } + accounts.value = newAccs + } + + await refreshAccounts() + + const accState = { + accounts, + refreshAccounts + } + + app.vueApp.provide(ApolloClients, apolloClients) + provide(AccountsInjectionKey, accState) + return accState +} + +export function useInjectedAccounts() { + const state = inject(AccountsInjectionKey) as DUIAccountsState + return state +} diff --git a/packages/dui3/nuxt.config.ts b/packages/dui3/nuxt.config.ts index f3658e0ce..a18ebaa86 100644 --- a/packages/dui3/nuxt.config.ts +++ b/packages/dui3/nuxt.config.ts @@ -6,7 +6,7 @@ export default defineNuxtConfig({ shim: false, strict: true }, - modules: ['@nuxtjs/tailwindcss'], + modules: ['@nuxtjs/tailwindcss', '@speckle/ui-components-nuxt'], alias: { // Rewriting all lodash calls to lodash-es for proper tree-shaking & chunk splitting lodash: 'lodash-es' diff --git a/packages/dui3/pages/index.vue b/packages/dui3/pages/index.vue index 67447869e..9e367c6f1 100644 --- a/packages/dui3/pages/index.vue +++ b/packages/dui3/pages/index.vue @@ -1,22 +1,45 @@ diff --git a/packages/dui3/plugins/00.cefPlugin.ts b/packages/dui3/plugins/00.cefPlugin.ts new file mode 100644 index 000000000..adf676f38 --- /dev/null +++ b/packages/dui3/plugins/00.cefPlugin.ts @@ -0,0 +1,26 @@ +import { ICefSharp, WebUiBindingType, MockedBindings } from '~/types' + +declare let CefSharp: ICefSharp +declare let WebUIBinding: WebUiBindingType + +export default defineNuxtPlugin(async () => { + let bindings: WebUiBindingType + + try { + if (!CefSharp) throw new Error('No global CefSharp object found.') + await CefSharp.BindObjectAsync('WebUIBinding') + console.info('Bound WebUIBinding object for CefSharp.') + bindings = WebUIBinding + } catch (e) { + console.error('Failed to bind CefSharp, will use mocked bindings.') + console.error(e) + + bindings = MockedBindings + } + + return { + provide: { + bindings + } + } +}) diff --git a/packages/dui3/plugins/apollo.ts b/packages/dui3/plugins/apollo.ts index 104300198..ddf4dcd77 100644 --- a/packages/dui3/plugins/apollo.ts +++ b/packages/dui3/plugins/apollo.ts @@ -1,34 +1,33 @@ -import { ApolloClient } from '@apollo/client/core' -import { ApolloClients } from '@vue/apollo-composable' -import { resolveClientConfig } from '~/lib/core/configs/apollo' +// import { ApolloClient } from '@apollo/client/core' +// import { ApolloClients } from '@vue/apollo-composable' +// import { resolveClientConfig } from '~/lib/core/configs/apollo' export default defineNuxtPlugin((nuxtApp) => { /** * TODO: You can use `window` here to get credentials for all of the clients * we need from the parent connectors. The following is just an example */ - - const apolloClients = { - latest: new ApolloClient( - // Imagine endpoint & token is resolved from window or something - resolveClientConfig({ - httpEndpoint: 'https://latest.speckle.systems/graphql', - authToken: () => null - }) - ), - xyz: new ApolloClient( - // Imagine endpoint & token is resolved from window or something - resolveClientConfig({ - httpEndpoint: 'https://speckle.xyz/graphql', - authToken: () => null - }) - ) - } - - nuxtApp.vueApp.provide(ApolloClients, apolloClients) - return { - provide: { - apolloClients - } - } + // const { $bindings } = useNuxtApp() + // const apolloClients = { + // latest: new ApolloClient( + // // Imagine endpoint & token is resolved from window or something + // resolveClientConfig({ + // httpEndpoint: 'https://latest.speckle.systems/graphql', + // authToken: () => null + // }) + // ), + // xyz: new ApolloClient( + // // Imagine endpoint & token is resolved from window or something + // resolveClientConfig({ + // httpEndpoint: 'https://speckle.xyz/graphql', + // authToken: () => null + // }) + // ) + // } + // nuxtApp.vueApp.provide(ApolloClients, apolloClients) + // return { + // provide: { + // apolloClients + // } + // } }) diff --git a/packages/dui3/types/index.ts b/packages/dui3/types/index.ts new file mode 100644 index 000000000..b637d3f75 --- /dev/null +++ b/packages/dui3/types/index.ts @@ -0,0 +1,40 @@ +/* eslint-disable @typescript-eslint/require-await */ +export type Account = { + id: string + isDefault: boolean + token: string + serverInfo: { + name: string + url: string + } + userInfo: { + id: string + avatar: string + email: string + name: string + commits: { totalCount: number } + streams: { totalCount: number } + } +} + +export interface ICefSharp { + BindObjectAsync: (arg: string) => Promise +} + +export type WebUiBindingType = { + getAccounts: () => Promise + sayHi: (name: string) => Promise + getSourceAppName: () => Promise +} + +export const MockedBindings: WebUiBindingType = { + async getAccounts() { + return '[]' + }, + async sayHi(name: string) { + return `Hi ${name} from (mocked bindings)!` + }, + async getSourceAppName() { + return 'Mocked App' + } +}