From a087ab2772bdb4334d7a439ac6f4ec447737ddb9 Mon Sep 17 00:00:00 2001 From: Jordan Stith Date: Wed, 11 Jan 2023 13:05:25 +0100 Subject: [PATCH] feat(page-metadata): adding ability to send page metadata to host --- apps/ifc-example-client/main.js | 13 +++- package-lock.json | 6 +- packages/iframe-coordinator-cli/src/App.vue | 1 + .../src/views/IframeEmbed.vue | 29 ++++++++- packages/iframe-coordinator/src/client.ts | 17 ++++++ .../src/messages/ClientToHost.ts | 10 +++- .../src/messages/PageMetadata.ts | 60 +++++++++++++++++++ 7 files changed, 128 insertions(+), 8 deletions(-) create mode 100644 packages/iframe-coordinator/src/messages/PageMetadata.ts diff --git a/apps/ifc-example-client/main.js b/apps/ifc-example-client/main.js index 0417740..6ca3a60 100644 --- a/apps/ifc-example-client/main.js +++ b/apps/ifc-example-client/main.js @@ -26,7 +26,7 @@ let iframeClient = new Client({ iframeClient.registerCustomElements(); -// Add a listener that will handled config data passed from the host to the +// Add a listener that will handle config data passed from the host to the // client at startup. iframeClient.addListener('environmentalData', envData => { // Transform link URLs to match top-level app. @@ -75,6 +75,17 @@ document.getElementById('do-publish').addEventListener('click', () => { const TOAST_LEVELS = ['info', 'success', 'error']; document.addEventListener('DOMContentLoaded', () => { + let metadata = { + title: document.querySelector('h1').innerText, + breadcrumbs: [{ + text: document.querySelector('h1').innerText, + href: window.location.href + }], + custom: undefined + } + + iframeClient.sendPageMetadata(metadata); + let toastBtnEl = document.querySelector('button.toast'); toastBtnEl.addEventListener('click', () => { let toast = { diff --git a/package-lock.json b/package-lock.json index 532d66a..9362c6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ } }, "apps/ifc-example-client": { - "version": "5.0.0-beta.3", + "version": "5.0.0", "dependencies": { "@babel/polyfill": "^7.12.1", "custom-event-polyfill": "^1.0.7", @@ -10104,7 +10104,7 @@ } }, "packages/iframe-coordinator": { - "version": "5.0.0-beta.3", + "version": "5.0.0", "license": "MIT", "dependencies": { "decoders": "1.15.0" @@ -10133,7 +10133,7 @@ } }, "packages/iframe-coordinator-cli": { - "version": "5.0.0-beta.3", + "version": "5.0.0", "license": "MIT", "dependencies": { "cheerio": "^1.0.0-rc.10", diff --git a/packages/iframe-coordinator-cli/src/App.vue b/packages/iframe-coordinator-cli/src/App.vue index 8331f63..945cecc 100644 --- a/packages/iframe-coordinator-cli/src/App.vue +++ b/packages/iframe-coordinator-cli/src/App.vue @@ -3,6 +3,7 @@ + diff --git a/packages/iframe-coordinator-cli/src/views/IframeEmbed.vue b/packages/iframe-coordinator-cli/src/views/IframeEmbed.vue index 732c0b0..ad71a9f 100644 --- a/packages/iframe-coordinator-cli/src/views/IframeEmbed.vue +++ b/packages/iframe-coordinator-cli/src/views/IframeEmbed.vue @@ -5,6 +5,10 @@ {{ frameRoute }} as {{ frameUrl }} +

No app is registered for {{ frameRoute }}

@@ -36,6 +40,7 @@ v-on:registeredKeyFired="handleKeyEvent" v-on:navRequest="handleNav" v-on:frameTransition="updateFrameUrl" + v-on:pageMetadata="updatePageMetadata" >
@@ -48,7 +53,8 @@ export default { return { frameUrl: '', showMenu: true, - clientConfig: {} + clientConfig: {}, + metadata: {} }; }, methods: { @@ -98,6 +104,12 @@ export default { updateFrameUrl(event) { this.frameUrl = event.detail; this.showMenu = this.frameUrl === 'about:blank'; + }, + updatePageMetadata(event) { + this.metadata = { + title: event.detail.title, + breadcrumbs: event.detail.breadcrumbs + } } }, mounted() { @@ -149,10 +161,23 @@ for more details. border-bottom: 2px solid #ff4f1f; } #routerLayout .app-route, -#routerLayout .frame-url { +#routerLayout .frame-url, +#routerLayout .metadata-container .metadata-content { color: #ff4f1f; } +#routerLayout .metadata-container { + display: flex; + text-align: left; + float: right; + width: 800px; +} + +#routerLayout .metadata-container .metadata-title { + margin-right: 5px; + width: 150px; +} + #appMenu { max-width: 80ch; margin: auto; diff --git a/packages/iframe-coordinator/src/client.ts b/packages/iframe-coordinator/src/client.ts index 98cb4fa..32cda15 100644 --- a/packages/iframe-coordinator/src/client.ts +++ b/packages/iframe-coordinator/src/client.ts @@ -31,6 +31,7 @@ import { import { ModalRequest } from './messages/ModalRequest'; import { NavRequest } from './messages/NavRequest'; import { Notification } from './messages/Notification'; +import { PageMetadata } from './messages/PageMetadata'; import { Publication } from './messages/Publication'; // Re-exports for doc visibility @@ -497,4 +498,20 @@ bad input into one of the iframe-coordinator client methods. msg: destination }); } + + /** + * Sends page metadata to host for display and browser settings + * + * title property is for the page title in the browser + * breadcrumbs is an array of breadcrumb data for display in host application + * custom is any custom data wanting to be sent by client app + * + * @param metadata data that will be used for display in host application and browser page title + */ + public sendPageMetadata(metadata: PageMetadata): void { + this._sendToHost({ + msgType: 'pageMetadata', + msg: metadata + }); + } } diff --git a/packages/iframe-coordinator/src/messages/ClientToHost.ts b/packages/iframe-coordinator/src/messages/ClientToHost.ts index a14645a..79d570b 100644 --- a/packages/iframe-coordinator/src/messages/ClientToHost.ts +++ b/packages/iframe-coordinator/src/messages/ClientToHost.ts @@ -4,6 +4,10 @@ import { LabeledStarted, startedDecoder } from './Lifecycle'; import { decoder as modalDecoder, LabeledModalRequest } from './ModalRequest'; import { decoder as navRequestDecoder, LabeledNavRequest } from './NavRequest'; import { decoder as notifyDecoder, LabeledNotification } from './Notification'; +import { + decoder as pageMetadataDecoder, + LabeledPageMetadata +} from './PageMetadata'; import { decoder as publicationDecoder, LabeledPublication @@ -19,7 +23,8 @@ export type ClientToHost = | LabeledNavRequest | LabeledStarted | LabeledKeyDown - | LabeledModalRequest; + | LabeledModalRequest + | LabeledPageMetadata; /** * Validates correctness of messages being sent from @@ -35,7 +40,8 @@ export function validate(msg: any): ClientToHost { navRequest: navRequestDecoder, notifyRequest: notifyDecoder, toastRequest: notifyDecoder, - modalRequest: modalDecoder + modalRequest: modalDecoder, + pageMetadata: pageMetadataDecoder }) )(msg); } diff --git a/packages/iframe-coordinator/src/messages/PageMetadata.ts b/packages/iframe-coordinator/src/messages/PageMetadata.ts new file mode 100644 index 0000000..f3bda53 --- /dev/null +++ b/packages/iframe-coordinator/src/messages/PageMetadata.ts @@ -0,0 +1,60 @@ +import { + array, + constant, + Decoder, + mixed, + object, + optional, + string +} from 'decoders'; +import { labeledDecoder, LabeledMsg } from './LabeledMsg'; + +/** + * The Page metadata + */ +export interface PageMetadata { + /** Title of the Page for the browser */ + title: string; + /** Breadcrumbs that lead to page */ + breadcrumbs: Breadcrumb[]; + /** holder for any custom data client wants to send for page */ + custom?: any; +} + +/** + * Single breadcrumb + */ +export interface Breadcrumb { + /** UI text for breadcrumb */ + text: string; + /** link href for routing to breadcrumb's page */ + href: string; +} + +/** + * A message used to send metadata of a page + * from the clients to the host application. + */ +export interface LabeledPageMetadata + extends LabeledMsg<'pageMetadata', PageMetadata> { + /** Message identifier */ + msgType: 'pageMetadata'; + /** Modal request details (type and data) */ + msg: PageMetadata; +} + +const decoder: Decoder = labeledDecoder( + constant<'pageMetadata'>('pageMetadata'), + object({ + title: string, + breadcrumbs: array( + object({ + text: string, + href: string + }) + ), + custom: optional(mixed) + }) +); + +export { decoder };