export function getSystemUpgrades(): Promise<{
upgrades: SystemUpgrade[];
- latestLTS: string;
+ latestLTA: string;
+ installedVersionActive: boolean;
updateCenterRefresh: string;
}> {
return getJSON('/api/system/upgrades');
}
};
}
+
+export function useAppState() {
+ return React.useContext(AppStateContext);
+}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { Banner, Variant } from 'design-system';
+import { Banner } from 'design-system';
import { groupBy, isEmpty, mapValues } from 'lodash';
import * as React from 'react';
import DismissableAlert from '../../../components/ui/DismissableAlert';
import { translate } from '../../../helpers/l10n';
import { hasGlobalPermission } from '../../../helpers/users';
import { useSystemUpgrades } from '../../../queries/system';
-import { AppState } from '../../../types/appstate';
import { Permissions } from '../../../types/permissions';
-import { Dict } from '../../../types/types';
-import { CurrentUser, isLoggedIn } from '../../../types/users';
-import withAppStateContext from '../app-state/withAppStateContext';
-import withCurrentUserContext from '../current-user/withCurrentUserContext';
-import { isMinorUpdate, isPatchUpdate, isPreLTSUpdate, isPreviousLTSUpdate } from './helpers';
-
-const MAP_VARIANT: Dict<Variant> = {
- [UpdateUseCase.NewMinorVersion]: 'info',
- [UpdateUseCase.NewPatch]: 'warning',
- [UpdateUseCase.PreLTS]: 'warning',
- [UpdateUseCase.PreviousLTS]: 'error',
-};
+import { isLoggedIn } from '../../../types/users';
+import { useAppState } from '../app-state/withAppStateContext';
+import { useCurrentUser } from '../current-user/CurrentUserContext';
+import { BANNER_VARIANT, isCurrentVersionLTA, isMinorUpdate, isPatchUpdate } from './helpers';
interface Props {
- dismissable: boolean;
- appState: AppState;
- currentUser: CurrentUser;
+ dismissable?: boolean;
}
const VERSION_PARSER = /^(\d+)\.(\d+)(\.(\d+))?/;
-export function UpdateNotification({ dismissable, appState, currentUser }: Readonly<Props>) {
+export default function UpdateNotification({ dismissable }: Readonly<Props>) {
+ const appState = useAppState();
+ const { currentUser } = useCurrentUser();
+
const canUserSeeNotification =
isLoggedIn(currentUser) && hasGlobalPermission(currentUser, Permissions.Admin);
const regExpParsedVersion = VERSION_PARSER.exec(appState.version);
+
const { data } = useSystemUpgrades({
enabled: canUserSeeNotification && regExpParsedVersion !== null,
});
return null;
}
- const { upgrades, latestLTS } = data;
+ const { upgrades, installedVersionActive, latestLTA } = data;
+
const parsedVersion = regExpParsedVersion
.slice(1)
.map(Number)
}),
);
- let useCase = UpdateUseCase.NewMinorVersion;
+ let useCase = UpdateUseCase.NewVersion;
- if (isPreviousLTSUpdate(parsedVersion, latestLTS, systemUpgrades)) {
- useCase = UpdateUseCase.PreviousLTS;
- } else if (isPreLTSUpdate(parsedVersion, latestLTS)) {
- useCase = UpdateUseCase.PreLTS;
- } else if (isPatchUpdate(parsedVersion, systemUpgrades)) {
+ if (!installedVersionActive) {
+ useCase = UpdateUseCase.CurrentVersionInactive;
+ } else if (
+ isPatchUpdate(parsedVersion, systemUpgrades) &&
+ (isCurrentVersionLTA(parsedVersion, latestLTA) || !isMinorUpdate(parsedVersion, systemUpgrades))
+ ) {
useCase = UpdateUseCase.NewPatch;
- } else if (isMinorUpdate(parsedVersion, systemUpgrades)) {
- useCase = UpdateUseCase.NewMinorVersion;
}
const latest = [...upgrades].sort(
return dismissable ? (
<DismissableAlert
alertKey={dismissKey}
- variant={MAP_VARIANT[useCase]}
+ variant={BANNER_VARIANT[useCase]}
className={`it__promote-update-notification it__upgrade-prompt-${useCase}`}
>
{translate('admin_notification.update', useCase)}
<SystemUpgradeButton
systemUpgrades={upgrades}
updateUseCase={useCase}
- latestLTS={latestLTS}
+ latestLTA={latestLTA}
/>
</DismissableAlert>
) : (
- <Banner variant={MAP_VARIANT[useCase]} className={`it__upgrade-prompt-${useCase}`}>
+ <Banner variant={BANNER_VARIANT[useCase]} className={`it__upgrade-prompt-${useCase}`}>
{translate('admin_notification.update', useCase)}
<SystemUpgradeButton
systemUpgrades={upgrades}
updateUseCase={useCase}
- latestLTS={latestLTS}
+ latestLTA={latestLTA}
/>
</Banner>
);
}
-
-export default withCurrentUserContext(withAppStateContext(UpdateNotification));
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { Variant } from 'design-system';
import { isEmpty } from 'lodash';
-import { sortUpgrades } from '../../../components/upgrade/utils';
+import { UpdateUseCase, sortUpgrades } from '../../../components/upgrade/utils';
import { SystemUpgrade } from '../../../types/system';
-
-const MONTH_BEFOR_PREVIOUS_LTS_NOTIFICATION = 6;
+import { Dict } from '../../../types/types';
type GroupedSystemUpdate = {
[x: string]: Record<string, SystemUpgrade[]>;
};
-export const isPreLTSUpdate = (parsedVersion: number[], latestLTS: string) => {
+export const isCurrentVersionLTA = (parsedVersion: number[], latestLTS: string) => {
const [currentMajor, currentMinor] = parsedVersion;
const [ltsMajor, ltsMinor] = latestLTS.split('.').map(Number);
- return currentMajor < ltsMajor || (currentMajor === ltsMajor && currentMinor < ltsMinor);
-};
-
-export const isPreviousLTSUpdate = (
- parsedVersion: number[],
- latestLTS: string,
- systemUpgrades: GroupedSystemUpdate,
-) => {
- const [ltsMajor, ltsMinor] = latestLTS.split('.').map(Number);
- let ltsOlderThan6Month = false;
- const beforeLts = isPreLTSUpdate(parsedVersion, latestLTS);
- if (beforeLts) {
- const allLTS = sortUpgrades(systemUpgrades[ltsMajor][ltsMinor]);
- const ltsReleaseDate = new Date(allLTS[allLTS.length - 1]?.releaseDate ?? '');
- if (isNaN(ltsReleaseDate.getTime())) {
- // We can not parse the LTS date.
- // It is unlikly that this could happen but consider LTS to be old.
- return true;
- }
- ltsOlderThan6Month =
- ltsReleaseDate.setMonth(ltsReleaseDate.getMonth() + MONTH_BEFOR_PREVIOUS_LTS_NOTIFICATION) -
- Date.now() <
- 0;
- }
- return ltsOlderThan6Month && beforeLts;
+ return currentMajor === ltsMajor && currentMinor === ltsMinor;
};
export const isMinorUpdate = (parsedVersion: number[], systemUpgrades: GroupedSystemUpdate) => {
export const isPatchUpdate = (parsedVersion: number[], systemUpgrades: GroupedSystemUpdate) => {
const [currentMajor, currentMinor, currentPatch] = parsedVersion;
const allMinor = systemUpgrades[currentMajor];
- const allPatch = sortUpgrades(allMinor[currentMinor] || []);
+ const allPatch = sortUpgrades(allMinor?.[currentMinor] ?? []);
if (!isEmpty(allPatch)) {
const [, , latestPatch] = allPatch[0].version.split('.').map(Number);
}
return false;
};
+
+export const BANNER_VARIANT: Dict<Variant> = {
+ [UpdateUseCase.NewVersion]: 'info',
+ [UpdateUseCase.CurrentVersionInactive]: 'error',
+ [UpdateUseCase.NewPatch]: 'warning',
+};
<Helmet defer={false} title={translate('system_info.page')} />
<PageContentFontWrapper className="sw-body-sm sw-pb-8">
<div>
- <UpdateNotification dismissable={false} />
+ <UpdateNotification />
</div>
{sysInfoData && (
<PageHeader
import { groupUpgrades, sortUpgrades, UpdateUseCase } from './utils';
interface Props {
- latestLTS: string;
+ latestLTA: string;
systemUpgrades: SystemUpgrade[];
- updateUseCase?: UpdateUseCase;
+ updateUseCase: UpdateUseCase;
}
export default function SystemUpgradeButton(props: Readonly<Props>) {
- const { latestLTS, systemUpgrades, updateUseCase } = props;
+ const { latestLTA, systemUpgrades, updateUseCase } = props;
const [isSystemUpgradeFormOpen, setSystemUpgradeFormOpen] = React.useState(false);
<SystemUpgradeForm
onClose={closeSystemUpgradeForm}
systemUpgrades={groupUpgrades(sortUpgrades(systemUpgrades))}
- latestLTS={latestLTS}
+ latestLTA={latestLTA}
updateUseCase={updateUseCase}
/>
)}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { FlagMessage, Link, Modal, Variant } from 'design-system';
+import { FlagMessage, Link, Modal } from 'design-system';
import { filter, flatMap, isEmpty, negate } from 'lodash';
import * as React from 'react';
-import withAppStateContext from '../../app/components/app-state/withAppStateContext';
+import { useAppState } from '../../app/components/app-state/withAppStateContext';
+import { BANNER_VARIANT } from '../../app/components/update-notification/helpers';
import { translate } from '../../helpers/l10n';
-import { AppState } from '../../types/appstate';
import { SystemUpgrade } from '../../types/system';
import SystemUpgradeItem from './SystemUpgradeItem';
import { SYSTEM_VERSION_REGEXP, UpdateUseCase } from './utils';
interface Props {
- appState: AppState;
onClose: () => void;
systemUpgrades: SystemUpgrade[][];
- latestLTS: string;
- updateUseCase?: UpdateUseCase;
+ latestLTA: string;
+ updateUseCase: UpdateUseCase;
}
-const MAP_ALERT: { [key in UpdateUseCase]?: Variant } = {
- [UpdateUseCase.NewPatch]: 'warning',
- [UpdateUseCase.PreLTS]: 'warning',
- [UpdateUseCase.PreviousLTS]: 'error',
-};
-
-export function SystemUpgradeForm(props: Readonly<Props>) {
- const { appState, latestLTS, onClose, updateUseCase, systemUpgrades } = props;
+export default function SystemUpgradeForm(props: Readonly<Props>) {
+ const appState = useAppState();
+ const { latestLTA, onClose, updateUseCase, systemUpgrades } = props;
let systemUpgradesWithPatch: SystemUpgrade[][] = [];
- const alertVariant = updateUseCase ? MAP_ALERT[updateUseCase] : undefined;
+ const alertVariant =
+ updateUseCase !== UpdateUseCase.NewVersion ? BANNER_VARIANT[updateUseCase] : undefined;
const header = translate('system.system_upgrade');
const parsedVersion = SYSTEM_VERSION_REGEXP.exec(appState.version);
let patches: SystemUpgrade[] = [];
systemUpgradesWithPatch.push(patches);
} else {
- let untilLTS = false;
+ let untilLTA = false;
for (const upgrades of systemUpgrades) {
- if (untilLTS === false) {
+ if (untilLTA === false) {
systemUpgradesWithPatch.push(upgrades);
- untilLTS = upgrades.some((upgrade) => upgrade.version.startsWith(latestLTS));
+ untilLTA = upgrades.some((upgrade) => upgrade.version.startsWith(latestLTA));
}
}
}
onClose={onClose}
body={
<>
- {alertVariant && updateUseCase && (
+ {alertVariant && (
<FlagMessage variant={alertVariant} className={`it__upgrade-alert-${updateUseCase}`}>
{translate('admin_notification.update', updateUseCase)}
</FlagMessage>
key={upgrades[upgrades.length - 1].version}
systemUpgrades={upgrades}
isPatch={upgrades === patches}
- isLTSVersion={upgrades.some((upgrade) => upgrade.version.startsWith(latestLTS))}
+ isLTAVersion={upgrades.some((upgrade) => upgrade.version.startsWith(latestLTA))}
/>
))}
</>
/>
);
}
-
-export default withAppStateContext(SystemUpgradeForm);
export interface SystemUpgradeItemProps {
edition: EditionKey | undefined;
- isLTSVersion: boolean;
+ isLTAVersion: boolean;
isPatch: boolean;
systemUpgrades: SystemUpgrade[];
}
export default function SystemUpgradeItem(props: SystemUpgradeItemProps) {
- const { edition, isPatch, isLTSVersion, systemUpgrades } = props;
+ const { edition, isPatch, isLTAVersion, systemUpgrades } = props;
const lastUpgrade = systemUpgrades[0];
const downloadUrl = getEditionDownloadUrl(
getEdition(edition || EditionKey.community),
lastUpgrade,
);
let header = translate('system.latest_version');
- if (isLTSVersion) {
- header = translate('system.lts_version');
+ if (isLTAVersion) {
+ header = translate('system.lta_version');
} else if (isPatch) {
header = translate('system.latest_patch');
}
header: byRole('heading', { name: 'system.system_upgrade' }),
downloadLink: byRole('link', { name: /system.see_sonarqube_downloads/ }),
- ltsVersionHeader: byRole('heading', { name: /system.lts_version/ }),
+ ltaVersionHeader: byRole('heading', { name: /system.lta_version/ }),
newPatchWarning: byText(/admin_notification.update/),
};
await user.click(ui.learnMoreButton.get());
expect(ui.header.get()).toBeInTheDocument();
- expect(ui.ltsVersionHeader.get()).toBeInTheDocument();
+ expect(ui.ltaVersionHeader.get()).toBeInTheDocument();
expect(ui.downloadLink.get()).toBeInTheDocument();
});
renderSystemUpgradeButton(
{
updateUseCase: UpdateUseCase.NewPatch,
- latestLTS: '9.9',
+ latestLTA: '9.9',
systemUpgrades: [{ downloadUrl: '', version: '9.9.1' }],
},
'9.9',
expect(ui.header.get()).toBeInTheDocument();
expect(ui.newPatchWarning.get()).toBeInTheDocument();
- expect(ui.ltsVersionHeader.get()).toBeInTheDocument();
+ expect(ui.ltaVersionHeader.get()).toBeInTheDocument();
expect(ui.downloadLink.get()).toBeInTheDocument();
});
) {
renderComponent(
<SystemUpgradeButton
- latestLTS="9.9"
+ updateUseCase={UpdateUseCase.NewVersion}
+ latestLTA="9.9"
systemUpgrades={[
{ downloadUrl: 'eight', version: '9.8' },
{ downloadUrl: 'lts', version: '9.9' },
import { SystemUpgrade } from '../../types/system';
export enum UpdateUseCase {
- NewMinorVersion = 'new_minor_version',
+ NewVersion = 'new_version',
+ CurrentVersionInactive = 'current_version_inactive',
NewPatch = 'new_patch',
- PreLTS = 'pre_lts',
- PreviousLTS = 'previous_lts',
}
export const SYSTEM_VERSION_REGEXP = /^(\d+)\.(\d+)(\.(\d+))?/;
# Admin notification
#
#------------------------------------------------------------------------------
-admin_notification.update.new_minor_version=There’s a new version of SonarQube available. Update to enjoy the latest updates and features.
admin_notification.update.new_patch=There’s an update available for your SonarQube instance. Please update to make sure you benefit from the latest security and bug fixes.
-admin_notification.update.pre_lts=You’re running a version of SonarQube that has reached end of life. Please upgrade to a supported version at your earliest convenience.
-admin_notification.update.previous_lts=You’re running a version of SonarQube that is past end of life. Please upgrade to a supported version immediately.
+admin_notification.update.new_version=There’s a new version of SonarQube available. Upgrade to the latest active version to access new updates and features.
+admin_notification.update.current_version_inactive=You’re running a version of SonarQube that is no longer active. Please upgrade to an active version immediately.
#------------------------------------------------------------------------------
#
system.how_to_upgrade=How to upgrade?
system.latest_version=Latest Version
system.latest_patch=Patch Release
-system.lts_version=Latest LTS Version
+system.lta_version=Latest LTA Version
system.log_level.warning=This level has performance impacts, please make sure to get back to INFO level once your investigation is done. Please note that when the server is restarted, logging will revert to the level configured in sonar.properties.
system.log_level.warning.short=Current logs level has performance impacts, get back to INFO level.
system.log_level.info=Your selection does not affect the Search Engine.