Portal Contexts
Two distinct approaches dictate how a portal manages applications and context, and this determination hinges on whether ContextTypes are specified within the base portal configuration object.
Context-Centric Approach
In this paradigm, users are required to select a contest prior to accessing any allocations. This ensures that applications served are tailored to the specific context, empowering businesses to dictate which applications their users encounter.
Application-Centric Approach
Under this framework, while administration remains necessary, applications can be seamlessly integrated into a portal, granting users access to all available applications upon startup. This approach allows applications to operate independently of context or dependency, with the portal dynamically responding to each application's requirements.
Onboarding Context and Portal Behaviors.
The current setup of the project portal requires a context to undergo onboarding before it can be utilized. This measure is implemented to prevent an overwhelming number of contexts from being enabled simultaneously. However, upon further consideration, the entire process of context onboarding may be deemed unnecessary if the context only intends to utilize global applications. By "global applications," I refer to those that support any context type or share the same context type as the selected contexts.
Currently, preventing access to contexts involves straightforward frontend code that triggers a modal when an un-onboarded context is selected. This functionality may be eliminated at some point to allow access to all contexts supported by the current portal.
Nevertheless, there remains a valid reason to continue onboarding contexts, particularly to accommodate context-specific applications. As a result, administrative contexts may be minimized to essential functionalities.
Context Implementation
to day the implementation of context in the portal had been identified as not optimal code is not centralized. This work should not be much for a fairly competent developer with knowledge to fusion framework and context. But the code is spread throughput. in this section i will try to locate all context related implementation to ease this work.
client/packages/portal-client/src/lib/portal-framework-config.ts
Context local storage setup / history
In this file there are two things done.
// Todo: should be moved to context setup section
fusion.portalConfig.state$.subscribe((state) => {
if (state?.portal?.contexts) {
configurePortalContext(fusion.context);
}
});
the configurePortalContext is for storing the current context in localStorage
and providing the context history.
Context URL handler
the next section in this file is url handling on context change and navigation if no context is set.
// Todo: should be moved to context setup section
fusion.context.currentContext$.pipe(skip(1)).subscribe((context) => {
const { navigator } = fusion.navigation;
const client = fusion.telemetry?.client;
if (!context) {
navigator.replace('/');
} else {
client?.trackEvent(
{
name: 'onContextChange',
},
{
contextId: context?.id,
contextTitle: context?.title,
source: 'context',
}
);
}
if (context && context.id && !window.location.pathname.includes(context.id)) {
const to = { pathname, search: window.location.search, hash: window.location.hash };
const pathname = replaceContextInPathname(context.id, window.location.pathname);
navigator.replace(to);
}
});
client/packages/portal-client/src/pages/AppPage/AppPage.tsx
Context and legacy applicators
This section should also be relocated to the context setup section. The primary purpose of the first event listener is to assist legacy applications in ensuring that context is included in the URL. It addresses the variability in how some applications handle this aspect, with some including context while others do not.
The second event listener ensures that the context is appropriately set for the loaded applications, specifically focusing on the new context implementation. Perhaps it would be beneficial to also incorporate the legacy context manager within this setup.
// todo move to context in core. handling legacy context
const useAppContextHandler = () => {
const { contextId } = useParams();
const framework = useFramework<[AppModule, NavigationModule]>();
const context = useFrameworkCurrentContext();
useEffect(() => {
return framework.modules.event.addEventListener('onReactAppLoaded', (e) => {
const contextProvider = (e.detail.modules as AppModulesInstance<[ContextModule]>).context;
if (contextProvider && context && !contextId && !verifyContextInURL(window.location.pathname)) {
framework.modules.navigation.replace(`${window.location.pathname}${context.id}`);
}
});
}, [framework, contextId, context]);
useEffect(() => {
return framework.modules.event.addEventListener('onReactAppLoaded', (e) => {
console.debug('onReactAppLoaded', 'using legacy context hack method');
const contextProvider = (e.detail.modules as AppModulesInstance<[ContextModule]>).context;
if (contextProvider && !contextProvider.currentContext && context) {
contextProvider.setCurrentContextAsync(context);
}
});
}, [framework, context]);
};
the legacy-Application loader has it's own context setup se the LegacyContextManager
this should be moved or incorporated with teh above onReactAppLoaded
section as this does that same thing but on two different systems.
but both need to be set, especial on a context driven portal.
//... more code
context.currentContext$
.pipe(
tap((x) => args.featureLogger.setCurrentContext(x?.id ?? null, x?.title ?? null)),
filter((x): x is ContextItem => !!x),
scan((acc, value) => {
if (!acc.find((x) => x.id === value.id)) {
return [value, ...acc].slice(0, 9);
}
return acc;
}, [] as Array<ContextItem>)
)
.subscribe((values) => {
const currentContext = values.shift();
this.setAsync('history', values);
this.setAsync('current', currentContext ?? null);
if (currentContext) {
args.featureLogger.log('Context selected', '0.0.1', {
selectedContext: currentContext,
// why do we need and array of all contexts?
previusContexts: values.map((c) => ({ id: c.id, name: c.title })),
});
}
});
//... more code