@equinor/fusion-framework-dev-portal 4.0.4 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +96 -31
- package/README.md +61 -55
- package/dist/lib-D7s4zR0Q.js +6058 -0
- package/dist/main.js +73023 -90431
- package/package.json +53 -37
- package/src/AppLoader.tsx +18 -9
- package/src/BookMarkSideSheet.tsx +11 -0
- package/src/ContextSelector/ContextSelector.tsx +11 -5
- package/src/ContextSelector/useContextResolver.ts +41 -11
- package/src/EquinorLoader.tsx +10 -1
- package/src/ErrorViewer.tsx +9 -0
- package/src/FusionLogo.tsx +12 -0
- package/src/Header.Actions.tsx +12 -0
- package/src/Header.tsx +7 -0
- package/src/PersonSideSheet/index.tsx +10 -2
- package/src/PersonSideSheet/sheets/FeatureSheetContent.tsx +6 -2
- package/src/PersonSideSheet/sheets/FeatureTogglerApp.tsx +4 -1
- package/src/PersonSideSheet/sheets/FeatureTogglerPortal.tsx +4 -1
- package/src/PersonSideSheet/sheets/LandingSheetContent.tsx +7 -1
- package/src/PersonSideSheet/sheets/Styled.tsx +4 -0
- package/src/PersonSideSheet/sheets/types.ts +9 -0
- package/src/Router.tsx +17 -0
- package/src/config.ts +23 -10
- package/src/main.tsx +11 -0
- package/src/resources/fallback-photo.svg.ts +5 -0
- package/src/useAppContextNavigation.ts +19 -10
- package/src/version.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@equinor/fusion-framework-dev-portal",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/main.js",
|
|
@@ -17,49 +17,65 @@
|
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@equinor/eds-core-react": "^
|
|
21
|
-
"@equinor/eds-icons": "^
|
|
22
|
-
"@equinor/eds-tokens": "^
|
|
23
|
-
"@equinor/fusion-react-context-selector": "^
|
|
20
|
+
"@equinor/eds-core-react": "^2.3.7",
|
|
21
|
+
"@equinor/eds-icons": "^1.3.0",
|
|
22
|
+
"@equinor/eds-tokens": "^2.2.0",
|
|
23
|
+
"@equinor/fusion-react-context-selector": "^2.0.1",
|
|
24
24
|
"@equinor/fusion-react-progress-indicator": "^0.3.0",
|
|
25
|
-
"@equinor/fusion-react-side-sheet": "2.0.0",
|
|
26
|
-
"@equinor/fusion-react-styles": "^0.
|
|
25
|
+
"@equinor/fusion-react-side-sheet": "^2.0.0",
|
|
26
|
+
"@equinor/fusion-react-styles": "^2.0.0",
|
|
27
27
|
"@equinor/fusion-wc-chip": "^1.2.2",
|
|
28
28
|
"@equinor/fusion-wc-person": "^3.4.0",
|
|
29
|
-
"@
|
|
30
|
-
"@types/
|
|
31
|
-
"@
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"react": "^
|
|
36
|
-
"react-dom": "^18.2.0",
|
|
37
|
-
"react-router-dom": "^6.15.0",
|
|
29
|
+
"@types/react": "^19.2.7",
|
|
30
|
+
"@types/react-dom": "^19.2.3",
|
|
31
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
32
|
+
"dotenv": "^17.3.1",
|
|
33
|
+
"react": "^19.2.1",
|
|
34
|
+
"react-dom": "^19.2.1",
|
|
35
|
+
"react-router-dom": "^7.9.5",
|
|
38
36
|
"rxjs": "^7.8.1",
|
|
39
|
-
"styled-components": "^6.
|
|
37
|
+
"styled-components": "^6.3.11",
|
|
40
38
|
"tsx": "^4.19.3",
|
|
41
|
-
"typescript": "^5.
|
|
42
|
-
"vite": "^
|
|
39
|
+
"typescript": "^5.9.3",
|
|
40
|
+
"vite": "^8.0.0",
|
|
41
|
+
"@equinor/fusion-framework": "8.0.0",
|
|
42
|
+
"@equinor/fusion-framework-app": "11.0.0",
|
|
43
|
+
"@equinor/fusion-framework-dev-server": "2.0.0",
|
|
44
|
+
"@equinor/fusion-framework-module-ag-grid": "36.0.0",
|
|
45
|
+
"@equinor/fusion-framework-module-app": "8.0.0",
|
|
46
|
+
"@equinor/fusion-framework-module-analytics": "2.0.0",
|
|
47
|
+
"@equinor/fusion-framework-module-bookmark": "4.0.0",
|
|
48
|
+
"@equinor/fusion-framework-module-feature-flag": "2.0.0",
|
|
49
|
+
"@equinor/fusion-framework-module-navigation": "7.0.0",
|
|
50
|
+
"@equinor/fusion-framework-module-services": "8.0.0",
|
|
51
|
+
"@equinor/fusion-framework-react": "8.0.0",
|
|
52
|
+
"@equinor/fusion-framework-module-telemetry": "5.0.0",
|
|
53
|
+
"@equinor/fusion-framework-react-components-bookmark": "2.0.0",
|
|
54
|
+
"@equinor/fusion-framework-react-components-people-provider": "2.0.0",
|
|
55
|
+
"@equinor/fusion-framework-module-context": "8.0.0",
|
|
56
|
+
"@equinor/fusion-framework-react-module-bookmark": "6.0.0",
|
|
57
|
+
"@equinor/fusion-observable": "9.0.0",
|
|
58
|
+
"@equinor/fusion-query": "7.0.0"
|
|
43
59
|
},
|
|
44
60
|
"peerDependencies": {
|
|
45
|
-
"@equinor/fusion-framework": "
|
|
46
|
-
"@equinor/fusion-framework-
|
|
47
|
-
"@equinor/fusion-framework-module-
|
|
48
|
-
"@equinor/fusion-framework-
|
|
49
|
-
"@equinor/fusion-framework-
|
|
50
|
-
"@equinor/fusion-framework-module-
|
|
51
|
-
"@equinor/fusion-framework-module-
|
|
52
|
-
"@equinor/fusion-framework
|
|
53
|
-
"@equinor/fusion-framework-module-feature-flag": "
|
|
54
|
-
"@equinor/fusion-framework-module-
|
|
55
|
-
"@equinor/fusion-framework-module-
|
|
56
|
-
"@equinor/fusion-framework-
|
|
57
|
-
"@equinor/fusion-framework-react-components-bookmark": "
|
|
58
|
-
"@equinor/fusion-framework-react-components-people-provider": "
|
|
59
|
-
"@equinor/fusion-framework-react-module-bookmark": "
|
|
60
|
-
"@equinor/fusion-
|
|
61
|
-
"@equinor/fusion-query": "
|
|
62
|
-
"@equinor/fusion-
|
|
61
|
+
"@equinor/fusion-framework-app": "11.0.0",
|
|
62
|
+
"@equinor/fusion-framework-module-ag-grid": "36.0.0",
|
|
63
|
+
"@equinor/fusion-framework-module-app": "8.0.0",
|
|
64
|
+
"@equinor/fusion-framework-module-analytics": "2.0.0",
|
|
65
|
+
"@equinor/fusion-framework-dev-server": "2.0.0",
|
|
66
|
+
"@equinor/fusion-framework-module-bookmark": "4.0.0",
|
|
67
|
+
"@equinor/fusion-framework-module-context": "8.0.0",
|
|
68
|
+
"@equinor/fusion-framework": "8.0.0",
|
|
69
|
+
"@equinor/fusion-framework-module-feature-flag": "2.0.0",
|
|
70
|
+
"@equinor/fusion-framework-module-navigation": "7.0.0",
|
|
71
|
+
"@equinor/fusion-framework-module-services": "8.0.0",
|
|
72
|
+
"@equinor/fusion-framework-module-telemetry": "5.0.0",
|
|
73
|
+
"@equinor/fusion-framework-react-components-bookmark": "2.0.0",
|
|
74
|
+
"@equinor/fusion-framework-react-components-people-provider": "2.0.0",
|
|
75
|
+
"@equinor/fusion-framework-react-module-bookmark": "6.0.0",
|
|
76
|
+
"@equinor/fusion-framework-react": "8.0.0",
|
|
77
|
+
"@equinor/fusion-query": "7.0.0",
|
|
78
|
+
"@equinor/fusion-observable": "9.0.0"
|
|
63
79
|
},
|
|
64
80
|
"peerDependenciesMeta": {
|
|
65
81
|
"@equinor/fusion-framework": {
|
package/src/AppLoader.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect,
|
|
1
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import { Subscription } from 'rxjs';
|
|
4
4
|
import { last } from 'rxjs/operators';
|
|
@@ -13,11 +13,18 @@ import { ErrorViewer } from './ErrorViewer';
|
|
|
13
13
|
import type { AppModule } from '@equinor/fusion-framework-module-app';
|
|
14
14
|
import EquinorLoader from './EquinorLoader';
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* URL search-parameter key used to specify an app version tag.
|
|
18
|
+
*
|
|
19
|
+
* When present in the URL as `?$tag=<value>`, the portal loads that
|
|
20
|
+
* specific version of the application instead of the default.
|
|
21
|
+
*/
|
|
16
22
|
export const TAG = '$tag';
|
|
17
23
|
|
|
18
24
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
25
|
+
* Reads the application version tag from the current URL search parameters.
|
|
26
|
+
*
|
|
27
|
+
* @returns The tag string if the `$tag` search parameter is present, otherwise `null`.
|
|
21
28
|
*/
|
|
22
29
|
export const getAppTagFromUrl = (): string | null => {
|
|
23
30
|
const url = new URL(window.location.href);
|
|
@@ -25,11 +32,14 @@ export const getAppTagFromUrl = (): string | null => {
|
|
|
25
32
|
};
|
|
26
33
|
|
|
27
34
|
/**
|
|
28
|
-
*
|
|
35
|
+
* Loads, initializes, and mounts a Fusion application by its key.
|
|
36
|
+
*
|
|
37
|
+
* Sets the current app on the framework's app module, observes initialization
|
|
38
|
+
* progress, and renders the app's script output into a private DOM element.
|
|
39
|
+
* Displays a loading spinner while the app initializes and an error view if
|
|
40
|
+
* manifest resolution or initialization fails.
|
|
29
41
|
*
|
|
30
|
-
*
|
|
31
|
-
* when the appKey changes, this component will try to initialize the referred application
|
|
32
|
-
* and render it.
|
|
42
|
+
* @param props.appKey - Unique key identifying the Fusion application to load.
|
|
33
43
|
*/
|
|
34
44
|
export const AppLoader = (props: { readonly appKey: string }) => {
|
|
35
45
|
const { appKey } = props;
|
|
@@ -37,7 +47,6 @@ export const AppLoader = (props: { readonly appKey: string }) => {
|
|
|
37
47
|
|
|
38
48
|
/** reference of application section/container */
|
|
39
49
|
const ref = useRef<HTMLElement>(null);
|
|
40
|
-
const applicationContentId = useId();
|
|
41
50
|
|
|
42
51
|
const [loading, setLoading] = useState<boolean>(false);
|
|
43
52
|
const [error, setError] = useState<Error | undefined>();
|
|
@@ -130,7 +139,7 @@ export const AppLoader = (props: { readonly appKey: string }) => {
|
|
|
130
139
|
}
|
|
131
140
|
|
|
132
141
|
return (
|
|
133
|
-
<section id=
|
|
142
|
+
<section id="app-section" ref={ref} style={{ display: 'contents' }}>
|
|
134
143
|
{loading && <EquinorLoader text="Loading Application" />}
|
|
135
144
|
</section>
|
|
136
145
|
);
|
|
@@ -3,11 +3,22 @@ import { Bookmark } from '@equinor/fusion-framework-react-components-bookmark';
|
|
|
3
3
|
import { useBookmarkComponentContext } from '@equinor/fusion-framework-react-components-bookmark';
|
|
4
4
|
import { SideSheet } from '@equinor/fusion-react-side-sheet';
|
|
5
5
|
|
|
6
|
+
/** Props for the {@link BookmarkSideSheet} component. */
|
|
6
7
|
type BookmarkSideSheetProps = {
|
|
8
|
+
/** Whether the side sheet is currently visible. */
|
|
7
9
|
readonly isOpen: boolean;
|
|
10
|
+
/** Callback invoked when the user dismisses the side sheet. */
|
|
8
11
|
readonly onClose: VoidFunction;
|
|
9
12
|
};
|
|
10
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Side sheet overlay for browsing and creating application bookmarks.
|
|
16
|
+
*
|
|
17
|
+
* Wraps the `Bookmark` component from `@equinor/fusion-framework-react-components-bookmark`
|
|
18
|
+
* in a dismissible side sheet with an "Add Bookmark" action button.
|
|
19
|
+
*
|
|
20
|
+
* @param props - {@link BookmarkSideSheetProps}
|
|
21
|
+
*/
|
|
11
22
|
export const BookmarkSideSheet = ({ isOpen, onClose }: BookmarkSideSheetProps) => {
|
|
12
23
|
const { provider, showCreateBookmark } = useBookmarkComponentContext();
|
|
13
24
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useEffect, useId, useMemo } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useId, useMemo, type ReactElement } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
ContextProvider,
|
|
4
4
|
ContextSearch,
|
|
@@ -9,11 +9,17 @@ import {
|
|
|
9
9
|
import { useContextResolver } from './useContextResolver';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* Context selector component wired to the current application's context module.
|
|
13
|
+
*
|
|
14
|
+
* Renders a search input with dropdown results from the Fusion context service.
|
|
15
|
+
* When the user selects a context item, it is set as the current context on the
|
|
16
|
+
* application's context provider. Clearing the selector resets the current context.
|
|
17
|
+
*
|
|
18
|
+
* @see {@link https://equinor.github.io/fusion-react-components/?path=/docs/data-contextselector--component | ContextSelector Storybook}
|
|
19
|
+
* @param props - Passthrough props for the underlying `ContextSearch` component.
|
|
20
|
+
* @returns The context selector element, or `null` if no context resolver is available.
|
|
15
21
|
*/
|
|
16
|
-
export const ContextSelector = (props: ContextSearchProps):
|
|
22
|
+
export const ContextSelector = (props: ContextSearchProps): ReactElement | null => {
|
|
17
23
|
const contextSelectorId = useId();
|
|
18
24
|
const {
|
|
19
25
|
resolver,
|
|
@@ -24,10 +24,22 @@ import type { AppModulesInstance } from '@equinor/fusion-framework-app';
|
|
|
24
24
|
import type { QueryClientError } from '@equinor/fusion-query/client';
|
|
25
25
|
import type { FusionContextSearchError } from '@equinor/fusion-framework-module-context/errors.js';
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Capitalizes the first letter of a string and lowercases the rest.
|
|
29
|
+
*
|
|
30
|
+
* @param string - The input string to capitalize.
|
|
31
|
+
* @returns The capitalized string.
|
|
32
|
+
*/
|
|
27
33
|
function capitalizeFirstLetter(string: string): string {
|
|
28
34
|
return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
|
|
29
35
|
}
|
|
30
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Converts a {@link ContextItem} graphic field to the shape expected by `ContextResultItem`.
|
|
39
|
+
*
|
|
40
|
+
* @param graphic - The graphic value from a context item (string, SVG object, or undefined).
|
|
41
|
+
* @returns An object with `graphic` and `graphicType` properties, or an empty object.
|
|
42
|
+
*/
|
|
31
43
|
function convertGraphic(
|
|
32
44
|
graphic: ContextItem['graphic'],
|
|
33
45
|
): Pick<ContextResultItem, 'graphic' | 'graphicType'> {
|
|
@@ -57,6 +69,12 @@ function convertGraphic(
|
|
|
57
69
|
};
|
|
58
70
|
}
|
|
59
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Converts a {@link ContextItem} meta field to the shape expected by `ContextResultItem`.
|
|
74
|
+
*
|
|
75
|
+
* @param meta - The meta value from a context item (string, SVG object, or undefined).
|
|
76
|
+
* @returns An object with `meta` and `metaType` properties, or an empty object.
|
|
77
|
+
*/
|
|
60
78
|
function convertMeta(meta: ContextItem['meta']): Pick<ContextResultItem, 'metaType' | 'meta'> {
|
|
61
79
|
if (meta === undefined) {
|
|
62
80
|
return {};
|
|
@@ -85,10 +103,13 @@ function convertMeta(meta: ContextItem['meta']): Pick<ContextResultItem, 'metaTy
|
|
|
85
103
|
}
|
|
86
104
|
|
|
87
105
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
106
|
+
* Maps an array of context items to `ContextResult` for the context selector dropdown.
|
|
107
|
+
*
|
|
108
|
+
* Applies custom rendering for `EquinorTask` (shows inactive state chip) and
|
|
109
|
+
* `OrgChart` (shows list icon and inactive state chip) context types.
|
|
110
|
+
*
|
|
111
|
+
* @param src - Array of context items from the context query.
|
|
112
|
+
* @returns Mapped array of `ContextResultItem` objects for the selector UI.
|
|
92
113
|
*/
|
|
93
114
|
const mapper = (src: ContextItem<{ taskState?: string; state?: string }>[]): ContextResult => {
|
|
94
115
|
return src.map((i) => {
|
|
@@ -127,19 +148,28 @@ const mapper = (src: ContextItem<{ taskState?: string; state?: string }>[]): Con
|
|
|
127
148
|
};
|
|
128
149
|
|
|
129
150
|
/**
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
151
|
+
* Creates a single `ContextResultItem` with sensible defaults.
|
|
152
|
+
*
|
|
153
|
+
* Used to generate placeholder or error entries in the context selector dropdown.
|
|
154
|
+
*
|
|
155
|
+
* @param props - Partial properties to merge into the default item shape.
|
|
156
|
+
* @returns A complete `ContextResultItem` with defaults for `id` and `title`.
|
|
133
157
|
*/
|
|
134
158
|
const singleItem = (props: Partial<ContextResultItem>): ContextResultItem => {
|
|
135
159
|
return Object.assign({ id: 'no-such-item', title: 'Change me' }, props);
|
|
136
160
|
};
|
|
137
161
|
|
|
138
162
|
/**
|
|
139
|
-
* Hook
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
163
|
+
* Hook that creates a context resolver, tracks the current context provider,
|
|
164
|
+
* and provides the currently selected context for the {@link ContextSelector}.
|
|
165
|
+
*
|
|
166
|
+
* Observes the current application's module instances. When the app exposes a
|
|
167
|
+
* context module, the hook wires up a search resolver that queries context items
|
|
168
|
+
* and maps results to `ContextResultItem`. It also handles error display and
|
|
169
|
+
* minimum query length enforcement.
|
|
170
|
+
*
|
|
171
|
+
* @see {@link https://equinor.github.io/fusion-react-components/?path=/docs/data-contextselector--component | ContextSelector Storybook}
|
|
172
|
+
* @returns An object containing the `resolver` for the selector, the current `provider`, and `currentContext` items.
|
|
143
173
|
*/
|
|
144
174
|
export const useContextResolver = (): {
|
|
145
175
|
resolver: ContextResolver | null;
|
package/src/EquinorLoader.tsx
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import { StarProgress } from '@equinor/fusion-react-progress-indicator';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Full-viewport loading indicator displaying the Equinor star spinner.
|
|
6
|
+
*
|
|
7
|
+
* Used as a fallback while the Fusion Framework or an application is initializing.
|
|
8
|
+
*
|
|
9
|
+
* @param props.text - Status message displayed below the spinner.
|
|
10
|
+
* @param props.children - Optional additional content rendered inside the spinner.
|
|
11
|
+
* @returns A centered full-screen loading overlay.
|
|
12
|
+
*/
|
|
4
13
|
export const EquinorLoader = ({
|
|
5
14
|
children,
|
|
6
15
|
text,
|
|
7
|
-
}: React.PropsWithChildren<{ readonly text: string }>):
|
|
16
|
+
}: React.PropsWithChildren<{ readonly text: string }>): React.ReactElement => {
|
|
8
17
|
return (
|
|
9
18
|
<div
|
|
10
19
|
style={{
|
package/src/ErrorViewer.tsx
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { Typography } from '@equinor/eds-core-react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Recursively renders an error and its causal chain.
|
|
5
|
+
*
|
|
6
|
+
* Displays the error message and stack trace for each error in the `cause`
|
|
7
|
+
* chain, providing full visibility into nested failures during app loading.
|
|
8
|
+
*
|
|
9
|
+
* @param props.error - The error to display, including any nested `cause` errors.
|
|
10
|
+
* @returns A bordered section showing the error message, stack trace, and any nested causes.
|
|
11
|
+
*/
|
|
3
12
|
export const ErrorViewer = ({ error }: { readonly error: Error }) => {
|
|
4
13
|
return (
|
|
5
14
|
<>
|
package/src/FusionLogo.tsx
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import { useId } from 'react';
|
|
2
2
|
import type { SVGProps } from 'react';
|
|
3
3
|
|
|
4
|
+
/** Props for the {@link FusionLogo} component. */
|
|
4
5
|
type FusionLogoProps = Omit<SVGProps<SVGSVGElement>, 'viewBox'> & {
|
|
6
|
+
/** Uniform scale multiplier applied via CSS transform. Defaults to `1`. */
|
|
5
7
|
readonly scale?: number;
|
|
6
8
|
};
|
|
7
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Inline SVG rendering of the Fusion logo.
|
|
12
|
+
*
|
|
13
|
+
* Uses unique gradient IDs per instance so multiple logos can coexist on the
|
|
14
|
+
* same page without gradient collisions.
|
|
15
|
+
*
|
|
16
|
+
* @param props.scale - Scale multiplier for the logo size.
|
|
17
|
+
* @param props.style - Additional inline styles merged with the computed transform.
|
|
18
|
+
* @returns An inline SVG element sized to `1em` height.
|
|
19
|
+
*/
|
|
8
20
|
export const FusionLogo = ({ scale = 1, style }: FusionLogoProps) => {
|
|
9
21
|
const paint0Id = useId();
|
|
10
22
|
const paint1Id = useId();
|
package/src/Header.Actions.tsx
CHANGED
|
@@ -6,12 +6,24 @@ PersonAvatarElement;
|
|
|
6
6
|
|
|
7
7
|
import { useBookmarkComponentContext } from '@equinor/fusion-framework-react-components-bookmark';
|
|
8
8
|
|
|
9
|
+
/** Props for the {@link HeaderActions} component. */
|
|
9
10
|
interface HeaderActionProps {
|
|
11
|
+
/** Azure AD object ID of the current user, used for the person avatar. */
|
|
10
12
|
readonly userAzureId?: string;
|
|
13
|
+
/** Toggle callback for the bookmark side sheet open/close state. */
|
|
11
14
|
readonly toggleBookmark: (open: (status: boolean) => boolean) => void;
|
|
15
|
+
/** Toggle callback for the person settings side sheet open/close state. */
|
|
12
16
|
readonly togglePerson: (open: (status: boolean) => boolean) => void;
|
|
13
17
|
}
|
|
14
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Action buttons displayed in the portal top bar header.
|
|
21
|
+
*
|
|
22
|
+
* Renders a bookmark toggle button (disabled when no bookmark provider is
|
|
23
|
+
* available) and a person-avatar button that opens the user settings sheet.
|
|
24
|
+
*
|
|
25
|
+
* @param props - {@link HeaderActionProps}
|
|
26
|
+
*/
|
|
15
27
|
export const HeaderActions = (props: HeaderActionProps) => {
|
|
16
28
|
const { toggleBookmark, togglePerson, userAzureId } = props;
|
|
17
29
|
|
package/src/Header.tsx
CHANGED
|
@@ -33,6 +33,13 @@ const Styled = {
|
|
|
33
33
|
`,
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Portal top bar header containing the Fusion logo, context selector, and action buttons.
|
|
38
|
+
*
|
|
39
|
+
* Composes the bookmark provider with the current app and user so bookmark
|
|
40
|
+
* and person side sheets can operate in context. Provides the sticky top bar
|
|
41
|
+
* layout used across all portal pages.
|
|
42
|
+
*/
|
|
36
43
|
export const Header = () => {
|
|
37
44
|
const currentUser = useCurrentUser();
|
|
38
45
|
const topBarId = useId();
|
|
@@ -7,15 +7,23 @@ import { Divider } from '@equinor/eds-core-react';
|
|
|
7
7
|
|
|
8
8
|
import { LandingSheetContent, FeatureSheetContent } from './sheets';
|
|
9
9
|
|
|
10
|
+
/** Props for the {@link PersonSideSheet} component. */
|
|
10
11
|
type PersonSideSheetProps = {
|
|
12
|
+
/** Azure AD object ID of the user to display in the side sheet. */
|
|
11
13
|
readonly azureId?: string;
|
|
14
|
+
/** Whether the side sheet is currently visible. */
|
|
12
15
|
readonly isOpen: boolean;
|
|
16
|
+
/** Callback invoked when the user dismisses the side sheet. */
|
|
13
17
|
onClose(): void;
|
|
14
18
|
};
|
|
15
19
|
|
|
16
20
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
21
|
+
* Side sheet overlay that displays user settings and feature toggles.
|
|
22
|
+
*
|
|
23
|
+
* Contains a person list item for the current user and navigable sub-sheets
|
|
24
|
+
* for viewing and toggling application and portal feature flags.
|
|
25
|
+
*
|
|
26
|
+
* @param props - {@link PersonSideSheetProps}
|
|
19
27
|
*/
|
|
20
28
|
export const PersonSideSheet = ({ azureId, isOpen, onClose }: PersonSideSheetProps) => {
|
|
21
29
|
const [currentSheet, setCurrentSheet] = useState<string>('landing');
|
|
@@ -9,8 +9,12 @@ Icon.add({ arrow_back, category });
|
|
|
9
9
|
import type { SheetContentProps } from './types';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Feature flags sub-sheet for the person settings side sheet.
|
|
13
|
+
*
|
|
14
|
+
* Contains tabbed panels for toggling application-level and portal-level
|
|
15
|
+
* feature flags. Includes a back-navigation button to return to the landing sheet.
|
|
16
|
+
*
|
|
17
|
+
* @param props.navigate - Callback to navigate back to the landing sheet.
|
|
14
18
|
*/
|
|
15
19
|
export const FeatureSheetContent = ({ navigate }: SheetContentProps) => {
|
|
16
20
|
const [tab, setTab] = useState<number>(0);
|
|
@@ -5,7 +5,10 @@ import { Typography, Switch } from '@equinor/eds-core-react';
|
|
|
5
5
|
import { Styled } from './Styled';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Feature toggle list for application-level feature flags.
|
|
9
|
+
*
|
|
10
|
+
* Reads feature flags from the current app's feature-flag module and renders
|
|
11
|
+
* each flag as a labeled switch. Clicking a row toggles the flag.
|
|
9
12
|
*/
|
|
10
13
|
export const FeatureTogglerApp = () => {
|
|
11
14
|
const { features, toggleFeature } = useCurrentAppFeatures();
|
|
@@ -5,7 +5,10 @@ import { Typography, Switch } from '@equinor/eds-core-react';
|
|
|
5
5
|
import { Styled } from './Styled';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Feature toggle list for portal-level feature flags.
|
|
9
|
+
*
|
|
10
|
+
* Reads feature flags from the framework's feature-flag module and renders
|
|
11
|
+
* each flag as a labeled switch. Clicking a row toggles the flag.
|
|
9
12
|
*/
|
|
10
13
|
export const FeatureTogglerPortal = () => {
|
|
11
14
|
const { features, toggleFeature } = useFrameworkFeatures();
|
|
@@ -15,7 +15,13 @@ const BtnListItem = styled.li`
|
|
|
15
15
|
`;
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* Landing page content for the person settings side sheet.
|
|
19
|
+
*
|
|
20
|
+
* Displays navigation buttons for sub-sheets (e.g., feature toggles) and
|
|
21
|
+
* an external link to the user's Delve profile.
|
|
22
|
+
*
|
|
23
|
+
* @param props.azureId - Azure AD object ID used to build the Delve profile link.
|
|
24
|
+
* @param props.navigate - Callback to navigate to a sub-sheet by key.
|
|
19
25
|
*/
|
|
20
26
|
export const LandingSheetContent = ({ azureId, navigate }: SheetContentProps) => {
|
|
21
27
|
return (
|
|
@@ -1,5 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared props for person side sheet sub-pages.
|
|
3
|
+
*
|
|
4
|
+
* Each sheet content component receives these props from the parent
|
|
5
|
+
* {@link PersonSideSheet} to support navigation between sheets.
|
|
6
|
+
*/
|
|
1
7
|
export type SheetContentProps = {
|
|
8
|
+
/** Azure AD object ID of the current user. */
|
|
2
9
|
readonly azureId?: string;
|
|
10
|
+
/** Key of the currently active sheet. */
|
|
3
11
|
readonly sheet?: string;
|
|
12
|
+
/** Navigates to a different sheet by key, or back to the landing sheet when called without arguments. */
|
|
4
13
|
navigate(sheet?: string): void;
|
|
5
14
|
};
|
package/src/Router.tsx
CHANGED
|
@@ -31,6 +31,12 @@ const Styled = {
|
|
|
31
31
|
`,
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Root layout component for the dev portal.
|
|
36
|
+
*
|
|
37
|
+
* Renders the header and a scrollable main area via `Outlet`. Activates
|
|
38
|
+
* bookmark-to-navigation linking through `useBookmarkNavigate`.
|
|
39
|
+
*/
|
|
34
40
|
const Root = () => {
|
|
35
41
|
useBookmarkNavigate({ resolveAppPath: (appKey: string) => `/apps/${appKey}` });
|
|
36
42
|
return (
|
|
@@ -45,12 +51,16 @@ const Root = () => {
|
|
|
45
51
|
);
|
|
46
52
|
};
|
|
47
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Route component that extracts the `appKey` parameter and delegates to {@link AppLoader}.
|
|
56
|
+
*/
|
|
48
57
|
// eslint-disable-next-line react/no-multi-comp
|
|
49
58
|
const AppRoute = () => {
|
|
50
59
|
const { appKey } = useParams();
|
|
51
60
|
return appKey ? <AppLoader appKey={appKey} /> : null;
|
|
52
61
|
};
|
|
53
62
|
|
|
63
|
+
/** Route definitions for the dev portal. */
|
|
54
64
|
const routes = [
|
|
55
65
|
{
|
|
56
66
|
path: '/',
|
|
@@ -64,6 +74,13 @@ const routes = [
|
|
|
64
74
|
},
|
|
65
75
|
];
|
|
66
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Top-level router for the Fusion Dev Portal.
|
|
79
|
+
*
|
|
80
|
+
* Creates a router instance from the framework navigation module and
|
|
81
|
+
* renders it via `RouterProvider`. Observes context changes through
|
|
82
|
+
* {@link useAppContextNavigation} to keep the URL in sync.
|
|
83
|
+
*/
|
|
67
84
|
// eslint-disable-next-line react/no-multi-comp
|
|
68
85
|
export const Router = () => {
|
|
69
86
|
const { navigation } = useFramework<[NavigationModule]>().modules;
|
package/src/config.ts
CHANGED
|
@@ -26,16 +26,21 @@ declare global {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
* Configures the Fusion Dev Portal with all required modules
|
|
29
|
+
* Configures the Fusion Dev Portal framework with all required modules.
|
|
30
30
|
*
|
|
31
|
-
*
|
|
32
|
-
* - Telemetry
|
|
33
|
-
* -
|
|
34
|
-
* -
|
|
35
|
-
* -
|
|
36
|
-
* -
|
|
31
|
+
* Enables and wires together:
|
|
32
|
+
* - **Telemetry** — portal-scoped usage analytics with version metadata.
|
|
33
|
+
* - **App module** — application manifest loading and lifecycle.
|
|
34
|
+
* - **Navigation** — router integration with optional telemetry.
|
|
35
|
+
* - **Services** — standard Fusion service integrations.
|
|
36
|
+
* - **AG Grid** — enterprise license key from `window.FUSION_AG_GRID_KEY`.
|
|
37
|
+
* - **Analytics** — console adapter gated by the `fusionLogAnalytics` feature flag.
|
|
38
|
+
* - **Bookmarks** — source-system metadata identifying CLI-created bookmarks.
|
|
39
|
+
* - **Feature flags** — local-storage and URL-based flag plugins for dev toggles.
|
|
37
40
|
*
|
|
38
|
-
*
|
|
41
|
+
* On initialization, exposes all modules on `window.Fusion` for debugging.
|
|
42
|
+
*
|
|
43
|
+
* @param config - The framework configurator instance to extend with portal modules.
|
|
39
44
|
*/
|
|
40
45
|
export const configure = async (config: FrameworkConfigurator) => {
|
|
41
46
|
// Enable telemetry tracking for portal usage analytics and monitoring
|
|
@@ -61,7 +66,15 @@ export const configure = async (config: FrameworkConfigurator) => {
|
|
|
61
66
|
|
|
62
67
|
enableAppModule(config);
|
|
63
68
|
|
|
64
|
-
enableNavigation(config
|
|
69
|
+
enableNavigation(config, {
|
|
70
|
+
configure: (config) => {
|
|
71
|
+
config.setTelemetry(async (args) => {
|
|
72
|
+
if (args.hasModule('telemetry')) {
|
|
73
|
+
return await args.requireInstance('telemetry');
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
});
|
|
65
78
|
|
|
66
79
|
enableServices(config);
|
|
67
80
|
|
|
@@ -121,7 +134,7 @@ export const configure = async (config: FrameworkConfigurator) => {
|
|
|
121
134
|
config.onInitialized(async (modules) => {
|
|
122
135
|
// NOTE: TypeScript ignore needed due to window object extension
|
|
123
136
|
// This provides developer access to all initialized modules via window.Fusion
|
|
124
|
-
// @ts-
|
|
137
|
+
// @ts-expect-error
|
|
125
138
|
window.Fusion = { modules };
|
|
126
139
|
});
|
|
127
140
|
};
|
package/src/main.tsx
CHANGED
|
@@ -11,8 +11,19 @@ import { Router } from './Router';
|
|
|
11
11
|
|
|
12
12
|
import fallbackSvg from './resources/fallback-photo.svg';
|
|
13
13
|
|
|
14
|
+
/** Fallback avatar image used when a person photo cannot be loaded. */
|
|
14
15
|
const fallbackImage = new Blob([fallbackSvg], { type: 'image/svg+xml' });
|
|
15
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Mounts the Fusion Dev Portal into the given DOM element.
|
|
19
|
+
*
|
|
20
|
+
* Creates a React root and renders the portal shell with the Equinor theme,
|
|
21
|
+
* Fusion Framework provider, people-resolver provider, and the portal router.
|
|
22
|
+
* This is the main entry point consumed by `@equinor/fusion-framework-dev-server`.
|
|
23
|
+
*
|
|
24
|
+
* @param target - The DOM element to mount the portal into.
|
|
25
|
+
* @param args - Render arguments containing a `ref` to the parent Fusion Framework instance.
|
|
26
|
+
*/
|
|
16
27
|
export const render: FusionRenderFn = (target, args) => {
|
|
17
28
|
ReactDOM.createRoot(target).render(
|
|
18
29
|
<ThemeProvider theme={theme}>
|