Skip to content

Commit

Permalink
Popup working
Browse files Browse the repository at this point in the history
  • Loading branch information
robmoffat committed Apr 18, 2024
1 parent 179ce24 commit d4c3b6d
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Messaging } from "da-proxy";
import { ChannelSelector, ChannelSelectorDetails, CSSPositioning } from "fdc3-common";
import { ChannelSelector, ChannelSelectorDetails, CSSPositioning, ChannelSelectionChoiceRequest } from "fdc3-common";
import { Channel } from "@finos/fdc3";

// const DEFAULT_SELECTOR_CONTAINER_CSS: CSSPositioning = {
// position: "fixed",
// zIndex: "1000",
// left: "10%",
// top: "10%",
// right: "10%",
// bottom: "10%"
// }
const DEFAULT_SELECTOR_CONTAINER_CSS: CSSPositioning = {
position: "fixed",
zIndex: "1000",
right: "0",
bottom: "10%",
width: "150px",
height: "200px"
}

const DEFAULT_ICON_CSS: CSSPositioning = {
position: "fixed",
Expand All @@ -27,13 +28,16 @@ const DEFAULT_ICON_CSS: CSSPositioning = {
*/
export class DefaultDesktopAgentChannelSelector implements ChannelSelector {

//private readonly m: Messaging
private readonly m: Messaging
private readonly details: ChannelSelectorDetails
private container: HTMLDivElement | undefined = undefined
private icon: HTMLImageElement | undefined = undefined
private availableChannels: Channel[] = []
private currentId: string | null = null
private callback: ((channelId: string) => void) | null = null

constructor(_m: Messaging, details: ChannelSelectorDetails) {
//this.m = m
constructor(m: Messaging, details: ChannelSelectorDetails) {
this.m = m
this.details = details
}

Expand Down Expand Up @@ -62,7 +66,9 @@ export class DefaultDesktopAgentChannelSelector implements ChannelSelector {
ifrm.style.height = "100%"
}

updateChannel(channelId: string | null): void {
updateChannel(channelId: string | null, availableChannels: Channel[]): void {
this.availableChannels = availableChannels
this.currentId = channelId
const src = this.details?.icon?.src
if (src) {
// the DA is asking for an icon
Expand All @@ -74,37 +80,60 @@ export class DefaultDesktopAgentChannelSelector implements ChannelSelector {
const popup = this.details.selector
if (popup) {
// need to allow for dragging here too
this.icon.addEventListener("touchend", this.chooseChannel)
this.icon.addEventListener("mouseup", this.chooseChannel)
this.icon.addEventListener("touchend", () => this.chooseChannel())
this.icon.addEventListener("mouseup", () => this.chooseChannel())
}
}

this.icon.src = this.buildSrc(src, channelId)
}
}

chooseChannel(): void {
// this.openFrame(appIntents)
buildUrl(): string {
return this.details.selector?.uri
+ "?currentId=" + encodeURIComponent(JSON.stringify(this.currentId))
+ "&availableChannels=" + encodeURIComponent(JSON.stringify(this.serializeChannels()))
}

serializeChannels(): any {
return this.availableChannels.map(ch => {
return {
id: ch.id,
displayMetadata: ch.displayMetadata
}
})
}

// const choice = await this.m.waitFor<IntentResolutionChoiceAgentResponse>(m => m.type == 'intentResolutionChoice')
openFrame(): void {
this.removeFrame()

// this.removeFrame()
this.container = document.createElement("div")
const ifrm = document.createElement("iframe")

// return choice.payload
this.theme(this.container, this.details.selector?.css ?? DEFAULT_SELECTOR_CONTAINER_CSS)
this.themeFrame(ifrm)

ifrm.setAttribute("src", this.buildUrl())

this.container.appendChild(ifrm)
document.body.appendChild(this.container)
}

openPopup(): void {
// this.removeFrame()
setChannelChangeCallback(callback: (channelId: string) => void): void {
this.callback = callback
}

// this.container = document.createElement("div")
// const ifrm = document.createElement("iframe")
async chooseChannel(): Promise<void> {
this.openFrame()

// this.themeContainer(this.container)
// this.themeFrame(ifrm)
const choice = await this.m.waitFor<ChannelSelectionChoiceRequest>(m => m.type == 'channelSelectionChoice')

// ifrm.setAttribute("src", this.buildUrl(appIntents))
this.removeFrame()

// this.container.appendChild(ifrm)
// document.body.appendChild(this.container)
if ((!choice.payload.cancelled) && (this.callback)) {
return this.callback(choice.payload.channelId)
}
}


}
16 changes: 14 additions & 2 deletions packages/da-proxy/src/channels/DefaultChannelSupport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ const NO_OP_CHANNEL_SELECTOR: ChannelSelector = {

updateChannel(_channelId: string | null): void {
// does nothing
},

setChannelChangeCallback(_callback: (channelId: string) => void): void {
// also does nothing
}

}
Expand All @@ -29,6 +33,14 @@ export class DefaultChannelSupport implements ChannelSupport {
this.userChannelState = userChannelState;
this.userChannel = userChannelState.find(c => c.id == initialChannelId) ?? null;
this.channelSelector = channelSelector
this.channelSelector.updateChannel(initialChannelId, userChannelState)
this.channelSelector.setChannelChangeCallback((channelId: string) => {
if (channelId == null) {
this.leaveUserChannel()
} else {
this.joinUserChannel(channelId)
}
})
}

mergeChannelState(newState: { [key: string]: ContextElement[]; }): void {
Expand Down Expand Up @@ -77,7 +89,7 @@ export class DefaultChannelSupport implements ChannelSupport {
this.userChannelListeners.forEach(
l => l.updateUnderlyingChannel(null, new Map())
)
this.channelSelector.updateChannel(null)
this.channelSelector.updateChannel(null, this.userChannelState)
return Promise.resolve();
}

Expand All @@ -86,7 +98,7 @@ export class DefaultChannelSupport implements ChannelSupport {
const newUserChannel = this.userChannelState.find(c => c.id == id)
if (newUserChannel) {
this.userChannel = newUserChannel;
this.channelSelector.updateChannel(id)
this.channelSelector.updateChannel(id, this.userChannelState)
this.userChannelListeners.forEach(
l => l.updateUnderlyingChannel(newUserChannel.id, newUserChannel.getState()))
} else {
Expand Down
3 changes: 3 additions & 0 deletions packages/demo/src/client/da/DemoServerContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ export class DemoServerContext implements ServerContext {
bottom: "20px",
position: "fixed"
}
},
selector: {
url: window.location.origin + "/static/da/channel-selector.html"
}

}
Expand Down
89 changes: 89 additions & 0 deletions packages/demo/src/client/da/channel-selector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { AppIdentifier, AppIntent, IntentMetadata } from "@finos/fdc3";
import { AppMetadata } from "@finos/fdc3/dist/bridging/BridgingTypes";
import { io } from "socket.io-client"
import { FDC3_APP_EVENT } from "../../message-types";
import { IntentResolutionChoiceAgentRequest } from "fdc3-common";
import { v4 as uuid } from 'uuid'

function getQueryVariable(variable: string): string {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}

return ""
}

function getAppIntents(): AppIntent[] {
const intentDetails = getQueryVariable("intentDetails")
const decoded = decodeURIComponent(intentDetails)
const object: AppIntent[] = JSON.parse(decoded)
return object
}

function getSource(): AppIdentifier {
const source = getQueryVariable("source")
const decoded = decodeURIComponent(source)
const object: AppIdentifier = JSON.parse(decoded)
return object
}

const socket = io()

socket.on("connect", async () => {

const intentDetails = getAppIntents()
const source = getSource()

const list = document.getElementById("intent-list")!!

function sendChosenIntent(intent: IntentMetadata, app: AppMetadata, source: AppMetadata) {
const out: IntentResolutionChoiceAgentRequest = {
type: "intentResolutionChoice",
meta: {
requestUuid: uuid(),
timestamp: new Date(),
source
},
payload: {
chosenApp: app,
intent: intent,
}
}

socket.emit(FDC3_APP_EVENT, out, source)
}

const debug = document.createElement("p")
debug.textContent = JSON.stringify(source)
document.body.appendChild(debug)

intentDetails.forEach(intent => {

intent.apps.forEach(app => {
const li = document.createElement("li")
const a = document.createElement("a")
const description = document.createElement("em")

if (app.instanceId) {
description.textContent = `${intent.intent.displayName ?? ""} on app instance ${app.instanceId} of ${app.appId}`
} else {
description.textContent = ` ${intent.intent.displayName ?? ""} on a new instance of ${app.appId}`
}

a.textContent = intent.intent.name

li.appendChild(a)
li.appendChild(description)
list.appendChild(li)
a.setAttribute("href", "#")
a.onclick = () => sendChosenIntent(intent.intent, app, source)
})

})

})
14 changes: 14 additions & 0 deletions packages/demo/static/da/channel-selector.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<html lang="en">

<head>
<title>Desktop Agent Intent Resolver</title>
<meta charset="UTF-8" />
<script type="module" src="/src/client/da/channel-selector.ts"></script>
</head>

<body style="background-color: white;">
<h1>Channel Selector</h1>
<ul id="channel-list"></ul>
</body>

</html>
15 changes: 13 additions & 2 deletions packages/fdc3-common/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AppIdentifier, AppMetadata, DesktopAgent, IntentMetadata, IntentResult } from "@finos/fdc3";
import { AppIdentifier, AppMetadata, DesktopAgent, IntentMetadata, IntentResult, Channel } from "@finos/fdc3";
import { exchange, exchangePostMessage, exchangeForMessagePort } from "./exchange";
import { AppIntent, PrivateChannelOnAddContextListenerAgentRequest, PrivateChannelOnAddContextListenerAgentRequestMeta, PrivateChannelOnUnsubscribeAgentRequest } from "@finos/fdc3/dist/bridging/BridgingTypes";

Expand Down Expand Up @@ -150,7 +150,9 @@ export interface SingleAppIntent {

export interface ChannelSelector {

updateChannel(channelId: string | null): void
updateChannel(channelId: string | null, availableChannels: Channel[]): void

setChannelChangeCallback(callback: (channelId: string) => void): void

}

Expand Down Expand Up @@ -180,3 +182,12 @@ export type IntentResolutionChoiceAgentResponse = {


export type IntentResolutionChoiceAgentRequest = IntentResolutionChoiceAgentResponse


export type ChannelSelectionChoiceRequest = {
type: 'channelSelectionChoice',
payload: {
channelId: string,
cancelled: boolean,
}
}

0 comments on commit d4c3b6d

Please sign in to comment.