Merge pull request #318 from umbraco/feature/resource-api-mixin
This commit is contained in:
@@ -2,12 +2,11 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
|
||||
import { ApiError, ProblemDetails, ProfilingResource } from '@umbraco-cms/backend-api';
|
||||
import { UmbContextConsumerMixin } from '@umbraco-cms/context-api';
|
||||
import { UmbNotificationDefaultData, UmbNotificationService } from '@umbraco-cms/services';
|
||||
import { UmbResourceController } from '@umbraco-cms/controllers';
|
||||
import { ProfilingResource } from '@umbraco-cms/backend-api';
|
||||
|
||||
@customElement('umb-dashboard-performance-profiling')
|
||||
export class UmbDashboardPerformanceProfilingElement extends UmbContextConsumerMixin(LitElement) {
|
||||
export class UmbDashboardPerformanceProfilingElement extends LitElement {
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
css`
|
||||
@@ -31,27 +30,7 @@ export class UmbDashboardPerformanceProfilingElement extends UmbContextConsumerM
|
||||
@state()
|
||||
private _profilingPerfomance = false;
|
||||
|
||||
private _notificationService?: UmbNotificationService;
|
||||
|
||||
private async _getProfilingStatus() {
|
||||
try {
|
||||
const status = await ProfilingResource.getProfilingStatus();
|
||||
this._profilingStatus = status.enabled;
|
||||
} catch (e) {
|
||||
if (e instanceof ApiError) {
|
||||
const error = e as ProblemDetails;
|
||||
const data: UmbNotificationDefaultData = { message: error.message ?? 'Something went wrong' };
|
||||
this._notificationService?.peek('danger', { data });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.consumeAllContexts(['umbNotificationService'], (instances) => {
|
||||
this._notificationService = instances['umbNotificationService'];
|
||||
});
|
||||
}
|
||||
private _resourceController = new UmbResourceController(this);
|
||||
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
@@ -59,6 +38,15 @@ export class UmbDashboardPerformanceProfilingElement extends UmbContextConsumerM
|
||||
this._profilingPerfomance = localStorage.getItem('profilingPerformance') === 'true';
|
||||
}
|
||||
|
||||
private async _getProfilingStatus() {
|
||||
const [profilingStatus] = await this._resourceController.tryExecuteAndNotify(
|
||||
ProfilingResource.getProfilingStatus()
|
||||
);
|
||||
if (profilingStatus) {
|
||||
this._profilingStatus = profilingStatus.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
private _changeProfilingPerformance() {
|
||||
this._profilingPerfomance = !this._profilingPerfomance;
|
||||
localStorage.setItem('profilingPerformance', this._profilingPerfomance.toString());
|
||||
|
||||
1
src/Umbraco.Web.UI.Client/src/core/controllers/index.ts
Normal file
1
src/Umbraco.Web.UI.Client/src/core/controllers/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './resource.controller';
|
||||
@@ -0,0 +1,126 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { ReactiveController, ReactiveControllerHost } from 'lit';
|
||||
import { ApiError, CancelablePromise, ProblemDetails } from '@umbraco-cms/backend-api';
|
||||
import { UmbNotificationOptions, UmbNotificationDefaultData, UmbNotificationService } from '@umbraco-cms/services';
|
||||
import { UmbContextConsumer } from '@umbraco-cms/context-api';
|
||||
|
||||
export class UmbResourceController implements ReactiveController {
|
||||
host: ReactiveControllerHost;
|
||||
|
||||
#promises: Promise<any>[] = [];
|
||||
|
||||
#notificationConsumer: UmbContextConsumer;
|
||||
|
||||
#notificationService?: UmbNotificationService;
|
||||
|
||||
constructor(host: ReactiveControllerHost) {
|
||||
(this.host = host).addController(this);
|
||||
|
||||
this.#notificationConsumer = new UmbContextConsumer(
|
||||
host as unknown as EventTarget,
|
||||
'umbNotificationService',
|
||||
(_instance: UmbNotificationService) => {
|
||||
this.#notificationService = _instance;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
hostConnected() {
|
||||
this.#promises.length = 0;
|
||||
this.#notificationConsumer.attach();
|
||||
}
|
||||
|
||||
hostDisconnected() {
|
||||
this.cancelAllResources();
|
||||
this.#notificationConsumer.detach();
|
||||
}
|
||||
|
||||
addResource(promise: Promise<any>): void {
|
||||
this.#promises.push(promise);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a given function and get the result as a promise.
|
||||
*/
|
||||
execute<T>(func: Promise<T>): Promise<T> {
|
||||
this.addResource(func);
|
||||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the {execute} function in a try/catch block and return a tuple with the result and the error.
|
||||
*/
|
||||
async tryExecute<T>(func: Promise<T>): Promise<[T | undefined, ProblemDetails | undefined]> {
|
||||
try {
|
||||
return [await this.execute(func), undefined];
|
||||
} catch (e) {
|
||||
return [undefined, this.#toProblemDetails(e)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the {execute} function in a try/catch block and return the result.
|
||||
* If the executor function throws an error, then show the details in a notification.
|
||||
*/
|
||||
async tryExecuteAndNotify<T>(
|
||||
func: Promise<T>,
|
||||
options?: UmbNotificationOptions<any>
|
||||
): Promise<[T | undefined, ProblemDetails | undefined]> {
|
||||
const [result, error] = await this.tryExecute(func);
|
||||
|
||||
if (error) {
|
||||
const data: UmbNotificationDefaultData = {
|
||||
headline: error.title ?? 'Server Error',
|
||||
message: error.detail ?? 'Something went wrong',
|
||||
};
|
||||
|
||||
if (this.#notificationService) {
|
||||
this.#notificationService?.peek('danger', { data, ...options });
|
||||
} else {
|
||||
console.group('UmbResourceController');
|
||||
console.error(error);
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
|
||||
return [result, error];
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel all resources that are currently being executed by this controller if they are cancelable.
|
||||
*
|
||||
* This works by checking if the promise is a CancelablePromise and if so, it will call the cancel method.
|
||||
*
|
||||
* This is useful when the controller is being disconnected from the DOM.
|
||||
*
|
||||
* @see CancelablePromise
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/AbortController
|
||||
*/
|
||||
cancelAllResources() {
|
||||
this.#promises.forEach((promise) => {
|
||||
if (promise instanceof CancelablePromise) {
|
||||
promise.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the ProblemDetails object from an ApiError.
|
||||
*
|
||||
* This assumes that all ApiErrors contain a ProblemDetails object in their body.
|
||||
*/
|
||||
#toProblemDetails(error: unknown): ProblemDetails | undefined {
|
||||
if (error instanceof ApiError) {
|
||||
const errorDetails = error.body as ProblemDetails;
|
||||
return errorDetails;
|
||||
} else if (error instanceof Error) {
|
||||
return {
|
||||
title: error.name,
|
||||
detail: error.message,
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,5 @@
|
||||
/* eslint-disable */
|
||||
|
||||
export * from './modal';
|
||||
export { UmbNotificationService } from './notification';
|
||||
export * from './notification';
|
||||
export type { UmbNotificationDefaultData } from './notification/layouts/default';
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"@umbraco-cms/observable-api": ["src/core/observable-api"],
|
||||
"@umbraco-cms/utils": ["src/core/utils"],
|
||||
"@umbraco-cms/test-utils": ["src/core/test-utils"],
|
||||
"@umbraco-cms/controllers": ["src/core/controllers"],
|
||||
"@umbraco-cms/services": ["src/core/services"],
|
||||
"@umbraco-cms/components/*": ["src/backoffice/components/*"],
|
||||
"@umbraco-cms/stores/*": ["src/core/stores/*"],
|
||||
|
||||
@@ -16,8 +16,11 @@ export default {
|
||||
'@umbraco-cms/context-api': './src/core/context-api/index.ts',
|
||||
'@umbraco-cms/extensions-api': './src/core/extensions-api/index.ts',
|
||||
'@umbraco-cms/observable-api': './src/core/observable-api/index.ts',
|
||||
'@umbraco-cms/resource-api': './src/core/resource-api',
|
||||
'@umbraco-cms/utils': './src/core/utils/index.ts',
|
||||
'@umbraco-cms/test-utils': './src/core/test-utils/index.ts',
|
||||
'@umbraco-cms/controllers': './src/core/controllers',
|
||||
'@umbraco-cms/services': './src/core/services',
|
||||
'@umbraco-cms/extensions-registry': './src/core/extensions-registry/index.ts',
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user