@equinor/fusion
Advanced tools
Comparing version 0.1.38 to 0.1.39
@@ -0,18 +1,27 @@ | ||
/// <reference types="react" /> | ||
import AppManifest from "./AppManifest"; | ||
import EventEmitter from "../utils/EventEmitter"; | ||
declare type RegisteredApp = { | ||
appKey: string; | ||
manifest: AppManifest; | ||
import ApiClients from "../http/apiClients"; | ||
declare type AppRegistration = { | ||
AppComponent: React.ComponentType; | ||
}; | ||
declare type AppContainerEvents = { | ||
update: (app: RegisteredApp) => void; | ||
update: (app: AppManifest) => void; | ||
change: (app: AppManifest) => void; | ||
}; | ||
export default class AppContainer extends EventEmitter<AppContainerEvents> { | ||
currentApp: AppManifest | null; | ||
private apps; | ||
private readonly fusionClient; | ||
constructor(apiClients: ApiClients); | ||
updateManifest(appKey: string, manifest: AppManifest): void; | ||
get(appKey: string): RegisteredApp | null; | ||
getAll(): readonly RegisteredApp[]; | ||
get(appKey: string | null): AppManifest | null; | ||
getAll(): readonly AppManifest[]; | ||
setCurrentAppAsync(appKey: string | null): Promise<this | undefined>; | ||
getAllAsync(): Promise<readonly AppManifest[]>; | ||
private addOrUpdate; | ||
} | ||
declare const appContainer: AppContainer; | ||
declare const registerApp: (appKey: string, manifest: AppManifest) => void; | ||
export { registerApp, appContainer, AppManifest }; | ||
declare const appContainerFactory: (appContainer: AppContainer) => void; | ||
declare const registerApp: (appKey: string, manifest: AppRegistration) => void; | ||
declare const useCurrentApp: () => AppManifest | null; | ||
export { registerApp, appContainerFactory, AppManifest, useCurrentApp }; |
import EventEmitter from "../utils/EventEmitter"; | ||
import { useFusionContext } from "../core/FusionContext"; | ||
export default class AppContainer extends EventEmitter { | ||
constructor() { | ||
super(...arguments); | ||
constructor(apiClients) { | ||
super(); | ||
this.currentApp = null; | ||
this.apps = []; | ||
this.fusionClient = apiClients.fusion; | ||
} | ||
@@ -10,13 +13,12 @@ updateManifest(appKey, manifest) { | ||
if (existingApp === null) { | ||
const newApp = { appKey, manifest }; | ||
this.apps.push(newApp); | ||
this.emit("update", newApp); | ||
const newApp = manifest; | ||
this.addOrUpdate(newApp); | ||
} | ||
else { | ||
existingApp.manifest = Object.assign({}, existingApp.manifest, manifest); | ||
this.emit("update", existingApp); | ||
const updatedApp = Object.assign({}, existingApp, manifest); | ||
this.addOrUpdate(updatedApp); | ||
} | ||
} | ||
get(appKey) { | ||
return this.apps.find(app => app.appKey === appKey) || null; | ||
return this.apps.find(app => app.key === appKey) || null; | ||
} | ||
@@ -26,5 +28,58 @@ getAll() { | ||
} | ||
async setCurrentAppAsync(appKey) { | ||
const app = this.get(appKey); | ||
if (app || !appKey) { | ||
this.currentApp = app; | ||
return this.emit("change", app); | ||
} | ||
const { data: manifest } = await this.fusionClient.getAppManifestAsync(appKey); | ||
const appManifest = manifest; | ||
this.updateManifest(appKey, appManifest); | ||
await this.fusionClient.loadAppScriptAsync(appKey); | ||
this.currentApp = appManifest; | ||
this.emit("change", manifest); | ||
} | ||
async getAllAsync() { | ||
const response = await this.fusionClient.getAppsAsync(); | ||
response.data.forEach(manifest => this.updateManifest(manifest.key, manifest)); | ||
return this.getAll(); | ||
} | ||
addOrUpdate(app) { | ||
const existingApp = this.get(app.key); | ||
if (existingApp) { | ||
this.apps = this.apps.map(a => (a.key === app.key ? app : a)); | ||
} | ||
else { | ||
this.apps = [...this.apps, app]; | ||
} | ||
this.emit("update", app); | ||
} | ||
} | ||
const appContainer = new AppContainer(); | ||
const registerApp = (appKey, manifest) => appContainer.updateManifest(appKey, manifest); | ||
export { registerApp, appContainer }; | ||
let appContainerSingleton = null; | ||
let appContainerPromise = null; | ||
let setAppContainerSingleton; | ||
const appContainerFactory = (appContainer) => { | ||
if (setAppContainerSingleton) { | ||
setAppContainerSingleton(appContainer); | ||
} | ||
}; | ||
const getAppContainer = () => { | ||
if (appContainerSingleton) { | ||
return Promise.resolve(appContainerSingleton); | ||
} | ||
if (appContainerPromise) { | ||
return appContainerPromise; | ||
} | ||
appContainerPromise = new Promise(resolve => { | ||
setAppContainerSingleton = resolve; | ||
}); | ||
return appContainerPromise; | ||
}; | ||
const registerApp = (appKey, manifest) => { | ||
getAppContainer().then(appContainer => appContainer.updateManifest(appKey, manifest)); | ||
}; | ||
const useCurrentApp = () => { | ||
const { app } = useFusionContext(); | ||
return app.container.currentApp; | ||
}; | ||
export { registerApp, appContainerFactory, useCurrentApp }; |
import React from "react"; | ||
import { Route, Link, Switch } from "react-router-dom"; | ||
import { useAppContext } from "./AppContext"; | ||
import { useCurrentApp } from "./AppContainer"; | ||
import combineUrls from "../utils/combineUrls"; | ||
const createAppPath = (appContext, location) => { | ||
return combineUrls("/apps", appContext.appKey, location.toString()); | ||
return combineUrls("/apps", appContext.key, location.toString()); | ||
}; | ||
const createLocationDescriptorFromContext = (appContext) => ({ | ||
pathname: appContext.appPath, | ||
pathname: combineUrls("/apps", appContext.key), | ||
search: "", | ||
@@ -21,4 +21,4 @@ state: null, | ||
const AppRoute = props => { | ||
const appContext = useAppContext(); | ||
if (!appContext || !appContext.appKey) { | ||
const appContext = useCurrentApp(); | ||
if (!appContext || !appContext.key) { | ||
return null; | ||
@@ -36,4 +36,4 @@ } | ||
const AppLink = props => { | ||
const appContext = useAppContext(); | ||
if (!appContext || !appContext.appKey) { | ||
const appContext = useCurrentApp(); | ||
if (!appContext || !appContext.key) { | ||
return null; | ||
@@ -49,4 +49,4 @@ } | ||
const AppSwitch = props => { | ||
const appContext = useAppContext(); | ||
if (!appContext || !appContext.appKey) { | ||
const appContext = useCurrentApp(); | ||
if (!appContext || !appContext.key) { | ||
return null; | ||
@@ -53,0 +53,0 @@ } |
@@ -1,8 +0,18 @@ | ||
import React, { useState, useEffect, useCallback } from "react"; | ||
import React, { useState, useEffect, useMemo } from "react"; | ||
import { Router } from "react-router-dom"; | ||
import { createBrowserHistory } from "history"; | ||
import { useFusionContext } from "../core/FusionContext"; | ||
import AppContext from "./AppContext"; | ||
import combineUrls from "../utils/combineUrls"; | ||
const AppWrapper = ({ appKey }) => { | ||
const { app: { container: appContainer }, http: { apiClients }, } = useFusionContext(); | ||
const { app: { container: appContainer }, } = useFusionContext(); | ||
const [isFetching, setIsFetching] = useState(false); | ||
const currentApp = appContainer.get(appKey); | ||
const setCurrentApp = async () => { | ||
setIsFetching(true); | ||
await appContainer.setCurrentAppAsync(appKey); | ||
setIsFetching(false); | ||
}; | ||
useEffect(() => { | ||
setCurrentApp(); | ||
}, [appKey]); | ||
const [, forceUpdate] = useState(); | ||
@@ -15,3 +25,3 @@ useEffect(() => { | ||
return appContainer.on("update", app => { | ||
if (app.appKey === appKey) { | ||
if (app.key === appKey) { | ||
forceUpdate(null); | ||
@@ -21,33 +31,16 @@ } | ||
}, [appKey]); | ||
const loadAppAsync = useCallback(async () => { | ||
const app = appContainer.get(appKey); | ||
if (app && app.manifest && app.manifest.AppComponent) { | ||
return; | ||
} | ||
setIsFetching(true); | ||
const { data: manifest } = await apiClients.fusion.getAppManifestAsync(appKey); | ||
appContainer.updateManifest(appKey, manifest); | ||
await apiClients.fusion.loadAppScriptAsync(appKey); | ||
setIsFetching(false); | ||
}, [appKey]); | ||
useEffect(() => { | ||
loadAppAsync(); | ||
}, [appKey]); | ||
const appHistory = useMemo(() => createBrowserHistory({ basename: combineUrls("app", appKey) }), [appKey]); | ||
if (currentApp === null && isFetching) { | ||
return React.createElement("div", null, "Is fetching"); | ||
} | ||
if (currentApp === null) { | ||
if (!currentApp) { | ||
return React.createElement("div", null, "Unable to find app"); | ||
} | ||
if (!currentApp.manifest || !currentApp.manifest.AppComponent) { | ||
const AppComponent = currentApp.AppComponent; | ||
if (!AppComponent) { | ||
return null; | ||
} | ||
const AppComponent = currentApp.manifest.AppComponent; | ||
return (React.createElement(AppContext.Provider, { value: { | ||
appKey: appKey, | ||
appPath: "apps/" + appKey, | ||
manifest: currentApp.manifest, | ||
} }, | ||
return (React.createElement(Router, { history: appHistory }, | ||
React.createElement(AppComponent, null))); | ||
}; | ||
export default AppWrapper; |
@@ -40,2 +40,3 @@ import AuthApp from "./AuthApp"; | ||
await this.cacheUserAsync(cachedUser); | ||
window.location.hash = ""; | ||
} | ||
@@ -42,0 +43,0 @@ catch (e) { |
@@ -11,3 +11,2 @@ import { MutableRefObject } from "react"; | ||
import AppContainer from "../app/AppContainer"; | ||
import AppManifest from "../app/AppManifest"; | ||
import { ComponentDisplayType } from "../core/ComponentDisplayType"; | ||
@@ -41,7 +40,2 @@ import ContextManager from "./ContextManager"; | ||
container: AppContainer; | ||
currentApp: { | ||
appKey: string; | ||
appPath: string; | ||
manifest: AppManifest | null; | ||
}; | ||
}; | ||
@@ -48,0 +42,0 @@ export interface IFusionContext { |
@@ -9,3 +9,3 @@ import { createContext, useContext } from "react"; | ||
import SettingsContainer from "../settings/SettingsContainer"; | ||
import { appContainer } from "../app/AppContainer"; | ||
import AppContainer, { appContainerFactory } from "../app/AppContainer"; | ||
import { ComponentDisplayType } from "../core/ComponentDisplayType"; | ||
@@ -36,2 +36,4 @@ import ContextManager from "./ContextManager"; | ||
const coreSettings = new SettingsContainer("core", authContainer.getCachedUser(), defaultSettings); | ||
const appContainer = new AppContainer(apiClients); | ||
appContainerFactory(appContainer); | ||
// Try to get the current context id from the current route if a user navigates directly to the app/context | ||
@@ -59,7 +61,2 @@ const contextRouteMatch = matchPath("apps/:appKey/:contextId", { | ||
container: appContainer, | ||
currentApp: { | ||
appKey: "", | ||
appPath: "/", | ||
manifest: null, | ||
}, | ||
}, | ||
@@ -66,0 +63,0 @@ contextManager, |
@@ -5,5 +5,5 @@ import { HttpResponse } from "../HttpClient"; | ||
export default class FusionClient extends BaseApiClient { | ||
getAppsAsync(): Promise<HttpResponse<any>>; | ||
getAppsAsync(): Promise<HttpResponse<AppManifest[]>>; | ||
getAppManifestAsync(appKey: string): Promise<HttpResponse<AppManifest>>; | ||
loadAppScriptAsync(appKey: string): Promise<void>; | ||
} |
@@ -7,2 +7,8 @@ import { ContextTypes } from '../../context'; | ||
declare type AppManifest = { | ||
key: string; | ||
name: string; | ||
shortName: string; | ||
version: string; | ||
description: string; | ||
tags: string[]; | ||
contextTypes?: ContextTypes[]; | ||
@@ -9,0 +15,0 @@ auth?: AppAuth; |
export { IAuthContainer, default as AuthContainer } from "./auth/AuthContainer"; | ||
export { default as useCurrentUser } from "./auth/useCurrentUser"; | ||
export { registerApp, appContainer } from "./app/AppContainer"; | ||
export { default as AppWrapper } from "./app/AppWrapper"; | ||
export { default as AppContext, IAppContext, useAppContext } from "./app/AppContext"; | ||
export { AppRoute, AppLink, AppSwitch } from "./app/AppRouter"; | ||
export { registerApp, useCurrentApp } from "./app/AppContainer"; | ||
export { default as FusionContext, IFusionContext, useFusionContext, createFusionContext } from "./core/FusionContext"; | ||
@@ -18,2 +15,3 @@ export { default as ServiceResolver } from "./http/resourceCollections/ServiceResolver"; | ||
export { useComponentDisplayType, ComponentDisplayType } from "./core/ComponentDisplayType"; | ||
export { default as combineUrls } from "./utils/combineUrls"; | ||
export * from "./http/hooks/dataProxy/useHandover"; |
export { default as AuthContainer } from "./auth/AuthContainer"; | ||
export { default as useCurrentUser } from "./auth/useCurrentUser"; | ||
export { registerApp, appContainer } from "./app/AppContainer"; | ||
export { default as AppWrapper } from "./app/AppWrapper"; | ||
export { default as AppContext, useAppContext } from "./app/AppContext"; | ||
export { AppRoute, AppLink, AppSwitch } from "./app/AppRouter"; | ||
export { registerApp, useCurrentApp } from "./app/AppContainer"; | ||
export { default as FusionContext, useFusionContext, createFusionContext } from "./core/FusionContext"; | ||
@@ -17,2 +14,3 @@ export { default as HttpClient } from "./http/HttpClient"; | ||
export { useComponentDisplayType, ComponentDisplayType } from "./core/ComponentDisplayType"; | ||
export { default as combineUrls } from "./utils/combineUrls"; | ||
export * from "./http/hooks/dataProxy/useHandover"; |
import { useState, useEffect } from "react"; | ||
import { useFusionContext } from "../core/FusionContext"; | ||
import { useAppContext } from "../app/AppContext"; | ||
import { useCurrentApp } from "../app/AppContainer"; | ||
import SettingsContainer from "./SettingsContainer"; | ||
@@ -17,4 +17,4 @@ import useCurrentUser from '../auth/useCurrentUser'; | ||
const { settings } = useFusionContext(); | ||
const { appKey } = useAppContext(); | ||
let appSettings = ensureAppSettings(settings, appKey); | ||
const currentApp = useCurrentApp(); | ||
let appSettings = ensureAppSettings(settings, currentApp ? currentApp.key : ""); | ||
const [localAppSettings, setLocalAppsettings] = useState(appSettings.toObject() || {}); | ||
@@ -21,0 +21,0 @@ useEffect(() => { |
{ | ||
"name": "@equinor/fusion", | ||
"version": "0.1.38", | ||
"version": "0.1.39", | ||
"description": "Everything a Fusion app needs to communicate with the core", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
114250
2644