diff options
author | Ismail Cherri <ismail.cherri@sonarsource.com> | 2024-12-02 18:17:25 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-12-04 20:03:23 +0000 |
commit | 82363aafd35b4c2569d2dd4136630a2700ee2010 (patch) | |
tree | 9e2ffba352f8f77577d4214c66a181e5c4990c37 | |
parent | ac98556dca2639470bc730a72707c28255fbdb49 (diff) | |
download | sonarqube-82363aafd35b4c2569d2dd4136630a2700ee2010.tar.gz sonarqube-82363aafd35b4c2569d2dd4136630a2700ee2010.zip |
SONAR-23656 Update footer to reflect instance mode
6 files changed, 116 insertions, 45 deletions
diff --git a/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx b/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx index 06496f14848..e1c14d66f7f 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx @@ -21,12 +21,20 @@ import styled from '@emotion/styled'; import { LinkHighlight, LinkStandalone } from '@sonarsource/echoes-react'; import { useIntl } from 'react-intl'; -import { FlagMessage, LAYOUT_VIEWPORT_MIN_WIDTH, themeBorder, themeColor } from '~design-system'; +import { + FlagMessage, + LAYOUT_VIEWPORT_MIN_WIDTH, + SeparatorCircleIcon, + themeBorder, + themeColor, +} from '~design-system'; import InstanceMessage from '../../components/common/InstanceMessage'; import AppVersionStatus from '../../components/shared/AppVersionStatus'; import { COMMUNITY_FORUM_URL, DocLink } from '../../helpers/doc-links'; import { useDocUrl } from '../../helpers/docs'; import { getEdition } from '../../helpers/editions'; +import { getInstanceVersionNumber } from '../../helpers/strings'; +import { useStandardExperienceModeQuery } from '../../queries/mode'; import { EditionKey } from '../../types/editions'; import GlobalFooterBranding from './GlobalFooterBranding'; import { useAppState } from './app-state/withAppStateContext'; @@ -37,8 +45,10 @@ interface GlobalFooterProps { export default function GlobalFooter({ hideLoggedInInfo }: Readonly<GlobalFooterProps>) { const appState = useAppState(); + const { data: isStandardMode } = useStandardExperienceModeQuery(); const currentEdition = appState?.edition && getEdition(appState.edition); const intl = useIntl(); + const version = getInstanceVersionNumber(appState.version); const docUrl = useDocUrl(); @@ -46,7 +56,7 @@ export default function GlobalFooter({ hideLoggedInInfo }: Readonly<GlobalFooter return ( <StyledFooter className="sw-p-6" id="footer"> - <div className="sw-typo-default sw-h-full sw-flex sw-flex-col sw-items-stretch"> + <div className="sw-h-full sw-flex sw-flex-col sw-items-stretch"> {appState?.productionDatabase === false && ( <FlagMessage className="sw-mb-4" id="evaluation_warning" variant="warning"> <p> @@ -63,21 +73,45 @@ export default function GlobalFooter({ hideLoggedInInfo }: Readonly<GlobalFooter </FlagMessage> )} - <div className="sw-flex sw-justify-between sw-items-center"> + <div className="sw-text-xs sw-flex sw-justify-between sw-items-center"> <GlobalFooterBranding /> - <ul className="sw-flex sw-items-center sw-gap-3 sw-ml-4"> - {!hideLoggedInInfo && currentEdition && <li>{currentEdition.name}</li>} + {!hideLoggedInInfo && ( + <ul className="sw-code sw-flex sw-items-center sw-gap-1"> + {currentEdition && ( + <> + <li>{currentEdition.name}</li> + <SeparatorCircleIcon aria-hidden as="li" /> + </> + )} - {!hideLoggedInInfo && appState?.version && ( - <li className="sw-code"> - <AppVersionStatus /> - </li> - )} + {appState?.version && ( + <> + <li>{intl.formatMessage({ id: 'footer.version.short' }, { version })}</li> + <SeparatorCircleIcon aria-hidden as="li" /> + <li> + <AppVersionStatus statusOnly /> + </li> + </> + )} + {isStandardMode !== undefined && ( + <> + <SeparatorCircleIcon aria-hidden as="li" /> + <li className="sw-uppercase"> + {intl.formatMessage({ + id: `footer.mode.${isStandardMode ? 'STANDARD' : 'MQR'}`, + })} + </li> + </> + )} + </ul> + )} + <ul className="sw-flex sw-items-center sw-gap-3"> <li> {isCommunityBuildRunning ? ( <LinkStandalone + shouldOpenInNewTab highlight={LinkHighlight.CurrentColor} to="https://www.gnu.org/licenses/lgpl-3.0.txt" > @@ -85,6 +119,7 @@ export default function GlobalFooter({ hideLoggedInInfo }: Readonly<GlobalFooter </LinkStandalone> ) : ( <LinkStandalone + shouldOpenInNewTab highlight={LinkHighlight.CurrentColor} to="https://www.sonarsource.com/legal/sonarqube/terms-and-conditions/" > @@ -94,19 +129,28 @@ export default function GlobalFooter({ hideLoggedInInfo }: Readonly<GlobalFooter </li> <li> - <LinkStandalone highlight={LinkHighlight.CurrentColor} to={COMMUNITY_FORUM_URL}> + <LinkStandalone + shouldOpenInNewTab + highlight={LinkHighlight.CurrentColor} + to={COMMUNITY_FORUM_URL} + > {intl.formatMessage({ id: 'footer.community' })} </LinkStandalone> </li> <li> - <LinkStandalone highlight={LinkHighlight.CurrentColor} to={docUrl(DocLink.Root)}> + <LinkStandalone + shouldOpenInNewTab + highlight={LinkHighlight.CurrentColor} + to={docUrl(DocLink.Root)} + > {intl.formatMessage({ id: 'footer.documentation' })} </LinkStandalone> </li> <li> <LinkStandalone + shouldOpenInNewTab highlight={LinkHighlight.CurrentColor} to={docUrl(DocLink.InstanceAdminPluginVersionMatrix)} > diff --git a/server/sonar-web/src/main/js/app/components/GlobalFooterBranding.tsx b/server/sonar-web/src/main/js/app/components/GlobalFooterBranding.tsx index 27a6e7a2ea4..2f82db1f585 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalFooterBranding.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalFooterBranding.tsx @@ -24,32 +24,42 @@ import { isOfficial } from '../../helpers/system'; export default function GlobalFooterBranding() { const official = isOfficial(); - return official ? ( - <div> - SonarQube™ technology is powered by{' '} - <Link highlight={LinkHighlight.CurrentColor} to="https://www.sonarsource.com"> - SonarSource SA - </Link> - </div> - ) : ( - <div> - This application is based on{' '} - <Link - highlight={LinkHighlight.CurrentColor} - to="https://www.sonarsource.com/products/sonarqube/?referrer=sonarqube" - title="SonarQube™" - > - SonarQube™ - </Link>{' '} - but is <strong>not</strong> an official version provided by{' '} - <Link - highlight={LinkHighlight.CurrentColor} - to="https://www.sonarsource.com" - title="SonarSource SA" - > - SonarSource SA - </Link> - . + return ( + <div className="max-[1400px]:sw-max-w-[12rem] sw-flex sw-items-center"> + {official ? ( + <span> + SonarQube™ technology is powered by{' '} + <Link + shouldOpenInNewTab + highlight={LinkHighlight.CurrentColor} + to="https://www.sonarsource.com" + > + SonarSource SA + </Link> + </span> + ) : ( + <span> + This application is based on{' '} + <Link + shouldOpenInNewTab + highlight={LinkHighlight.CurrentColor} + to="https://www.sonarsource.com/products/sonarqube/?referrer=sonarqube" + title="SonarQube™" + > + SonarQube™ + </Link>{' '} + but is <strong>not</strong> an official version provided by{' '} + <Link + shouldOpenInNewTab + highlight={LinkHighlight.CurrentColor} + to="https://www.sonarsource.com" + title="SonarSource SA" + > + SonarSource SA + </Link> + . + </span> + )} </div> ); } diff --git a/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooter-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooter-test.tsx index 004b857d034..a00ba6c3d13 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooter-test.tsx +++ b/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooter-test.tsx @@ -20,6 +20,7 @@ import { addDays, subDays } from 'date-fns'; import { byRole, byText } from '~sonar-aligned/helpers/testSelector'; +import { ModeServiceMock } from '../../../api/mocks/ModeServiceMock'; import SystemServiceMock from '../../../api/mocks/SystemServiceMock'; import { getEdition } from '../../../helpers/editions'; import { mockAppState } from '../../../helpers/testMocks'; @@ -27,13 +28,16 @@ import { renderComponent } from '../../../helpers/testReactTestingUtils'; import { AppState } from '../../../types/appstate'; import { EditionKey } from '../../../types/editions'; import { FCProps } from '../../../types/misc'; +import { Mode } from '../../../types/mode'; import GlobalFooter from '../GlobalFooter'; const systemMock = new SystemServiceMock(); +const modeHandler = new ModeServiceMock(); const COMMUNITY = getEdition(EditionKey.community).name; afterEach(() => { + modeHandler.reset(); systemMock.reset(); }); @@ -42,7 +46,7 @@ it('should render the logged-in information', async () => { expect(ui.databaseWarningMessage.query()).not.toBeInTheDocument(); - expect(ui.footerListItems.getAll()).toHaveLength(7); + expect(ui.footerListItems.getAll()).toHaveLength(8); expect(byText(COMMUNITY).get()).toBeInTheDocument(); expect(await ui.versionLabel('4.2').find()).toBeInTheDocument(); @@ -78,6 +82,16 @@ it('should show inactive status if offline and reached EOL', async () => { expect(await ui.ltaDocumentationLinkInactive.find()).toBeInTheDocument(); }); +it.each([ + ['Standard', Mode.Standard, 'STANDARD'], + ['MQR', Mode.MQR, 'MQR'], +])('should show correct %s mode', async (_, mode, expected) => { + modeHandler.setMode(mode); + renderGlobalFooter(); + + expect(await byText(`footer.mode.${expected}`).find()).toBeInTheDocument(); +}); + it('should not render missing logged-in information', () => { renderGlobalFooter({}, { edition: undefined, version: '' }); @@ -124,7 +138,7 @@ const ui = { databaseWarningMessage: byText('footer.production_database_warning'), versionLabel: (version?: string) => - version ? byText(/footer\.version\.*(\d.\d)/) : byText(/footer\.version/), + version ? byText(/footer\.version\.short\.*(\d.\d)/) : byText(/footer\.version\.short/), // links websiteLink: byRole('link', { name: 'SonarQube™' }), diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/SystemApp-it.tsx b/server/sonar-web/src/main/js/apps/system/components/__tests__/SystemApp-it.tsx index bd30797fb90..cdd86c1660c 100644 --- a/server/sonar-web/src/main/js/apps/system/components/__tests__/SystemApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/SystemApp-it.tsx @@ -148,7 +148,7 @@ function getPageObjects() { healthCauseWarning: byText('Friendly warning'), saveButton: byRole('button', { name: 'save' }), versionLabel: (version?: string) => - version ? byText(/footer\.version\s*(\d.\d)/) : byText(/footer\.version/), + version ? byText(/footer\.version\.full\s*(\d.\d)/) : byText(/footer\.version\.full/), ltaDocumentationLinkActive: byRole('link', { name: `footer.version.status.active`, }), diff --git a/server/sonar-web/src/main/js/components/shared/AppVersionStatus.tsx b/server/sonar-web/src/main/js/components/shared/AppVersionStatus.tsx index bd481c9c061..6af7f6e8f56 100644 --- a/server/sonar-web/src/main/js/components/shared/AppVersionStatus.tsx +++ b/server/sonar-web/src/main/js/components/shared/AppVersionStatus.tsx @@ -29,7 +29,7 @@ import { isCurrentVersionEOLActive } from '../../helpers/system'; import { useSystemUpgrades } from '../../queries/system'; import { EditionKey } from '../../types/editions'; -export default function AppVersionStatus() { +export default function AppVersionStatus({ statusOnly }: Readonly<{ statusOnly?: boolean }>) { const { data } = useSystemUpgrades(); const { edition, version, versionEOL } = useAppState(); @@ -45,7 +45,7 @@ export default function AppVersionStatus() { const intl = useIntl(); return intl.formatMessage( - { id: `footer.version` }, + { id: statusOnly ? `footer.version.status` : `footer.version.full` }, { version: getInstanceVersionNumber(version), status: edition && edition !== EditionKey.community && ( diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 4f70d1535a6..056494d574f 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -4779,11 +4779,14 @@ footer.production_database_warning=Embedded database should be used for evaluati footer.security=Security footer.status=Status footer.terms=Terms -footer.version=v{version}{status} +footer.version.full=v{version}{status} +footer.version.short=v{version} +footer.version.status={status} footer.version.status.active=ACTIVE footer.version.status.inactive=NO LONGER ACTIVE footer.web_api=Web API - +footer.mode.STANDARD=Standard Experience +footer.mode.MQR=MQR Mode #------------------------------------------------------------------------------ # |