diff --git a/easyflow-ui-admin/app/package.json b/easyflow-ui-admin/app/package.json index 007cdce..0644837 100644 --- a/easyflow-ui-admin/app/package.json +++ b/easyflow-ui-admin/app/package.json @@ -29,7 +29,7 @@ "@easyflow/types": "workspace:*", "@easyflow/utils": "workspace:*", "@element-plus/icons-vue": "^2.3.2", - "@tinyflow-ai/vue": "^1.2.2", + "@tinyflow-ai/vue": "workspace:*", "@vueuse/core": "catalog:", "dayjs": "catalog:", "dompurify": "^3.3.1", diff --git a/easyflow-ui-admin/app/vite.config.mts b/easyflow-ui-admin/app/vite.config.mts index ae2ab8d..3510ba8 100644 --- a/easyflow-ui-admin/app/vite.config.mts +++ b/easyflow-ui-admin/app/vite.config.mts @@ -1,4 +1,4 @@ -import { defineConfig } from '@easyflow/vite-config'; +import {defineConfig} from '@easyflow/vite-config'; import ElementPlus from 'unplugin-element-plus/vite'; @@ -6,6 +6,13 @@ export default defineConfig(async () => { return { application: {}, vite: { + resolve: { + alias: { + // @vueuse/motion expects tslib default export during dev pre-bundling + // and breaks when Vite resolves to ESM-only modules/index.js. + tslib: 'tslib/tslib.js', + }, + }, plugins: [ ElementPlus({ format: 'esm', diff --git a/easyflow-ui-admin/eslint.config.mjs b/easyflow-ui-admin/eslint.config.mjs index 0337b46..5f742df 100644 --- a/easyflow-ui-admin/eslint.config.mjs +++ b/easyflow-ui-admin/eslint.config.mjs @@ -1,5 +1,9 @@ // @ts-check -import { defineConfig } from '@easyflow/eslint-config'; +import {defineConfig} from '@easyflow/eslint-config'; -export default defineConfig(); +export default defineConfig([ + { + ignores: ['packages/tinyflow-ui/**', 'packages/tinyflow-vue/**'], + }, +]); diff --git a/easyflow-ui-admin/internal/vite-config/src/config/application.ts b/easyflow-ui-admin/internal/vite-config/src/config/application.ts index 2e0e3fc..d92c0de 100644 --- a/easyflow-ui-admin/internal/vite-config/src/config/application.ts +++ b/easyflow-ui-admin/internal/vite-config/src/config/application.ts @@ -1,18 +1,18 @@ -import type { CSSOptions, UserConfig } from 'vite'; +import type {CSSOptions, UserConfig} from 'vite'; +import {defineConfig, loadEnv, mergeConfig} from 'vite'; -import type { DefineApplicationOptions } from '../typing'; +import type {DefineApplicationOptions} from '../typing'; -import path, { relative } from 'node:path'; +import path, {relative} from 'node:path'; -import { findMonorepoRoot } from '@easyflow/node-utils'; +import {findMonorepoRoot} from '@easyflow/node-utils'; -import { NodePackageImporter } from 'sass'; -import { defineConfig, loadEnv, mergeConfig } from 'vite'; +import {NodePackageImporter} from 'sass'; -import { defaultImportmapOptions, getDefaultPwaOptions } from '../options'; -import { loadApplicationPlugins } from '../plugins'; -import { loadAndConvertEnv } from '../utils/env'; -import { getCommonConfig } from './common'; +import {defaultImportmapOptions, getDefaultPwaOptions} from '../options'; +import {loadApplicationPlugins} from '../plugins'; +import {loadAndConvertEnv} from '../utils/env'; +import {getCommonConfig} from './common'; function defineApplicationConfig(userConfigPromise?: DefineApplicationOptions) { return defineConfig(async (config) => { @@ -78,6 +78,11 @@ function defineApplicationConfig(userConfigPromise?: DefineApplicationOptions) { : [], legalComments: 'none', }, + // Workspace packages expose `development` entry to source files. + // Keep this condition enabled in build mode to avoid resolving to stubbed dist artifacts. + resolve: { + conditions: ['development'], + }, plugins, server: { host: true, diff --git a/easyflow-ui-admin/package.json b/easyflow-ui-admin/package.json index 731959f..7477f85 100644 --- a/easyflow-ui-admin/package.json +++ b/easyflow-ui-admin/package.json @@ -18,8 +18,11 @@ "check:type": "turbo run typecheck", "clean": "node ./scripts/clean.mjs", "commit": "czg", - "dev": "turbo-run dev", + "dev": "pnpm run dev:app", "dev:app": "pnpm -F @easyflow/app run dev", + "dev:all": "turbo-run dev", + "dev:tinyflow": "pnpm --filter @tinyflow-ai/ui run build && pnpm --filter @tinyflow-ai/vue run build && pnpm --parallel --filter @tinyflow-ai/ui --filter @tinyflow-ai/vue run build:watch", + "dev:app:tinyflow": "pnpm run dev:tinyflow & pnpm run dev:app", "format": "vsh lint --format", "lint": "vsh lint", "postinstall": "pnpm -r run stub --if-present", diff --git a/easyflow-ui-admin/packages/tinyflow-ui/.eslintrc.cjs b/easyflow-ui-admin/packages/tinyflow-ui/.eslintrc.cjs new file mode 100644 index 0000000..a6e9733 --- /dev/null +++ b/easyflow-ui-admin/packages/tinyflow-ui/.eslintrc.cjs @@ -0,0 +1,5 @@ +module.exports = { + rules: { + '@typescript-eslint/no-explicit-any': ['off'] + } +}; diff --git a/easyflow-ui-admin/packages/tinyflow-ui/package.json b/easyflow-ui-admin/packages/tinyflow-ui/package.json new file mode 100644 index 0000000..fbe5ca5 --- /dev/null +++ b/easyflow-ui-admin/packages/tinyflow-ui/package.json @@ -0,0 +1,76 @@ +{ + "name": "@tinyflow-ai/ui", + "version": "1.2.2", + "type": "module", + "keywords": [ + "tinyflow", + "ai", + "ai flow", + "agent flow", + "agents flow" + ], + "types": "./dist/index.d.ts", + "main": "./dist/index.js", + "module": "./dist/index.js", + "browser": "./dist/index.umd.js", + "license": "LGPL-3.0-or-later", + "files": [ + "dist", + "LICENSE", + "README.md" + ], + "scripts": { + "dev": "vite", + "build": "vite build", + "build:watch": "vite build --watch --emptyOutDir false", + "preview": "vite preview", + "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json" + }, + "devDependencies": { + "@rollup/plugin-replace": "^6.0.2", + "@sveltejs/vite-plugin-svelte": "^6.2.1", + "@tsconfig/svelte": "^5.0.5", + "@types/node": "^22.18.12", + "autoprefixer": "^10.4.21", + "less": "^4.2.2", + "svelte": "^5.45.2", + "svelte-check": "^4.3.4", + "typescript": "^5.6.2", + "vite": "^7.2.4", + "vite-plugin-dts": "^4.5.4" + }, + "dependencies": { + "@floating-ui/dom": "^1.7.4", + "@xyflow/svelte": "^1.4.2" + }, + "imports": { + "#*": [ + "./src/*.ts", + "./src/*.svelte" + ] + }, + "exports": { + ".": { + "svelte": "./src/index.ts", + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.js" + }, + "./dist/index.css": { + "import": "./dist/index.css", + "require": "./dist/index.css" + } + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "repository": { + "type": "git", + "url": "https://github.com/tinyflow-ai/tinyflow" + }, + "bugs": { + "url": "https://github.com/tinyflow-ai/tinyflow/issues" + }, + "homepage": "https://github.com/tinyflow-ai/tinyflow#readme" +} diff --git a/easyflow-ui-admin/packages/tinyflow-ui/src/Tinyflow.ts b/easyflow-ui-admin/packages/tinyflow-ui/src/Tinyflow.ts new file mode 100644 index 0000000..0f4d26d --- /dev/null +++ b/easyflow-ui-admin/packages/tinyflow-ui/src/Tinyflow.ts @@ -0,0 +1,91 @@ +import {type useSvelteFlow} from '@xyflow/svelte'; +import {componentName} from './consts'; +import type {TinyflowData, TinyflowOptions} from './types'; + +type FlowInstance = ReturnType; + +export class Tinyflow { + private options!: TinyflowOptions; + private rootEl!: Element; + private svelteFlowInstance!: FlowInstance; + + constructor(options: TinyflowOptions) { + if (typeof options.element !== 'string' && !(options.element instanceof Element)) { + throw new Error('element must be a string or Element'); + } + this._setOptions(options); + this._init(); + } + + private _init() { + if (typeof this.options.element === 'string') { + this.rootEl = document.querySelector(this.options.element)!; + if (!this.rootEl) { + throw new Error( + `element not found by document.querySelector('${this.options.element}')` + ); + } + } else if (this.options.element instanceof Element) { + this.rootEl = this.options.element; + } else { + throw new Error('element must be a string or Element'); + } + + const tinyflowEl = document.createElement(componentName) as HTMLElement & { + options: TinyflowOptions; + onInit: (svelteFlowInstance: FlowInstance) => void; + }; + tinyflowEl.style.display = 'block'; + tinyflowEl.style.width = '100%'; + tinyflowEl.style.height = '100%'; + tinyflowEl.classList.add('tf-theme-light'); + + tinyflowEl.options = this.options; + tinyflowEl.onInit = (svelteFlowInstance: FlowInstance) => { + this.svelteFlowInstance = svelteFlowInstance; + }; + + this.rootEl.appendChild(tinyflowEl); + } + + private _setOptions(options: TinyflowOptions) { + this.options = { + ...options + }; + } + + getOptions() { + return this.options; + } + + getData() { + return this.svelteFlowInstance.toObject(); + } + + setData(data: TinyflowData) { + this.options.data = data; + + const tinyflowEl = document.createElement(componentName) as HTMLElement & { + options: TinyflowOptions; + onInit: (svelteFlowInstance: FlowInstance) => void; + }; + tinyflowEl.style.display = 'block'; + tinyflowEl.style.width = '100%'; + tinyflowEl.style.height = '100%'; + tinyflowEl.classList.add('tf-theme-light'); + + tinyflowEl.options = this.options; + tinyflowEl.onInit = (svelteFlowInstance: FlowInstance) => { + this.svelteFlowInstance = svelteFlowInstance; + }; + + this.destroy(); + this.rootEl.appendChild(tinyflowEl); + } + + destroy() { + while (this.rootEl.firstChild) { + this.rootEl.removeChild(this.rootEl.firstChild); + } + } +} diff --git a/easyflow-ui-admin/packages/tinyflow-ui/src/components/TinyflowComponent.svelte b/easyflow-ui-admin/packages/tinyflow-ui/src/components/TinyflowComponent.svelte new file mode 100644 index 0000000..633baec --- /dev/null +++ b/easyflow-ui-admin/packages/tinyflow-ui/src/components/TinyflowComponent.svelte @@ -0,0 +1,38 @@ + + + + + + + + diff --git a/easyflow-ui-admin/packages/tinyflow-ui/src/components/TinyflowCore.svelte b/easyflow-ui-admin/packages/tinyflow-ui/src/components/TinyflowCore.svelte new file mode 100644 index 0000000..5881b96 --- /dev/null +++ b/easyflow-ui-admin/packages/tinyflow-ui/src/components/TinyflowCore.svelte @@ -0,0 +1,441 @@ + + + +
+ { + showEdgePanel = true; + currentEdge = e.edge; + }} + onbeforeconnect={(edge) => { + return { + ...edge, + id:genShortId(), + } + }} + ondelete={onDelete} + onclick={(e) => { + const el = e.target as HTMLElement; + if (el.classList.contains("svelte-flow__edge-interaction") + || el.classList.contains('panel-content') + || el.closest('.panel-content')){ + return + } + showEdgePanel = false; + currentEdge = null; + }} + defaultEdgeOptions={{ + // animated: true, + // label: 'edge label', + markerEnd: { + type: MarkerType.ArrowClosed, + // color: 'red', + width: 20, + height: 20 + } + }} + > + + + + + {#if showEdgePanel} + +
+
边属性设置
+
边条件设置
+
+ diff --git a/easyflow-ui-admin/packages/tinyflow-ui/src/components/base/types.d.ts b/easyflow-ui-admin/packages/tinyflow-ui/src/components/base/types.d.ts new file mode 100644 index 0000000..da7301c --- /dev/null +++ b/easyflow-ui-admin/packages/tinyflow-ui/src/components/base/types.d.ts @@ -0,0 +1,14 @@ +import type { + HTMLAttributes, + HTMLButtonAttributes, + HTMLInputAttributes, + HTMLTextareaAttributes, +} from 'svelte/elements'; + +export interface MyHTMLButtonAttributes extends HTMLButtonAttributes {} + +export interface MyHTMLInputAttributes extends HTMLInputAttributes {} + +export interface MyHTMLTextareaAttributes extends HTMLTextareaAttributes {} + +export interface MyHTMLAttributes extends HTMLAttributes {} diff --git a/easyflow-ui-admin/packages/tinyflow-ui/src/components/core/ConfirmParameterItem.svelte b/easyflow-ui-admin/packages/tinyflow-ui/src/components/core/ConfirmParameterItem.svelte new file mode 100644 index 0000000..3021833 --- /dev/null +++ b/easyflow-ui-admin/packages/tinyflow-ui/src/components/core/ConfirmParameterItem.svelte @@ -0,0 +1,178 @@ + + + +
+ updateParamByEvent('name', event)} /> +
+
+ {#if param.refType === 'fixed'} + updateParamByEvent('value', event)} /> + {:else if (param.refType !== 'input')} + +
+
+ 确认方式: +