Skip to content

Commit

Permalink
Added support for saving the layout
Browse files Browse the repository at this point in the history
as well as title and icons.

Also added extra layouts
  • Loading branch information
johnman committed Jun 18, 2024
1 parent 1774e9c commit 3c1bcec
Show file tree
Hide file tree
Showing 20 changed files with 1,634 additions and 798 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { getSettings } from "../platform/settings";

window.addEventListener("DOMContentLoaded", async () => {
if (window.fdc3) {
await init();
} else {
window.addEventListener("fdc3Ready", async () => {
await init();
});
}
});

/**
* Initialize the settings.
*/
async function init(): Promise<void> {
const settings = await getSettings();
if (settings === undefined) {
console.error("Unable to run the example as we have been unable to load the web manifest and it's settings from the currently running html page. Please ensure that the web manifest is being served and that it contains the custom_settings section.");
return;
}

// platform settings
const title = document.querySelector<HTMLInputElement>("#title");
const subTitle = document.querySelector<HTMLInputElement>("#subTitle");
const logo = document.querySelector<HTMLInputElement>("#logo");

// cloud settings
const userId = document.querySelector<HTMLInputElement>("#userId");
const password = document.querySelector<HTMLInputElement>("#password");
const platformId = document.querySelector<HTMLInputElement>("#platformId");
const cloudUrl = document.querySelector<HTMLInputElement>("#cloudUrl");
const sourceId = document.querySelector<HTMLInputElement>("#sourceId");
const sourceDisplayName = document.querySelector<HTMLInputElement>("#sourceDisplayName");

const saveButton = document.querySelector<HTMLButtonElement>("#save");
const resetButton = document.querySelector<HTMLButtonElement>("#reset");
const cancelButton = document.querySelector<HTMLButtonElement>("#cancel");

// assign returned settings to the input fields
if(title === null || subTitle === null || logo === null ||
userId === null || password === null || platformId === null ||
cloudUrl === null || sourceId === null || sourceDisplayName === null ||
saveButton === null || resetButton === null || cancelButton === null) {
console.error("Unable to use settings as there are missing input fields/buttons.");
return;
}

title.value = settings?.platform?.ui?.title;
subTitle.value = settings?.platform?.ui?.subTitle;
logo.value = settings?.platform?.ui?.logo;
userId.value = settings?.platform.cloudInterop?.connectParams?.userId;
password.value = settings?.platform.cloudInterop?.connectParams?.password;
platformId.value = settings?.platform.cloudInterop?.connectParams?.platformId;
cloudUrl.value = settings?.platform.cloudInterop?.connectParams?.url;
sourceId.value = settings?.platform.cloudInterop?.connectParams.sourceId ?? "";
sourceDisplayName.value = settings?.platform.cloudInterop?.connectParams.sourceDisplayName ?? "";

const channel = "platform/settings/dialog";
const appChannel = await window.fdc3.getOrCreateChannel(channel);

saveButton.addEventListener("click", async () => {
settings.platform.ui.title = title.value;
settings.platform.ui.subTitle = subTitle.value;
settings.platform.ui.logo = logo.value;
settings.platform.cloudInterop.connectParams.userId = userId.value;
settings.platform.cloudInterop.connectParams.password = password.value;
settings.platform.cloudInterop.connectParams.platformId = platformId.value;
settings.platform.cloudInterop.connectParams.url = cloudUrl.value;
settings.platform.cloudInterop.connectParams.sourceId = sourceId.value;
settings.platform.cloudInterop.connectParams.sourceDisplayName = sourceDisplayName.value;

// an example of using an app channel.
await appChannel.broadcast({ type: "platform.settings.dialog.action", id: { action: "save-reload" }, settings });
});

resetButton.addEventListener("click", async () => {
// an example of using an app channel.
await appChannel.broadcast({ type: "platform.settings.dialog.action", id: { action: "reset-reload" } });
});

cancelButton.addEventListener("click", async () => {
// an example of using an app channel.
await appChannel.broadcast({ type: "platform.settings.dialog.action", id: { action: "close" } });
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,21 @@ export async function getApps(): Promise<PlatformApp[]> {
return cachedApps;
}
const settings = await getSettings();
if (settings?.platform?.app?.directory) {
const response = await fetch(settings.platform.app.directory);
const appDirectory = (await response.json()) as { applications: PlatformApp[] };
cachedApps = appDirectory.applications;
return cachedApps;
}
if (Array.isArray(settings?.platform?.app?.directory)) {
// Fetch data from all URLs concurrently
const responses = await Promise.all(
settings.platform.app.directory.map(async (url) => fetch(url))
);
// Parse the JSON from all responses
const appDirectories = await Promise.all(
responses.map(async (response) => response.json())
);
// Combine all applications into a single array
cachedApps = appDirectories.flatMap(
(appDirectory) => appDirectory.applications
);
return cachedApps;
}
cachedApps = [];
return cachedApps;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,29 +50,51 @@ export function makeOverride(
}
}

/**
* Our implementation of getLayoutSnapshot that contains titles.
* @returns Promise<PlatformLayoutSnapshot>
*/
public async getLayoutSnapshot(): Promise<PlatformLayoutSnapshot> {
const layoutSnapshot = await super.getLayoutSnapshot();
const platformLayoutSnapshot: PlatformLayoutSnapshot = {
layouts: layoutSnapshot.layouts,
layoutTitles: {},
layoutSelected: this._selectedLayout
};
for (const layout of this._layoutMapArray) {
if(layout.layoutTitle !== undefined) {
platformLayoutSnapshot.layoutTitles[layout.layoutName] = layout.layoutTitle;
}
}
return platformLayoutSnapshot;
}

/**
* Override for applying multiple snapshots.
* @param snapshot The layouts object containing the fixed set of available layouts.
*/
public async applyLayoutSnapshot(snapshot: WebLayoutSnapshot): Promise<void> {
console.log(`[Apply Layout] Does this exist? ${Boolean(this._layoutContainer)}`);
if (this._layoutContainer !== null && this._layoutContainer !== undefined) {
const snapShotWithTitles = snapshot as PlatformLayoutSnapshot;
const platformLayoutSnapshot = snapshot as PlatformLayoutSnapshot;
for (const [key, value] of Object.entries(snapshot.layouts)) {
const layoutTitle = platformLayoutSnapshot?.layoutTitles === undefined
? undefined : platformLayoutSnapshot.layoutTitles[key];
this._layoutMapArray.push({
layoutName: key,
layoutTitle: snapShotWithTitles?.layoutTitles[key],
layoutTitle,
layout: value,
container: this._layoutContainer
});
}
setTimeout(async () => {
const entries = Object.entries(snapshot.layouts);
const entries = Object.entries(platformLayoutSnapshot.layouts);
let entryInstance = 0;
for (const entry of entries) {
entryInstance++;
const layoutName = entry[0];
await this.createLayout(layoutName, entry[1], entryInstance, entries.length);
await this.createLayout(layoutName, entry[1], entryInstance, entries.length,
platformLayoutSnapshot.layoutSelected);
}
}, 1000);
console.log("[Apply Layout] Layouts loaded");
Expand Down Expand Up @@ -178,12 +200,14 @@ export function makeOverride(
* @param layout LayoutOptions.
* @param entry the entry from the batch that is being created.
* @param length the total number of layouts to create.
* @param selectedLayout the layout that is selected.
*/
private async createLayout(
layoutName: string,
layout: OpenFin.LayoutOptions,
entry: number,
length: number
length: number,
selectedLayout: string | undefined
): Promise<void> {
// Create a new div container for the layout.
const container = document.createElement("div");
Expand All @@ -192,8 +216,9 @@ export function makeOverride(
container.style.display = "none";
this._layoutContainer?.append(container);
if (entry === length) {
this.bindLayoutSelector(layoutName);
await this.showLayout({ layoutName, uuid: fin.me.uuid, name: fin.me.name });
this.bindLayoutSelector(selectedLayout ?? layoutName);
await this.showLayout({ layoutName: selectedLayout ?? layoutName,
uuid: fin.me.uuid, name: fin.me.name });
}
// Finally, call the Layout.create() function to apply the snapshot layout to the div we just created.
await fin.Platform.Layout.create({ layoutName, layout, container });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
import type { WebLayoutSnapshot } from "@openfin/core-web";
import type { Settings } from "../shapes/setting-shapes";
import type { ManifestSettings, Settings } from "../shapes/setting-shapes";

/**
* Fetches the settings for the application.
* @returns The settings for the application.
*/
export async function getSettings(): Promise<Settings | undefined> {
const savedSettings = await getSavedSettings();
if (savedSettings) {
return savedSettings;
}
const settings = await getManifestSettings();
if (settings === undefined) {
if (!Array.isArray(settings?.endpointProvider?.endpoints)) {
console.error(
"Unable to run the example as settings are required and we fetch them from the link web manifest from the html page that is being served. It should exist in the customSettings section of the web manifest."
);
return;
}
const settingsEndpoint = settings.endpointProvider.endpoints.find((endpoint) => endpoint.id === "platform-settings");

if(settingsEndpoint === undefined || settingsEndpoint.type !== "fetch" || settingsEndpoint.options.method !== "GET" || settingsEndpoint.options.url === undefined) {
console.error(
"Unable to run the example as settings are required and we fetch them from the endpoint defined with the id: 'platform-settings' in the manifest. It needs to be of type fetch, performing a GET and it must have a url defined."
);
return;
}
return settings;
const platformSettings = await fetch(settingsEndpoint?.options.url);
const settingsJson = (await platformSettings.json()) as Settings;
return settingsJson;
}

/**
Expand All @@ -39,12 +54,54 @@ export async function getDefaultLayout(): Promise<WebLayoutSnapshot | undefined>
* Returns the settings from the manifest file.
* @returns customSettings for this example
*/
async function getManifestSettings(): Promise<Settings | undefined> {
async function getManifestSettings(): Promise<ManifestSettings | undefined> {
// Get the manifest link
const link = document.querySelector<HTMLLinkElement>('link[rel="manifest"]');
if (link !== null) {
const manifestResponse = await fetch(link.href);
const manifestJson = (await manifestResponse.json()) as { custom_settings: Settings };
const manifestJson = (await manifestResponse.json()) as { custom_settings: ManifestSettings };
return manifestJson.custom_settings;
}
}

/**
* Clears any saved settings.
* @returns The saved settings.
*/
export async function clearSettings(): Promise<void> {
const settingsId = getSavedSettingsId();
localStorage.removeItem(settingsId);
}

/**
* Saves the settings.
* @param settings The settings to save.
*/
export async function saveSettings(settings: Settings): Promise<void> {
const settingsId = getSavedSettingsId();
localStorage.setItem(settingsId, JSON.stringify(settings));
}

/**
* Retrieves saved settings from local storage.
* @returns The saved settings.
*/
async function getSavedSettings(): Promise<Settings | undefined> {
const settingsId = getSavedSettingsId();
const settings = localStorage.getItem(settingsId);
if (settings !== null) {
return JSON.parse(settings);
}
}

/**
* Get the Id used for saving and fetching settings from storage.
* @returns The settings id.
*/
function getSavedSettingsId(): string {
const urlParams = new URLSearchParams(window.location.search);
const env = urlParams.get("env");

const settingsKey = env ? `${env}-settings` : "settings";
return settingsKey;
}
Loading

0 comments on commit 3c1bcec

Please sign in to comment.