client-ts: Port services/app/components/component

This commit is contained in:
Elian Doran 2024-07-25 19:21:24 +03:00
parent 65563cb29e
commit 411234dd9c
No known key found for this signature in database
3 changed files with 21 additions and 20 deletions

View File

@ -12,6 +12,11 @@ import utils from '../services/utils.js';
* event / command is executed in all components - by simply awaiting the `triggerEvent()`.
*/
export default class Component {
private componentId: string;
private children: Component[];
private initialized: Promise<void> | null;
private parent?: Component;
constructor() {
this.componentId = `${this.sanitizedClassName}-${utils.randomString(8)}`;
/** @type Component[] */
@ -24,13 +29,12 @@ export default class Component {
return this.constructor.name.replace(/[^A-Z0-9]/ig, "_");
}
setParent(parent) {
/** @type Component */
setParent(parent: Component) {
this.parent = parent;
return this;
}
child(...components) {
child(...components: Component[]) {
for (const component of components) {
component.setParent(this);
@ -40,12 +44,11 @@ export default class Component {
return this;
}
/** @returns {Promise<void>} */
handleEvent(name, data) {
handleEvent(name: string, data: unknown): Promise<unknown> | null {
try {
const callMethodPromise = this.initialized
? this.initialized.then(() => this.callMethod(this[`${name}Event`], data))
: this.callMethod(this[`${name}Event`], data);
? this.initialized.then(() => this.callMethod((this as any)[`${name}Event`], data))
: this.callMethod((this as any)[`${name}Event`], data);
const childrenPromise = this.handleEventInChildren(name, data);
@ -54,20 +57,18 @@ export default class Component {
? Promise.all([callMethodPromise, childrenPromise])
: (callMethodPromise || childrenPromise);
}
catch (e) {
catch (e: any) {
console.error(`Handling of event '${name}' failed in ${this.constructor.name} with error ${e.message} ${e.stack}`);
return null;
}
}
/** @returns {Promise<void>} */
triggerEvent(name, data = {}) {
return this.parent.triggerEvent(name, data);
triggerEvent(name: string, data = {}): Promise<unknown> | undefined {
return this.parent?.triggerEvent(name, data);
}
/** @returns {Promise<void>} */
handleEventInChildren(name, data = {}) {
handleEventInChildren(name: string, data: unknown = {}) {
const promises = [];
for (const child of this.children) {
@ -82,19 +83,18 @@ export default class Component {
return promises.length > 0 ? Promise.all(promises) : null;
}
/** @returns {Promise<*>} */
triggerCommand(name, data = {}) {
const fun = this[`${name}Command`];
triggerCommand(name: string, data = {}): Promise<unknown> | undefined {
const fun = (this as any)[`${name}Command`];
if (fun) {
return this.callMethod(fun, data);
}
else {
return this.parent.triggerCommand(name, data);
return this.parent?.triggerCommand(name, data);
}
}
callMethod(fun, data) {
callMethod(fun: (arg: unknown) => Promise<unknown>, data: unknown) {
if (typeof fun !== 'function') {
return;
}

View File

@ -301,7 +301,7 @@ function dynamicRequire(moduleName: string) {
}
}
function timeLimit(promise: Promise<void>, limitMs: number, errorMessage: string) {
function timeLimit<T>(promise: Promise<T>, limitMs: number, errorMessage: string) {
if (!promise || !promise.then) { // it's not actually a promise
return promise;
}
@ -309,7 +309,7 @@ function timeLimit(promise: Promise<void>, limitMs: number, errorMessage: string
// better stack trace if created outside of promise
const error = new Error(errorMessage || `Process exceeded time limit ${limitMs}`);
return new Promise((res, rej) => {
return new Promise<T>((res, rej) => {
let resolved = false;
promise.then(result => {

View File

@ -25,6 +25,7 @@ interface CustomGlobals {
csrfToken: string;
baseApiUrl: string;
isProtectedSessionAvailable: boolean;
isDev: boolean;
}
type RequireMethod = (moduleName: string) => any;