Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: portal framework #781

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2cf89d2
feat: portal framework poc
Noggling Sep 2, 2024
f9dbe6a
Refactor main.tsx to remove unused imports and components
Noggling Sep 2, 2024
5e89697
chore: update
Noggling Sep 2, 2024
f5c3b73
poc
Noggling Sep 3, 2024
0a96511
chore: allowing for other portals
Noggling Sep 5, 2024
249951e
fix: handle missing basename in useAppLoader
Noggling Sep 10, 2024
238bf3e
fix: handle missing basename in useAppLoader
Noggling Sep 10, 2024
ac10ac8
fix: Update portal configuration types to include new properties
Noggling Sep 11, 2024
a202b67
feat: Update ProjectPage logic to handle missing contextId
Noggling Sep 16, 2024
fa974a3
chore: update style components (#770)
Noggling Sep 23, 2024
400daca
chore: remove unused hook use-store-current-view-id (#759)
Noggling Sep 23, 2024
433f4ef
Merge branch 'main' into feat/portal-framework
Noggling Sep 24, 2024
df5bef5
chore: Update style components to latest version
Noggling Sep 24, 2024
78b60f3
chore: Remove unused code for portal configuration
Noggling Sep 24, 2024
97559a6
chore: Remove unused code for portal configuration
Noggling Sep 24, 2024
a1d8cc3
chore: Refactor AppIcon component and update dependencies
Noggling Sep 24, 2024
c393601
chore: Update dependencies and refactor AppIcon component
Noggling Sep 24, 2024
a98035f
Merge branch 'main' into feat/portal-framework
Noggling Sep 25, 2024
d77b701
refactor: Remove unused import and unnecessary code in portal-framewo…
Noggling Sep 26, 2024
da8279f
refactor: Remove unused import and unnecessary code in portal-framewo…
Noggling Sep 30, 2024
c2b6ae6
refactor: Update portal-config module to handle optional ref parameter
Noggling Sep 30, 2024
ac41f95
refactor: Update portal-config module to handle optional ref parameter
Noggling Sep 30, 2024
c1dd083
refactor: Update portal-config module to handle optional ref paramete…
Noggling Sep 30, 2024
85e3559
refactor: Update PortalRouter component to display "Configuring Porta…
Noggling Sep 30, 2024
7ef957b
refactor: Remove legacyAppLoader files and configurations
Noggling Oct 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changeset/pr-759-2080482692.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

---
---
3 changes: 3 additions & 0 deletions .changeset/pr-770-2086136734.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

---
---
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"type": "module",
"main": "src/index.ts",
"scripts": {
"prebuild": "rm -f ../client/packages/portal-client/src/assets/appLegacyLoader.js",
"build": "fusion-framework-cli app build && mv ./dist/app-bundle.js ../client/packages/portal-client/src/assets/appLegacyLoader.js",
"prebuild": "rm -f ../../packages/portal-client/src/assets/appLegacyLoader.js",
"build:appLoader": "fusion-framework-cli app build && mv ./dist/app-bundle.js ../../packages/portal-client/src/assets/appLegacyLoader.js",
"build:resources": "tsc && vite build",
"dev": "fusion-framework-cli app dev -c vite.config.js",
"docker": "cd .. && sh docker-script.sh app-react",
Expand Down Expand Up @@ -42,4 +42,4 @@
"@types/react-router-dom": "^5.3.3",
"vite-plugin-static-copy": "^0.17.0"
}
}
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { lazy } from 'react';
import AppWrapperLegacy, { getLegacyFusion } from './LegacyAppWrapper';

import { AppConfig } from '@equinor/fusion-framework-module-app';
import { AppManifest as LegacyAppManifest } from '@equinor/fusion';

import LegacyAppContainer from '../legacy-interopt/LegacyAppContainer';
import { MessagePage } from './MessagePage';
export type LegacyEnv = {
basename: string;
config: AppConfig;
manifest: LegacyAppManifest;
};

export const createLegacyAppLoader = (appKey: string) =>
lazy(async () => {
const appContainer = getLegacyFusion().app.container as LegacyAppContainer;
const [basename] = window.location.pathname.match(/\/?apps\/[a-z|-]+\//) ?? [''];

if (Object.keys(appContainer.allApps).length === 0) {
await appContainer.getAllAsync();
}

const config = await appContainer.setCurrentAppAsync(appKey);

if (!config) {
return {
default: () => <MessagePage type="Warning" title="No config" />,
};
}

const env = {
basename,
config,
manifest: { ...appContainer.currentApp } as LegacyAppManifest,
};

return {
default: () => (
<>
<AppWrapperLegacy appKey={appKey} env={env} />
</>
),
};
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Suspense, useMemo } from 'react';

import { useFramework } from '@equinor/fusion-framework-react';

import { GLOBAL_FUSION_CONTEXT_KEY } from '../legacy-interopt/static';
import { createLegacyRender } from '../legacy-interopt';

import { MessagePage } from './MessagePage';
import { ProgressLoader } from './ProgressLoader';

import { LegacyEnv } from './LegacyAppLoader';

const DEBUG_LOG = false;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
export const getLegacyFusion = () => window[GLOBAL_FUSION_CONTEXT_KEY];
/**
* Legacy wrapper element
* this should be removed in future when applications are moved over to ESM
*/

export const AppWrapperLegacy = (props: { appKey: string; env: LegacyEnv }): JSX.Element => {
const { appKey, env } = props;
const fusion = useFramework();
const legacyFusion = getLegacyFusion();
const manifest = getLegacyFusion().app.container.get(appKey) || null;

const AppComponent = useMemo(() => {
if (!manifest) {
console.warn('🌍❗️ Portal Legacy:', 'missing application manifest');
return null;
}

/** sanity check if the `registerApp` has been loaded */
if (!manifest.render && !manifest.AppComponent) {
DEBUG_LOG &&
console.warn('🌍❗️ Portal Legacy:', 'no render or component, make sure app script is loading');
return null;
}

DEBUG_LOG && console.debug('🌍 Portal:', 'creating application component', manifest);

const render = manifest.render ?? createLegacyRender(manifest, legacyFusion);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return render(fusion, env);
}, [fusion, legacyFusion, manifest, env]);

if (!AppComponent) {
return (
<MessagePage title="Loader Error">
<p>Failed to render application, missing app component</p>
</MessagePage>
);
}
return (
<Suspense fallback={<ProgressLoader title="Loading" />}>
<AppComponent />
</Suspense>
);
};

export default AppWrapperLegacy;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useFramework } from '@equinor/fusion-framework-react';
import { PropsWithChildren } from 'react';

import { AppModule } from '@equinor/fusion-framework-module-app';
import { NavigationModule } from '@equinor/fusion-framework-module-navigation';
import { LegacyFusionWrapper } from '../legacy-interopt/components';
import { useAppModules } from '@equinor/fusion-framework-react-app';
import { ProgressLoader } from './ProgressLoader';

export const LegacyWrapper = ({ children }: PropsWithChildren<unknown>) => {
const framework = useFramework<[AppModule, NavigationModule]>();
const appFramework = useAppModules<[AppModule]>();

return (
<LegacyFusionWrapper
framework={framework}
loader={<ProgressLoader title="Loading" />}
appFramework={appFramework}
>
{children}
</LegacyFusionWrapper>
);
};
File renamed without changes.
44 changes: 24 additions & 20 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"start": "npx lerna run serve",
"build": "npx lerna run build",
"build:apps": "npx lerna run build:apps",
"build:appLoader": "npx lerna run build:appLoader",
"test:all": "test:coverage && build:coverage",
"test": "lerna run test",
"test:coverage": "lerna run test:coverage",
Expand Down Expand Up @@ -64,27 +65,30 @@
"@equinor/eds-core-react": "^0.36.0",
"@equinor/eds-icons": "^0.17.0",
"@equinor/eds-tokens": "^0.9.0",
"@equinor/fusion-framework-app": "^8.1.1",
"@equinor/fusion-framework-module-ag-grid": "^31.0.1",
"@equinor/fusion-framework-module-app": "^5.2.13",
"@equinor/fusion-framework-module-context": "^4.0.21",
"@equinor/fusion-framework-module-feature-flag": "^1.0.2",
"@equinor/fusion-framework-module-http": "^5.1.6",
"@equinor/fusion-framework-module-navigation": "^3.1.4",
"@equinor/fusion-framework-module-services": "^3.2.4",
"@equinor/fusion-framework-module-signalr": "^2.0.19",
"@equinor/fusion-framework-react": "^6.0.2",
"@equinor/fusion-framework-react-app": "^4.3.3",
"@equinor/fusion-framework-react-components-bookmark": "0.3.7",
"@equinor/fusion-framework-react-components-people-provider": "^1.1.15",
"@equinor/fusion-framework-react-module-signalr": "^2.0.18",
"@equinor/fusion-observable": "^8.1.5",
"@equinor/fusion-react-context-selector": "^0.6.0",
"@equinor/fusion-react-person": "^0.7.0",
"@equinor/fusion-react-side-sheet": "1.3.0",
"@equinor/fusion-framework-app": "^9.1.8",
"@equinor/fusion-framework-module-ag-grid": "^32.2.0",
"@equinor/fusion-framework-module-app": "^5.3.11",
"@equinor/fusion-framework-module-context": "^5.0.12",
"@equinor/fusion-framework-module-feature-flag": "^1.1.9",
"@equinor/fusion-framework-module-http": "^6.1.0",
"@equinor/fusion-framework-module-msal": "^3.1.5",
"@equinor/fusion-framework-module-navigation": "^4.0.7",
"@equinor/fusion-framework-module-service-discovery": "^8.0.0",
"@equinor/fusion-framework-module-services": "^4.1.4",
"@equinor/fusion-framework-module-signalr": "^4.0.0",
"@equinor/fusion-framework-react": "^7.2.2",
"@equinor/fusion-framework-react-app": "^5.2.8",
"@equinor/fusion-framework-react-components-bookmark": "0.5.0",
"@equinor/fusion-framework-react-components-people-provider": "^1.4.7",
"@equinor/fusion-framework-react-module-signalr": "^3.0.15",
"@equinor/fusion-observable": "^8.4.1",
"@equinor/fusion-react-context-selector": "^0.6.6",
"@equinor/fusion-react-person": "^0.9.2",
"@equinor/fusion-react-side-sheet": "1.3.3",
"@equinor/fusion-react-skeleton": "^0.3.0",
"@equinor/fusion-react-styles": "^0.6.1",
"@equinor/fusion-react-styles": "^0.6.2",
"@equinor/fusion-react-tooltip": "^1.1.11",
"@equinor/fusion-react-utils": "^2.1.1",
"@hookform/resolvers": "^3.3.2",
"@microsoft/applicationinsights-web": "^3.0.2",
"@microsoft/signalr": "^7.0.0",
Expand All @@ -100,7 +104,7 @@
"react-query": "^3.39.2",
"react-router-dom": "^6.16.0",
"rxjs": "^7.5.7",
"styled-components": "5.3.11",
"styled-components": "^6.1.13",
"swiper": "^9.3.2",
"zod": "^3.22.4"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import styled, { css } from 'styled-components';
import { Skeleton, HTMLSkeletonCustomElement } from '@equinor/fusion-react-skeleton';
import { WebComponent } from '@equinor/fusion-react-utils';
import { tokens } from '@equinor/eds-tokens';

import { AppCardType } from '../../types/types';

export const primaryColor = tokens.colors.interactive.primary__resting.hex;

type ElementProps = React.PropsWithChildren<
Partial<Pick<HTMLSkeletonCustomElement, 'size' | 'variant' | 'inactive' | 'fluid'>>
>;

export const AppIconSkeleton = styled(Skeleton as WebComponent<HTMLSkeletonCustomElement, ElementProps>)<{
$display: AppCardType;
}>`
--fwc-skeleton-fill-color: var(--app-color-skeleton, ${primaryColor}33);
${({ $display }) => {
switch ($display) {
default:
case 'card':
return css`
margin: 1.313rem 0.625rem;
`;
case 'portal':
return css`
margin: 1.625rem 1.25rem;
`;
}
}}
`;
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import styled, { css } from 'styled-components';
import { Skeleton } from '@equinor/fusion-react-skeleton';
import { tokens } from '@equinor/eds-tokens';

import { SkeletonSize, SkeletonVariant } from '@equinor/fusion-react-skeleton';
import { AppCardType } from '../../types/types';
import { defaultIcon } from './defaultIcon';
import { AppManifest } from '../../types/types';
import { AppIconSkeleton, primaryColor } from './IconSceleton';

const primaryColor = tokens.colors.interactive.primary__resting.hex;

export const Styled = {
export const Styles = {
AppIcon: styled.div<{ $display: AppCardType }>`
${({ $display }) => {
switch ($display) {
Expand All @@ -21,7 +19,7 @@ export const Styled = {
`;
case 'card':
return css`
--app-icon-size: 1.5rem;
--app-icon-size: 1.5rem;a
--background-radius: 0.25rem 0 0 0.25rem;
padding: 0 0.375rem;
`;
Expand Down Expand Up @@ -76,22 +74,6 @@ export const Styled = {
return '';
}}
`,
AppIconSkeleton: styled(Skeleton)<{ $display: AppCardType }>`
--fwc-skeleton-fill-color: var(--app-color-skeleton, ${primaryColor}33);
${({ $display }) => {
switch ($display) {
default:
case 'card':
return css`
margin: 1.313rem 0.625rem;
`;
case 'portal':
return css`
margin: 1.625rem 1.25rem;
`;
}
}}
`,
};

type AppIconProps = {
Expand All @@ -106,17 +88,17 @@ export const AppIconContainer = ({ app, display, loading }: AppIconProps): JSX.E

if (loading) {
return (
<Styled.AppIconSkeletonContainer $display={display}>
<Styled.AppIconSkeleton
<Styles.AppIconSkeletonContainer $display={display}>
<AppIconSkeleton
$display={display}
size={display === 'card' ? SkeletonSize.XSmall : SkeletonSize.small}
variant={SkeletonVariant.Square}
/>
</Styled.AppIconSkeletonContainer>
</Styles.AppIconSkeletonContainer>
);
}

return <Styled.AppIcon $display={display} dangerouslySetInnerHTML={{ __html: appIcon || defaultIcon }} />;
return <Styles.AppIcon $display={display} dangerouslySetInnerHTML={{ __html: appIcon || defaultIcon }} />;
};

export default AppIconContainer;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { tokens } from '@equinor/eds-tokens';
import { Link } from 'react-router-dom';
import { Typography } from '@equinor/eds-core-react';

import AppIconContainer, { Styled as IconStyled } from './AppIcon';
import AppIconContainer, { Styles as IconStyled } from './AppIcon';
import PinButtonContainer from './PinButton';
import { AppManifest } from '../types/types';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Styled as FavoriteStyled } from './FavoriteCard';
import { tokens } from '@equinor/eds-tokens';
import { Typography } from '@equinor/eds-core-react';

import AppIconContainer, { Styled as IconStyled } from './AppIcon';
import AppIconContainer, { Styles as IconStyled } from './AppIcon';
import { getAppCardColor } from '../util/app-card-color';
import { AppManifest } from '../types/types';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useFavorites } from '@portal/core';
import styled from 'styled-components';
import { MessageCard } from '@portal/ui';
import { useFramework } from '@equinor/fusion-framework-react';

const Styles = {
AppMessageWrapper: styled.div`
Expand All @@ -12,9 +13,10 @@ const APP_COUNT = 15;

export const AppContextMessage = () => {
const { apps } = useFavorites();
const { context } = useFramework().modules;
return (
<>
{apps && apps.length < APP_COUNT && (
{apps && apps.length < APP_COUNT && context.currentContext && (
<Styles.AppMessageWrapper>
<MessageCard
title="Application and Context Expansion"
Expand Down
3 changes: 3 additions & 0 deletions client/packages/core/src/app/hooks/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export const getAppManifestsMock = vi.fn();

export const appProvider = new AppModuleProvider({
config: {
proxy: {
path: '',
},
client: {
getAppConfig: {
client: {
Expand Down
4 changes: 1 addition & 3 deletions client/packages/core/src/app/hooks/use-app-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ export const useAppLoader = (appKey: string) => {
appRef.current = createAppElement();

// Generate basename for application regex extracts /apps/:appKey
const [basename] = window.location.pathname.match(/\/?apps\/[a-z|-]+\//g) ?? [
window.location.pathname,
];
const [basename] = location.pathname.match(/\/?apps\/[a-z|-]+\//g) ?? [location.pathname];

try {
//Casting to se if manifest is for fusion legacy application
Expand Down
3 changes: 3 additions & 0 deletions client/packages/core/src/app/hooks/use-current-app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export const getAppManifestsMock = vi.fn();

export const appProvider = new AppModuleProvider({
config: {
proxy: {
path: '',
},
client: {
getAppConfig: {
client: {
Expand Down
Loading
Loading