import { themeColor, themeContrast, themeShadow } from '../helpers/theme'; | import { themeColor, themeContrast, themeShadow } from '../helpers/theme'; | ||||
export const TopBar = styled.nav` | export const TopBar = styled.nav` | ||||
${tw`sw-z-top-navbar`} | |||||
${tw`sw-px-6 sw-pt-4`} | ${tw`sw-px-6 sw-pt-4`} | ||||
${tw`sw-box-border`}; | ${tw`sw-box-border`}; | ||||
${tw`sw-w-full`}; | ${tw`sw-w-full`}; |
import { differenceBy } from 'lodash'; | import { differenceBy } from 'lodash'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { createPortal } from 'react-dom'; | |||||
import { Helmet } from 'react-helmet-async'; | import { Helmet } from 'react-helmet-async'; | ||||
import { Outlet } from 'react-router-dom'; | import { Outlet } from 'react-router-dom'; | ||||
import { validateProjectAlmBinding } from '../../api/alm-settings'; | import { validateProjectAlmBinding } from '../../api/alm-settings'; | ||||
watchStatusTimer?: number; | watchStatusTimer?: number; | ||||
mounted = false; | mounted = false; | ||||
state: State = { isPending: false, loading: true }; | state: State = { isPending: false, loading: true }; | ||||
portalAnchor: Element | null = null; | |||||
componentDidMount() { | componentDidMount() { | ||||
this.mounted = true; | this.mounted = true; | ||||
this.fetchComponent(); | this.fetchComponent(); | ||||
this.portalAnchor = document.querySelector('#component-nav-portal'); | |||||
} | } | ||||
componentDidUpdate(prevProps: Props) { | componentDidUpdate(prevProps: Props) { | ||||
{component && | {component && | ||||
!([ComponentQualifier.File, ComponentQualifier.TestFile] as string[]).includes( | !([ComponentQualifier.File, ComponentQualifier.TestFile] as string[]).includes( | ||||
component.qualifier | component.qualifier | ||||
) && ( | |||||
) && | |||||
this.portalAnchor && | |||||
/* Use a portal to fix positioning until we can fully review the layout */ | |||||
createPortal( | |||||
<ComponentNav | <ComponentNav | ||||
component={component} | component={component} | ||||
currentTask={currentTask} | currentTask={currentTask} | ||||
isInProgress={isInProgress} | isInProgress={isInProgress} | ||||
isPending={isPending} | isPending={isPending} | ||||
projectBindingErrors={projectBindingErrors} | projectBindingErrors={projectBindingErrors} | ||||
/> | |||||
/>, | |||||
this.portalAnchor | |||||
)} | )} | ||||
{loading ? ( | {loading ? ( |
<NCDAutoUpdateMessage /> | <NCDAutoUpdateMessage /> | ||||
<UpdateNotification dismissable /> | <UpdateNotification dismissable /> | ||||
<GlobalNav location={location} /> | <GlobalNav location={location} /> | ||||
{/* The following is the portal anchor point for the component nav | |||||
* See ComponentContainer.tsx | |||||
*/} | |||||
<div id="component-nav-portal" /> | |||||
</div> | </div> | ||||
<Outlet /> | <Outlet /> | ||||
</MetricsContextProvider> | </MetricsContextProvider> |
} | } | ||||
.system-announcement-banner { | .system-announcement-banner { | ||||
position: fixed; | |||||
width: 100%; | width: 100%; | ||||
z-index: var(--globalBannerZIndex); | z-index: var(--globalBannerZIndex); | ||||
} | } |
} | } | ||||
.indexation-notification-banner { | .indexation-notification-banner { | ||||
position: fixed; | |||||
width: 100%; | width: 100%; | ||||
z-index: var(--globalBannerZIndex); | z-index: var(--globalBannerZIndex); | ||||
margin-bottom: 0 !important; | margin-bottom: 0 !important; |
*/ | */ | ||||
import { TopBar } from 'design-system'; | import { TopBar } from 'design-system'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import ScreenPositionHelper from '../../../../components/common/ScreenPositionHelper'; | |||||
import NCDAutoUpdateMessage from '../../../../components/new-code-definition/NCDAutoUpdateMessage'; | import NCDAutoUpdateMessage from '../../../../components/new-code-definition/NCDAutoUpdateMessage'; | ||||
import { translate } from '../../../../helpers/l10n'; | import { translate } from '../../../../helpers/l10n'; | ||||
import { ProjectAlmBindingConfigurationErrors } from '../../../../types/alm-settings'; | import { ProjectAlmBindingConfigurationErrors } from '../../../../types/alm-settings'; | ||||
} | } | ||||
}, [component, component.key]); | }, [component, component.key]); | ||||
let prDecoNotifComponent: JSX.Element; | |||||
if (projectBindingErrors !== undefined) { | |||||
prDecoNotifComponent = <ComponentNavProjectBindingErrorNotif component={component} />; | |||||
} | |||||
return ( | return ( | ||||
<ScreenPositionHelper className="sw-inline"> | |||||
{({ top }) => ( | |||||
<> | |||||
<TopBar | |||||
className="sw-sticky" | |||||
id="context-navigation" | |||||
aria-label={translate('qualifier', component.qualifier)} | |||||
style={{ top: `${top}px` }} | |||||
> | |||||
<div className="sw-min-h-10 sw-flex sw-justify-between"> | |||||
<Header component={component} /> | |||||
<HeaderMeta | |||||
component={component} | |||||
currentTask={currentTask} | |||||
isInProgress={isInProgress} | |||||
isPending={isPending} | |||||
/> | |||||
</div> | |||||
<Menu component={component} isInProgress={isInProgress} isPending={isPending} /> | |||||
</TopBar> | |||||
<NCDAutoUpdateMessage component={component} /> | |||||
{prDecoNotifComponent} | |||||
</> | |||||
<> | |||||
<TopBar id="context-navigation" aria-label={translate('qualifier', component.qualifier)}> | |||||
<div className="sw-min-h-10 sw-flex sw-justify-between"> | |||||
<Header component={component} /> | |||||
<HeaderMeta | |||||
component={component} | |||||
currentTask={currentTask} | |||||
isInProgress={isInProgress} | |||||
isPending={isPending} | |||||
/> | |||||
</div> | |||||
<Menu component={component} isInProgress={isInProgress} isPending={isPending} /> | |||||
</TopBar> | |||||
<NCDAutoUpdateMessage component={component} /> | |||||
{projectBindingErrors !== undefined && ( | |||||
<ComponentNavProjectBindingErrorNotif component={component} /> | |||||
)} | )} | ||||
</ScreenPositionHelper> | |||||
</> | |||||
); | ); | ||||
} | } |
.promote-update-notification .dismissable-alert-banner { | .promote-update-notification .dismissable-alert-banner { | ||||
margin-bottom: 0 !important; | margin-bottom: 0 !important; | ||||
position: fixed; | |||||
width: 100%; | width: 100%; | ||||
z-index: var(--globalBannerZIndex); | z-index: var(--globalBannerZIndex); | ||||
} | } |