Merge branch 'v15/dev' into contrib

This commit is contained in:
Andy Butland
2025-01-20 11:47:52 +01:00
7 changed files with 116 additions and 67 deletions

View File

@@ -78,10 +78,10 @@ export class UmbBackofficeContext extends UmbContextBase<UmbBackofficeContext> {
this.#activeSectionAlias.setValue(alias);
}
public async serverUpgradeCheck(): Promise<boolean> {
public async serverUpgradeCheck() {
const version = await this.observe(this.version).asPromise();
const repository = new UmbSysinfoRepository(this);
const check = await repository.serverUpgradeCheck();
return !!check;
return repository.serverUpgradeCheck(version);
}
}

View File

@@ -3,9 +3,10 @@ import { isCurrentUserAnAdmin } from '@umbraco-cms/backoffice/current-user';
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UMB_APP_CONTEXT } from '@umbraco-cms/backoffice/app';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UMB_NEWVERSION_MODAL, UMB_SYSINFO_MODAL } from '@umbraco-cms/backoffice/sysinfo';
import { UMB_APP_CONTEXT } from '@umbraco-cms/backoffice/app';
import type { UmbServerUpgradeCheck } from '@umbraco-cms/backoffice/sysinfo';
@customElement('umb-backoffice-header-logo')
export class UmbBackofficeHeaderLogoElement extends UmbLitElement {
@@ -16,7 +17,7 @@ export class UmbBackofficeHeaderLogoElement extends UmbLitElement {
private _isUserAdmin = false;
@state()
private _serverUpgradeCheck = false;
private _serverUpgradeCheck: UmbServerUpgradeCheck | null = null;
@state()
private _serverUrl = '';
@@ -52,7 +53,7 @@ export class UmbBackofficeHeaderLogoElement extends UmbLitElement {
this._isUserAdmin = await isCurrentUserAnAdmin(this);
if (this._isUserAdmin) {
this._serverUpgradeCheck = this.#backofficeContext ? await this.#backofficeContext.serverUpgradeCheck() : false;
this._serverUpgradeCheck = this.#backofficeContext ? await this.#backofficeContext.serverUpgradeCheck() : null;
}
}
@@ -76,7 +77,7 @@ export class UmbBackofficeHeaderLogoElement extends UmbLitElement {
${this._serverUpgradeCheck
? html`<uui-button
@click=${this.#openNewVersion}
color="danger"
color="positive"
label=${this.localize.term('general_newVersionAvailable')}></uui-button>`
: ''}
@@ -98,9 +99,15 @@ export class UmbBackofficeHeaderLogoElement extends UmbLitElement {
}
async #openNewVersion() {
if (!this._serverUpgradeCheck) return;
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
modalManager
.open(this, UMB_NEWVERSION_MODAL)
.open(this, UMB_NEWVERSION_MODAL, {
data: {
comment: this._serverUpgradeCheck.comment,
downloadUrl: this._serverUpgradeCheck.url,
},
})
.onSubmit()
.catch(() => {});
}

View File

@@ -59,8 +59,8 @@ export const serverInformationHandlers = [
ctx.status(200),
ctx.json<GetServerUpgradeCheckResponse>({
type: 'Minor',
comment: "14.2.0.0 is released. Upgrade today - it's free!",
url: 'https://our.umbraco.com/download/releases/1420',
comment: "15.2.0 is released. Upgrade today - it's free!",
url: 'https://our.umbraco.com/download/releases/1520',
}),
);
}),

View File

@@ -1,30 +1,19 @@
import { UmbSysinfoRepository } from '../repository/sysinfo.repository.js';
import type { UmbServerUpgradeCheck } from '../types.js';
import { css, customElement, html, state, when } from '@umbraco-cms/backoffice/external/lit';
import type { UmbNewVersionModalData } from '../modals/new-version-modal.token.js';
import { css, customElement, html, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
@customElement('umb-new-version')
export class UmbNewVersionElement extends UmbModalBaseElement {
export class UmbNewVersionElement extends UmbModalBaseElement<UmbNewVersionModalData> {
@state()
private _serverUpgradeCheck: UmbServerUpgradeCheck | null = null;
#sysinfoRepository = new UmbSysinfoRepository(this);
override async connectedCallback() {
super.connectedCallback();
this._serverUpgradeCheck = await this.#sysinfoRepository.serverUpgradeCheck();
}
override render() {
return html`
<uui-dialog>
<uui-dialog-layout headline=${this.localize.term('general_newVersionAvailable')}>
${when(
this._serverUpgradeCheck === null,
() => html`<uui-loader-bar></uui-loader-bar>`,
() => html` <div>${this._serverUpgradeCheck!.comment}</div> `,
)}
${this.data?.comment}
<uui-button
@click=${this._submitModal}
@@ -32,9 +21,9 @@ export class UmbNewVersionElement extends UmbModalBaseElement {
look="secondary"
label=${this.localize.term('general_close')}></uui-button>
${this._serverUpgradeCheck?.url
${this.data?.downloadUrl
? html` <uui-button
.href=${this._serverUpgradeCheck.url}
.href=${this.data.downloadUrl}
target="_blank"
slot="actions"
look="primary"

View File

@@ -1,6 +1,18 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export const UMB_NEWVERSION_MODAL = new UmbModalToken('Umb.Modal.NewVersion', {
export interface UmbNewVersionModalData {
/**
* The release notes of the new version.
*/
comment: string;
/**
* The download URL of the new version.
*/
downloadUrl: string;
}
export const UMB_NEWVERSION_MODAL = new UmbModalToken<UmbNewVersionModalData>('Umb.Modal.NewVersion', {
modal: {
type: 'dialog',
size: 'medium',

View File

@@ -20,48 +20,103 @@ export class UmbSysinfoRepository extends UmbRepositoryBase {
return data;
}
async serverUpgradeCheck(): Promise<UmbServerUpgradeCheck | null> {
/**
* Check if the server has an upgrade available and return the result.
* If the server has an upgrade available, the result will be stored in local storage.
* If the server does not have an upgrade available, the result will be stored in local storage as well.
* @param {string} currentVersion The current version of the server.
* @returns {Promise<UmbServerUpgradeCheck | null>} The server upgrade check result or null if the check is not allowed or if the check failed.
*/
async serverUpgradeCheck(currentVersion: string): Promise<UmbServerUpgradeCheck | null> {
// Check if we are allowed to check again
const appContext = await this.getContext(UMB_APP_CONTEXT);
const versionCheckPeriod = await this.observe(appContext.getServerConnection().versionCheckPeriod).asPromise();
if (versionCheckPeriod <= 0) {
// We do not need to check the server for an upgrade
return null;
}
let shouldCheck = true;
const lastUpgradeCheck = this.#getStoredServerUpgradeCheck(currentVersion);
const lastCheck = localStorage.getItem('umb:lastUpgradeCheck');
const now = new Date();
if (lastCheck) {
const lastCheckDate = new Date(lastCheck);
const diff = now.getTime() - lastCheckDate.getTime();
const diffDays = diff / (1000 * 3600 * 24);
// If we have a stored check, then return it if it is still valid
if (lastUpgradeCheck !== null) {
// If we have a stored check, then check if we should check again based on the period
if (lastUpgradeCheck.createdAt) {
const lastCheckDate = new Date(lastUpgradeCheck.createdAt);
const diff = new Date().getTime() - lastCheckDate.getTime();
const diffDays = diff / (1000 * 3600 * 24);
if (diffDays < versionCheckPeriod) {
shouldCheck = false;
}
// If we should not check, then return what we have stored if it is still valid
if (!shouldCheck) {
return this.#getStoredServerUpgradeCheck(lastCheckDate);
if (diffDays < versionCheckPeriod) {
// If we should not check, then return what we have stored if it is still valid
if (lastUpgradeCheck.type.toLowerCase() !== 'none') {
return lastUpgradeCheck;
}
return null; // no upgrade available
}
}
}
if (!shouldCheck) {
// Check the server for an upgrade because we have no stored check or the stored check is invalid
return this.#fetchServerUpgradeCheck(versionCheckPeriod, currentVersion);
}
/**
* Get the stored server upgrade check if it is still valid, otherwise return null and remove the stored check.
* @param {string} currentVersion The current version of the server.
* @returns {UmbServerUpgradeCheck | null} The stored server upgrade check or null if it is not valid.
*/
#getStoredServerUpgradeCheck(currentVersion: string): UmbServerUpgradeCheck | null {
const storedCheck = localStorage.getItem('umb:serverUpgradeCheck');
if (!storedCheck) {
return null;
}
// Check the server
const upgradeCheck: UmbServerUpgradeCheck = JSON.parse(storedCheck);
// Check that the stored check is for the same version
if (upgradeCheck.version !== currentVersion) {
localStorage.removeItem('umb:serverUpgradeCheck');
return null;
}
// Check that the stored check is not older than the last check
if (upgradeCheck.createdAt) {
const createdAt = new Date(upgradeCheck.createdAt);
const expiresAt = new Date(upgradeCheck.expires);
if (expiresAt.getTime() <= createdAt.getTime()) {
localStorage.removeItem('umb:serverUpgradeCheck');
return null;
}
}
return upgradeCheck;
}
/**
* Fetch the server upgrade check from the server and store the result in local storage.
* @param {number} versionCheckPeriod A period in days to wait before checking the server again.
* @param {string} currentVersion The current version of the server.
* @returns {Promise<UmbServerUpgradeCheck | null>} The server upgrade check result or null if the check failed.
*/
async #fetchServerUpgradeCheck(
versionCheckPeriod: number,
currentVersion: string,
): Promise<UmbServerUpgradeCheck | null> {
// Check the server for an upgrade because we have no stored check or the stored check is invalid
const { data } = await tryExecute(ServerService.getServerUpgradeCheck());
if (data) {
// Save the last check date including the data received
const expiresAt = new Date();
expiresAt.setDate(expiresAt.getDate() + versionCheckPeriod);
const upgradeCheck = { ...data, expires: expiresAt.toISOString() } satisfies UmbServerUpgradeCheck;
const upgradeCheck = {
...data,
expires: expiresAt.toISOString(),
version: currentVersion,
createdAt: new Date().toISOString(),
} satisfies UmbServerUpgradeCheck;
localStorage.setItem('umb:serverUpgradeCheck', JSON.stringify(upgradeCheck));
localStorage.setItem('umb:lastUpgradeCheck', now.toISOString());
// Only return if we have a valid type
if (data.type.toLowerCase() !== 'none') {
@@ -69,24 +124,6 @@ export class UmbSysinfoRepository extends UmbRepositoryBase {
}
}
return null;
}
#getStoredServerUpgradeCheck(lastCheck: Date): UmbServerUpgradeCheck | null {
const storedCheck = localStorage.getItem('umb:serverUpgradeCheck');
if (storedCheck) {
const upgradeCheck: UmbServerUpgradeCheck = JSON.parse(storedCheck);
// Check that the stored check is not older than the last check
const expiresAt = new Date(upgradeCheck.expires);
if (expiresAt.getTime() > lastCheck.getTime()) {
if (upgradeCheck.type.toLowerCase() !== 'none') {
return upgradeCheck;
}
} else {
localStorage.removeItem('umb:serverUpgradeCheck');
}
}
return null;
return null; // no upgrade available
}
}

View File

@@ -1,3 +1,7 @@
import type { UpgradeCheckResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
export type UmbServerUpgradeCheck = UpgradeCheckResponseModel & { expires: string };
export type UmbServerUpgradeCheck = UpgradeCheckResponseModel & {
expires: string;
version?: string;
createdAt?: string;
};