Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions ui/src/api/API_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ src/api/
│ │ ├── application/ # 智能体接口
│ │ ├── knowledge/ # 知识库接口
│ │ ├── model/ # 模型接口
│ │ ├── trigger/ # 触发器分页查询接口
│ │ ├── trigger/ # 触发器查询及维护接口
│ │ ├── tool/ # 工具、工具工作流及工具商店接口
│ │ └── <resource>.ts # 工作空间公共资源接口
│ └── provider.ts # Workspace 与 System 共用的模型供应商接口
Expand Down Expand Up @@ -186,7 +186,8 @@ API 枚举与类型统一在 `src/api` 范围内管理,相关规则由本文
`resource_user_permission/resource/<target>/resource/<resource>`;与 System 用户视角的
`user_resource_permission` 区分。分页使用 `ParamsPage`,直接返回
`ResponsePage<ResourceUserPermission>`;提交 `ResourceUserPermissionPayload[]`。
查询和更新接口内部调用 `getWorkspaceId()` 获取路由工作空间,调用方不传工作空间 ID。
用户及用户组的查询和更新接口均以必填的 `workspaceId` 为首个参数,由调用方从资源或文件夹
接口数据的 `workspace_id` 传入,不读取或回退到路由工作空间。
`ResourceAuthorizationTargetType` 包含资源类型和三个 `_FOLDER` 类型,文件夹类型用于后端
鉴权。包含子资源时传 `include_children: true` 及经过管理权限筛选的 `folder_ids`,
普通资源或仅当前文件夹不传子文件夹 ID。loading、刷新及成功提示由抽屉负责。
Expand All @@ -200,15 +201,27 @@ API 枚举与类型统一在 `src/api` 范围内管理,相关规则由本文

System 资源管理的用户授权维护在 `admin/system/resource-management/resource-authorization.ts`,
使用 `/system/workspace/<workspaceId>/resource_management/resource/<target>/resource/<resource>`。
查询与保存签名、分页类型、响应类型及提交类型与 Workspace 用户授权保持一致;工作空间 ID
由接口内部读取,loading 由组件管理。`ResourceAuthorizationDrawer` 内部通过
`isSystemResource()` 选择完整的用户授权 API 对象,作为该抽屉的范围选择例外;用户组仍使用
查询与保存方法以必填的 `workspaceId` 为首个参数,由调用方从资源数据的 `workspace_id` 传入,
不得读取或回退到路由工作空间。其余参数、分页类型、响应类型及提交类型与 Workspace 用户授权一致。
loading 由组件管理。`ResourceAuthorizationDrawer` 内部通过 `isSystemResource()` 选择完整的用户授权
API 对象和工作空间上下文,作为该抽屉的范围选择例外;用户组仍使用
现有 Workspace 接口,不推测 System 用户组路径。

### 关联资源

`admin/workspace/related-resources.ts` 维护关联资源查询:
`getResourceDependencies` 查询当前资源依赖的资源,对应后端 `mapping_resource`;
`getResourceDependents` 查询引用当前资源的资源,对应后端 `resource_mapping`。
前端按关联资源语义命名,后端接口路径保持不变。该文件当前保留旧版请求签名,
尚未完成 v3 请求适配及页面接入。
前端按关联资源语义命名,后端接口路径保持不变。方法接收工作空间 ID、资源类型、资源 ID、`ParamsPage`
和查询参数;工作空间 ID 由目标资源数据的 `workspace_id` 显式传入,不读取路由。返回 `ResponsePage<RelatedResource>`,
不传 loading,不重复解包响应。`RelatedResource` 通过 `@/api/types` 导出,保留
`source_*`、`target_*` 字段。依赖查询按 `target_type` 筛选,被依赖查询按 `source_type`
筛选,类型数组沿用请求层的数组序列化。页面负责按资源范围传入完整 API,未推测 System 接口。

### 触发器维护

`workspace/trigger/trigger.ts` 维护分页、详情、新建、编辑、删除及批量接口。
`putBatchActivateTrigger(ids, isActive)` 提交 `{ id_list, is_active }` 到 `batch_activate`;
`putBatchDeleteTrigger(ids)` 提交 `{ id_list }` 到 `batch_delete`。单项启停通过 `putTrigger`
仅提交 `is_active`。`Trigger` 为分页摘要,`TriggerDetail` 为含任务参数的完整详情;
`TriggerPayload` 用于新建和编辑,ID 在新建前生成以展示事件回调 URL。
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
import { get, put } from '../../core/request'
import type { ParamsPage, ResponsePage } from '../../core/types'
import type { Dict, ResourceAuthorizationTargetType, ResourceUserPermission, ResourceUserPermissionPayload } from '@/api/types'
import { getWorkspaceId } from '@/utils/resource-context'

const getPrefix = () => `/system/workspace/${getWorkspaceId()}/resource_management`
const getPrefix = (workspaceId: string) => `/system/workspace/${workspaceId}/resource_management`

/** 获取 System 资源管理中指定资源或文件夹的用户权限分页列表。 */
const getResourceAuthorization = (targetId: string, resource: ResourceAuthorizationTargetType, page: ParamsPage, query?: Dict<unknown>) => {
const getResourceAuthorization = (
workspaceId: string,
targetId: string,
resource: ResourceAuthorizationTargetType,
page: ParamsPage,
query?: Dict<unknown>,
) => {
return get<ResponsePage<ResourceUserPermission>>(
`${getPrefix()}/resource/${targetId}/resource/${resource}/${page.currentPage}/${page.pageSize}`,
`${getPrefix(workspaceId)}/resource/${targetId}/resource/${resource}/${page.currentPage}/${page.pageSize}`,
query,
)
}

/** 更新 System 资源管理中的用户权限及文件夹生效范围。 */
const putResourceAuthorization = (targetId: string, resource: ResourceAuthorizationTargetType, permissions: ResourceUserPermissionPayload[]) => {
const putResourceAuthorization = (
workspaceId: string,
targetId: string,
resource: ResourceAuthorizationTargetType,
permissions: ResourceUserPermissionPayload[],
) => {
return put<ResourceUserPermissionPayload[], ResourceUserPermissionPayload[]>(
`${getPrefix()}/resource/${targetId}/resource/${resource}`,
`${getPrefix(workspaceId)}/resource/${targetId}/resource/${resource}`,
permissions,
)
}
Expand Down
42 changes: 15 additions & 27 deletions ui/src/api/admin/workspace/related-resources.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,21 @@
import { Result } from '@/request/Result'
import { get, put, post, del } from '@/request/index'
import type { Ref } from 'vue'
import type { pageRequest } from '@/api/type/common'
const prefix = '/workspace'
import { get } from '../core/request'
import type { ParamsPage, ResponsePage } from '../core/types'
import type { Dict, RelatedResource, ResourceType } from '@/api/types'

/** 获取引用当前资源的资源。 */
const getResourceDependents: (
workspace_id: string,
resource: string,
resource_id: string,
page: pageRequest,
params?: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (workspace_id, resource, resource_id, page, params, loading) => {
return get(`${prefix}/${workspace_id}/resource_mapping/${resource}/${resource_id}/${page.current_page}/${page.page_size}`, params, loading)
const getResourceDependents = (workspaceId: string, resource: ResourceType, resourceId: string, page: ParamsPage, query?: Dict<unknown>) => {
return get<ResponsePage<RelatedResource>>(
`/workspace/${workspaceId}/resource_mapping/${resource}/${resourceId}/${page.currentPage}/${page.pageSize}`,
query,
)
}

/** 获取当前资源依赖的资源。 */
const getResourceDependencies: (
workspace_id: string,
resource: string,
resource_id: string,
page: pageRequest,
params?: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (workspace_id, resource, resource_id, page, params, loading) => {
return get(`${prefix}/${workspace_id}/mapping_resource/${resource}/${resource_id}/${page.current_page}/${page.page_size}`, params, loading)
const getResourceDependencies = (workspaceId: string, resource: ResourceType, resourceId: string, page: ParamsPage, query?: Dict<unknown>) => {
return get<ResponsePage<RelatedResource>>(
`/workspace/${workspaceId}/mapping_resource/${resource}/${resourceId}/${page.currentPage}/${page.pageSize}`,
query,
)
}

export default {
getResourceDependents,
getResourceDependencies,
}
export default { getResourceDependents, getResourceDependencies }
38 changes: 26 additions & 12 deletions ui/src/api/admin/workspace/resource-authorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,58 @@ import type {
ResourceUserPermission,
ResourceUserPermissionPayload,
} from '@/api/types'
import { getWorkspaceId } from '@/utils/resource-context'

const getPrefix = () => {
const workspaceId = getWorkspaceId()
return `/workspace/${workspaceId}`
}
const getPrefix = (workspaceId: string) => `/workspace/${workspaceId}`
/** 获取指定资源或文件夹的用户权限分页列表。 */
const getResourceAuthorization = (targetId: string, resource: ResourceAuthorizationTargetType, page: ParamsPage, query?: Dict<unknown>) => {
const getResourceAuthorization = (
workspaceId: string,
targetId: string,
resource: ResourceAuthorizationTargetType,
page: ParamsPage,
query?: Dict<unknown>,
) => {
return get<ResponsePage<ResourceUserPermission>>(
`${getPrefix()}/resource_user_permission/resource/${targetId}/resource/${resource}/${page.currentPage}/${page.pageSize}`,
`${getPrefix(workspaceId)}/resource_user_permission/resource/${targetId}/resource/${resource}/${page.currentPage}/${page.pageSize}`,
query,
)
}

/** 更新资源的用户权限,可同时应用到有管理权限的子文件夹及资源。 */
const putResourceAuthorization = (targetId: string, resource: ResourceAuthorizationTargetType, permissions: ResourceUserPermissionPayload[]) => {
const putResourceAuthorization = (
workspaceId: string,
targetId: string,
resource: ResourceAuthorizationTargetType,
permissions: ResourceUserPermissionPayload[],
) => {
return put<ResourceUserPermissionPayload[], ResourceUserPermissionPayload[]>(
`${getPrefix()}/resource_user_permission/resource/${targetId}/resource/${resource}`,
`${getPrefix(workspaceId)}/resource_user_permission/resource/${targetId}/resource/${resource}`,
permissions,
)
}

/** 获取指定资源或文件夹的用户组权限分页列表。 */
const getResourceUserGroupAuthorization = (targetId: string, resource: ResourceAuthorizationTargetType, page: ParamsPage, query?: Dict<unknown>) => {
const getResourceUserGroupAuthorization = (
workspaceId: string,
targetId: string,
resource: ResourceAuthorizationTargetType,
page: ParamsPage,
query?: Dict<unknown>,
) => {
return get<ResponsePage<ResourceUserGroupPermission>>(
`${getPrefix()}/resource_user_group_permission/resource/${targetId}/resource/${resource}/${page.currentPage}/${page.pageSize}`,
`${getPrefix(workspaceId)}/resource_user_group_permission/resource/${targetId}/resource/${resource}/${page.currentPage}/${page.pageSize}`,
query,
)
}

/** 更新资源的用户组权限,可应用到有管理权限的子文件夹及资源。 */
const putResourceUserGroupAuthorization = (
workspaceId: string,
targetId: string,
resource: ResourceAuthorizationTargetType,
permissions: ResourceUserGroupPermissionPayload[],
) => {
return put<ResourceUserGroupPermissionPayload[], ResourceUserGroupPermissionPayload[]>(
`${getPrefix()}/resource_user_group_permission/resource/${targetId}/resource/${resource}`,
`${getPrefix(workspaceId)}/resource_user_group_permission/resource/${targetId}/resource/${resource}`,
permissions,
)
}
Expand Down
27 changes: 21 additions & 6 deletions ui/src/api/admin/workspace/trigger/trigger.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import { get } from '../../core/request'
import { get, post, put, del } from '../../core/request'
import type { ParamsPage, ResponsePage } from '../../core/types'
import type { Dict, Trigger } from '@/api/types'
import type { Dict, Trigger, TriggerDetail, TriggerPayload } from '@/api/types'
import { getWorkspaceId } from '@/utils/resource-context'

const getPrefix = () => `/workspace/${getWorkspaceId()}/trigger`

/** 获取当前工作空间的触发器分页列表。 */
const getTriggerPage = (page: ParamsPage, query: Dict<unknown> = {}) => {
return get<ResponsePage<Trigger>>(`/workspace/${getWorkspaceId()}/trigger/${page.currentPage}/${page.pageSize}`, query)
}
const getTriggerPage = (page: ParamsPage, query: Dict<unknown> = {}) =>
get<ResponsePage<Trigger>>(`${getPrefix()}/${page.currentPage}/${page.pageSize}`, query)
/** 获取触发器配置和关联任务详情。 */
const getTriggerDetail = (triggerId: string) => get<TriggerDetail>(`${getPrefix()}/${triggerId}`)
/** 创建触发器及关联任务。 */
const postTrigger = (payload: TriggerPayload) => post<TriggerPayload, TriggerPayload>(getPrefix(), payload)
/** 更新触发器配置或启用状态。 */
const putTrigger = (triggerId: string, payload: Partial<TriggerPayload>) =>
put<Partial<TriggerPayload>, TriggerDetail>(`${getPrefix()}/${triggerId}`, payload)
/** 删除触发器及关联记录。 */
const deleteTrigger = (triggerId: string) => del<undefined, boolean>(`${getPrefix()}/${triggerId}`)
/** 批量删除触发器。 */
const putBatchDeleteTrigger = (triggerIds: string[]) => put<{ id_list: string[] }, boolean>(`${getPrefix()}/batch_delete`, { id_list: triggerIds })
/** 批量启用或禁用触发器。 */
const putBatchActivateTrigger = (triggerIds: string[], isActive: boolean) =>
put<{ id_list: string[]; is_active: boolean }, boolean>(`${getPrefix()}/batch_activate`, { id_list: triggerIds, is_active: isActive })

export default { getTriggerPage }
export default { getTriggerPage, getTriggerDetail, postTrigger, putTrigger, deleteTrigger, putBatchDeleteTrigger, putBatchActivateTrigger }
9 changes: 9 additions & 0 deletions ui/src/api/enums/trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,12 @@ export const TRIGGER_TYPE = {
SCHEDULED: 'SCHEDULED',
EVENT: 'EVENT',
} as const

/** 定时触发周期。 */
export const TRIGGER_SCHEDULE_TYPE = { DAILY: 'daily', WEEKLY: 'weekly', MONTHLY: 'monthly', INTERVAL: 'interval', CRON: 'cron' } as const
/** 触发任务参数来源。 */
export const TRIGGER_PARAMETER_SOURCE = { CUSTOM: 'custom', REFERENCE: 'reference' } as const
/** 事件请求参数类型。 */
export const TRIGGER_BODY_TYPE = { STRING: 'string', INT: 'int', DICT: 'dict', ARRAY: 'array', FLOAT: 'float', BOOLEAN: 'boolean' } as const
/** 定时间隔单位。 */
export const TRIGGER_INTERVAL_UNIT = { MINUTES: 'minutes', HOURS: 'hours' } as const
1 change: 1 addition & 0 deletions ui/src/api/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export type * from './folder'
export type * from './tool'
export type * from './knowledge'
export type * from './trigger'
export type * from './related-resources'
18 changes: 18 additions & 0 deletions ui/src/api/types/related-resources.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/** 关联资源分页查询返回的资源关系及展示信息。 */
import type { ResourceType } from './resource-authorization'

export interface RelatedResource {
id: string
name: string | null
desc?: string | null
source_id: string
source_type: ResourceType
target_id: string
target_type: ResourceType
type?: string | null
icon?: string | null
username?: string | null
workspace_id?: string | null
workspace_name?: string | null
folder_id?: string | null
}
54 changes: 53 additions & 1 deletion ui/src/api/types/trigger.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import type { TRIGGER_TYPE } from '@/api/enums'
import type {
RESOURCE_TYPE,
TRIGGER_SCHEDULE_TYPE,
TRIGGER_PARAMETER_SOURCE,
TRIGGER_BODY_TYPE,
TRIGGER_INTERVAL_UNIT,
TRIGGER_TYPE,
} from '@/api/enums'

export type TriggerType = (typeof TRIGGER_TYPE)[keyof typeof TRIGGER_TYPE]

Expand All @@ -21,3 +28,48 @@ export interface Trigger {
create_user: string | null
create_time: string
}

export type TriggerTaskSource = typeof RESOURCE_TYPE.APPLICATION | typeof RESOURCE_TYPE.TOOL
export interface TriggerParameter {
source: (typeof TRIGGER_PARAMETER_SOURCE)[keyof typeof TRIGGER_PARAMETER_SOURCE]
value: string | string[]
}
export type TriggerParameters = Record<string, TriggerParameter | Record<string, TriggerParameter>>
export interface TriggerTaskPayload {
id?: string
source_type: TriggerTaskSource
source_id: string
is_active?: boolean
parameter: TriggerParameters
meta?: Record<string, unknown>
}
export interface TriggerBodyField {
field: string
type: (typeof TRIGGER_BODY_TYPE)[keyof typeof TRIGGER_BODY_TYPE]
desc?: string
required?: boolean
}
export interface TriggerSetting {
schedule_type?: (typeof TRIGGER_SCHEDULE_TYPE)[keyof typeof TRIGGER_SCHEDULE_TYPE]
interval_unit?: (typeof TRIGGER_INTERVAL_UNIT)[keyof typeof TRIGGER_INTERVAL_UNIT]
interval_value?: number
days?: (number | string)[]
time?: string[]
cron_expression?: string
token?: string
body?: TriggerBodyField[]
}
export interface TriggerPayload {
id: string
name: string
desc: string
trigger_type: TriggerType
trigger_setting: TriggerSetting
trigger_task: TriggerTaskPayload[]
is_active?: boolean
meta?: Record<string, unknown>
}
export interface TriggerDetail extends TriggerPayload {
application_task_list?: Partial<import('./application').ApplicationDetail>[]
tool_task_list?: Partial<import('./tool').ToolItem>[]
}
8 changes: 8 additions & 0 deletions ui/src/assets/trigger/icon_event.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading