@cognizant-ai-lab/ui-common 1.3.3
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/dist/components/AgentChat/ChatCommon.d.ts +94 -0
- package/dist/components/AgentChat/ChatCommon.js +581 -0
- package/dist/components/AgentChat/ControlButtons.d.ts +16 -0
- package/dist/components/AgentChat/ControlButtons.js +24 -0
- package/dist/components/AgentChat/FormattedMarkdown.d.ts +32 -0
- package/dist/components/AgentChat/FormattedMarkdown.js +82 -0
- package/dist/components/AgentChat/Greetings.d.ts +1 -0
- package/dist/components/AgentChat/Greetings.js +38 -0
- package/dist/components/AgentChat/LlmChatButton.d.ts +12 -0
- package/dist/components/AgentChat/LlmChatButton.js +33 -0
- package/dist/components/AgentChat/SendButton.d.ts +12 -0
- package/dist/components/AgentChat/SendButton.js +28 -0
- package/dist/components/AgentChat/SyntaxHighlighterThemes.d.ts +14 -0
- package/dist/components/AgentChat/SyntaxHighlighterThemes.js +27 -0
- package/dist/components/AgentChat/Types.d.ts +17 -0
- package/dist/components/AgentChat/Types.js +26 -0
- package/dist/components/AgentChat/UserQueryDisplay.d.ts +5 -0
- package/dist/components/AgentChat/UserQueryDisplay.js +33 -0
- package/dist/components/AgentChat/Utils.d.ts +11 -0
- package/dist/components/AgentChat/Utils.js +64 -0
- package/dist/components/AgentChat/VoiceChat/MicrophoneButton.d.ts +29 -0
- package/dist/components/AgentChat/VoiceChat/MicrophoneButton.js +55 -0
- package/dist/components/AgentChat/VoiceChat/VoiceChat.d.ts +33 -0
- package/dist/components/AgentChat/VoiceChat/VoiceChat.js +180 -0
- package/dist/components/Authentication/Auth.d.ts +14 -0
- package/dist/components/Authentication/Auth.js +58 -0
- package/dist/components/ChatBot/ChatBot.d.ts +20 -0
- package/dist/components/ChatBot/ChatBot.js +75 -0
- package/dist/components/Common/Breadcrumbs.d.ts +6 -0
- package/dist/components/Common/Breadcrumbs.js +36 -0
- package/dist/components/Common/LlmChatOptionsButton.d.ts +9 -0
- package/dist/components/Common/LlmChatOptionsButton.js +31 -0
- package/dist/components/Common/LoadingSpinner.d.ts +10 -0
- package/dist/components/Common/LoadingSpinner.js +24 -0
- package/dist/components/Common/MUIAccordion.d.ts +17 -0
- package/dist/components/Common/MUIAccordion.js +76 -0
- package/dist/components/Common/MUIAlert.d.ts +11 -0
- package/dist/components/Common/MUIAlert.js +41 -0
- package/dist/components/Common/MUIDialog.d.ts +16 -0
- package/dist/components/Common/MUIDialog.js +40 -0
- package/dist/components/Common/Navbar.d.ts +15 -0
- package/dist/components/Common/Navbar.js +137 -0
- package/dist/components/Common/PageLoader.d.ts +5 -0
- package/dist/components/Common/PageLoader.js +26 -0
- package/dist/components/Common/Snackbar.d.ts +5 -0
- package/dist/components/Common/Snackbar.js +84 -0
- package/dist/components/Common/confirmationModal.d.ts +14 -0
- package/dist/components/Common/confirmationModal.js +65 -0
- package/dist/components/Common/notification.d.ts +18 -0
- package/dist/components/Common/notification.js +79 -0
- package/dist/components/ErrorPage/ErrorBoundary.d.ts +38 -0
- package/dist/components/ErrorPage/ErrorBoundary.js +77 -0
- package/dist/components/ErrorPage/ErrorPage.d.ts +12 -0
- package/dist/components/ErrorPage/ErrorPage.js +46 -0
- package/dist/components/MultiAgentAccelerator/AgentFlow.d.ts +21 -0
- package/dist/components/MultiAgentAccelerator/AgentFlow.js +394 -0
- package/dist/components/MultiAgentAccelerator/AgentNode.d.ts +18 -0
- package/dist/components/MultiAgentAccelerator/AgentNode.js +129 -0
- package/dist/components/MultiAgentAccelerator/GraphLayouts.d.ts +33 -0
- package/dist/components/MultiAgentAccelerator/GraphLayouts.js +297 -0
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.d.ts +17 -0
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +208 -0
- package/dist/components/MultiAgentAccelerator/PlasmaEdge.d.ts +3 -0
- package/dist/components/MultiAgentAccelerator/PlasmaEdge.js +124 -0
- package/dist/components/MultiAgentAccelerator/Sidebar.d.ts +12 -0
- package/dist/components/MultiAgentAccelerator/Sidebar.js +204 -0
- package/dist/components/MultiAgentAccelerator/ThoughtBubbleEdge.d.ts +12 -0
- package/dist/components/MultiAgentAccelerator/ThoughtBubbleEdge.js +15 -0
- package/dist/components/MultiAgentAccelerator/ThoughtBubbleOverlay.d.ts +11 -0
- package/dist/components/MultiAgentAccelerator/ThoughtBubbleOverlay.js +466 -0
- package/dist/components/MultiAgentAccelerator/const.d.ts +7 -0
- package/dist/components/MultiAgentAccelerator/const.js +39 -0
- package/dist/const.d.ts +10 -0
- package/dist/const.js +30 -0
- package/dist/controller/agent/Agent.d.ts +56 -0
- package/dist/controller/agent/Agent.js +162 -0
- package/dist/controller/llm/LlmChat.d.ts +18 -0
- package/dist/controller/llm/LlmChat.js +65 -0
- package/dist/controller/llm/endpoints.d.ts +1 -0
- package/dist/controller/llm/endpoints.js +17 -0
- package/dist/generated/neuro-san/NeuroSanClient.d.ts +413 -0
- package/dist/generated/neuro-san/NeuroSanClient.js +28 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +52 -0
- package/dist/state/UserInfo.d.ts +16 -0
- package/dist/state/UserInfo.js +27 -0
- package/dist/state/environment.d.ts +18 -0
- package/dist/state/environment.js +33 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/utils/Authentication.d.ts +31 -0
- package/dist/utils/Authentication.js +94 -0
- package/dist/utils/BrowserNavigation.d.ts +5 -0
- package/dist/utils/BrowserNavigation.js +22 -0
- package/dist/utils/Theme.d.ts +7 -0
- package/dist/utils/Theme.js +7 -0
- package/dist/utils/agentConversations.d.ts +24 -0
- package/dist/utils/agentConversations.js +113 -0
- package/dist/utils/text.d.ts +28 -0
- package/dist/utils/text.js +64 -0
- package/dist/utils/title.d.ts +1 -0
- package/dist/utils/title.js +20 -0
- package/dist/utils/types.d.ts +17 -0
- package/dist/utils/types.js +16 -0
- package/dist/utils/useLocalStorage.d.ts +1 -0
- package/dist/utils/useLocalStorage.js +55 -0
- package/dist/utils/zIndexLayers.d.ts +2 -0
- package/dist/utils/zIndexLayers.js +29 -0
- package/package.json +69 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
Copyright 2025 Cognizant Technology Solutions Corp, www.cognizant.com.
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import CloseIcon from "@mui/icons-material/Close";
|
|
18
|
+
import { styled } from "@mui/material";
|
|
19
|
+
import Dialog from "@mui/material/Dialog";
|
|
20
|
+
import DialogActions from "@mui/material/DialogActions";
|
|
21
|
+
import DialogContent from "@mui/material/DialogContent";
|
|
22
|
+
import DialogTitle from "@mui/material/DialogTitle";
|
|
23
|
+
import IconButton from "@mui/material/IconButton";
|
|
24
|
+
// #region: Styled Components
|
|
25
|
+
const StyledDialogTitle = styled(DialogTitle)({
|
|
26
|
+
fontSize: "1rem",
|
|
27
|
+
maxWidth: "580px",
|
|
28
|
+
paddingBottom: "0",
|
|
29
|
+
overflow: "hidden",
|
|
30
|
+
textOverflow: "ellipsis",
|
|
31
|
+
whiteSpace: "nowrap",
|
|
32
|
+
});
|
|
33
|
+
// #endregion: Types
|
|
34
|
+
export const MUIDialog = ({ children, className, closeable = true, contentSx, footer, id, isOpen, onClose, paperProps, title, }) => (_jsxs(Dialog, { "data-testid": id, id: id, onClose: onClose, open: isOpen, className: className, slotProps: {
|
|
35
|
+
paper: { sx: paperProps },
|
|
36
|
+
}, children: [_jsx(StyledDialogTitle, { id: `${id}-title`, children: title }), closeable && (_jsx(IconButton, { "aria-label": "close", id: `${id}-close-icon-btn`, onClick: onClose, sx: {
|
|
37
|
+
position: "absolute",
|
|
38
|
+
right: 8,
|
|
39
|
+
top: 8,
|
|
40
|
+
}, children: _jsx(CloseIcon, { "data-testid": `${id}-close-icon`, id: `${id}-close-icon`, sx: { color: "var(--bs-gray-medium)", fontSize: "1rem" } }) })), _jsx(DialogContent, { id: `${id}-content`, sx: contentSx, children: children }), _jsx(DialogActions, { id: `${id}-footer`, sx: { padding: "10px" }, children: footer })] }));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { JSX as ReactJSX } from "react";
|
|
2
|
+
export interface NavbarProps {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly logo: string;
|
|
5
|
+
readonly query: Record<string, string | string[]>;
|
|
6
|
+
readonly pathname: string;
|
|
7
|
+
readonly userInfo: {
|
|
8
|
+
name: string;
|
|
9
|
+
image: string;
|
|
10
|
+
};
|
|
11
|
+
readonly authenticationType: string;
|
|
12
|
+
readonly signOut: () => void;
|
|
13
|
+
readonly supportEmailAddress: string;
|
|
14
|
+
}
|
|
15
|
+
export declare const Navbar: ({ authenticationType, id, logo, pathname, query, signOut, supportEmailAddress, userInfo, }: NavbarProps) => ReactJSX.Element;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
Copyright 2025 Cognizant Technology Solutions Corp, www.cognizant.com.
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Main navigation bar that appears at the top of each page
|
|
19
|
+
*/
|
|
20
|
+
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
|
|
21
|
+
import DarkModeIcon from "@mui/icons-material/DarkMode";
|
|
22
|
+
import { IconButton, Menu, MenuItem, Tooltip, Typography, useColorScheme } from "@mui/material";
|
|
23
|
+
import Grid from "@mui/material/Grid";
|
|
24
|
+
import { useEffect, useState } from "react";
|
|
25
|
+
import { ConfirmationModal } from "./confirmationModal.js";
|
|
26
|
+
import { LoadingSpinner } from "./LoadingSpinner.js";
|
|
27
|
+
import { authenticationEnabled, CONTACT_US_CONFIRMATION_DIALOG_TEXT, CONTACT_US_CONFIRMATION_DIALOG_TITLE, DEFAULT_USER_IMAGE, NEURO_SAN_UI_VERSION, } from "../../const.js";
|
|
28
|
+
import { navigateToUrl } from "../../utils/BrowserNavigation.js";
|
|
29
|
+
import { isDarkMode } from "../../utils/Theme.js";
|
|
30
|
+
const MENU_ITEM_TEXT_PROPS = {
|
|
31
|
+
color: "var(--bs-white)",
|
|
32
|
+
backgroundColor: "var(--bs-primary)",
|
|
33
|
+
fontFamily: "var(--bs-body-font-family)",
|
|
34
|
+
fontSize: "18px",
|
|
35
|
+
};
|
|
36
|
+
const DISABLE_OUTLINE_PROPS = {
|
|
37
|
+
outline: "none",
|
|
38
|
+
"&:focus": {
|
|
39
|
+
outline: "none",
|
|
40
|
+
},
|
|
41
|
+
"&:active": {
|
|
42
|
+
outline: "none",
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
export const Navbar = ({ authenticationType, id, logo, pathname, query, signOut, supportEmailAddress, userInfo, }) => {
|
|
46
|
+
// For email dialog
|
|
47
|
+
const [emailDialogOpen, setEmailDialogOpen] = useState(false);
|
|
48
|
+
// Dark mode
|
|
49
|
+
const { mode, setMode, systemMode } = useColorScheme();
|
|
50
|
+
const darkMode = isDarkMode(mode, systemMode);
|
|
51
|
+
// Gate to make sure we only attempt to render after Next.js has completed its rehydration
|
|
52
|
+
const [hydrated, setHydrated] = useState(false);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
// Indicate that the component has been hydrated
|
|
55
|
+
setHydrated(true);
|
|
56
|
+
}, []);
|
|
57
|
+
// Help menu wiring
|
|
58
|
+
const [helpMenuAnchorEl, setHelpMenuAnchorEl] = useState(null);
|
|
59
|
+
const helpMenuOpen = Boolean(helpMenuAnchorEl);
|
|
60
|
+
const handleCloseHelpMenu = () => {
|
|
61
|
+
setHelpMenuAnchorEl(null);
|
|
62
|
+
};
|
|
63
|
+
// User menu wiring
|
|
64
|
+
const [userMenuAnchorEl, setUserMenuAnchorEl] = useState(null);
|
|
65
|
+
const userMenuOpen = Boolean(userMenuAnchorEl);
|
|
66
|
+
const handleCloseUserMenu = () => {
|
|
67
|
+
setUserMenuAnchorEl(null);
|
|
68
|
+
};
|
|
69
|
+
// Explore menu wiring
|
|
70
|
+
const [exploreMenuAnchorEl, setExploreMenuAnchorEl] = useState(null);
|
|
71
|
+
const exploreMenuOpen = Boolean(exploreMenuAnchorEl);
|
|
72
|
+
const handleCloseExploreMenu = () => {
|
|
73
|
+
setExploreMenuAnchorEl(null);
|
|
74
|
+
};
|
|
75
|
+
return hydrated ? (_jsxs(Grid, { id: "nav-bar-container", container: true, alignItems: "center", sx: {
|
|
76
|
+
...MENU_ITEM_TEXT_PROPS,
|
|
77
|
+
color: "var(--bs-white)",
|
|
78
|
+
padding: "0.25rem",
|
|
79
|
+
}, children: [_jsx("a", { id: "splash-logo-link", href: "https://www.cognizant.com/us/en", style: {
|
|
80
|
+
display: "flex",
|
|
81
|
+
paddingLeft: "0.15rem",
|
|
82
|
+
}, target: "_blank", rel: "noopener noreferrer", children: _jsx("img", { id: "logo-img", width: "200", height: "45", src: "/cognizant-logo-white.svg", alt: "Cognizant Logo" }) }), _jsx(Grid, { id: id, children: _jsx(Typography, { id: "nav-bar-brand", sx: {
|
|
83
|
+
...MENU_ITEM_TEXT_PROPS,
|
|
84
|
+
color: "var(--bs-white)",
|
|
85
|
+
marginLeft: "0.85rem",
|
|
86
|
+
fontSize: "16px",
|
|
87
|
+
fontWeight: "bold",
|
|
88
|
+
}, children: _jsxs("a", { id: "navbar-brand-link", style: {
|
|
89
|
+
fontWeight: 500,
|
|
90
|
+
fontSize: "1.1rem",
|
|
91
|
+
color: "var(--bs-white)",
|
|
92
|
+
position: "relative",
|
|
93
|
+
bottom: "1px",
|
|
94
|
+
textDecoration: "none",
|
|
95
|
+
}, href: Object.keys(query || {}).length > 0
|
|
96
|
+
? `/?${new URLSearchParams(query).toString()}`
|
|
97
|
+
: "/", children: [logo, " ", pathname === "/multiAgentAccelerator" ? "Multi-Agent Accelerator" : "Decisioning"] }) }) }), _jsx(Grid, { id: "build", sx: {
|
|
98
|
+
flex: 1, // Take available space
|
|
99
|
+
display: "flex",
|
|
100
|
+
justifyContent: "flex-end", // Right align
|
|
101
|
+
alignItems: "center", // Vertically center
|
|
102
|
+
color: "var(--bs-white)",
|
|
103
|
+
marginRight: "50px",
|
|
104
|
+
}, children: _jsxs(Typography, { id: "build-text", sx: { ...MENU_ITEM_TEXT_PROPS }, children: ["Build: ", _jsx("strong", { id: "build-strong", children: NEURO_SAN_UI_VERSION })] }) }), _jsxs(Grid, { id: "explore-dropdown", sx: { cursor: "pointer", marginRight: "30px" }, children: [_jsxs(Typography, { id: "explore-toggle", sx: {
|
|
105
|
+
...MENU_ITEM_TEXT_PROPS,
|
|
106
|
+
display: "flex",
|
|
107
|
+
alignItems: "center",
|
|
108
|
+
}, onClick: (event) => {
|
|
109
|
+
setExploreMenuAnchorEl(event.currentTarget);
|
|
110
|
+
}, children: ["Explore", _jsx(ArrowDropDownIcon, { id: "nav-explore-dropdown-arrow", sx: { color: "var(--bs-white)", fontSize: 22 } })] }), _jsxs(Menu, { id: "explore-menu", anchorEl: exploreMenuAnchorEl, open: exploreMenuOpen, onClose: handleCloseExploreMenu, children: [_jsx(MenuItem, { id: "explore-neuro-san-studio", component: "a", href: "https://github.com/cognizant-ai-lab/neuro-san-studio", target: "_blank", sx: { ...DISABLE_OUTLINE_PROPS }, children: "Neuro-san studio (examples)" }, "explore-neuro-san-studio"), _jsx(MenuItem, { id: "explore-neuro-san", component: "a", href: "https://github.com/cognizant-ai-lab/neuro-san", target: "_blank", sx: { ...DISABLE_OUTLINE_PROPS }, children: "Neuro-san (core)" }, "explore-neuro-san")] })] }), _jsxs(Grid, { id: "help-dropdown", sx: { cursor: "pointer", marginRight: "30px" }, children: [_jsxs(Typography, { id: "help-toggle", sx: {
|
|
111
|
+
...MENU_ITEM_TEXT_PROPS,
|
|
112
|
+
display: "flex",
|
|
113
|
+
alignItems: "center",
|
|
114
|
+
}, onClick: (event) => {
|
|
115
|
+
setHelpMenuAnchorEl(event.currentTarget);
|
|
116
|
+
}, children: ["Help", _jsx(ArrowDropDownIcon, { id: "nav-help-dropdown-arrow", sx: { color: "var(--bs-white)", fontSize: 22 } })] }), _jsxs(Menu, { id: "help-menu", anchorEl: helpMenuAnchorEl, open: helpMenuOpen, onClose: handleCloseHelpMenu, children: [_jsx(MenuItem, { id: "user-guide", component: "a", href: "/userguide", target: "_blank", sx: { ...DISABLE_OUTLINE_PROPS }, children: "User guide" }, "user-guide"), _jsx(MenuItem, { href: null, id: "contact-us-help", onClick: () => setEmailDialogOpen(true), children: "Contact Us" }, "contact-us-help")] })] }), emailDialogOpen ? (_jsx(ConfirmationModal, { id: "email-dialog", content: CONTACT_US_CONFIRMATION_DIALOG_TEXT, handleCancel: () => {
|
|
117
|
+
setEmailDialogOpen(false);
|
|
118
|
+
}, handleOk: () => {
|
|
119
|
+
navigateToUrl(`mailto:${supportEmailAddress}`);
|
|
120
|
+
setEmailDialogOpen(false);
|
|
121
|
+
}, title: CONTACT_US_CONFIRMATION_DIALOG_TITLE })) : null, userInfo ? (_jsxs(Grid, { id: "user-dropdown", children: [_jsxs(IconButton, { "aria-label": "User dropdown toggle", id: "user-dropdown-toggle", onClick: (event) => {
|
|
122
|
+
setUserMenuAnchorEl(event.currentTarget);
|
|
123
|
+
}, sx: {
|
|
124
|
+
...MENU_ITEM_TEXT_PROPS,
|
|
125
|
+
}, children: [_jsx("img", { id: "user-image", src: userInfo.image || DEFAULT_USER_IMAGE, width: 30, height: 30, title: userInfo.name, alt: "" }), _jsx(ArrowDropDownIcon, { id: "nav-user-dropdown-arrow", sx: { color: "var(--bs-white)", fontSize: 22 } })] }), _jsxs(Menu, { id: "user-menu", anchorEl: userMenuAnchorEl, open: userMenuOpen, onClose: handleCloseUserMenu, children: [_jsx(MenuItem, { id: "user-signed-in-as", disabled: true, sx: { fontWeight: "bold" }, children: "Signed in as" }), _jsx(MenuItem, { id: "user-name", disabled: true, sx: {
|
|
126
|
+
whiteSpace: "normal",
|
|
127
|
+
wordWrap: "break-word",
|
|
128
|
+
fontSize: "smaller",
|
|
129
|
+
}, children: userInfo.name }), _jsx(MenuItem, { id: "auth-type-title", disabled: true, sx: { fontWeight: "bold" }, children: "Authentication" }), _jsx(MenuItem, { id: "authentication-type-menu-item", disabled: true, sx: { fontSize: "smaller" }, children: authenticationType }), authenticationEnabled() && (_jsx(MenuItem, { id: "user-sign-out", sx: { ...DISABLE_OUTLINE_PROPS, fontWeight: "bold" }, onClick: signOut, children: "Sign out" }))] })] })) : null, _jsx(Tooltip, { id: "dark-mode-toggle", title: "Toggle dark mode", children: _jsx(DarkModeIcon, { id: "dark-mode-icon", sx: {
|
|
130
|
+
marginRight: "1rem",
|
|
131
|
+
fontSize: "1rem",
|
|
132
|
+
cursor: "pointer",
|
|
133
|
+
color: darkMode ? "var(--bs-yellow)" : "var(--bs-gray-dark)",
|
|
134
|
+
}, onClick: () => {
|
|
135
|
+
setMode(darkMode ? "light" : "dark");
|
|
136
|
+
} }) })] })) : (_jsx(LoadingSpinner, { id: "navbar-loading-spinner" }));
|
|
137
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
Copyright 2025 Cognizant Technology Solutions Corp, www.cognizant.com.
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { CircularProgress, Typography } from "@mui/material";
|
|
18
|
+
export const PageLoader = ({ id }) => (_jsxs("div", { id: `${id}__loader`, style: {
|
|
19
|
+
left: "0",
|
|
20
|
+
position: "absolute",
|
|
21
|
+
right: "0",
|
|
22
|
+
textAlign: "center",
|
|
23
|
+
top: "50%",
|
|
24
|
+
}, children: [_jsx(Typography, { id: `${id}-loader__message`, variant: "h3", children: "Loading... Please wait" }), _jsx(CircularProgress, { id: `${id}-loader__spinner`, sx: {
|
|
25
|
+
color: "var(--bs-primary)",
|
|
26
|
+
}, size: "100px" })] }));
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { CustomContentProps } from "notistack";
|
|
2
|
+
export interface SnackbarProps extends CustomContentProps {
|
|
3
|
+
description: string;
|
|
4
|
+
}
|
|
5
|
+
export declare const Snackbar: import("react").ForwardRefExoticComponent<SnackbarProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
Copyright 2025 Cognizant Technology Solutions Corp, www.cognizant.com.
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import CloseIcon from "@mui/icons-material/Close";
|
|
18
|
+
import { styled, useColorScheme } from "@mui/material";
|
|
19
|
+
import Box from "@mui/material/Box";
|
|
20
|
+
import IconButton from "@mui/material/IconButton";
|
|
21
|
+
import { SnackbarContent, useSnackbar } from "notistack";
|
|
22
|
+
import { forwardRef } from "react";
|
|
23
|
+
import { isDarkMode } from "../../utils/Theme.js";
|
|
24
|
+
// #region: Styled Components
|
|
25
|
+
const IconBox = styled(Box)({
|
|
26
|
+
position: "relative",
|
|
27
|
+
bottom: "2px",
|
|
28
|
+
"&.success": {
|
|
29
|
+
color: "var(--bs-success)",
|
|
30
|
+
},
|
|
31
|
+
"&.error": {
|
|
32
|
+
color: "var(--bs-danger)",
|
|
33
|
+
},
|
|
34
|
+
"&.warning": {
|
|
35
|
+
color: "var(--bs-warning)",
|
|
36
|
+
},
|
|
37
|
+
"&.info": {
|
|
38
|
+
color: "var(--bs-info)",
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
// #endregion: Types
|
|
42
|
+
// Passing Snackbar callback as a function because if we use an arrow function here we'd have to set displayName
|
|
43
|
+
export const Snackbar = forwardRef(
|
|
44
|
+
// eslint-disable-next-line prefer-arrow-callback
|
|
45
|
+
function Snackbar({ description, hideIconVariant = false, iconVariant, id, message, variant }, ref) {
|
|
46
|
+
const { closeSnackbar } = useSnackbar();
|
|
47
|
+
const handleCloseSnackbar = () => closeSnackbar(id);
|
|
48
|
+
const icon = iconVariant[variant];
|
|
49
|
+
const { mode, systemMode } = useColorScheme();
|
|
50
|
+
const darkMode = isDarkMode(mode, systemMode);
|
|
51
|
+
// Temporary styling for implementation of dark mode
|
|
52
|
+
const darkModeStyling = {
|
|
53
|
+
backgroundColor: darkMode ? "var(--bs-dark-mode-dim)" : "var(--bs-white)",
|
|
54
|
+
color: darkMode ? "var(--bs-white)" : "var(--bs-primary)",
|
|
55
|
+
};
|
|
56
|
+
return (_jsx(SnackbarContent, { ref: ref, role: "alert", children: _jsxs(Box, { className: `${variant}-snackbar-notification`, id: `${id}-snackbar-box`, sx: {
|
|
57
|
+
...darkModeStyling,
|
|
58
|
+
borderColor: "transparent",
|
|
59
|
+
borderRadius: "var(--bs-border-radius)",
|
|
60
|
+
borderWidth: "1px",
|
|
61
|
+
boxShadow: `0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12),
|
|
62
|
+
0 9px 28px 8px rgba(0, 0, 0, 0.05)`,
|
|
63
|
+
maxWidth: "450px",
|
|
64
|
+
minWidth: "250px",
|
|
65
|
+
padding: "0.9rem",
|
|
66
|
+
}, children: [!hideIconVariant && (_jsx(Box, { id: `${id}-snackbar-icon-box-container`, sx: { display: "inline-flex", flexDirection: "column" }, children: _jsx(IconBox, { className: variant, "data-testid": `${id}-snackbar-icon-box`, id: `${id}-snackbar-icon-box`, children: icon }) })), _jsxs(Box, { id: `${id}-snackbar-content-box`, sx: {
|
|
67
|
+
display: "inline-flex",
|
|
68
|
+
flexDirection: "column",
|
|
69
|
+
width: "88%",
|
|
70
|
+
wordWrap: "break-word",
|
|
71
|
+
}, children: [_jsx(Box, { id: `${id}-snackbar-message-box`, sx: {
|
|
72
|
+
display: "block",
|
|
73
|
+
// If no description, this is the only message, so reduce font size
|
|
74
|
+
fontSize: description ? "0.95rem" : "0.85rem",
|
|
75
|
+
paddingRight: "25px",
|
|
76
|
+
}, children: message }), _jsx(IconButton, { "aria-label": "close", id: `${id}-close-icon-btn`, onClick: handleCloseSnackbar, sx: {
|
|
77
|
+
position: "absolute",
|
|
78
|
+
right: 4,
|
|
79
|
+
top: 4,
|
|
80
|
+
}, children: _jsx(CloseIcon, { "data-testid": `${id}-close-icon`, id: `${id}-close-icon`, sx: {
|
|
81
|
+
color: "var(--bs-gray-medium)",
|
|
82
|
+
fontSize: "0.6em",
|
|
83
|
+
} }) }), description && (_jsx(Box, { id: `${id}-snackbar-description-box`, sx: { fontSize: "0.8rem", paddingTop: "10px", paddingBottom: "10px" }, children: description }))] })] }) }));
|
|
84
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { FC, ReactNode } from "react";
|
|
2
|
+
interface ConfirmationModalProps {
|
|
3
|
+
cancelBtnLabel?: string;
|
|
4
|
+
closeable?: boolean;
|
|
5
|
+
content: ReactNode;
|
|
6
|
+
handleCancel?: () => void;
|
|
7
|
+
handleOk?: () => void;
|
|
8
|
+
id: string;
|
|
9
|
+
maskCloseable?: boolean;
|
|
10
|
+
okBtnLabel?: string;
|
|
11
|
+
title: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
export declare const ConfirmationModal: FC<ConfirmationModalProps>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
Copyright 2025 Cognizant Technology Solutions Corp, www.cognizant.com.
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { styled } from "@mui/material";
|
|
18
|
+
import Box from "@mui/material/Box";
|
|
19
|
+
import Button from "@mui/material/Button";
|
|
20
|
+
import { useState } from "react";
|
|
21
|
+
import { MUIDialog } from "./MUIDialog.js";
|
|
22
|
+
// #region: Styled Components
|
|
23
|
+
const StyledButton = styled(Button)({
|
|
24
|
+
fontSize: "0.8em",
|
|
25
|
+
padding: "0px 7px",
|
|
26
|
+
});
|
|
27
|
+
const StyledOKButton = styled(StyledButton)(({ disabled }) => ({
|
|
28
|
+
backgroundColor: disabled ? "rgba(0, 0, 0, 0.12) !important" : "var(--bs-primary) !important",
|
|
29
|
+
}));
|
|
30
|
+
// #endregion: Types
|
|
31
|
+
export const ConfirmationModal = ({ cancelBtnLabel, closeable = true, content = "", handleCancel = null, handleOk = null, id = "", maskCloseable = false, okBtnLabel, title = "", }) => {
|
|
32
|
+
const [modalOpen, setModalOpen] = useState(true);
|
|
33
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
34
|
+
const handleCloseWrapper = (_event, reason) => {
|
|
35
|
+
// Prevent closing on click of gray background mask
|
|
36
|
+
if (!maskCloseable && reason === "backdropClick") {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
handleCancel?.(); // call handleCancel if it's not null
|
|
40
|
+
setModalOpen(false);
|
|
41
|
+
};
|
|
42
|
+
const handleOKWrapper = async () => {
|
|
43
|
+
try {
|
|
44
|
+
if (handleOk) {
|
|
45
|
+
setIsLoading(true);
|
|
46
|
+
handleOk();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
setModalOpen(false);
|
|
51
|
+
setIsLoading(false);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const Footer = (_jsxs(_Fragment, { children: [handleCancel && ( // If there is no handleCancel passed, Cancel button will not be rendered
|
|
55
|
+
_jsx(StyledButton
|
|
56
|
+
// This ID needs to be dynamic because there can be several instances of this on the page
|
|
57
|
+
, {
|
|
58
|
+
// This ID needs to be dynamic because there can be several instances of this on the page
|
|
59
|
+
id: `${id}-confirm-cancel-btn`, onClick: () => handleCloseWrapper(), disabled: isLoading, variant: "outlined", children: cancelBtnLabel ?? "Cancel" }, "confirm-cancel")), _jsx(StyledOKButton
|
|
60
|
+
// This ID needs to be dynamic because there can be several instances of this on the page
|
|
61
|
+
, {
|
|
62
|
+
// This ID needs to be dynamic because there can be several instances of this on the page
|
|
63
|
+
id: `${id}-confirm-ok-btn`, disabled: isLoading, onClick: () => handleOKWrapper(), variant: "contained", children: okBtnLabel ?? "Confirm" }, "confirm-ok")] }));
|
|
64
|
+
return (_jsx(MUIDialog, { closeable: closeable, contentSx: { fontSize: "0.8rem", minWidth: "550px", paddingTop: "0" }, footer: Footer, id: `${id}-confirm-main`, isOpen: modalOpen, onClose: (_event, reason) => handleCloseWrapper(_event, reason), title: title, children: _jsx(Box, { id: `${id}-confirm-content`, sx: { marginTop: "15px" }, children: content }) }));
|
|
65
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SnackbarKey, SnackbarOrigin } from "notistack";
|
|
2
|
+
import { JSX as ReactJSX } from "react";
|
|
3
|
+
export declare enum NotificationType {
|
|
4
|
+
"success" = 0,
|
|
5
|
+
"info" = 1,
|
|
6
|
+
"warning" = 2,
|
|
7
|
+
"error" = 3
|
|
8
|
+
}
|
|
9
|
+
export declare function closeNotification(snackbarId?: SnackbarKey): void;
|
|
10
|
+
/**
|
|
11
|
+
* Convenience method to allow sending notifications to user with a one-liner.
|
|
12
|
+
* Simply wraps @Notification function
|
|
13
|
+
* @param variantType Indicates whether it's error, warning, info etc.
|
|
14
|
+
* @param message Brief summary of the notification
|
|
15
|
+
* @param description More complete description of the notification
|
|
16
|
+
* @param placement Where to show notification. Defaults to top-right.
|
|
17
|
+
*/
|
|
18
|
+
export declare function sendNotification(variantType: NotificationType, message: string, description?: string | ReactJSX.Element, placement?: SnackbarOrigin): void;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
Copyright 2025 Cognizant Technology Solutions Corp, www.cognizant.com.
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { closeSnackbar, enqueueSnackbar } from "notistack";
|
|
18
|
+
import { renderToString } from "react-dom/server";
|
|
19
|
+
export var NotificationType;
|
|
20
|
+
(function (NotificationType) {
|
|
21
|
+
NotificationType[NotificationType["success"] = 0] = "success";
|
|
22
|
+
NotificationType[NotificationType["info"] = 1] = "info";
|
|
23
|
+
NotificationType[NotificationType["warning"] = 2] = "warning";
|
|
24
|
+
NotificationType[NotificationType["error"] = 3] = "error";
|
|
25
|
+
})(NotificationType || (NotificationType = {}));
|
|
26
|
+
// Display warning and error notification popups for this many seconds
|
|
27
|
+
const ERROR_WARNING_NOTIFICATION_DURATION_MS = 15_000;
|
|
28
|
+
// Display info notification popups for this many seconds
|
|
29
|
+
const SUCCESS_NOTIFICATION_DURATION_MS = 5000;
|
|
30
|
+
export function closeNotification(snackbarId) {
|
|
31
|
+
closeSnackbar(snackbarId);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Convenience method to allow sending notifications to user with a one-liner.
|
|
35
|
+
* Simply wraps @Notification function
|
|
36
|
+
* @param variantType Indicates whether it's error, warning, info etc.
|
|
37
|
+
* @param message Brief summary of the notification
|
|
38
|
+
* @param description More complete description of the notification
|
|
39
|
+
* @param placement Where to show notification. Defaults to top-right.
|
|
40
|
+
*/
|
|
41
|
+
export function sendNotification(variantType, message, description = "",
|
|
42
|
+
// eslint-disable-next-line unicorn/no-object-as-default-parameter
|
|
43
|
+
placement = {
|
|
44
|
+
vertical: "top",
|
|
45
|
+
horizontal: "right",
|
|
46
|
+
}) {
|
|
47
|
+
// Log a copy to the console for troubleshooting
|
|
48
|
+
const descriptionAsString = typeof description === "string" ? description : renderToString(description);
|
|
49
|
+
console.debug(`Notification: Message: "${message}" Description: "${descriptionAsString}"`);
|
|
50
|
+
// Show error and warnings for longer
|
|
51
|
+
let duration;
|
|
52
|
+
switch (variantType) {
|
|
53
|
+
case NotificationType.info:
|
|
54
|
+
case NotificationType.success:
|
|
55
|
+
duration = SUCCESS_NOTIFICATION_DURATION_MS;
|
|
56
|
+
break;
|
|
57
|
+
case NotificationType.warning:
|
|
58
|
+
case NotificationType.error:
|
|
59
|
+
default:
|
|
60
|
+
duration = ERROR_WARNING_NOTIFICATION_DURATION_MS;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
// Use some minor customization to be able to inject ids for testing
|
|
64
|
+
const messageForId = message
|
|
65
|
+
.replaceAll(" ", "-")
|
|
66
|
+
.replace(/[^a-zA-Z0-9-]/gu, "")
|
|
67
|
+
.toLowerCase();
|
|
68
|
+
const baseId = `notification-message-${messageForId}-${NotificationType[variantType]}`;
|
|
69
|
+
const messageSpan = _jsx("span", { id: `${baseId}-span`, children: message });
|
|
70
|
+
enqueueSnackbar(messageSpan, {
|
|
71
|
+
anchorOrigin: placement,
|
|
72
|
+
autoHideDuration: duration,
|
|
73
|
+
disableWindowBlurListener: true,
|
|
74
|
+
// @ts-expect-error - Could "declare module" to fix this
|
|
75
|
+
description,
|
|
76
|
+
key: baseId,
|
|
77
|
+
variant: NotificationType[variantType],
|
|
78
|
+
});
|
|
79
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Component, ErrorInfo, ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Interface to define the state for this component
|
|
4
|
+
*/
|
|
5
|
+
interface ErrorBoundaryState {
|
|
6
|
+
readonly hasError: boolean;
|
|
7
|
+
readonly error: unknown;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Interface to define the incoming props for this component
|
|
11
|
+
*/
|
|
12
|
+
interface ErrorBoundaryProps {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly children: ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Implements a system-wide error handler for NextJS pages in our app.
|
|
18
|
+
* Taken from here: https://nextjs.org/docs/advanced-features/error-handling
|
|
19
|
+
*
|
|
20
|
+
* Note: as of writing (April 2023) ReactJS does not support error boundaries for functional components (like all of
|
|
21
|
+
* those in UniLEAF are) so we take the approach of wrapping all components in our app with this class component that
|
|
22
|
+
* handles the error boundary.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
25
|
+
/**
|
|
26
|
+
* @public
|
|
27
|
+
* This is the key override called by ReactJS when an unhandled error is thrown. And this is why you cannot create
|
|
28
|
+
* error boundaries in functional components -- no way to override this method.
|
|
29
|
+
*/
|
|
30
|
+
static getDerivedStateFromError(error: unknown): {
|
|
31
|
+
hasError: boolean;
|
|
32
|
+
error: unknown;
|
|
33
|
+
};
|
|
34
|
+
constructor(props: ErrorBoundaryProps);
|
|
35
|
+
componentDidCatch(error: unknown, errorInfo: ErrorInfo): void;
|
|
36
|
+
render(): string | number | boolean | Iterable<ReactNode> | import("react").PromiseLikeOfReactNode | import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
}
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
Copyright 2025 Cognizant Technology Solutions Corp, www.cognizant.com.
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { Component } from "react";
|
|
18
|
+
import ErrorPage from "./ErrorPage.js";
|
|
19
|
+
/**
|
|
20
|
+
* Implements a system-wide error handler for NextJS pages in our app.
|
|
21
|
+
* Taken from here: https://nextjs.org/docs/advanced-features/error-handling
|
|
22
|
+
*
|
|
23
|
+
* Note: as of writing (April 2023) ReactJS does not support error boundaries for functional components (like all of
|
|
24
|
+
* those in UniLEAF are) so we take the approach of wrapping all components in our app with this class component that
|
|
25
|
+
* handles the error boundary.
|
|
26
|
+
*/
|
|
27
|
+
export class ErrorBoundary extends Component {
|
|
28
|
+
/**
|
|
29
|
+
* @public
|
|
30
|
+
* This is the key override called by ReactJS when an unhandled error is thrown. And this is why you cannot create
|
|
31
|
+
* error boundaries in functional components -- no way to override this method.
|
|
32
|
+
*/
|
|
33
|
+
static getDerivedStateFromError(error) {
|
|
34
|
+
// Update state so the next render will show the fallback UI
|
|
35
|
+
return { hasError: true, error };
|
|
36
|
+
}
|
|
37
|
+
constructor(props) {
|
|
38
|
+
super(props);
|
|
39
|
+
// Define a state variable to track whether is an error or not
|
|
40
|
+
this.state = { hasError: false, error: null };
|
|
41
|
+
}
|
|
42
|
+
// No need for "this" here
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
44
|
+
componentDidCatch(error, errorInfo) {
|
|
45
|
+
// TODO: Send this to central logging service once it's available
|
|
46
|
+
console.error({ error, errorInfo });
|
|
47
|
+
}
|
|
48
|
+
render() {
|
|
49
|
+
// Check if the error is thrown
|
|
50
|
+
if (this.state.hasError) {
|
|
51
|
+
// Render fallback UI
|
|
52
|
+
const id = this.props.id;
|
|
53
|
+
const error = this.state.error;
|
|
54
|
+
let fileName = "Unknown";
|
|
55
|
+
let lineNumber = null;
|
|
56
|
+
let columnNumber = null;
|
|
57
|
+
let message = "";
|
|
58
|
+
if (error instanceof Error) {
|
|
59
|
+
// the error object is an instance of the built-in Error type in JavaScript
|
|
60
|
+
const customError = error;
|
|
61
|
+
if (customError.fileName) {
|
|
62
|
+
fileName = customError.fileName;
|
|
63
|
+
}
|
|
64
|
+
if (customError.lineNumber != null) {
|
|
65
|
+
lineNumber = customError.lineNumber;
|
|
66
|
+
}
|
|
67
|
+
if (customError.columnNumber != null) {
|
|
68
|
+
columnNumber = customError.columnNumber;
|
|
69
|
+
}
|
|
70
|
+
message = customError.message;
|
|
71
|
+
}
|
|
72
|
+
return (_jsx(ErrorPage, { id: id, errorText: `${message} in ${fileName} line ${lineNumber} column ${columnNumber}` }));
|
|
73
|
+
}
|
|
74
|
+
// Return children components in case of no error
|
|
75
|
+
return this.props.children;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ReactElement } from "react";
|
|
2
|
+
interface ErrorPageProps {
|
|
3
|
+
id: string;
|
|
4
|
+
errorText: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* This is the page that will be shown to users when the outer error boundary is triggered
|
|
8
|
+
* @param id HTML id for the <code>div</code> for this page
|
|
9
|
+
* @param errorText Error text to be displayed
|
|
10
|
+
*/
|
|
11
|
+
export default function ErrorPage({ id, errorText }: ErrorPageProps): ReactElement;
|
|
12
|
+
export {};
|