UNPKG

@boomerang-io/carbon-addons-boomerang-react

Version:
215 lines (208 loc) 18.1 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var React = require('react'); var reactQuery = require('@tanstack/react-query'); var react = require('@carbon/react'); var icons = require('@carbon/react/icons'); var HeaderAppSwitcher = require('./HeaderAppSwitcher.js'); var HeaderTeamSwitcher = require('./HeaderTeamSwitcher.js'); var HeaderMenu = require('./HeaderMenu.js'); var NotificationsContainer = require('../Notifications/NotificationsContainer.js'); var PlatformNotificationsContainer = require('../PlatformNotifications/PlatformNotificationsContainer.js'); var UserRequests = require('./UserRequests.js'); var useHeaderMenu = require('../../hooks/useHeaderMenu.js'); var useWindowSize = require('../../hooks/useWindowSize.js'); var servicesConfig = require('../../config/servicesConfig.js'); var settings = require('../../internal/settings.js'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var React__default = /*#__PURE__*/_interopDefault(React); /* IBM Confidential 694970X, 69497O0 © Copyright IBM Corp. 2022, 2025 */ const MenuListId = { Notifcations: "header-notifications-dialog", Profile: "header-profile-menu", Requests: "header-user-requests-menu", RightPanel: "header-right-panel-dialog", SideNav: "header-sidenav-menu", Support: "header-support-menu", instanceSwitcher: "header-instanceSwitcher-menu", Switcher: "header-switcher-menu", TeamSwitcher: "header-team-switcher-menu", }; const MenuButtonId = { Notifcations: "header-notifications-dialog-button", Profile: "header-profile-menu-button", Requests: "header-user-requests-menu-button", RightPanel: "header-right-panel-dialog-button", SideNav: "header-sidenav-menu-button", Support: "header-support-menu-button", InstanceSwitcher: "header-instanceSwitcher-menu-button", Switcher: "header-switcher-menu-button", TeamSwitcher: "header-team-switcher-menu-button", }; const MenuAriaLabelRecord = { Notifcations: "Notifications dialog", Profile: "Profile menu", Requests: "Requests menu", RightPanel: "RightPanel dialog", SideNav: "SideNav menu", instanceSwitcher: "Instance Switcher Menu", Support: "Support menu", Switcher: "Switcher menu", TeamSwitcher: "Team Switcher menu", }; const headerButtonClassNames = "cds--btn--icon-only cds--header__action cds--btn cds--btn--primary cds--btn--icon-only cds--btn cds--btn--primary"; const instanceCheckMarkContainerClass = "instance-checkmark-style-container"; function Header(props) { const { analyticsHelpers, productName, baseEnvUrl, baseServicesUrl, carbonTheme = "g10", className, createJoinTeamTrigger, enableTeamSwitcher = true, history, isLaunchpad = false, isLoadingTeamSwitcher, isSuccessTeamSwitcher, setIsSuccessTeamSwitcher, navLinks, platform, prefixName = "", refetchUser, refetchNavigation, rightPanel, skipToContentProps, templateMeteringEvent, trackEvent, triggerEvent, user, userTeams, userTeamsAssets, } = props; const hasUserTeams = Boolean(userTeams); const userTeamsUrl = servicesConfig.serviceUrl.getUserTeamsServices({ baseServicesUrl }); const teamsQuery = reactQuery.useQuery({ queryKey: [userTeamsUrl], queryFn: servicesConfig.resolver.query(userTeamsUrl, null), enabled: !hasUserTeams && Boolean(baseServicesUrl), }); const showTeamSwitcher = enableTeamSwitcher && Boolean(user); return (React__default.default.createElement(React__default.default.Fragment, null, React__default.default.createElement(react.Theme, { theme: carbonTheme }, React__default.default.createElement(react.Header, { "aria-label": "App navigation header", className: className }, skipToContentProps ? React__default.default.createElement(react.SkipToContent, { ...skipToContentProps }) : null, React__default.default.createElement(SidenavMenu, { leftPanel: props.leftPanel, navLinks: props.navLinks }), React__default.default.createElement(react.HeaderName, { href: `${baseEnvUrl}/launchpad`, prefix: prefixName, "data-testid": "header-product" }, productName), React__default.default.createElement(react.HeaderNavigation, { "aria-label": "Platform navigation" }, Array.isArray(navLinks) ? navLinks.map((link) => (React__default.default.createElement(react.HeaderMenuItem, { "aria-label": `Link for ${link.name}`, "data-testid": "header-menu-link", href: link.url, isCurrentPage: window?.location?.href && link.url ? window.location.href.startsWith(link.url) : false, key: link.name, target: link.isExternal ? "_blank" : undefined, rel: link.isExternal ? "noopener noreferrer" : undefined }, link.name))) : null), React__default.default.createElement(react.HeaderGlobalBar, null, showTeamSwitcher ? (React__default.default.createElement(HeaderTeamSwitcher.default, { analyticsHelpers: analyticsHelpers, baseServicesUrl: baseServicesUrl, createJoinTeamTrigger: createJoinTeamTrigger, history: history, isLaunchpad: isLaunchpad, isLoadingTeamSwitcher: isLoadingTeamSwitcher, isSuccessTeamSwitcher: isSuccessTeamSwitcher, setIsSuccessTeamSwitcher: setIsSuccessTeamSwitcher, menuAriaLabelRecord: MenuAriaLabelRecord.TeamSwitcher, menuButtonId: MenuButtonId.TeamSwitcher, menuListId: MenuListId.TeamSwitcher, navigationPlatform: platform, refetchUser: refetchUser, refetchNavigation: refetchNavigation, teamsQuery: teamsQuery, trackEvent: trackEvent, user: user, userTeams: userTeams })) : null, props?.instanceSwitcherEnabled && (React__default.default.createElement(InstanceSwitcherMenu, { enabled: Boolean(props.instanceSwitcherEnabled), menuItems: platform?.instances })), React__default.default.createElement(RequestsMenu, { baseEnvUrl: baseEnvUrl, enabled: Boolean(props.requestSummary), summary: props.requestSummary }), React__default.default.createElement(NotificationsMenu, { baseEnvUrl: baseEnvUrl, baseServicesUrl: baseServicesUrl, enabled: Boolean(props.enableNotifications), countEnabled: Boolean(props.enableNotificationsCount) }), React__default.default.createElement(SupportMenu, { enabled: Array.isArray(props.supportMenuItems) && props.supportMenuItems.length > 0, menuItems: props.supportMenuItems }), React__default.default.createElement(ProfileMenu, { enabled: Array.isArray(props.profileMenuItems) && props.profileMenuItems.length > 0, menuItems: props.profileMenuItems }), React__default.default.createElement(AppSwitcherMenu, { baseEnvUrl: baseEnvUrl, baseServicesUrl: baseServicesUrl, enabled: props.enableAppSwitcher, templateMeteringEvent: templateMeteringEvent, triggerEvent: triggerEvent, userTeams: userTeamsAssets }), React__default.default.createElement(RightPanelMenu, { enabled: Boolean(rightPanel && Object.keys(rightPanel).length), ...rightPanel })))), React__default.default.createElement(NotificationsContainer.default, { enableMultiContainer: true, containerId: `${settings.prefix}--bmrg-header-notifications` }))); } function InstanceSwitcherMenu(props) { const currentURL = window?.location?.href; const { isOpen, toggleActive, ref } = useHeaderMenu.default(MenuButtonId.InstanceSwitcher); if (!props.enabled) { return null; } return (React__default.default.createElement("div", { className: `${settings.prefix}--bmrg-header-instance-switcher`, style: { position: "relative" }, ref: ref }, React__default.default.createElement("button", { "aria-controls": MenuListId.instanceSwitcher, "aria-expanded": isOpen, "aria-haspopup": "menu", "aria-label": MenuAriaLabelRecord.instanceSwitcher, className: headerButtonClassNames, "data-testid": "header-instanceSwitcher-link", id: MenuButtonId.InstanceSwitcher, onClick: toggleActive }, React__default.default.createElement(icons.Wikis, { size: 20 })), isOpen ? (React__default.default.createElement(HeaderMenu.default, { "aria-labelledby": MenuButtonId.InstanceSwitcher, id: MenuListId.instanceSwitcher }, Array.isArray(props.menuItems) ? props.menuItems.map((item) => (React__default.default.createElement(react.HeaderMenuItem, { "aria-label": `Instance Switcher for ${item.instanceName}`, "data-testid": "header-menu-instance-switcher", href: item.url, key: item.instanceName, target: "_self", rel: "noopener noreferrer" }, React__default.default.createElement("div", { className: instanceCheckMarkContainerClass }, React__default.default.createElement("span", null, item.instanceName), item.url && currentURL?.includes(item.url) ? (React__default.default.createElement("span", null, React__default.default.createElement(icons.Checkmark, null), " ")) : (""))))) : null)) : null)); } function RequestsMenu(props) { const { isOpen, toggleActive, ref } = useHeaderMenu.default(MenuButtonId.Requests); if (!props.enabled) { return null; } return (React__default.default.createElement("div", { style: { position: "relative" }, ref: ref }, React__default.default.createElement("button", { "aria-controls": MenuListId.Requests, "aria-expanded": isOpen, "aria-haspopup": "menu", "aria-label": MenuAriaLabelRecord.Requests, className: headerButtonClassNames, id: MenuButtonId.Requests, "data-testid": "header-requests-link", onClick: toggleActive }, React__default.default.createElement(icons.Collaborate, { size: 20 })), isOpen ? (React__default.default.createElement(HeaderMenu.default, { "aria-labelledby": MenuButtonId.Requests, id: MenuListId.Requests }, React__default.default.createElement(UserRequests.default, { baseEnvUrl: props.baseEnvUrl, summary: props.summary }))) : null)); } function NotificationBadge(props) { return (React__default.default.createElement("div", { className: `${settings.prefix}--bmrg-header-notifications-badge__icon-container` }, React__default.default.createElement(icons.Notification, { size: 20 }), props.count > 0 && (React__default.default.createElement("span", { className: `${settings.prefix}--bmrg-header-notifications-badge__icon-badge` }, props.count)))); } function NotificationsMenu(props) { const { isOpen, toggleActive, ref } = useHeaderMenu.default(MenuButtonId.Notifcations); const [hasNewNotifications, setHasNewNotifications] = React__default.default.useState(false); const [notificationsCount, setNotificationsCount] = React__default.default.useState(0); let icon = null; if (!props.enabled || !props.baseEnvUrl || !props.baseServicesUrl) { return null; } icon = hasNewNotifications ? React__default.default.createElement(icons.NotificationNew, { size: 20 }) : React__default.default.createElement(icons.Notification, { size: 20 }); if (props.countEnabled && hasNewNotifications) { icon = React__default.default.createElement(NotificationBadge, { count: notificationsCount }); } return (React__default.default.createElement("div", { style: { position: "relative" }, ref: ref }, React__default.default.createElement("button", { "aria-controls": MenuListId.Notifcations, "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-label": MenuAriaLabelRecord.Notifcations, className: headerButtonClassNames, "data-testid": "header-notifications-link", id: MenuButtonId.Notifcations, onClick: toggleActive }, icon), React__default.default.createElement(PlatformNotificationsContainer.default, { "aria-labelledby": MenuButtonId.Notifcations, baseEnvUrl: props.baseEnvUrl, baseServicesUrl: props.baseServicesUrl, id: MenuListId.Notifcations, isOpen: isOpen, setHasNewNotifications: setHasNewNotifications, setNotificationsCount: setNotificationsCount }))); } function SupportMenu(props) { const { isOpen, toggleActive, ref } = useHeaderMenu.default(MenuButtonId.Support); if (!props.enabled) { return null; } return (React__default.default.createElement("div", { style: { position: "relative" }, ref: ref }, React__default.default.createElement("button", { "aria-controls": MenuListId.Support, "aria-expanded": isOpen, "aria-haspopup": "menu", "aria-label": MenuAriaLabelRecord.Support, className: headerButtonClassNames, "data-testid": "header-support-link", id: MenuButtonId.Support, onClick: toggleActive }, React__default.default.createElement(icons.Help, { size: 20 })), isOpen ? (React__default.default.createElement(HeaderMenu.default, { "aria-labelledby": MenuButtonId.Support, id: MenuListId.Support }, props.menuItems)) : null)); } function ProfileMenu(props) { const { isOpen, toggleActive, ref } = useHeaderMenu.default(MenuButtonId.Profile); if (!props.enabled) { return null; } return (React__default.default.createElement("div", { style: { position: "relative" }, ref: ref }, React__default.default.createElement("button", { "aria-controls": MenuListId.Profile, "aria-expanded": isOpen, "aria-haspopup": "menu", "aria-label": MenuAriaLabelRecord.Profile, className: headerButtonClassNames, "data-testid": "header-profile-link", id: MenuButtonId.Profile, onClick: toggleActive }, React__default.default.createElement(icons.UserAvatar, { size: 20 })), isOpen ? (React__default.default.createElement(HeaderMenu.default, { "aria-labelledby": MenuButtonId.Profile, id: MenuListId.Profile }, props.menuItems)) : null)); } function AppSwitcherMenu(props) { const { isOpen, toggleActive, ref } = useHeaderMenu.default(MenuButtonId.Switcher); const hasUserTeamsAssets = Boolean(props.userTeams); const userTeamsAssetsUrl = servicesConfig.serviceUrl.getUserTeamsServicesAssets({ baseServicesUrl: props.baseServicesUrl }); const queryEnabled = isOpen && props.enabled && !hasUserTeamsAssets && Boolean(props.baseServicesUrl); const teamsAssetsQuery = reactQuery.useQuery({ queryKey: [userTeamsAssetsUrl], queryFn: servicesConfig.resolver.query(userTeamsAssetsUrl, null), enabled: queryEnabled, }); if (!props.enabled || !props.baseServicesUrl) { return null; } return (React__default.default.createElement("div", { ref: ref }, React__default.default.createElement("button", { "aria-controls": MenuListId.Switcher, "aria-expanded": isOpen, "aria-haspopup": "menu", "aria-label": MenuAriaLabelRecord.Switcher, className: headerButtonClassNames, "data-testid": "header-appswitcher-link", id: MenuButtonId.Switcher, onClick: toggleActive }, isOpen ? React__default.default.createElement(icons.Close, { size: 20 }) : React__default.default.createElement(icons.Switcher, { size: 20 })), React__default.default.createElement(HeaderAppSwitcher.default, { baseEnvUrl: props.baseEnvUrl, baseServicesUrl: props.baseServicesUrl, id: MenuListId.Switcher, isOpen: isOpen, teamsQuery: teamsAssetsQuery, templateMeteringEvent: props.templateMeteringEvent, triggerEvent: props.triggerEvent, userTeams: props.userTeams }))); } function RightPanelMenu(props) { const { isOpen, toggleActive, ref } = useHeaderMenu.default(MenuButtonId.RightPanel); if (!props.enabled) { return null; } return (React__default.default.createElement("div", { ref: ref }, React__default.default.createElement("button", { "aria-controls": MenuListId.RightPanel, "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-label": MenuAriaLabelRecord.RightPanel, className: headerButtonClassNames, "data-testid": "header-right-panel", id: MenuButtonId.RightPanel, onClick: toggleActive }, props.icon ?? React__default.default.createElement(icons.OpenPanelFilledRight, { size: 20 })), React__default.default.createElement(react.HeaderPanel, { id: MenuListId.RightPanel, role: "dialog", "aria-label": MenuAriaLabelRecord.RightPanel, expanded: isOpen }, props.component))); } function SidenavMenu(props) { const { ref, isOpen, setIsOpen, toggleActive } = useHeaderMenu.default(MenuButtonId.SideNav); const windowSize = useWindowSize.default(); const isMobileSidenavActive = windowSize.width < 1056; const closeMenu = () => { setIsOpen(false); }; if (typeof props.leftPanel === "function") { return (React__default.default.createElement("div", { ref: ref, "data-testid": "header-sidenav-menu" }, React__default.default.createElement(react.HeaderMenuButton, { "aria-label": isOpen ? "Close Side Nav" : "Expand Side Nav", id: MenuButtonId.SideNav, isActive: isOpen, isCollapsible: true, onClick: toggleActive }), props.leftPanel({ isOpen: isOpen, close: closeMenu, navLinks: isMobileSidenavActive ? props.navLinks : undefined, }))); } return (React__default.default.createElement("div", { ref: ref, "data-testid": "header-sidenav-menu" }, isMobileSidenavActive ? (React__default.default.createElement(React__default.default.Fragment, null, React__default.default.createElement(react.HeaderMenuButton, { "aria-label": isOpen ? "Close Side Nav" : "Expand Side Nav", id: MenuButtonId.SideNav, isActive: isOpen, isCollapsible: false, onClick: toggleActive }), // @ts-ignore React__default.default.createElement("div", { inert: isOpen ? undefined : "true" }, React__default.default.createElement(react.SideNav, { isChildOfHeader: true, "aria-label": "Side navigation", expanded: isOpen, isPersistent: false, onOverlayClick: closeMenu }, React__default.default.createElement(react.SideNavItems, null, props.navLinks?.map((link) => (React__default.default.createElement(react.SideNavLink, { large: true, "aria-label": `Link for ${link.name}`, href: link.url, isActive: window?.location?.href && link.url ? window.location.href.startsWith(link.url) : false, key: link.url + link.name }, link.name)))))))) : null)); } exports.default = Header;