UNPKG

@nocobase/flow-engine

Version:

A standalone flow engine for NocoBase, managing workflows, models, and actions.

144 lines (120 loc) 3.83 kB
/** * This file is part of the NocoBase (R) project. * Copyright (c) 2020-2024 NocoBase Co., Ltd. * Authors: NocoBase Team. * * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. * For more information, please refer to: https://www.nocobase.com/agreement. */ import { observable } from '@formily/reactive'; import { FlowContext, FlowEngineContext } from '../flowContext'; interface TDataItem { id: string | number; [key: string]: any; } type TDataItemWithKey = TDataItem & { _rowKey: string }; function toErrMessages(error) { if (typeof error?.response?.data === 'string') { const tempElement = document.createElement('div'); tempElement.innerHTML = error?.response?.data; let message = tempElement.textContent || tempElement.innerText; if (message.includes('Error occurred while trying')) { message = 'The application may be starting up. Please try again later.'; return [{ code: 'APP_WARNING', message }]; } if (message.includes('502 Bad Gateway')) { message = 'The application may be starting up. Please try again later.'; return [{ code: 'APP_WARNING', message }]; } return [{ message }]; } if (error?.response?.data?.error) { return [error?.response?.data?.error]; } return ( error?.response?.data?.errors || error?.response?.data?.messages || error?.response?.error || [{ message: error.message || 'Server error' }] ); } export class ResourceError extends Error { data: { message: string; code?: string }; constructor(error) { const data = toErrMessages(error).shift(); super(data.message); this.name = 'ResponseError'; } get code() { return this.data?.code || 'UNKNOWN_ERROR'; } get message() { return this.data?.message || 'An unknown error occurred'; } } export class FlowResource<TData = any> { protected _data = observable.ref<TData>(null); protected _meta = observable.ref<Record<string, any>>({}); protected _error = observable.ref<ResourceError>(null); protected context: FlowContext; constructor(context: FlowContext) { this.context = new FlowContext(); this.context.addDelegate(context); } getData(): TData { return this._data.value; } hasData(): boolean { const data = this.getData(); if (Array.isArray(data)) { return data.length > 0; } else if (data && typeof data === 'object') { return Object.keys(data).length > 0; } return false; } setData(value: TData) { this._data.value = value; return this; } getMeta(metaKey?: string) { return metaKey ? this._meta.value[metaKey] : this._meta.value; } setMeta(meta: Record<string, any>) { this._meta.value = { ...this._meta.value, ...meta }; return this; } get error(): ResourceError | null { return this._error.value; } getError(): ResourceError | null { return this._error.value; } setError(error: ResourceError | null): this { this._error.value = error; return this; } clearError(): this { this._error.value = null; return this; } private events: Record<string, Array<(...args: any[]) => void>> = {}; on(event: string, callback: (...args: any[]) => void) { (this.events[event] ||= []).push(callback); } once(event: string, callback: (...args: any[]) => void) { const wrapper = (...args: any[]) => { // 触发回调 callback(...args); // 自动移除监听器 this.off(event, wrapper); }; // 注册包装后的回调 this.on(event, wrapper); } off(event: string, callback: (...args: any[]) => void) { this.events[event] = (this.events[event] || []).filter((fn) => fn !== callback); } emit(event: string, ...args: any[]) { (this.events[event] || []).forEach((fn) => fn(...args)); } }