需要重写工作流相关的页面功能

This commit is contained in:
dengqichen 2024-12-05 18:18:01 +08:00
parent 4ac57479a4
commit ac4626e0c3
25 changed files with 3579 additions and 1777 deletions

659
backend/docs/api.md Normal file
View File

@ -0,0 +1,659 @@
# API 接口文档
## 1. 通用说明
### 1.1 接口规范
- 基础路径: `/api/v1`
- 请求方式: REST风格
- 数据格式: JSON
- 字符编码: UTF-8
- 时间格式: ISO8601 (YYYY-MM-DDTHH:mm:ss.SSSZ)
### 1.2 通用响应格式
```json
{
"code": 0, // 响应码0表示成功非0表示失败
"message": "成功", // 响应消息
"data": { // 响应数据
// 具体数据结构
}
}
```
### 1.3 通用查询参数
分页查询参数:
```json
{
"page": 1, // 页码从1开始
"size": 10, // 每页大小
"sort": ["id,desc"], // 排序字段,可选
"keyword": "", // 关键字搜索,可选
}
```
### 1.4 通用错误码
| 错误码 | 说明 | 处理建议 |
|--------|------|----------|
| 0 | 成功 | - |
| 1000 | 系统内部错误 | 联系管理员 |
| 1001 | 数据库操作失败 | 重试或联系管理员 |
| 1002 | 并发操作冲突 | 刷新后重试 |
| 2000 | 参数验证失败 | 检查参数 |
| 2001 | 数据不存在 | 检查参数 |
| 2002 | 数据已存在 | 检查参数 |
## 2. 工作流定义<E5AE9A><E4B989>
### 2.1 创建工作流定义
**接口说明**:创建新的工作流定义
**请求路径**POST /workflow-definitions
**请求参数**
```json
{
"code": "string", // 工作流编码,必填,唯一
"name": "string", // 工作流名称,必填
"description": "string", // 描述,可选
"nodeConfig": { // 节点配置,必填
"nodes": [{
"id": "string", // 节点ID
"type": "string", // 节点类型
"name": "string", // 节点名称
"config": { // 节点配置
// 具体配置项根据节点类型定义
}
}]
},
"transitionConfig": { // 流转配置,必填
"transitions": [{
"from": "string", // 来源节点ID
"to": "string", // 目标节点ID
"condition": "string" // 流转条件
}]
},
"formDefinition": { // 表单定义,必填
// 表单配置项
},
"graphDefinition": { // 图形定义,必填
// 图形布局配置
}
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": {
"id": "long", // 工作流定义ID
"code": "string", // 工作流编码
"name": "string", // 工作流名称
"description": "string", // 描述
"version": 1, // 版本号
"status": "DRAFT", // 状态DRAFT-草稿、PUBLISHED-已发布、DISABLED-已禁用
"enabled": true, // 是否启用
"nodeConfig": {}, // 节点配置
"transitionConfig": {}, // 流转配置
"formDefinition": {}, // 表单定义
"graphDefinition": {}, // 图形定义
"createTime": "string", // 创建时间
"updateTime": "string" // 更新时间
}
}
```
### 2.2 更新工作流定义
**接口说明**:更新工作流定义,仅草稿状态可更新
**请求路径**PUT /workflow-definitions/{id}
**路径参数**
- id: 工作流定义ID
**请求参数**:同创建接口
**响应数据**:同创建接口
### 2.3 发布工作流定义
**接口说明**:发布工作流定义,使其可被使用
**请求路径**POST /workflow-definitions/{id}/publish
**路径参数**
- id: 工作流定义ID
**响应数据**:同创建接口
### 2.4 禁用工作流定义
**接口说明**:禁用工作流定义,禁止新建实例
**请求路径**POST /workflow-definitions/{id}/disable
**路径参数**
- id: 工作流定义ID
**响应数据**:同创建接口
### 2.5 启用工作流定义
**接口说明**启用已<E794A8><E5B7B2>用的工作流定义
**请求路径**POST /workflow-definitions/{id}/enable
**路径参数**
- id: 工作流定义ID
**响应数据**:同创建接口
### 2.6 创建新版本
**接口说明**:基于现有工作流定义创建新版本
**请求路径**POST /workflow-definitions/{id}/versions
**路径参数**
- id: 工作流定义ID
**响应数据**:同创建接口
### 2.7 查询工作流定义列表
**接口说明**:分页查询工作流定义列表
**请求路径**GET /workflow-definitions
**请求参数**
```json
{
"page": 1, // 页码从1开始
"size": 10, // 每页大小
"sort": ["id,desc"], // 排序字段
"keyword": "", // 关键字搜索
"status": "DRAFT", // 状态过滤
"enabled": true // 是否启用
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": {
"content": [{ // 列表数据
// 工作流定义数据,同创建接口
}],
"totalElements": 100, // 总记录数
"totalPages": 10, // 总页数
"size": 10, // 每页大小
"number": 1 // 当前页码
}
}
```
## 3. 工作流实例接口
### 3.1 创建工作流实例
**接口说明**:创建工作流实例
**请求路径**POST /workflow-instances
**请求参数**
```json
{
"definitionId": "long", // 工作流定义ID必填
"businessKey": "string", // 业务标识,可选
"variables": { // 初始变量,可选
"key": "value"
}
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": {
"id": "long", // 实例ID
"definitionId": "long", // 定义ID
"businessKey": "string",// 业务标识
"status": "CREATED", // 状态CREATED-已创建、RUNNING-运行中、SUSPENDED-已暂停、COMPLETED-已完成、TERMINATED-已终止
"startTime": "string", // 开始时间
"endTime": "string", // 结束时间
"variables": {}, // 变量
"createTime": "string", // 创建时间
"updateTime": "string" // 更新时间
}
}
```
### 3.2 启动工作流实例
**接口说明**:启动工作流实例
**请求路径**POST /workflow-instances/{id}/start
**路径参数**
- id: 实例ID
**响应数据**:同创建接口
### 3.3 暂停工作流实例
**接口说明**:暂停运行中的工作流实例
**请求路径**POST /workflow-instances/{id}/suspend
**路径参数**
- id: 实例ID
**响应数据**:同创建接口
### 3.4 恢复工作流实例
**接口说明**:恢复已暂停的工作流实例
**请求路径**POST /workflow-instances/{id}/resume
**路径参数**
- id: 实例ID
**响应数据**:同创建接口
### 3.5 终止工作流实例
**接口说明**:强制终止工作流实例
**请求路径**POST /workflow-instances/{id}/terminate
**路径参数**
- id: 实例ID
**响应数据**:同创建接口
### 3.6 查询工作流实例列表
**接口说明**:分页查询工作流实例列表
**请求路径**GET /workflow-instances
**请求参数**
```json
{
"page": 1, // 页码从1开始
"size": 10, // 每页大小
"sort": ["id,desc"], // 排序字段
"keyword": "", // 关键字搜索
"status": "RUNNING", // 状态过滤
"definitionId": "long", // 定义ID过滤
"businessKey": "string" // 业务标识过滤
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": {
"content": [{ // 列表数据
// 工作流实例数据,同创建接口
}],
"totalElements": 100, // 总记录数
"totalPages": 10, // 总页数
"size": 10, // 每页大小
"number": 1 // 当前页码
}
}
```
## 4. 节点实例接口
### 4.1 查询节点实例列表
**接口说明**:查询工作流实例的节点列表
**请求路径**GET /workflow-instances/{instanceId}/nodes
**路径参数**
- instanceId: 工作流实例ID
**请求参数**
```json
{
"status": "RUNNING" // 状态过滤,可选
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": [{
"id": "long", // 节点实例ID
"workflowInstanceId": "long", // 工作流实例ID
"nodeId": "string", // 节点定义ID
"nodeName": "string", // 节点名称
"nodeType": "string", // 节点类型
"status": "string", // 状态CREATED、RUNNING、COMPLETED、FAILED
"startTime": "string", // 开始时间
"endTime": "string", // 结束时间
"output": "string", // 输出结果
"error": "string", // 错误信息
"createTime": "string", // 创建时间
"updateTime": "string" // 更新时间
}]
}
```
## 5. 工作流变量接口
### 5.1 设置变量
**接口说明**:设置工作流实例变量
**请求路径**POST /workflow-instances/{instanceId}/variables
**路径参数**
- instanceId: 工作流实例ID
**请求参数**
```json
{
"name": "string", // 变量名,必填
"value": "object", // 变量值<EFBC8C><E5BF85>
"scope": "GLOBAL" // 作用域GLOBAL-全局、NODE-节点可选默认GLOBAL
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功"
}
```
### 5.2 获取变量
**接口说明**:获取工作流实例变量
**请求路径**GET /workflow-instances/{instanceId}/variables
**路径参数**
- instanceId: 工作流实例ID
**请求参数**
```json
{
"scope": "GLOBAL" // 作用域过滤,可选
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": {
"variableName": "variableValue"
}
}
```
## 6. 工作流日志接口
### 6.1 查询日志列表
**接口说明**:查询工作流实例日志
**请求路径**GET /workflow-instances/{instanceId}/logs
**路径参数**
- instanceId: 工作流实例ID
**请求参数**
```json
{
"nodeId": "string", // 节点ID过滤可选
"level": "INFO", // 日志级别过滤DEBUG、INFO、WARN、ERROR可选
"startTime": "string", // 开始时间过滤,可选
"endTime": "string" // 结束时间过滤,可选
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": [{
"id": "long", // 日志ID
"workflowInstanceId": "long", // 工作流实例ID
"nodeId": "string", // 节点ID
"level": "string", // 日志级别
"content": "string", // 日志内容
"detail": "string", // 详细信息
"createTime": "string" // 创建时间
}]
}
```
## 7. 节点类型接口
### 7.1 查询节点类型列表
**接口说明**:查询可用的节点类型列表
**请求路径**GET /node-types
**请求参数**
```json
{
"enabled": true, // 是否启用过滤,可选
"category": "TASK" // 类型分类过滤TASK、EVENT、GATEWAY可选
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": [{
"id": "long", // 节点类型ID
"code": "string", // 节点类型编码
"name": "string", // 节点类型名称
"category": "string", // 分类
"description": "string", // 描述
"enabled": true, // 是否启用
"icon": "string", // 图标
"color": "string", // 颜色
"executors": [{ // 执行器列表仅TASK类型
"code": "string", // 执行器编码
"name": "string", // 执行器名称
"description": "string", // 描述
"configSchema": {} // 配置模式
}],
"createTime": "string", // 创建时间
"updateTime": "string" // 更新时间
}]
}
```
### 7.2 获取节点执行器列表
**接口说明**:获取指定节点类型支持的执行器列表
**请求路径**GET /node-types/{code}/executors
**路径参数**
- code: 节点类型编码
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": [{
"code": "string", // 执行器编码
"name": "string", // 执行器名称
"description": "string", // 描述
"configSchema": { // 配置模式
"type": "object",
"properties": {
// 具体配置项定义
},
"required": [] // 必填项
}
}]
}
```
## 8. 错误码说明
### 8.1 系统错误 (1xxx)
- 1000: 系统内部错误
- 1001: 数据库操作失败
- 1002: 并发操作冲突
### 8.2 通用业务错误 (2xxx)
- 2000: 参数验证失败
- 2001: 数据不存在
- 2002: 数据已存在
### 8.3 工作流定义错误 (3xxx)
- 3000: 工作流定义不存在
- 3001: 工作流编码已存在
- 3002: 工作流定义非草稿状态
- 3003: 工作流定义未发布
- 3004: 工作流定义已禁用
- 3005: 节点配置无效
- 3006: 流转配置无效
- 3007: 表单配置无效
### 8.4 工作流实例错误 (4xxx)
- 4000: 工作流实例不存在
- 4001: 工作流实例状态无效
- 4002: 工作流实例已终止
- 4003: 节点实例不存在
- 4004: 变量类型无效
## 9. 数据结构说明
### 9.1 工作流状态
```typescript
enum WorkflowStatus {
DRAFT = "DRAFT", // 草稿
PUBLISHED = "PUBLISHED", // 已发布
DISABLED = "DISABLED" // 已禁用
}
```
### 9.2 实例状态
```typescript
enum InstanceStatus {
CREATED = "CREATED", // 已创建
RUNNING = "RUNNING", // 运行中
SUSPENDED = "SUSPENDED", // 已暂停
COMPLETED = "COMPLETED", // 已完成
TERMINATED = "TERMINATED"// 已终止
}
```
### 9.3 节点状态
```typescript
enum NodeStatus {
CREATED = "CREATED", // 已创建
RUNNING = "RUNNING", // 运行中
COMPLETED = "COMPLETED", // 已完成
FAILED = "FAILED" // 失败
}
```
### 9.4 日志级别
```typescript
enum LogLevel {
DEBUG = "DEBUG",
INFO = "INFO",
WARN = "WARN",
ERROR = "ERROR"
}
```
### 9.5 变量作用域
```typescript
enum VariableScope {
GLOBAL = "GLOBAL", // 全局变量
NODE = "NODE" // 节点变量
}
```
## 10. 最佳实践
### 10.1 工作流设计
1. 工作流定义创建流程:
- 创建草稿
- 配置节点和流转
- 验证配置
- 发布使用
2. 节点类型选择:
- 根据业务场景选择合适的节点类型
- 配置合适的执行器
- 设置必要的变量
### 10.2 实例管理
1. 实例生命周期管理:
- 创建 -> 启动 -> 运行 -> 完成
- 必要时可暂停或终止
- 记录关键节点日志
2. 变量使用:
- 合理使用变量作用域
- 及时清理无用变量
- 注意变量类型匹配
### 10.3 错误处理
1. 异常处理:
- 捕获所有可能的错误码
- 提供友好的错误提示
- 记录详细的错误日志
2. 重试机制:
- 对非致命错误进行重试
- 设置合理的重试间隔
- 限制最大重试次数
### 10.4 性能优化
1. 查询优化:
- 合理使用分页
- 避免大量数据查询
- 使用合适的查询条件
2. 缓存使用:
- 缓存常用数据
- 及时更新缓存
- 避免缓存穿透

1598
backend/docs/architecture.md Normal file

File diff suppressed because it is too large Load Diff

659
frontend/api.md Normal file
View File

@ -0,0 +1,659 @@
# API 接口文档
## 1. 通用说明
### 1.1 接口规范
- 基础路径: `/api/v1`
- 请求方式: REST风格
- 数据格式: JSON
- 字符编码: UTF-8
- 时间格式: ISO8601 (YYYY-MM-DDTHH:mm:ss.SSSZ)
### 1.2 通用响应格式
```json
{
"code": 0, // 响应码0表示成功非0表示失败
"message": "成功", // 响应消息
"data": { // 响应数据
// 具体数据结构
}
}
```
### 1.3 通用查询参数
分页查询参数:
```json
{
"page": 1, // 页码从1开始
"size": 10, // 每页大小
"sort": ["id,desc"], // 排序字段,可选
"keyword": "", // 关键字搜索,可选
}
```
### 1.4 通用错误码
| 错误码 | 说明 | 处理建议 |
|--------|------|----------|
| 0 | 成功 | - |
| 1000 | 系统内部错误 | 联系管理员 |
| 1001 | 数据库操作失败 | 重试或联系管理员 |
| 1002 | 并发操作冲突 | 刷新后重试 |
| 2000 | 参数验证失败 | 检查参数 |
| 2001 | 数据不存在 | 检查参数 |
| 2002 | 数据已存在 | 检查参数 |
## 2. 工作流定义<E5AE9A><E4B989>
### 2.1 创建工作流定义
**接口说明**:创建新的工作流定义
**请求路径**POST /workflow-definitions
**请求参数**
```json
{
"code": "string", // 工作流编码,必填,唯一
"name": "string", // 工作流名称,必填
"description": "string", // 描述,可选
"nodeConfig": { // 节点配置,必填
"nodes": [{
"id": "string", // 节点ID
"type": "string", // 节点类型
"name": "string", // 节点名称
"config": { // 节点配置
// 具体配置项根据节点类型定义
}
}]
},
"transitionConfig": { // 流转配置,必填
"transitions": [{
"from": "string", // 来源节点ID
"to": "string", // 目标节点ID
"condition": "string" // 流转条件
}]
},
"formDefinition": { // 表单定义,必填
// 表单配置项
},
"graphDefinition": { // 图形定义,必填
// 图形布局配置
}
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": {
"id": "long", // 工作流定义ID
"code": "string", // 工作流编码
"name": "string", // 工作流名称
"description": "string", // 描述
"version": 1, // 版本号
"status": "DRAFT", // 状态DRAFT-草稿、PUBLISHED-已发布、DISABLED-已禁用
"enabled": true, // 是否启用
"nodeConfig": {}, // 节点配置
"transitionConfig": {}, // 流转配置
"formDefinition": {}, // 表单定义
"graphDefinition": {}, // 图形定义
"createTime": "string", // 创建时间
"updateTime": "string" // 更新时间
}
}
```
### 2.2 更新工作流定义
**接口说明**:更新工作流定义,仅草稿状态可更新
**请求路径**PUT /workflow-definitions/{id}
**路径参数**
- id: 工作流定义ID
**请求参数**:同创建接口
**响应数据**:同创建接口
### 2.3 发布工作流定义
**接口说明**:发布工作流定义,使其可被使用
**请求路径**POST /workflow-definitions/{id}/publish
**路径参数**
- id: 工作流定义ID
**响应数据**:同创建接口
### 2.4 禁用工作流定义
**接口说明**:禁用工作流定义,禁止新建实例
**请求路径**POST /workflow-definitions/{id}/disable
**路径参数**
- id: 工作流定义ID
**响应数据**:同创建接口
### 2.5 启用工作流定义
**接口说明**启用已<E794A8><E5B7B2>用的工作流定义
**请求路径**POST /workflow-definitions/{id}/enable
**路径参数**
- id: 工作流定义ID
**响应数据**:同创建接口
### 2.6 创建新版本
**接口说明**:基于现有工作流定义创建新版本
**请求路径**POST /workflow-definitions/{id}/versions
**路径参数**
- id: 工作流定义ID
**响应数据**:同创建接口
### 2.7 查询工作流定义列表
**接口说明**:分页查询工作流定义列表
**请求路径**GET /workflow-definitions
**请求参数**
```json
{
"page": 1, // 页码从1开始
"size": 10, // 每页大小
"sort": ["id,desc"], // 排序字段
"keyword": "", // 关键字搜索
"status": "DRAFT", // 状态过滤
"enabled": true // 是否启用
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": {
"content": [{ // 列表数据
// 工作流定义数据,同创建接口
}],
"totalElements": 100, // 总记录数
"totalPages": 10, // 总页数
"size": 10, // 每页大小
"number": 1 // 当前页码
}
}
```
## 3. 工作流实例接口
### 3.1 创建工作流实例
**接口说明**:创建工作流实例
**请求路径**POST /workflow-instances
**请求参数**
```json
{
"definitionId": "long", // 工作流定义ID必填
"businessKey": "string", // 业务标识,可选
"variables": { // 初始变量,可选
"key": "value"
}
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": {
"id": "long", // 实例ID
"definitionId": "long", // 定义ID
"businessKey": "string",// 业务标识
"status": "CREATED", // 状态CREATED-已创建、RUNNING-运行中、SUSPENDED-已暂停、COMPLETED-已完成、TERMINATED-已终止
"startTime": "string", // 开始时间
"endTime": "string", // 结束时间
"variables": {}, // 变量
"createTime": "string", // 创建时间
"updateTime": "string" // 更新时间
}
}
```
### 3.2 启动工作流实例
**接口说明**:启动工作流实例
**请求路径**POST /workflow-instances/{id}/start
**路径参数**
- id: 实例ID
**响应数据**:同创建接口
### 3.3 暂停工作流实例
**接口说明**:暂停运行中的工作流实例
**请求路径**POST /workflow-instances/{id}/suspend
**路径参数**
- id: 实例ID
**响应数据**:同创建接口
### 3.4 恢复工作流实例
**接口说明**:恢复已暂停的工作流实例
**请求路径**POST /workflow-instances/{id}/resume
**路径参数**
- id: 实例ID
**响应数据**:同创建接口
### 3.5 终止工作流实例
**接口说明**:强制终止工作流实例
**请求路径**POST /workflow-instances/{id}/terminate
**路径参数**
- id: 实例ID
**响应数据**:同创建接口
### 3.6 查询工作流实例列表
**接口说明**:分页查询工作流实例列表
**请求路径**GET /workflow-instances
**请求参数**
```json
{
"page": 1, // 页码从1开始
"size": 10, // 每页大小
"sort": ["id,desc"], // 排序字段
"keyword": "", // 关键字搜索
"status": "RUNNING", // 状态过滤
"definitionId": "long", // 定义ID过滤
"businessKey": "string" // 业务标识过滤
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": {
"content": [{ // 列表数据
// 工作流实例数据,同创建接口
}],
"totalElements": 100, // 总记录数
"totalPages": 10, // 总页数
"size": 10, // 每页大小
"number": 1 // 当前页码
}
}
```
## 4. 节点实例接口
### 4.1 查询节点实例列表
**接口说明**:查询工作流实例的节点列表
**请求路径**GET /workflow-instances/{instanceId}/nodes
**路径参数**
- instanceId: 工作流实例ID
**请求参数**
```json
{
"status": "RUNNING" // 状态过滤,可选
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": [{
"id": "long", // 节点实例ID
"workflowInstanceId": "long", // 工作流实例ID
"nodeId": "string", // 节点定义ID
"nodeName": "string", // 节点名称
"nodeType": "string", // 节点类型
"status": "string", // 状态CREATED、RUNNING、COMPLETED、FAILED
"startTime": "string", // 开始时间
"endTime": "string", // 结束时间
"output": "string", // 输出结果
"error": "string", // 错误信息
"createTime": "string", // 创建时间
"updateTime": "string" // 更新时间
}]
}
```
## 5. 工作流变量接口
### 5.1 设置变量
**接口说明**:设置工作流实例变量
**请求路径**POST /workflow-instances/{instanceId}/variables
**路径参数**
- instanceId: 工作流实例ID
**请求参数**
```json
{
"name": "string", // 变量名,必填
"value": "object", // 变量值<EFBC8C><E5BF85>
"scope": "GLOBAL" // 作用域GLOBAL-全局、NODE-节点可选默认GLOBAL
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功"
}
```
### 5.2 获取变量
**接口说明**:获取工作流实例变量
**请求路径**GET /workflow-instances/{instanceId}/variables
**路径参数**
- instanceId: 工作流实例ID
**请求参数**
```json
{
"scope": "GLOBAL" // 作用域过滤,可选
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": {
"variableName": "variableValue"
}
}
```
## 6. 工作流日志接口
### 6.1 查询日志列表
**接口说明**:查询工作流实例日志
**请求路径**GET /workflow-instances/{instanceId}/logs
**路径参数**
- instanceId: 工作流实例ID
**请求参数**
```json
{
"nodeId": "string", // 节点ID过滤可选
"level": "INFO", // 日志级别过滤DEBUG、INFO、WARN、ERROR可选
"startTime": "string", // 开始时间过滤,可选
"endTime": "string" // 结束时间过滤,可选
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": [{
"id": "long", // 日志ID
"workflowInstanceId": "long", // 工作流实例ID
"nodeId": "string", // 节点ID
"level": "string", // 日志级别
"content": "string", // 日志内容
"detail": "string", // 详细信息
"createTime": "string" // 创建时间
}]
}
```
## 7. 节点类型接口
### 7.1 查询节点类型列表
**接口说明**:查询可用的节点类型列表
**请求路径**GET /node-types
**请求参数**
```json
{
"enabled": true, // 是否启用过滤,可选
"category": "TASK" // 类型分类过滤TASK、EVENT、GATEWAY可选
}
```
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": [{
"id": "long", // 节点类型ID
"code": "string", // 节点类型编码
"name": "string", // 节点类型名称
"category": "string", // 分类
"description": "string", // 描述
"enabled": true, // 是否启用
"icon": "string", // 图标
"color": "string", // 颜色
"executors": [{ // 执行器列表仅TASK类型
"code": "string", // 执行器编码
"name": "string", // 执行器名称
"description": "string", // 描述
"configSchema": {} // 配置模式
}],
"createTime": "string", // 创建时间
"updateTime": "string" // 更新时间
}]
}
```
### 7.2 获取节点执行器列表
**接口说明**:获取指定节点类型支持的执行器列表
**请求路径**GET /node-types/{code}/executors
**路径参数**
- code: 节点类型编码
**响应数据**
```json
{
"code": 0,
"message": "成功",
"data": [{
"code": "string", // 执行器编码
"name": "string", // 执行器名称
"description": "string", // 描述
"configSchema": { // 配置模式
"type": "object",
"properties": {
// 具体配置项定义
},
"required": [] // 必填项
}
}]
}
```
## 8. 错误码说明
### 8.1 系统错误 (1xxx)
- 1000: 系统内部错误
- 1001: 数据库操作失败
- 1002: 并发操作冲突
### 8.2 通用业务错误 (2xxx)
- 2000: 参数验证失败
- 2001: 数据不存在
- 2002: 数据已存在
### 8.3 工作流定义错误 (3xxx)
- 3000: 工作流定义不存在
- 3001: 工作流编码已存在
- 3002: 工作流定义非草稿状态
- 3003: 工作流定义未发布
- 3004: 工作流定义已禁用
- 3005: 节点配置无效
- 3006: 流转配置无效
- 3007: 表单配置无效
### 8.4 工作流实例错误 (4xxx)
- 4000: 工作流实例不存在
- 4001: 工作流实例状态无效
- 4002: 工作流实例已终止
- 4003: 节点实例不存在
- 4004: 变量类型无效
## 9. 数据结构说明
### 9.1 工作流状态
```typescript
enum WorkflowStatus {
DRAFT = "DRAFT", // 草稿
PUBLISHED = "PUBLISHED", // 已发布
DISABLED = "DISABLED" // 已禁用
}
```
### 9.2 实例状态
```typescript
enum InstanceStatus {
CREATED = "CREATED", // 已创建
RUNNING = "RUNNING", // 运行中
SUSPENDED = "SUSPENDED", // 已暂停
COMPLETED = "COMPLETED", // 已完成
TERMINATED = "TERMINATED"// 已终止
}
```
### 9.3 节点状态
```typescript
enum NodeStatus {
CREATED = "CREATED", // 已创建
RUNNING = "RUNNING", // 运行中
COMPLETED = "COMPLETED", // 已完成
FAILED = "FAILED" // 失败
}
```
### 9.4 日志级别
```typescript
enum LogLevel {
DEBUG = "DEBUG",
INFO = "INFO",
WARN = "WARN",
ERROR = "ERROR"
}
```
### 9.5 变量作用域
```typescript
enum VariableScope {
GLOBAL = "GLOBAL", // 全局变量
NODE = "NODE" // 节点变量
}
```
## 10. 最佳实践
### 10.1 工作流设计
1. 工作流定义创建流程:
- 创建草稿
- 配置节点和流转
- 验证配置
- 发布使用
2. 节点类型选择:
- 根据业务场景选择合适的节点类型
- 配置合适的执行器
- 设置必要的变量
### 10.2 实例管理
1. 实例生命周期管理:
- 创建 -> 启动 -> 运行 -> 完成
- 必要时可暂停或终止
- 记录关键节点日志
2. 变量使用:
- 合理使用变量作用域
- 及时清理无用变量
- 注意变量类型匹配
### 10.3 错误处理
1. 异常处理:
- 捕获所有可能的错误码
- 提供友好的错误提示
- 记录详细的错误日志
2. 重试机制:
- 对非致命错误进行重试
- 设置合理的重试间隔
- 限制最大重试次数
### 10.4 性能优化
1. 查询优化:
- 合理使用分页
- 避免大量数据查询
- 使用合适的查询条件
2. 缓存使用:
- 缓存常用数据
- 及时更新缓存
- 避免缓存穿透

View File

@ -11,6 +11,13 @@
"@ant-design/icons": "^5.2.6", "@ant-design/icons": "^5.2.6",
"@antv/layout": "^1.2.14-beta.8", "@antv/layout": "^1.2.14-beta.8",
"@antv/x6": "^2.18.1", "@antv/x6": "^2.18.1",
"@antv/x6-plugin-clipboard": "^2.1.6",
"@antv/x6-plugin-export": "^2.1.6",
"@antv/x6-plugin-history": "^2.2.4",
"@antv/x6-plugin-keyboard": "^2.2.3",
"@antv/x6-plugin-selection": "^2.2.2",
"@antv/x6-plugin-snapline": "^2.1.7",
"@antv/x6-plugin-transform": "^2.1.8",
"@antv/x6-react-shape": "^2.2.3", "@antv/x6-react-shape": "^2.2.3",
"@logicflow/core": "^2.0.9", "@logicflow/core": "^2.0.9",
"@logicflow/extension": "^2.0.13", "@logicflow/extension": "^2.0.13",
@ -20,6 +27,7 @@
"dagre": "^0.8.5", "dagre": "^0.8.5",
"form-render": "^2.5.1", "form-render": "^2.5.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-diff-viewer-continued": "^3.4.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-redux": "^9.0.4", "react-redux": "^9.0.4",
"react-router-dom": "^6.21.0" "react-router-dom": "^6.21.0"
@ -35,6 +43,7 @@
"eslint": "^8.55.0", "eslint": "^8.55.0",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5", "eslint-plugin-react-refresh": "^0.4.5",
"less": "^4.2.1",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.0.8" "vite": "^5.0.8"
} }
@ -193,6 +202,7 @@
"version": "2.18.1", "version": "2.18.1",
"resolved": "https://registry.npmmirror.com/@antv/x6/-/x6-2.18.1.tgz", "resolved": "https://registry.npmmirror.com/@antv/x6/-/x6-2.18.1.tgz",
"integrity": "sha512-FkWdbLOpN9J7dfJ+kiBxzowSx2N6syBily13NMVdMs+wqC6Eo5sLXWCZjQHateTFWgFw7ZGi2y9o3Pmdov1sXw==", "integrity": "sha512-FkWdbLOpN9J7dfJ+kiBxzowSx2N6syBily13NMVdMs+wqC6Eo5sLXWCZjQHateTFWgFw7ZGi2y9o3Pmdov1sXw==",
"license": "MIT",
"dependencies": { "dependencies": {
"@antv/x6-common": "^2.0.16", "@antv/x6-common": "^2.0.16",
"@antv/x6-geometry": "^2.0.5", "@antv/x6-geometry": "^2.0.5",
@ -215,10 +225,77 @@
"integrity": "sha512-MId6riEQkxphBpVeTcL4ZNXL4lScyvDEPLyIafvWMcWNTGK0jgkK7N20XSzqt8ltJb0mGUso5s56mrk8ysHu2A==", "integrity": "sha512-MId6riEQkxphBpVeTcL4ZNXL4lScyvDEPLyIafvWMcWNTGK0jgkK7N20XSzqt8ltJb0mGUso5s56mrk8ysHu2A==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@antv/x6-plugin-clipboard": {
"version": "2.1.6",
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-clipboard/-/x6-plugin-clipboard-2.1.6.tgz",
"integrity": "sha512-roZPLnZx6PK8MBvee0QMo90fz/TXeF0WNe4EGin2NBq5M1I5XTWrYvA6N2XVIiWAAI67gjQeEE8TpkL7f8QdqA==",
"license": "MIT",
"peerDependencies": {
"@antv/x6": "^2.x"
}
},
"node_modules/@antv/x6-plugin-export": {
"version": "2.1.6",
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-export/-/x6-plugin-export-2.1.6.tgz",
"integrity": "sha512-m0ukMmZhrFE5n7uCR43DVQBdiUfpjGN+vm1mc+6RTZdHK8pa6Mxr0RZztaxPy34YA4tli+bGY3ePslsNPfh6PQ==",
"license": "MIT",
"peerDependencies": {
"@antv/x6": "^2.x"
}
},
"node_modules/@antv/x6-plugin-history": {
"version": "2.2.4",
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-history/-/x6-plugin-history-2.2.4.tgz",
"integrity": "sha512-9gHHvEW4Fla+1hxUV49zNgJyIMoV9CjVM52MrFgAJcvyRn1Kvxz4MfxiKlG+DEZUs+/zvfjl9pS6gJOd8laRkg==",
"license": "MIT",
"peerDependencies": {
"@antv/x6": "^2.x"
}
},
"node_modules/@antv/x6-plugin-keyboard": {
"version": "2.2.3",
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-keyboard/-/x6-plugin-keyboard-2.2.3.tgz",
"integrity": "sha512-pnCIC+mDyKKfkcDyLePfGxKVIqXBcldTgannITkHC1kc0IafRS1GMvzpvuDGrM5haRYd6Nwz8kjkJyHkJE4GPA==",
"license": "MIT",
"dependencies": {
"mousetrap": "^1.6.5"
},
"peerDependencies": {
"@antv/x6": "^2.x"
}
},
"node_modules/@antv/x6-plugin-selection": {
"version": "2.2.2",
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-selection/-/x6-plugin-selection-2.2.2.tgz",
"integrity": "sha512-s2gtR9Onlhr7HOHqyqg0d+4sG76JCcQEbvrZZ64XmSChlvieIPlC3YtH4dg1KMNhYIuBmBmpSum6S0eVTEiPQw==",
"license": "MIT",
"peerDependencies": {
"@antv/x6": "^2.x"
}
},
"node_modules/@antv/x6-plugin-snapline": {
"version": "2.1.7",
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-snapline/-/x6-plugin-snapline-2.1.7.tgz",
"integrity": "sha512-AsysoCb9vES0U2USNhEpYuO/W8I0aYfkhlbee5Kt4NYiMfQfZKQyqW/YjDVaS2pm38C1NKu1LdPVk/BBr4CasA==",
"license": "MIT",
"peerDependencies": {
"@antv/x6": "^2.x"
}
},
"node_modules/@antv/x6-plugin-transform": {
"version": "2.1.8",
"resolved": "https://registry.npmmirror.com/@antv/x6-plugin-transform/-/x6-plugin-transform-2.1.8.tgz",
"integrity": "sha512-GvJuiJ4BKp0H7+qx3R1I+Vzbw5gXp9+oByXo/WyVxE3urOC7LC5sqnaDfIjyYMN6ROLPYPZraLSeSyYBgMgcDw==",
"license": "MIT",
"peerDependencies": {
"@antv/x6": "^2.x"
}
},
"node_modules/@antv/x6-react-shape": { "node_modules/@antv/x6-react-shape": {
"version": "2.2.3", "version": "2.2.3",
"resolved": "https://registry.npmmirror.com/@antv/x6-react-shape/-/x6-react-shape-2.2.3.tgz", "resolved": "https://registry.npmmirror.com/@antv/x6-react-shape/-/x6-react-shape-2.2.3.tgz",
"integrity": "sha512-42PGxk3XLnx9bsHQiRPauai5UQCrsh0MbWI3MyHRpjQaC30FK1rqyjH/EJ8qH0p6/cAndszZzCaiPqBbs3FqLQ==", "integrity": "sha512-42PGxk3XLnx9bsHQiRPauai5UQCrsh0MbWI3MyHRpjQaC30FK1rqyjH/EJ8qH0p6/cAndszZzCaiPqBbs3FqLQ==",
"license": "MIT",
"peerDependencies": { "peerDependencies": {
"@antv/x6": "^2.x", "@antv/x6": "^2.x",
"react": ">=18.0.0", "react": ">=18.0.0",
@ -229,7 +306,6 @@
"version": "7.26.2", "version": "7.26.2",
"resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.26.2.tgz", "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.26.2.tgz",
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/helper-validator-identifier": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9",
"js-tokens": "^4.0.0", "js-tokens": "^4.0.0",
@ -291,7 +367,6 @@
"version": "7.26.2", "version": "7.26.2",
"resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.26.2.tgz", "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.26.2.tgz",
"integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/parser": "^7.26.2", "@babel/parser": "^7.26.2",
"@babel/types": "^7.26.0", "@babel/types": "^7.26.0",
@ -332,7 +407,6 @@
"version": "7.25.9", "version": "7.25.9",
"resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
"integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/traverse": "^7.25.9", "@babel/traverse": "^7.25.9",
"@babel/types": "^7.25.9" "@babel/types": "^7.25.9"
@ -371,7 +445,6 @@
"version": "7.25.9", "version": "7.25.9",
"resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
"dev": true,
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@ -380,7 +453,6 @@
"version": "7.25.9", "version": "7.25.9",
"resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
"dev": true,
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@ -411,7 +483,6 @@
"version": "7.26.2", "version": "7.26.2",
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.2.tgz", "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.2.tgz",
"integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/types": "^7.26.0" "@babel/types": "^7.26.0"
}, },
@ -467,7 +538,6 @@
"version": "7.25.9", "version": "7.25.9",
"resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.25.9.tgz", "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.25.9.tgz",
"integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.25.9", "@babel/code-frame": "^7.25.9",
"@babel/parser": "^7.25.9", "@babel/parser": "^7.25.9",
@ -481,7 +551,6 @@
"version": "7.25.9", "version": "7.25.9",
"resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.25.9.tgz", "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.25.9.tgz",
"integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.25.9", "@babel/code-frame": "^7.25.9",
"@babel/generator": "^7.25.9", "@babel/generator": "^7.25.9",
@ -499,7 +568,6 @@
"version": "7.26.0", "version": "7.26.0",
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.26.0.tgz", "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.26.0.tgz",
"integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==",
"dev": true,
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.25.9", "@babel/helper-string-parser": "^7.25.9",
"@babel/helper-validator-identifier": "^7.25.9" "@babel/helper-validator-identifier": "^7.25.9"
@ -516,16 +584,143 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/@emotion/babel-plugin": {
"version": "11.13.5",
"resolved": "https://registry.npmmirror.com/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
"integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==",
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.16.7",
"@babel/runtime": "^7.18.3",
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/serialize": "^1.3.3",
"babel-plugin-macros": "^3.1.0",
"convert-source-map": "^1.5.0",
"escape-string-regexp": "^4.0.0",
"find-root": "^1.1.0",
"source-map": "^0.5.7",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/babel-plugin/node_modules/@emotion/hash": {
"version": "0.9.2",
"resolved": "https://registry.npmmirror.com/@emotion/hash/-/hash-0.9.2.tgz",
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
"license": "MIT"
},
"node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
"license": "MIT"
},
"node_modules/@emotion/babel-plugin/node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@emotion/babel-plugin/node_modules/stylis": {
"version": "4.2.0",
"resolved": "https://registry.npmmirror.com/stylis/-/stylis-4.2.0.tgz",
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
"license": "MIT"
},
"node_modules/@emotion/cache": {
"version": "11.13.5",
"resolved": "https://registry.npmmirror.com/@emotion/cache/-/cache-11.13.5.tgz",
"integrity": "sha512-Z3xbtJ+UcK76eWkagZ1onvn/wAVb1GOMuR15s30Fm2wrMgC7jzpnO2JZXr4eujTTqoQFUrZIw/rT0c6Zzjca1g==",
"license": "MIT",
"dependencies": {
"@emotion/memoize": "^0.9.0",
"@emotion/sheet": "^1.4.0",
"@emotion/utils": "^1.4.2",
"@emotion/weak-memoize": "^0.4.0",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/cache/node_modules/stylis": {
"version": "4.2.0",
"resolved": "https://registry.npmmirror.com/stylis/-/stylis-4.2.0.tgz",
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
"license": "MIT"
},
"node_modules/@emotion/css": {
"version": "11.13.5",
"resolved": "https://registry.npmmirror.com/@emotion/css/-/css-11.13.5.tgz",
"integrity": "sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==",
"license": "MIT",
"dependencies": {
"@emotion/babel-plugin": "^11.13.5",
"@emotion/cache": "^11.13.5",
"@emotion/serialize": "^1.3.3",
"@emotion/sheet": "^1.4.0",
"@emotion/utils": "^1.4.2"
}
},
"node_modules/@emotion/hash": { "node_modules/@emotion/hash": {
"version": "0.8.0", "version": "0.8.0",
"resolved": "https://registry.npmmirror.com/@emotion/hash/-/hash-0.8.0.tgz", "resolved": "https://registry.npmmirror.com/@emotion/hash/-/hash-0.8.0.tgz",
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
}, },
"node_modules/@emotion/memoize": {
"version": "0.9.0",
"resolved": "https://registry.npmmirror.com/@emotion/memoize/-/memoize-0.9.0.tgz",
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
"license": "MIT"
},
"node_modules/@emotion/serialize": {
"version": "1.3.3",
"resolved": "https://registry.npmmirror.com/@emotion/serialize/-/serialize-1.3.3.tgz",
"integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==",
"license": "MIT",
"dependencies": {
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/unitless": "^0.10.0",
"@emotion/utils": "^1.4.2",
"csstype": "^3.0.2"
}
},
"node_modules/@emotion/serialize/node_modules/@emotion/hash": {
"version": "0.9.2",
"resolved": "https://registry.npmmirror.com/@emotion/hash/-/hash-0.9.2.tgz",
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
"license": "MIT"
},
"node_modules/@emotion/serialize/node_modules/@emotion/unitless": {
"version": "0.10.0",
"resolved": "https://registry.npmmirror.com/@emotion/unitless/-/unitless-0.10.0.tgz",
"integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
"license": "MIT"
},
"node_modules/@emotion/sheet": {
"version": "1.4.0",
"resolved": "https://registry.npmmirror.com/@emotion/sheet/-/sheet-1.4.0.tgz",
"integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
"license": "MIT"
},
"node_modules/@emotion/unitless": { "node_modules/@emotion/unitless": {
"version": "0.7.5", "version": "0.7.5",
"resolved": "https://registry.npmmirror.com/@emotion/unitless/-/unitless-0.7.5.tgz", "resolved": "https://registry.npmmirror.com/@emotion/unitless/-/unitless-0.7.5.tgz",
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
}, },
"node_modules/@emotion/utils": {
"version": "1.4.2",
"resolved": "https://registry.npmmirror.com/@emotion/utils/-/utils-1.4.2.tgz",
"integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==",
"license": "MIT"
},
"node_modules/@emotion/weak-memoize": {
"version": "0.4.0",
"resolved": "https://registry.npmmirror.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
"license": "MIT"
},
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5", "version": "0.21.5",
"resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@ -1672,6 +1867,12 @@
"undici-types": "~6.19.2" "undici-types": "~6.19.2"
} }
}, },
"node_modules/@types/parse-json": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/@types/parse-json/-/parse-json-4.0.2.tgz",
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
"license": "MIT"
},
"node_modules/@types/prop-types": { "node_modules/@types/prop-types": {
"version": "15.7.13", "version": "15.7.13",
"resolved": "https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.13.tgz", "resolved": "https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.13.tgz",
@ -2278,6 +2479,21 @@
"proxy-from-env": "^1.1.0" "proxy-from-env": "^1.1.0"
} }
}, },
"node_modules/babel-plugin-macros": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.5",
"cosmiconfig": "^7.0.0",
"resolve": "^1.19.0"
},
"engines": {
"node": ">=10",
"npm": ">=6"
}
},
"node_modules/babel-runtime": { "node_modules/babel-runtime": {
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmmirror.com/babel-runtime/-/babel-runtime-6.26.0.tgz", "resolved": "https://registry.npmmirror.com/babel-runtime/-/babel-runtime-6.26.0.tgz",
@ -2369,7 +2585,6 @@
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
@ -2523,6 +2738,19 @@
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true "dev": true
}, },
"node_modules/copy-anything": {
"version": "2.0.6",
"resolved": "https://registry.npmmirror.com/copy-anything/-/copy-anything-2.0.6.tgz",
"integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-what": "^3.14.1"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/copy-to-clipboard": { "node_modules/copy-to-clipboard": {
"version": "3.3.3", "version": "3.3.3",
"resolved": "https://registry.npmmirror.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", "resolved": "https://registry.npmmirror.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
@ -2538,6 +2766,22 @@
"deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
"hasInstallScript": true "hasInstallScript": true
}, },
"node_modules/cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
"integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
"license": "MIT",
"dependencies": {
"@types/parse-json": "^4.0.0",
"import-fresh": "^3.2.1",
"parse-json": "^5.0.0",
"path-type": "^4.0.0",
"yaml": "^1.10.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/create-react-class": { "node_modules/create-react-class": {
"version": "15.7.0", "version": "15.7.0",
"resolved": "https://registry.npmmirror.com/create-react-class/-/create-react-class-15.7.0.tgz", "resolved": "https://registry.npmmirror.com/create-react-class/-/create-react-class-15.7.0.tgz",
@ -2655,7 +2899,6 @@
"version": "4.3.7", "version": "4.3.7",
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz", "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dev": true,
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
}, },
@ -2682,6 +2925,15 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/diff": {
"version": "5.2.0",
"resolved": "https://registry.npmmirror.com/diff/-/diff-5.2.0.tgz",
"integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/dir-glob": { "node_modules/dir-glob": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz", "resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz",
@ -2738,6 +2990,35 @@
"node": ">=10.13.0" "node": ">=10.13.0"
} }
}, },
"node_modules/errno": {
"version": "0.1.8",
"resolved": "https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz",
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"prr": "~1.0.1"
},
"bin": {
"errno": "cli.js"
}
},
"node_modules/error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"license": "MIT",
"dependencies": {
"is-arrayish": "^0.2.1"
}
},
"node_modules/error-ex/node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
"license": "MIT"
},
"node_modules/es-module-lexer": { "node_modules/es-module-lexer": {
"version": "1.5.4", "version": "1.5.4",
"resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz", "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz",
@ -2794,7 +3075,6 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
"engines": { "engines": {
"node": ">=10" "node": ">=10"
}, },
@ -3087,6 +3367,12 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/find-root/-/find-root-1.1.0.tgz",
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
"license": "MIT"
},
"node_modules/find-up": { "node_modules/find-up": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz", "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz",
@ -3258,6 +3544,15 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0" "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
} }
}, },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gensync": { "node_modules/gensync": {
"version": "1.0.0-beta.2", "version": "1.0.0-beta.2",
"resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz",
@ -3337,7 +3632,6 @@
"version": "11.12.0", "version": "11.12.0",
"resolved": "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz", "resolved": "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
"dev": true,
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
@ -3365,8 +3659,7 @@
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "4.2.11", "version": "4.2.11",
"resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
"peer": true
}, },
"node_modules/graphemer": { "node_modules/graphemer": {
"version": "1.4.0", "version": "1.4.0",
@ -3390,11 +3683,37 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/hoist-non-react-statics": { "node_modules/hoist-non-react-statics": {
"version": "2.5.5", "version": "2.5.5",
"resolved": "https://registry.npmmirror.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", "resolved": "https://registry.npmmirror.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
"integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
}, },
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz",
@ -3404,6 +3723,20 @@
"node": ">= 4" "node": ">= 4"
} }
}, },
"node_modules/image-size": {
"version": "0.5.5",
"resolved": "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz",
"integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==",
"dev": true,
"license": "MIT",
"optional": true,
"bin": {
"image-size": "bin/image-size.js"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/immer": { "node_modules/immer": {
"version": "10.1.1", "version": "10.1.1",
"resolved": "https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz", "resolved": "https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz",
@ -3417,7 +3750,6 @@
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz", "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz",
"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
"dev": true,
"dependencies": { "dependencies": {
"parent-module": "^1.0.0", "parent-module": "^1.0.0",
"resolve-from": "^4.0.0" "resolve-from": "^4.0.0"
@ -3470,6 +3802,21 @@
"resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz", "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
}, },
"node_modules/is-core-module": {
"version": "2.15.1",
"resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.15.1.tgz",
"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-extglob": { "node_modules/is-extglob": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
@ -3509,6 +3856,13 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/is-what": {
"version": "3.14.1",
"resolved": "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz",
"integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==",
"dev": true,
"license": "MIT"
},
"node_modules/isexe": { "node_modules/isexe": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz",
@ -3573,7 +3927,6 @@
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.0.2.tgz", "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.0.2.tgz",
"integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
"dev": true,
"bin": { "bin": {
"jsesc": "bin/jsesc" "jsesc": "bin/jsesc"
}, },
@ -3590,8 +3943,7 @@
"node_modules/json-parse-even-better-errors": { "node_modules/json-parse-even-better-errors": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
"peer": true
}, },
"node_modules/json-schema-traverse": { "node_modules/json-schema-traverse": {
"version": "0.4.1", "version": "0.4.1",
@ -3632,6 +3984,33 @@
"json-buffer": "3.0.1" "json-buffer": "3.0.1"
} }
}, },
"node_modules/less": {
"version": "4.2.1",
"resolved": "https://registry.npmmirror.com/less/-/less-4.2.1.tgz",
"integrity": "sha512-CasaJidTIhWmjcqv0Uj5vccMI7pJgfD9lMkKtlnTHAdJdYK/7l8pM9tumLyJ0zhbD4KJLo/YvTj+xznQd5NBhg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"copy-anything": "^2.0.1",
"parse-node-version": "^1.0.1",
"tslib": "^2.3.0"
},
"bin": {
"lessc": "bin/lessc"
},
"engines": {
"node": ">=6"
},
"optionalDependencies": {
"errno": "^0.1.1",
"graceful-fs": "^4.1.2",
"image-size": "~0.5.0",
"make-dir": "^2.1.0",
"mime": "^1.4.1",
"needle": "^3.1.0",
"source-map": "~0.6.0"
}
},
"node_modules/levn": { "node_modules/levn": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz", "resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz",
@ -3645,6 +4024,12 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"license": "MIT"
},
"node_modules/loader-runner": { "node_modules/loader-runner": {
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz", "resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz",
@ -3720,11 +4105,43 @@
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
}, },
"node_modules/make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz",
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"pify": "^4.0.1",
"semver": "^5.6.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/make-dir/node_modules/semver": {
"version": "5.7.2",
"resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"license": "ISC",
"optional": true,
"bin": {
"semver": "bin/semver"
}
},
"node_modules/medium-editor": { "node_modules/medium-editor": {
"version": "5.23.3", "version": "5.23.3",
"resolved": "https://registry.npmmirror.com/medium-editor/-/medium-editor-5.23.3.tgz", "resolved": "https://registry.npmmirror.com/medium-editor/-/medium-editor-5.23.3.tgz",
"integrity": "sha512-he9/TdjX8f8MGdXGfCs8AllrYnqXJJvjNkDKmPg3aPW/uoIrlRqtkFthrwvmd+u4QyzEiadhCCM0EwTiRdUCJw==" "integrity": "sha512-he9/TdjX8f8MGdXGfCs8AllrYnqXJJvjNkDKmPg3aPW/uoIrlRqtkFthrwvmd+u4QyzEiadhCCM0EwTiRdUCJw=="
}, },
"node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
"license": "MIT"
},
"node_modules/merge-stream": { "node_modules/merge-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz",
@ -3753,6 +4170,20 @@
"node": ">=8.6" "node": ">=8.6"
} }
}, },
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"dev": true,
"license": "MIT",
"optional": true,
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/mime-db": { "node_modules/mime-db": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
@ -3859,8 +4290,7 @@
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
"dev": true
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.7", "version": "3.3.7",
@ -3886,6 +4316,24 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true "dev": true
}, },
"node_modules/needle": {
"version": "3.3.1",
"resolved": "https://registry.npmmirror.com/needle/-/needle-3.3.1.tgz",
"integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"iconv-lite": "^0.6.3",
"sax": "^1.2.4"
},
"bin": {
"needle": "bin/needle"
},
"engines": {
"node": ">= 4.4.x"
}
},
"node_modules/neo-async": { "node_modules/neo-async": {
"version": "2.6.2", "version": "2.6.2",
"resolved": "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz", "resolved": "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz",
@ -3965,7 +4413,6 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
"dependencies": { "dependencies": {
"callsites": "^3.0.0" "callsites": "^3.0.0"
}, },
@ -3973,6 +4420,34 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/parse-json": {
"version": "5.2.0",
"resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz",
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.0.0",
"error-ex": "^1.3.1",
"json-parse-even-better-errors": "^2.3.0",
"lines-and-columns": "^1.1.6"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/parse-node-version": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz",
"integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/path-exists": { "node_modules/path-exists": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz",
@ -4000,11 +4475,16 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"license": "MIT"
},
"node_modules/path-type": { "node_modules/path-type": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true,
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
@ -4031,6 +4511,17 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/pify": {
"version": "4.0.1",
"resolved": "https://registry.npmmirror.com/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"dev": true,
"license": "MIT",
"optional": true,
"engines": {
"node": ">=6"
}
},
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.49", "version": "8.4.49",
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.49.tgz", "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.49.tgz",
@ -4097,6 +4588,14 @@
"resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
}, },
"node_modules/prr": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz",
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
"dev": true,
"license": "MIT",
"optional": true
},
"node_modules/punycode": { "node_modules/punycode": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz",
@ -4818,6 +5317,26 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/react-diff-viewer-continued": {
"version": "3.4.0",
"resolved": "https://registry.npmmirror.com/react-diff-viewer-continued/-/react-diff-viewer-continued-3.4.0.tgz",
"integrity": "sha512-kMZmUyb3Pv5L9vUtCfIGYsdOHs8mUojblGy1U1Sm0D7FhAOEsH9QhnngEIRo5hXWIPNGupNRJls1TJ6Eqx84eg==",
"license": "MIT",
"dependencies": {
"@emotion/css": "^11.11.2",
"classnames": "^2.3.2",
"diff": "^5.1.0",
"memoize-one": "^6.0.0",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">= 8"
},
"peerDependencies": {
"react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "18.3.1", "version": "18.3.1",
"resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-18.3.1.tgz", "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-18.3.1.tgz",
@ -4934,11 +5453,27 @@
"resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", "resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
}, },
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.8.tgz",
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
"license": "MIT",
"dependencies": {
"is-core-module": "^2.13.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/resolve-from": { "node_modules/resolve-from": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
@ -5049,6 +5584,22 @@
], ],
"peer": true "peer": true
}, },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"license": "MIT",
"optional": true
},
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmmirror.com/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
"dev": true,
"license": "ISC",
"optional": true
},
"node_modules/scheduler": { "node_modules/scheduler": {
"version": "0.23.2", "version": "0.23.2",
"resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.2.tgz", "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.2.tgz",
@ -5162,7 +5713,6 @@
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"peer": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@ -5232,6 +5782,18 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/tapable": { "node_modules/tapable": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmmirror.com/tapable/-/tapable-2.2.1.tgz", "resolved": "https://registry.npmmirror.com/tapable/-/tapable-2.2.1.tgz",
@ -5669,6 +6231,15 @@
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true "dev": true
}, },
"node_modules/yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"license": "ISC",
"engines": {
"node": ">= 6"
}
},
"node_modules/yocto-queue": { "node_modules/yocto-queue": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz",

View File

@ -13,6 +13,13 @@
"@ant-design/icons": "^5.2.6", "@ant-design/icons": "^5.2.6",
"@antv/layout": "^1.2.14-beta.8", "@antv/layout": "^1.2.14-beta.8",
"@antv/x6": "^2.18.1", "@antv/x6": "^2.18.1",
"@antv/x6-plugin-clipboard": "^2.1.6",
"@antv/x6-plugin-export": "^2.1.6",
"@antv/x6-plugin-history": "^2.2.4",
"@antv/x6-plugin-keyboard": "^2.2.3",
"@antv/x6-plugin-selection": "^2.2.2",
"@antv/x6-plugin-snapline": "^2.1.7",
"@antv/x6-plugin-transform": "^2.1.8",
"@antv/x6-react-shape": "^2.2.3", "@antv/x6-react-shape": "^2.2.3",
"@logicflow/core": "^2.0.9", "@logicflow/core": "^2.0.9",
"@logicflow/extension": "^2.0.13", "@logicflow/extension": "^2.0.13",
@ -22,6 +29,7 @@
"dagre": "^0.8.5", "dagre": "^0.8.5",
"form-render": "^2.5.1", "form-render": "^2.5.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-diff-viewer-continued": "^3.4.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-redux": "^9.0.4", "react-redux": "^9.0.4",
"react-router-dom": "^6.21.0" "react-router-dom": "^6.21.0"
@ -37,6 +45,7 @@
"eslint": "^8.55.0", "eslint": "^8.55.0",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5", "eslint-plugin-react-refresh": "^0.4.5",
"less": "^4.2.1",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.0.8" "vite": "^5.0.8"
} }

View File

@ -5,6 +5,7 @@ import zhCN from 'antd/locale/zh_CN';
import router from './router'; import router from './router';
const App: React.FC = () => { const App: React.FC = () => {
console.log('App');
return ( return (
<ConfigProvider locale={zhCN}> <ConfigProvider locale={zhCN}>
<RouterProvider router={router} /> <RouterProvider router={router} />

View File

@ -1,32 +0,0 @@
.flowDesigner {
display: flex;
gap: 16px;
height: 100%;
}
.nodeTypes {
width: 200px;
flex-shrink: 0;
}
.nodeType {
margin: 8px 0;
padding: 8px 12px;
border-radius: 4px;
cursor: move;
user-select: none;
transition: all 0.3s;
}
.nodeType:hover {
opacity: 0.8;
transform: translateY(-1px);
}
.canvas {
flex: 1;
border: 1px solid #e8e8e8;
border-radius: 4px;
background: #f5f5f5;
min-height: 600px;
}

View File

@ -1,471 +0,0 @@
import React, { useEffect, useRef, useState } from 'react';
import { Graph, Node, Edge, Shape, Cell } from '@antv/x6';
import dagre from 'dagre';
import { getNodeTypes } from '@/pages/Workflow/service';
import type { NodeTypeDTO } from '@/pages/Workflow/types';
import styles from './index.module.css';
import { Card } from 'antd';
// 节点类型映射
const NODE_TYPE_MAP: Record<string, string> = {
'TASK': 'SHELL', // 任务节点映射到 SHELL
'START': 'START',
'END': 'END'
};
interface FlowDesignerProps {
value?: string;
onChange?: (value: string) => void;
workflowInstanceId?: number;
readOnly?: boolean;
}
const FlowDesigner: React.FC<FlowDesignerProps> = ({
value,
onChange,
workflowInstanceId,
readOnly = false
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const graphRef = useRef<Graph>();
const [nodeTypes, setNodeTypes] = useState<NodeTypeDTO[]>([]);
const registeredNodesRef = useRef(new Set<string>());
// 注册节点类型
const registerNodeTypes = (types: NodeTypeDTO[]) => {
types.forEach(nodeType => {
const nodeTypeCode = nodeType.code;
// 如果节点类型已经注册,则跳过
if (registeredNodesRef.current.has(nodeTypeCode)) {
return;
}
try {
// 根据节点类型注册不同的节点
Graph.registerNode(nodeTypeCode, {
inherit: nodeType.category === 'GATEWAY' ? 'polygon' :
nodeType.category === 'BASIC' ? 'circle' : 'rect',
width: nodeType.category === 'BASIC' ? 60 : 120,
height: nodeType.category === 'BASIC' ? 60 : 60,
attrs: {
body: {
fill: nodeType.color || '#fff',
stroke: nodeType.color || '#1890ff',
strokeWidth: 2,
...(nodeType.category === 'GATEWAY' ? {
refPoints: '0,10 10,0 20,10 10,20',
} : nodeType.category === 'TASK' ? {
rx: 4,
ry: 4,
} : {}),
},
label: {
text: nodeType.name,
fill: nodeType.category === 'BASIC' ? '#fff' : '#000',
fontSize: 12,
fontWeight: nodeType.category === 'BASIC' ? 'bold' : 'normal',
},
},
ports: {
groups: {
in: {
position: 'left',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: nodeType.color || '#1890ff',
strokeWidth: 2,
fill: '#fff',
},
},
},
out: {
position: 'right',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: nodeType.color || '#1890ff',
strokeWidth: 2,
fill: '#fff',
},
},
},
},
items: nodeTypeCode === 'START' ? [
{ id: 'out', group: 'out' }
] : nodeTypeCode === 'END' ? [
{ id: 'in', group: 'in' }
] : [
{ id: 'in', group: 'in' },
{ id: 'out', group: 'out' }
],
},
});
registeredNodesRef.current.add(nodeTypeCode);
console.log(`Node type ${nodeTypeCode} registered successfully`);
} catch (error) {
console.warn(`Node type ${nodeTypeCode} registration failed:`, error);
}
});
};
// 加载节点类型
useEffect(() => {
const loadNodeTypes = async () => {
try {
const response = await getNodeTypes();
setNodeTypes(response);
} catch (error) {
console.error('加载节点类型失败:', error);
}
};
loadNodeTypes();
// 清理函数
return () => {
registeredNodesRef.current.clear();
if (graphRef.current) {
graphRef.current.dispose();
}
};
}, []);
// 初始化画布
useEffect(() => {
if (!containerRef.current || !nodeTypes.length) return;
// 注册节点类型
registerNodeTypes(nodeTypes);
// 创建画布
const graph = new Graph({
container: containerRef.current,
width: 800,
height: 600,
grid: {
size: 10,
visible: true,
type: 'doubleMesh',
args: [
{
color: '#eee',
thickness: 1,
},
{
color: '#ddd',
thickness: 1,
factor: 4,
},
],
},
connecting: {
router: 'manhattan',
connector: {
name: 'rounded',
args: { radius: 8 },
},
anchor: 'center',
connectionPoint: 'anchor',
allowBlank: false,
snap: { radius: 20 },
createEdge() {
return new Shape.Edge({
attrs: {
line: {
stroke: '#1890ff',
strokeWidth: 2,
targetMarker: {
name: 'block',
width: 12,
height: 8,
},
},
},
});
},
validateConnection({ sourceView, targetView, sourceMagnet, targetMagnet }) {
if (!sourceMagnet || !targetMagnet) return false;
// 开始节点只能有出口连线
if (sourceView?.cell.shape === 'START' && sourceMagnet.getAttribute('port-group') !== 'out') return false;
if (targetView?.cell.shape === 'START') return false;
// 结束节点只能有入口连线
if (sourceView?.cell.shape === 'END') return false;
if (targetView?.cell.shape === 'END' && targetMagnet.getAttribute('port-group') !== 'in') return false;
// 普通节点的连线规则
if (sourceMagnet.getAttribute('port-group') !== 'out') return false;
if (targetMagnet.getAttribute('port-group') !== 'in') return false;
return sourceView !== targetView;
},
},
highlighting: {
magnetAvailable: {
name: 'stroke',
args: {
padding: 4,
attrs: {
strokeWidth: 4,
stroke: '#1890ff',
},
},
},
},
interacting: {
nodeMovable: !readOnly,
edgeMovable: !readOnly,
magnetConnectable: !readOnly,
},
background: {
color: '#f5f5f5',
},
});
// 添加拖拽事件处理
const container = containerRef.current;
container.addEventListener('dragover', (e) => {
e.preventDefault();
});
container.addEventListener('drop', (e) => {
e.preventDefault();
const nodeTypeData = e.dataTransfer?.getData('nodeType');
if (!nodeTypeData) return;
try {
const nodeType = JSON.parse(nodeTypeData);
const { clientX, clientY } = e;
const { left, top } = container.getBoundingClientRect();
const x = clientX - left;
const y = clientY - top;
// 创建节点
const node = graph.addNode({
shape: nodeType.code,
x,
y,
data: {
type: nodeType.code
}
});
// 触发更新
const updateEvent = new Event('node:moved');
container.dispatchEvent(updateEvent);
} catch (error) {
console.error('创建节点失败:', error);
}
});
// 监听事件
if (!readOnly) {
let updateTimer: number | null = null;
const updateGraph = () => {
if (updateTimer) {
window.clearTimeout(updateTimer);
}
updateTimer = window.setTimeout(() => {
const nodes = graph.getNodes().map(node => ({
id: node.id,
type: node.data?.type || node.shape,
x: node.position().x,
y: node.position().y,
name: node.attr('label/text'),
}));
const edges = graph.getEdges().map(edge => ({
source: edge.getSourceCellId(),
target: edge.getTargetCellId(),
}));
const data = {
nodes,
edges,
transitionConfig: JSON.stringify({
transitions: edges.map(edge => ({
from: edge.source,
to: edge.target
}))
})
};
onChange?.(JSON.stringify(data));
}, 300);
};
// 监听节点变化
graph.on('node:moved', updateGraph);
graph.on('edge:connected', updateGraph);
graph.on('cell:removed', updateGraph);
// 添加边的右键菜单删除功能
graph.on('edge:contextmenu', ({ cell, e }) => {
e.preventDefault();
cell.remove();
});
}
// 加载流程数据
if (value) {
try {
const graphData = JSON.parse(value);
console.log('原始数据:', graphData);
const cells: Cell[] = [];
// 添加节点
const nodesMap = new Map<string, Cell>();
if (graphData.nodes) {
console.log('处理节点数据:', graphData.nodes);
graphData.nodes.forEach((node: any) => {
// 将 TASK 类型映射到 SHELL
const nodeShape = NODE_TYPE_MAP[node.type] || node.type;
const cell = graph.createNode({
id: node.id, // 保持原始 ID
shape: nodeShape,
x: node.x || 100,
y: node.y || 100,
label: node.name || node.type,
data: {
...node,
type: node.type // 保存原始类型
},
});
cells.push(cell);
nodesMap.set(node.id, cell);
});
}
// 处理边数据
let edges: any[] = [];
if (graphData.edges) {
edges = graphData.edges;
} else if (graphData.transitionConfig) {
try {
const transitionConfig = typeof graphData.transitionConfig === 'string'
? JSON.parse(graphData.transitionConfig)
: graphData.transitionConfig;
edges = transitionConfig.transitions.map((t: any) => ({
source: t.from,
target: t.to
}));
} catch (error) {
console.error('解析 transitionConfig 失败:', error);
}
}
// 添加边
if (edges.length > 0) {
console.log('处理边数据:', edges);
edges.forEach((edge: any) => {
const sourceNode = nodesMap.get(edge.source);
const targetNode = nodesMap.get(edge.target);
console.log('连线:', edge.source, '->', edge.target, '节点:', sourceNode?.id, targetNode?.id);
if (sourceNode && targetNode) {
const edgeCell = graph.createEdge({
source: { cell: sourceNode.id, port: 'out' },
target: { cell: targetNode.id, port: 'in' },
router: {
name: 'manhattan',
args: {
padding: 20,
startDirections: ['right'],
endDirections: ['left'],
},
},
connector: {
name: 'rounded',
args: { radius: 8 },
},
attrs: {
line: {
stroke: '#1890ff',
strokeWidth: 2,
targetMarker: {
name: 'block',
width: 12,
height: 8,
},
},
},
});
cells.push(edgeCell);
}
});
}
// 重置画布并应用布局
console.log('重置前的 cells:', cells);
console.log('重置前的 cells 内容:', cells.map(cell => ({
id: cell.id,
isNode: cell.isNode(),
isEdge: cell.isEdge(),
source: cell.isEdge() ? cell.getSourceCellId() : undefined,
target: cell.isEdge() ? cell.getTargetCellId() : undefined
})));
graph.resetCells(cells);
console.log('重置后的节点:', graph.getNodes().map(node => ({
id: node.id,
type: node.data?.type,
shape: node.shape
})));
console.log('重置后的边:', graph.getEdges().map(edge => ({
source: edge.getSourceCellId(),
target: edge.getTargetCellId()
})));
graph.centerContent();
} catch (error) {
console.error('加载流程数据失败:', error);
}
}
graphRef.current = graph;
return () => {
// 清理事件监听
container.removeEventListener('dragover', (e) => e.preventDefault());
container.removeEventListener('drop', (e) => e.preventDefault());
graph.dispose();
};
}, [nodeTypes, value, onChange, readOnly]);
return (
<div className={styles.flowDesigner}>
<div className={styles.nodeTypes}>
<Card title="节点类型" size="small" bordered={false}>
{nodeTypes.map(nodeType => (
<div
key={nodeType.code}
className={styles.nodeType}
style={{
backgroundColor: nodeType.color,
color: nodeType.category === 'BASIC' ? '#fff' : '#000'
}}
draggable
onDragStart={(e) => {
e.dataTransfer.setData('nodeType', JSON.stringify(nodeType));
}}
>
{nodeType.name}
</div>
))}
</Card>
</div>
<div
className={styles.canvas}
ref={containerRef}
style={{ minHeight: '600px' }}
/>
</div>
);
};
export default FlowDesigner;

View File

@ -1,59 +0,0 @@
import React, { useState } from 'react';
import { Card } from 'antd';
import FormRender, { useForm } from 'form-render';
interface FormDesignerProps {
value?: string;
onChange?: (value: string) => void;
readOnly?: boolean;
}
const defaultSchema = {
type: 'object',
properties: {
input1: {
title: '输入框',
type: 'string'
}
}
};
const FormDesigner: React.FC<FormDesignerProps> = ({
value,
onChange,
readOnly = false
}) => {
const [schema, setSchema] = useState<any>(() => {
try {
return value ? JSON.parse(value) : defaultSchema;
} catch (error) {
return defaultSchema;
}
});
const form = useForm();
const handleSubmit = (formData: any) => {
console.log('Form data:', formData);
};
const handleFinishFailed = (errors: any) => {
console.log('Form validation errors:', errors);
};
return (
<div style={{ padding: 24 }}>
<Card title="表单预览">
<FormRender
form={form}
schema={schema}
onFinish={handleSubmit}
onFinishFailed={handleFinishFailed}
disabled={readOnly}
/>
</Card>
</div>
);
};
export default FormDesigner;

View File

@ -1,131 +0,0 @@
import React, { useEffect } from 'react';
import { Form, Button, Space, Input } from 'antd';
import type { FormInstance } from 'antd';
// @ts-ignore
import FormRender from 'form-render';
import type { NodeTypeDTO } from '@/pages/Workflow/types';
interface NodeConfigProps {
node: {
id: string;
type: string;
text?: { value: string; x: number; y: number };
properties?: Record<string, any>;
};
nodeType?: NodeTypeDTO;
onSave: (config: any) => void;
onCancel: () => void;
}
const NodeConfig: React.FC<NodeConfigProps> = ({
node,
nodeType,
onSave,
onCancel
}) => {
const [form] = Form.useForm();
useEffect(() => {
if (node.properties) {
form.setFieldsValue({
...node.properties,
text: node.text?.value
});
}
}, [node, form]);
const handleFinish = (values: any) => {
onSave({
...values,
text: { value: values.text, x: node.text?.x, y: node.text?.y }
});
};
const handleFinishFailed = (errors: any) => {
console.log('Form validation errors:', errors);
};
// 如果没有节点类型信息,显示基础配置
if (!nodeType) {
return (
<div style={{ padding: 16 }}>
<Form
form={form}
layout="vertical"
onFinish={handleFinish}
onFinishFailed={handleFinishFailed}
>
<Form.Item
label="节点名称"
name="text"
rules={[{ required: true, message: '请输入节点名称' }]}
>
<Input />
</Form.Item>
<Form.Item>
<Space>
<Button type="primary" htmlType="submit">
</Button>
<Button onClick={onCancel}>
</Button>
</Space>
</Form.Item>
</Form>
</div>
);
}
// 解析配置模式
const configSchema = nodeType.configSchema ? JSON.parse(nodeType.configSchema) : {};
const defaultConfig = nodeType.defaultConfig ? JSON.parse(nodeType.defaultConfig) : {};
// 合并节点类型的配置模式
const schema = {
type: 'object',
properties: {
text: {
title: '节点名称',
type: 'string',
required: true
},
...configSchema.properties
},
required: ['text', ...(configSchema.required || [])]
};
return (
<div style={{ padding: 16 }}>
<FormRender
form={form as any}
schema={schema}
onFinish={handleFinish}
onFinishFailed={handleFinishFailed}
defaultValue={{
text: node.text?.value,
...defaultConfig
}}
widgets={{
// 这里可以添加自定义组件
}}
watch={{
// 这里可以添加表单联动逻辑
}}
/>
<div style={{ marginTop: 16 }}>
<Space>
<Button type="primary" onClick={() => form.submit()}>
</Button>
<Button onClick={onCancel}>
</Button>
</Space>
</div>
</div>
);
};
export default NodeConfig;

View File

@ -1,134 +0,0 @@
import React, { useEffect, useState } from 'react';
import { Card, Tabs, Button, Form, Input, message } from 'antd';
import type { TabsProps } from 'antd';
import { useNavigate, useParams } from 'react-router-dom';
import FlowDesigner from './components/FlowDesigner';
import FormDesigner from './components/FormDesigner';
import { getDefinition, createDefinition, updateDefinition } from '../../service';
import type { WorkflowDefinitionRequest, WorkflowStatus } from '../../types';
const Edit: React.FC = () => {
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [graphData, setGraphData] = useState('');
const [formData, setFormData] = useState('');
useEffect(() => {
if (id) {
setLoading(true);
getDefinition(parseInt(id))
.then(data => {
form.setFieldsValue({
name: data.name,
code: data.code,
description: data.description
});
setGraphData(data.graphDefinition || '');
setFormData(data.formDefinition || '');
})
.finally(() => {
setLoading(false);
});
}
}, [id, form]);
const handleSave = async () => {
try {
const values = await form.validateFields();
const data: WorkflowDefinitionRequest = {
...values,
graphDefinition: graphData,
formDefinition: formData,
nodeConfig: '{}',
transitionConfig: '{}',
enabled: true,
version: 1,
status: 'DRAFT' as WorkflowStatus
};
if (id) {
await updateDefinition(parseInt(id), data);
} else {
await createDefinition(data);
}
message.success('保存成功');
navigate('/workflow/definition');
} catch (error) {
console.error('Save failed:', error);
message.error('保存失败');
}
};
const items: TabsProps['items'] = [
{
key: 'basic',
label: '基本信息',
children: (
<Form
form={form}
layout="vertical"
style={{ maxWidth: 600, margin: '24px auto' }}
>
<Form.Item
label="流程名称"
name="name"
rules={[{ required: true, message: '请输入流程名称' }]}
>
<Input />
</Form.Item>
<Form.Item
label="流程编码"
name="code"
rules={[{ required: true, message: '请输入流程编码' }]}
>
<Input />
</Form.Item>
<Form.Item
label="描述"
name="description"
>
<Input.TextArea rows={4} />
</Form.Item>
</Form>
)
},
{
key: 'flow',
label: '流程设计',
children: (
<FlowDesigner
value={graphData}
onChange={setGraphData}
/>
)
},
{
key: 'form',
label: '表单设计',
children: (
<FormDesigner
value={formData}
onChange={setFormData}
/>
)
}
];
return (
<Card
title={id ? '编辑流程' : '新建流程'}
extra={
<Button type="primary" onClick={handleSave}>
</Button>
}
>
<Tabs items={items} />
</Card>
);
};
export default Edit;

View File

@ -1,177 +0,0 @@
import React, { useState, useEffect } from 'react';
import { Card, Table, Button, Space, Tag, Popconfirm, message } from 'antd';
import { useNavigate } from 'react-router-dom';
import type { ColumnsType } from 'antd/es/table';
import { getDefinitions, deleteDefinition, publishDefinition, disableDefinition, enableDefinition } from '../service';
import { WorkflowDefinitionResponse, WorkflowStatus } from '../types';
const Definition: React.FC = () => {
const navigate = useNavigate();
const [loading, setLoading] = useState(false);
const [list, setList] = useState<WorkflowDefinitionResponse[]>([]);
const loadData = async () => {
try {
setLoading(true);
const response = await getDefinitions();
if (response) {
setList(response.content);
}
} catch (error) {
message.error('加载数据失败');
} finally {
setLoading(false);
}
};
useEffect(() => {
loadData();
}, []);
const handlePublish = async (id: number) => {
try {
await publishDefinition(id);
message.success('发布成功');
loadData();
} catch (error) {
message.error('发布失败');
}
};
const handleDisable = async (id: number) => {
try {
await disableDefinition(id);
message.success('禁用成功');
loadData();
} catch (error) {
message.error('禁用失败');
}
};
const handleEnable = async (id: number) => {
try {
await enableDefinition(id);
message.success('启用成功');
loadData();
} catch (error) {
message.error('启用失败');
}
};
const handleDelete = async (id: number) => {
try {
await deleteDefinition(id);
message.success('删除成功');
loadData();
} catch (error) {
message.error('删除失败');
}
};
const columns: ColumnsType<WorkflowDefinitionResponse> = [
{
title: '流程名称',
dataIndex: 'name',
width: 200,
},
{
title: '流程编码',
dataIndex: 'code',
width: 200,
},
{
title: '状态',
dataIndex: 'status',
width: 120,
render: (status: WorkflowStatus) => {
const statusMap = {
'DRAFT': { text: '草稿', color: 'default' },
'PUBLISHED': { text: '已发布', color: 'success' },
'DISABLED': { text: '已禁用', color: 'error' },
};
const { text, color } = statusMap[status];
return <Tag color={color}>{text}</Tag>;
},
},
{
title: '描述',
dataIndex: 'description',
ellipsis: true,
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 180,
},
{
title: '操作',
width: 280,
render: (_, record) => (
<Space>
<Button
type="link"
onClick={() => navigate(`/workflow/definition/edit/${record.id}`)}
>
</Button>
{record.status === 'DRAFT' && (
<Button
type="link"
onClick={() => handlePublish(record.id)}
>
</Button>
)}
{record.status === 'PUBLISHED' && (
<Button
type="link"
danger
onClick={() => handleDisable(record.id)}
>
</Button>
)}
{record.status === 'DISABLED' && (
<Button
type="link"
onClick={() => handleEnable(record.id)}
>
</Button>
)}
<Popconfirm
title="确定要删除吗?"
onConfirm={() => handleDelete(record.id)}
>
<Button type="link" danger>
</Button>
</Popconfirm>
</Space>
),
},
];
return (
<Card
title="流程定义"
extra={
<Button
type="primary"
onClick={() => navigate('/workflow/definition/edit')}
>
</Button>
}
>
<Table
columns={columns}
dataSource={list}
loading={loading}
rowKey="id"
/>
</Card>
);
};
export default Definition;

View File

@ -1,12 +0,0 @@
import React from 'react';
import { Card } from 'antd';
const WorkflowInstance: React.FC = () => {
return (
<Card>
<div></div>
</Card>
);
};
export default WorkflowInstance;

View File

@ -1,12 +0,0 @@
import React from 'react';
import { Card } from 'antd';
const WorkflowMonitor: React.FC = () => {
return (
<Card>
<div></div>
</Card>
);
};
export default WorkflowMonitor;

View File

@ -1,104 +0,0 @@
import request from '@/utils/request';
import type { Page } from '@/types/base/page';
import type { BaseResponse } from '@/types/base/response';
import type {
WorkflowDefinitionResponse,
WorkflowDefinitionRequest,
WorkflowDefinitionQuery,
WorkflowInstanceResponse,
WorkflowInstanceQuery,
NodeInstanceResponse,
WorkflowLogResponse,
WorkflowDefinition,
NodeTypeDTO
} from './types';
const DEFINITION_URL = '/api/v1/workflow-definitions';
const INSTANCE_URL = '/api/v1/workflow-instance';
const NODE_URL = '/api/v1/node-instance';
const LOG_URL = '/api/v1/workflow-logs';
const NODE_TYPE_URL = '/api/v1/node-types';
// 工作流定义相关接口
export const getDefinitions = (params?: WorkflowDefinitionQuery) =>
request.get<Page<WorkflowDefinitionResponse>>(`${DEFINITION_URL}/page`, { params });
export const getDefinition = (id: number) =>
request.get<WorkflowDefinitionResponse>(`${DEFINITION_URL}/${id}`);
export const createDefinition = (data: WorkflowDefinitionRequest) =>
request.post<WorkflowDefinitionResponse>(DEFINITION_URL, data);
export const updateDefinition = (id: number, data: WorkflowDefinitionRequest) =>
request.put<WorkflowDefinitionResponse>(`${DEFINITION_URL}/${id}`, data);
export const deleteDefinition = (id: number) =>
request.delete(`${DEFINITION_URL}/${id}`);
export const publishDefinition = (id: number) =>
request.post(`${DEFINITION_URL}/${id}/publish`);
export const disableDefinition = (id: number) =>
request.post(`${DEFINITION_URL}/${id}/disable`);
export const enableDefinition = (id: number) =>
request.post(`${DEFINITION_URL}/${id}/enable`);
// 工作流实例相关接口
export const getInstances = (params?: WorkflowInstanceQuery) =>
request.get<Page<WorkflowInstanceResponse>>(`${INSTANCE_URL}`, { params });
export const getInstance = (id: number) =>
request.get<WorkflowInstanceResponse>(`${INSTANCE_URL}/${id}`);
export const createInstance = (definitionId: number, businessKey: string, variables?: Record<string, any>) =>
request.post<WorkflowInstanceResponse>(INSTANCE_URL, { definitionId, businessKey, variables });
export const startInstance = (id: number) =>
request.post(`${INSTANCE_URL}/${id}/start`);
export const cancelInstance = (id: number) =>
request.post(`${INSTANCE_URL}/${id}/cancel`);
export const pauseInstance = (id: number) =>
request.post(`${INSTANCE_URL}/${id}/pause`);
export const resumeInstance = (id: number) =>
request.post(`${INSTANCE_URL}/${id}/resume`);
// 节点实例相关接口
export const getNodeInstances = (workflowInstanceId: number) =>
request.get<NodeInstanceResponse[]>(`${NODE_URL}/workflow/${workflowInstanceId}`);
export const getNodeInstancesByStatus = (workflowInstanceId: number, status: string) =>
request.get<NodeInstanceResponse[]>(`${NODE_URL}/workflow/${workflowInstanceId}/status/${status}`);
export const updateNodeStatus = (id: number, status: string) =>
request.put(`${NODE_URL}/${id}/status`, { status });
// 日志相关接口
export const getWorkflowLogs = (workflowInstanceId: number) =>
request.get<WorkflowLogResponse[]>(`${LOG_URL}/workflow/${workflowInstanceId}`);
export const getNodeLogs = (workflowInstanceId: number, nodeId: string) =>
request.get<WorkflowLogResponse[]>(`${LOG_URL}/node/${workflowInstanceId}/${nodeId}`);
export const recordLog = (data: Omit<WorkflowLogResponse, keyof BaseResponse>) =>
request.post<WorkflowLogResponse>(`${LOG_URL}/record`, data);
// 获取工作流定义列表
export const getDefinitionList = (params: WorkflowDefinitionQuery) =>
request.get<WorkflowDefinitionResponse[]>('/api/v1/workflow/definition', { params });
// 保存工作流定义
export const saveDefinition = (data: WorkflowDefinition) => {
if (data.id) {
return request.put<WorkflowDefinitionResponse>(`/api/v1/workflow/definition/${data.id}`, data);
}
return request.post<WorkflowDefinitionResponse>('/api/v1/workflow/definition', data);
};
// 获取节点类型列表
export const getNodeTypes = () =>
request.get<NodeTypeDTO[]>(NODE_TYPE_URL);

View File

@ -1,161 +0,0 @@
import { BaseResponse } from '@/types/base/response';
import { BaseQuery } from '@/types/base/query';
// 工作流状态枚举
export enum WorkflowStatus {
DRAFT = 'DRAFT',
PUBLISHED = 'PUBLISHED',
DISABLED = 'DISABLED'
}
// 节点类型枚举
export enum NodeType {
START = 'START',
END = 'END',
TASK = 'TASK',
GATEWAY = 'GATEWAY',
SUB_PROCESS = 'SUB_PROCESS',
SHELL = 'SHELL'
}
// 节点状态枚举
export enum NodeStatus {
PENDING = 'PENDING',
RUNNING = 'RUNNING',
COMPLETED = 'COMPLETED',
FAILED = 'FAILED',
CANCELLED = 'CANCELLED',
PAUSED = 'PAUSED',
SKIPPED = 'SKIPPED'
}
// 工作流实例状态枚举
export enum InstanceStatus {
RUNNING = 'RUNNING',
COMPLETED = 'COMPLETED',
FAILED = 'FAILED',
CANCELLED = 'CANCELLED',
PAUSED = 'PAUSED'
}
// 日志级别枚举
export enum LogLevel {
INFO = 'INFO',
WARN = 'WARN',
ERROR = 'ERROR'
}
// 工作流定义基础接口
export interface WorkflowDefinition {
id?: number;
name: string;
code: string;
description?: string;
nodeConfig: string;
transitionConfig: string;
formDefinition: string;
graphDefinition: string;
enabled: boolean;
version: number;
status: WorkflowStatus;
remark?: string;
createTime?: string;
updateTime?: string;
}
// 工作流定义响应数据
export interface WorkflowDefinitionResponse extends BaseResponse, WorkflowDefinition {
id: number;
createTime: string;
updateTime: string;
}
// 工作流定义查询参数
export interface WorkflowDefinitionQuery extends BaseQuery {
name?: string;
code?: string;
status?: WorkflowStatus;
}
// 工作流定义请求数据
export interface WorkflowDefinitionRequest extends Omit<WorkflowDefinition, 'id' | 'createTime' | 'updateTime'> {
id?: number;
}
// 节点定义响应数据
export interface NodeDefinitionResponse extends BaseResponse {
nodeId: string;
name: string;
type: NodeType;
config: string;
description?: string;
workflowDefinitionId: number;
orderNum: number;
}
// 工作流实例查询参数
export interface WorkflowInstanceQuery extends BaseQuery {
definitionId?: number;
status?: InstanceStatus;
startTime?: string;
endTime?: string;
}
// 工作流实例响应数据
export interface WorkflowInstanceResponse extends BaseResponse {
definitionId: number;
businessKey: string;
status: InstanceStatus;
startTime: string;
endTime?: string;
variables: string;
error?: string;
}
// 节点实例响应数据
export interface NodeInstanceResponse extends BaseResponse {
workflowInstanceId: number;
nodeId: string;
nodeType: NodeType;
name: string;
status: NodeStatus;
startTime: string;
endTime?: string;
config: string;
input: string;
output: string;
error?: string;
preNodeId: string;
}
// 工作流日志响应数据
export interface WorkflowLogResponse extends BaseResponse {
workflowInstanceId: number;
nodeId: string;
message: string;
level: LogLevel;
detail?: string;
}
// 节点类型数据结构
export interface NodeTypeDTO extends BaseResponse {
code: string; // 节点类型编码
name: string; // 节点类型名称
description: string; // 节点类型描述
category: 'BASIC' | 'TASK' | 'GATEWAY' | 'EVENT'; // 节点类型分类
icon: string; // 节点图标
color: string; // 节点颜色
executors?: Array<{ // 支持的执行器列表
code: string; // 执行器编码
name: string; // 执行器名称
description: string; // 执行器描述
configSchema: any; // 执行器配置模式
}>;
configSchema?: any; // 节点配置模式
defaultConfig?: any; // 默认配置
enabled: boolean; // 是否启用
deleted: boolean; // 是否删除
version: number; // 版本号
createBy: string; // 创建人
updateBy: string; // 更新人
}

View File

@ -1,212 +0,0 @@
import React, { useEffect, useRef } from 'react';
import { Graph } from '@antv/x6';
import { register } from '@antv/x6-react-shape';
import { Selection } from '@antv/x6-plugin-selection';
import { Keyboard } from '@antv/x6-plugin-keyboard';
import { Snapline } from '@antv/x6-plugin-snapline';
import { Transform } from '@antv/x6-plugin-transform';
import { History } from '@antv/x6-plugin-history';
import { Export } from '@antv/x6-plugin-export';
// 注册自定义节点
register({
shape: 'custom-node',
width: 100,
height: 40,
component: ({ node }) => {
const data = node.getData() || {};
return (
<div className="custom-node" style={{
padding: '8px',
border: '1px solid #ddd',
borderRadius: '4px',
backgroundColor: '#fff'
}}>
<span>{data.label || 'Node'}</span>
</div>
);
},
});
interface FlowGraphProps {
onNodeSelected?: (nodeId: string) => void;
onEdgeSelected?: (edgeId: string) => void;
}
const FlowGraph: React.FC<FlowGraphProps> = ({ onNodeSelected, onEdgeSelected }) => {
const containerRef = useRef<HTMLDivElement>(null);
const graphRef = useRef<Graph>();
useEffect(() => {
if (!containerRef.current) return;
const graph = new Graph({
container: containerRef.current,
width: 800,
height: 600,
grid: {
size: 10,
visible: true,
type: 'dot',
args: {
color: '#ccc',
thickness: 1,
},
},
connecting: {
snap: true,
allowBlank: false,
allowLoop: false,
highlight: true,
connector: 'smooth',
connectionPoint: 'boundary',
createEdge() {
return this.createEdge({
shape: 'edge',
attrs: {
line: {
stroke: '#5F95FF',
strokeWidth: 1,
targetMarker: {
name: 'classic',
size: 8,
},
},
},
router: {
name: 'manhattan',
},
});
},
},
highlighting: {
magnetAvailable: {
name: 'stroke',
args: {
padding: 4,
attrs: {
strokeWidth: 4,
stroke: '#52c41a',
},
},
},
},
mousewheel: {
enabled: true,
modifiers: ['ctrl', 'meta'],
},
interacting: {
magnetConnectable: true,
nodeMovable: true,
},
});
// 注册插件
graph.use(
new Selection({
multiple: true,
rubberband: true,
movable: true,
showNodeSelectionBox: true,
})
);
graph.use(
new Keyboard({
enabled: true,
})
);
graph.use(new Snapline());
graph.use(new Transform());
graph.use(new History());
graph.use(new Export());
// 监听事件
graph.on('node:click', ({ node }) => {
onNodeSelected?.(node.id);
});
graph.on('edge:click', ({ edge }) => {
onEdgeSelected?.(edge.id);
});
// 快捷键
graph.bindKey(['meta+c', 'ctrl+c'], () => {
const cells = graph.getSelectedCells();
if (cells.length) {
graph.copy(cells);
}
return false;
});
graph.bindKey(['meta+v', 'ctrl+v'], () => {
if (!graph.isClipboardEmpty()) {
const cells = graph.paste({ offset: 32 });
graph.cleanSelection();
graph.select(cells);
}
return false;
});
graph.bindKey(['meta+z', 'ctrl+z'], () => {
if (graph.canUndo()) {
graph.undo();
}
return false;
});
graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
if (graph.canRedo()) {
graph.redo();
}
return false;
});
graph.bindKey('delete', () => {
const cells = graph.getSelectedCells();
if (cells.length) {
graph.removeCells(cells);
}
});
graphRef.current = graph;
// 添加示例节点
graph.addNode({
shape: 'custom-node',
x: 100,
y: 100,
data: { label: '开始' },
});
graph.addNode({
shape: 'custom-node',
x: 300,
y: 100,
data: { label: '处理' },
});
graph.addNode({
shape: 'custom-node',
x: 500,
y: 100,
data: { label: '结束' },
});
return () => {
graph.dispose();
};
}, [onNodeSelected, onEdgeSelected]);
return (
<div
ref={containerRef}
style={{
border: '1px solid #ddd',
borderRadius: '4px',
backgroundColor: '#fff'
}}
/>
);
};
export default FlowGraph;

View File

@ -1,20 +0,0 @@
import React from 'react';
import { Menu } from 'antd';
import type { MenuProps } from 'antd';
import { DeleteOutlined, EditOutlined, CopyOutlined } from '@ant-design/icons';
export const NodeContextMenu = () => {
return (
<Menu>
<Menu.Item key="1" icon={<DeleteOutlined />}>
Delete
</Menu.Item>
<Menu.Item key="2" icon={<EditOutlined />}>
Edit
</Menu.Item>
<Menu.Item key="3" icon={<CopyOutlined />}>
Copy
</Menu.Item>
</Menu>
);
};

View File

@ -1,88 +0,0 @@
import React, { useState } from 'react';
import { Card, Space, Button, Drawer, Form, Input, Select } from 'antd';
import FlowGraph from './components/FlowGraph';
const FlowDesigner: React.FC = () => {
const [selectedNode, setSelectedNode] = useState<string | null>(null);
const [drawerVisible, setDrawerVisible] = useState(false);
const [form] = Form.useForm();
const handleNodeSelected = (nodeId: string) => {
setSelectedNode(nodeId);
setDrawerVisible(true);
};
const handleSave = async () => {
try {
const values = await form.validateFields();
console.log('保存节点属性:', values);
setDrawerVisible(false);
} catch (error) {
console.error('表单验证失败:', error);
}
};
return (
<div style={{ padding: '24px' }}>
<Card
title="流程设计器"
extra={
<Space>
<Button></Button>
<Button></Button>
<Button type="primary"></Button>
</Space>
}
>
<FlowGraph
onNodeSelected={handleNodeSelected}
onEdgeSelected={(edgeId) => console.log('选中连线:', edgeId)}
/>
</Card>
<Drawer
title="节点属性"
placement="right"
onClose={() => setDrawerVisible(false)}
open={drawerVisible}
width={400}
extra={
<Space>
<Button onClick={() => setDrawerVisible(false)}></Button>
<Button type="primary" onClick={handleSave}>
</Button>
</Space>
}
>
<Form form={form} layout="vertical">
<Form.Item
label="节点名称"
name="name"
rules={[{ required: true, message: '请输入节点名称' }]}
>
<Input placeholder="请输入节点名称" />
</Form.Item>
<Form.Item
label="节点类型"
name="type"
rules={[{ required: true, message: '请选择节点类型' }]}
>
<Select
options={[
{ label: '开始节点', value: 'start' },
{ label: '处理节点', value: 'process' },
{ label: '结束节点', value: 'end' },
]}
/>
</Form.Item>
<Form.Item label="描述" name="description">
<Input.TextArea rows={4} placeholder="请输入节点描述" />
</Form.Item>
</Form>
</Drawer>
</div>
);
};
export default FlowDesigner;

View File

@ -1,24 +0,0 @@
import { http } from '@/utils/http';
import type { FlowResponse, FlowQuery, FlowRequest } from './types';
const baseUrl = '/api/v1/flows';
// 获取流程列表
export const getList = (params?: FlowQuery) =>
http.get<FlowResponse[]>(baseUrl, { params });
// 获取流程详情
export const getDetail = (id: number) =>
http.get<FlowResponse>(`${baseUrl}/${id}`);
// 创建流程
export const create = (data: FlowRequest) =>
http.post<FlowResponse>(baseUrl, data);
// 更新流程
export const update = (id: number, data: FlowRequest) =>
http.put<FlowResponse>(`${baseUrl}/${id}`, data);
// 删除流程
export const remove = (id: number) =>
http.delete(`${baseUrl}/${id}`);

View File

@ -1,41 +0,0 @@
import { BaseResponse, BaseQuery } from '@/types/base';
export interface Node {
id: string;
shape: string;
x: number;
y: number;
width: number;
height: number;
label: string;
data?: Record<string, any>;
}
export interface Edge {
id: string;
source: string;
target: string;
label?: string;
data?: Record<string, any>;
}
export interface FlowData {
nodes: Node[];
edges: Edge[];
}
export interface FlowResponse extends BaseResponse {
name: string;
description?: string;
flowData: FlowData;
}
export interface FlowQuery extends BaseQuery {
name?: string;
}
export interface FlowRequest {
name: string;
description?: string;
flowData: FlowData;
}

View File

@ -32,10 +32,11 @@ const Menu = lazy(() => import('../pages/System/Menu'));
const Department = lazy(() => import('../pages/System/Department')); const Department = lazy(() => import('../pages/System/Department'));
const External = lazy(() => import('../pages/System/External')); const External = lazy(() => import('../pages/System/External'));
const X6Test = lazy(() => import('../pages/X6Test')); const X6Test = lazy(() => import('../pages/X6Test'));
const WorkflowDefinition = lazy(() => import('../pages/Workflow/Definition')); // const WorkflowDefinition = lazy(() => import('../pages/Workflow/Definition'));
const WorkflowDefinitionEdit = lazy(() => import('../pages/Workflow/Definition/Edit')); // const WorkflowDefinitionEdit = lazy(() => import('../pages/Workflow/Definition/Edit'));
const WorkflowInstance = lazy(() => import('../pages/Workflow/Instance')); // const WorkflowInstance = lazy(() => import('../pages/Workflow/Instance'));
const WorkflowMonitor = lazy(() => import('../pages/Workflow/Monitor')); // const WorkflowMonitor = lazy(() => import('../pages/Workflow/Monitor'));
// const FlowDesigner = lazy(() => import('../pages/Workflow/Definition/Designer'));
// 创建路由 // 创建路由
const router = createBrowserRouter([ const router = createBrowserRouter([
@ -116,48 +117,56 @@ const router = createBrowserRouter([
</Suspense> </Suspense>
) )
}, },
{ // {
path: 'workflow', // path: 'workflow',
children: [ // children: [
{ // {
path: 'definition', // path: 'definition',
children: [ // children: [
{ // {
path: '', // path: '',
element: ( // element: (
<Suspense fallback={<LoadingComponent/>}> // <Suspense fallback={<LoadingComponent/>}>
<WorkflowDefinition/> // <WorkflowDefinition/>
</Suspense> // </Suspense>
) // )
}, // },
{ // {
path: 'edit/:id?', // path: 'edit/:id?',
element: ( // element: (
<Suspense fallback={<LoadingComponent/>}> // <Suspense fallback={<LoadingComponent/>}>
<WorkflowDefinitionEdit/> // <WorkflowDefinitionEdit/>
</Suspense> // </Suspense>
) // )
} // },
] // {
}, // path: 'designer/:id?',
{ // element: (
path: 'instance', // <Suspense fallback={<LoadingComponent/>}>
element: ( // <FlowDesigner/>
<Suspense fallback={<LoadingComponent/>}> // </Suspense>
<WorkflowInstance/> // )
</Suspense> // }
) // ]
}, // },
{ // {
path: 'monitor', // path: 'instance',
element: ( // element: (
<Suspense fallback={<LoadingComponent/>}> // <Suspense fallback={<LoadingComponent/>}>
<WorkflowMonitor/> // <WorkflowInstance/>
</Suspense> // </Suspense>
) // )
} // },
] // {
}, // path: 'monitor',
// element: (
// <Suspense fallback={<LoadingComponent/>}>
// <WorkflowMonitor/>
// </Suspense>
// )
// }
// ]
// },
{ {
path: '*', path: '*',
element: <Navigate to="/dashboard"/> element: <Navigate to="/dashboard"/>

View File

@ -1,26 +0,0 @@
export interface LoginParams {
username: string;
password: string;
tenantId?: string;
}
export interface UserInfo {
username: string;
nickname?: string;
email?: string;
phone?: string;
}
export interface LoginResult {
token: string;
id: number;
username: string;
nickname: string;
email: string;
phone: string;
}
export interface UserState {
token: string | null;
userInfo: LoginResult | null;
}

View File

@ -1 +0,0 @@

View File

@ -19,7 +19,8 @@
"paths": { "paths": {
"@/*": ["src/*"] "@/*": ["src/*"]
}, },
"types": ["@antv/x6"] "types": ["@antv/x6"],
"allowSyntheticDefaultImports": true
}, },
"include": ["src"], "include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }] "references": [{ "path": "./tsconfig.node.json" }]