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()`. * event / command is executed in all components - by simply awaiting the `triggerEvent()`.
*/ */
export default class Component { export default class Component {
private componentId: string;
private children: Component[];
private initialized: Promise<void> | null;
private parent?: Component;
constructor() { constructor() {
this.componentId = `${this.sanitizedClassName}-${utils.randomString(8)}`; this.componentId = `${this.sanitizedClassName}-${utils.randomString(8)}`;
/** @type Component[] */ /** @type Component[] */
@ -24,13 +29,12 @@ export default class Component {
return this.constructor.name.replace(/[^A-Z0-9]/ig, "_"); return this.constructor.name.replace(/[^A-Z0-9]/ig, "_");
} }
setParent(parent) { setParent(parent: Component) {
/** @type Component */
this.parent = parent; this.parent = parent;
return this; return this;
} }
child(...components) { child(...components: Component[]) {
for (const component of components) { for (const component of components) {
component.setParent(this); component.setParent(this);
@ -40,12 +44,11 @@ export default class Component {
return this; return this;
} }
/** @returns {Promise<void>} */ handleEvent(name: string, data: unknown): Promise<unknown> | null {
handleEvent(name, data) {
try { try {
const callMethodPromise = this.initialized const callMethodPromise = this.initialized
? this.initialized.then(() => this.callMethod(this[`${name}Event`], data)) ? this.initialized.then(() => this.callMethod((this as any)[`${name}Event`], data))
: this.callMethod(this[`${name}Event`], data); : this.callMethod((this as any)[`${name}Event`], data);
const childrenPromise = this.handleEventInChildren(name, data); const childrenPromise = this.handleEventInChildren(name, data);
@ -54,20 +57,18 @@ export default class Component {
? Promise.all([callMethodPromise, childrenPromise]) ? Promise.all([callMethodPromise, childrenPromise])
: (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}`); console.error(`Handling of event '${name}' failed in ${this.constructor.name} with error ${e.message} ${e.stack}`);
return null; return null;
} }
} }
/** @returns {Promise<void>} */ triggerEvent(name: string, data = {}): Promise<unknown> | undefined {
triggerEvent(name, data = {}) { return this.parent?.triggerEvent(name, data);
return this.parent.triggerEvent(name, data);
} }
/** @returns {Promise<void>} */ handleEventInChildren(name: string, data: unknown = {}) {
handleEventInChildren(name, data = {}) {
const promises = []; const promises = [];
for (const child of this.children) { for (const child of this.children) {
@ -82,19 +83,18 @@ export default class Component {
return promises.length > 0 ? Promise.all(promises) : null; return promises.length > 0 ? Promise.all(promises) : null;
} }
/** @returns {Promise<*>} */ triggerCommand(name: string, data = {}): Promise<unknown> | undefined {
triggerCommand(name, data = {}) { const fun = (this as any)[`${name}Command`];
const fun = this[`${name}Command`];
if (fun) { if (fun) {
return this.callMethod(fun, data); return this.callMethod(fun, data);
} }
else { 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') { if (typeof fun !== 'function') {
return; 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 if (!promise || !promise.then) { // it's not actually a promise
return promise; return promise;
} }
@ -309,7 +309,7 @@ function timeLimit(promise: Promise<void>, limitMs: number, errorMessage: string
// better stack trace if created outside of promise // better stack trace if created outside of promise
const error = new Error(errorMessage || `Process exceeded time limit ${limitMs}`); const error = new Error(errorMessage || `Process exceeded time limit ${limitMs}`);
return new Promise((res, rej) => { return new Promise<T>((res, rej) => {
let resolved = false; let resolved = false;
promise.then(result => { promise.then(result => {

View File

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