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
5 changes: 5 additions & 0 deletions ui/src/api/API_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ FormData;保存返回完整配置,页面以该返回值作为唯一数据来

### 四类特殊资源 API

根据资源范围或业务上下文选择出的 API 对象统一命名为 `requestApi`,包括 `computed` 结果和
局部变量,不使用 `toolApi`、`authorizationApi` 或 `request` 等名称。同一作用域确需同时使用
多套 API 时,以 `request` 为前缀加业务名区分,例如 `requestModelApi`、`requestToolApi`。
直接导入的 API 保持 PascalCase 命名;请求返回的 Promise 不属于此命名规则。

`application`、`knowledge`、`model`、`tool` 是需要同时考虑 Workspace、System 资源管理和
System 共享资源的四类特殊资源。其接口按真实后端边界分别维护在 `admin/workspace/` 与
`admin/system/` 下,不把不同范围的 URL 合并为页面侧 API Map,也不让卡片或 Action 根据路由拼接
Expand Down
4 changes: 3 additions & 1 deletion ui/src/components/COMPONENT_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,9 @@ Python 与 JSON 编辑器通过 `<style lang="scss" scoped src="./style.scss">`
编辑器单独设置高度。不在全局 `app.scss` 中覆盖 `.cm-editor`。

基于 CodeMirror 6 的 Python 代码编辑器,通过 `v-model` 管理代码,并在组件内部调用工具 pylint
接口生成诊断。组件最多展示 50 条诊断,并在代码停止输入 500ms 后检查。编辑器提供内置全屏
接口生成诊断。组件通过资源上下文方法判断当前路由范围,分别选择 Workspace、System 资源管理
或 System 共享资源的工具 API;普通编辑与全屏编辑使用相同的接口选择逻辑。
组件最多展示 50 条诊断,并在代码停止输入 500ms 后检查。编辑器提供内置全屏
入口;全屏确认时更新 `v-model` 并触发 `submit-dialog`,`header-extra` 插槽用于添加全屏标题栏操作。

### JsonInput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const folderData = ref<FolderItem>()
const submitting = ref(false)

/* System 资源管理使用专属用户/用户组授权接口,工作空间沿用现有接口。 */
const authorizationApi = computed(() => (isSystemResource() ? SystemResourceAuthorizationApi : ResourceAuthorizationApi))
const requestApi = computed(() => (isSystemResource() ? SystemResourceAuthorizationApi : ResourceAuthorizationApi))

/* 资源类型与权限选项 */
const folderPermissionMap = {
Expand Down Expand Up @@ -105,13 +105,13 @@ function submitPermissions(permission: ResourcePermission, includeChildren: bool
const authorizationRef = isUserGroup ? userGroupAuthorizationRef.value : userAuthorizationRef.value
submitting.value = true
const request = isUserGroup
? authorizationApi.value.putResourceUserGroupAuthorization(
? requestApi.value.putResourceUserGroupAuthorization(
workspaceId,
targetId.value,
authorizationType.value,
pendingSubjectIds.value.map((id) => ({ user_group_id: id, ...permissionScope })),
)
: authorizationApi.value.putResourceAuthorization(
: requestApi.value.putResourceAuthorization(
workspaceId,
targetId.value,
authorizationType.value,
Expand Down Expand Up @@ -164,7 +164,7 @@ defineExpose({ open })
v-if="targetType === 'user-group' && targetId && workspaceId"
:key="targetId"
:submitting="submitting"
:api="authorizationApi"
:api="requestApi"
:workspace-id="workspaceId"
:target-id="targetId"
:type="authorizationType"
Expand All @@ -177,7 +177,7 @@ defineExpose({ open })
v-if="targetType === 'user' && targetId && workspaceId"
:key="targetId"
:submitting="submitting"
:api="authorizationApi"
:api="requestApi"
:workspace-id="workspaceId"
:target-id="targetId"
:type="authorizationType"
Expand Down
8 changes: 4 additions & 4 deletions ui/src/components/business/select-model/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@ function getProviderIcon(modelId: unknown) {
// 创建模型:根据当前资源范围传入完整 API,创建后由调用方刷新选项。
const selectRef = useTemplateRef<SelectInstance>('selectRef')
const allModelProvider: ModelProviderItem = { icon: '', name: '全部模型', provider: 'all' }
const createModelApi = computed(() => {
const requestApi = computed(() => {
if (isWorkspaceResource()) return ModelApi
if (isSystemSharedResource()) return SystemSharedModelApi
return undefined
})

function handleOpenCreateModel(open: () => void) {
if (props.disabled || !props.canAdd || !createModelApi.value) return
if (props.disabled || !props.canAdd || !requestApi.value) return
selectRef.value?.blur()
open()
}
Expand Down Expand Up @@ -157,9 +157,9 @@ function openModelParams() {
</div>
</template>

<template v-if="canAdd && createModelApi" #footer>
<template v-if="canAdd && requestApi" #footer>
<slot name="footer">
<ButtonAddModel :api="createModelApi" :current-provider="allModelProvider" :providers="providerOptions" @refresh="emit('refresh')">
<ButtonAddModel :api="requestApi" :current-provider="allModelProvider" :providers="providerOptions" @refresh="emit('refresh')">
<template #default="{ open }">
<el-button type="primary" link :disabled="disabled" @click.stop="handleOpenCreateModel(open)">
<MkIcon name="icon_add_outlined" />
Expand Down
15 changes: 13 additions & 2 deletions ui/src/components/codemirror-editor/python.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
<script setup lang="ts">
import { ref } from 'vue'
import { computed, ref } from 'vue'
import type { EditorState } from '@codemirror/state'
import { linter, type Diagnostic } from '@codemirror/lint'
import { python } from '@codemirror/lang-python'
import { Codemirror } from 'vue-codemirror'
import ToolApi from '@/api/admin/workspace/tool/tool'
import SystemResourceToolApi from '@/api/admin/system/resource-management/tool/tool'
import SystemSharedToolApi from '@/api/admin/system/shared-resources/tool/tool'
import type { ToolPylintIssue } from '@/api/types'
import { isSystemResource, isSystemSharedResource } from '@/utils/resource-context'

defineOptions({ name: 'PythonCodeEditor', inheritAttrs: false })

Expand All @@ -16,6 +19,13 @@ const emit = defineEmits<{ submitDialog: [code: string] }>()

defineSlots<{ 'header-extra'?(): unknown }>()

// Python 校验使用当前资源范围的工具接口。
const requestApi = computed(() => {
if (isSystemResource()) return SystemResourceToolApi
if (isSystemSharedResource()) return SystemSharedToolApi
return ToolApi
})

function getDocumentPosition(state: EditorState, line: number, column: number) {
const safeLine = Math.max(1, Math.min(line, state.doc.lines))
const documentLine = state.doc.line(safeLine)
Expand All @@ -35,7 +45,8 @@ const codeLinter = linter(
const lintSource = view.state.doc.toString()
if (!lintSource.trim()) return []

return ToolApi.postToolPylint(lintSource)
return requestApi.value
.postToolPylint(lintSource)
.then((issues) => {
if (lintSource !== view.state.doc.toString()) return []
return issues.slice(0, 50).map((issue) => createDiagnostic(view.state, issue))
Expand Down
5 changes: 5 additions & 0 deletions ui/src/components/global/mk-icon/LoadingIcon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ const loadingSize = computed(() => (typeof props.size === 'number' ? `${props.si
</template>
<style scoped lang="scss">
.loading-icon {
:deep(.el-loading-spinner .circular) {
display: block;
margin-inline: auto;
}

:deep(.el-loading-spinner .path) {
stroke-width: 4px;
}
Expand Down
2 changes: 1 addition & 1 deletion ui/src/constants/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const DEFAULT_THEME_SETTING = { icon: '', loginLogo: '', loginImage: '',

export const DEFAULT_PLATFORM_SETTING = {
showUserManual: true,
userManualUrl: 'https://maxkb.cn/docs/v2/',
userManualUrl: 'https://docs.fit2cloud.com/maxkb/',
showForum: true,
forumUrl: 'https://bbs.fit2cloud.com/c/mk/11',
showProject: true,
Expand Down
4 changes: 2 additions & 2 deletions ui/src/views/knowledge/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ function handleSearchChange(query?: Dict<unknown>) {
}

function loadKnowledgePage(pagination: { currentPage: number; pageSize: number }) {
const request = isShared.value ? SharedApi : KnowledgeApi
const requestApi = isShared.value ? SharedApi : KnowledgeApi
const folderId = isShared.value ? {} : { folder_id: currentFolder.value.id || FOLDER_ENTRY_ID.ALL }
return request.getKnowledgePage(pagination, { ...knowledgeQuery.value, ...folderId })
return requestApi.getKnowledgePage(pagination, { ...knowledgeQuery.value, ...folderId })
}

/* 知识库维护 */
Expand Down
4 changes: 2 additions & 2 deletions ui/src/views/tool/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ function handleSearchChange(query?: Dict<unknown>) {
const toolType = ref<ToolType | ''>('')

function loadToolsPage(pagination: { currentPage: number; pageSize: number }) {
const request = isShared.value ? SharedApi : ToolApi
const requestApi = isShared.value ? SharedApi : ToolApi
const folderId = isShared.value ? {} : { folder_id: currentFolder.value.id || FOLDER_ENTRY_ID.ALL }
return request.getToolPage(pagination, { ...toolQuery.value, tool_type: toolType.value, ...folderId })
return requestApi.getToolPage(pagination, { ...toolQuery.value, tool_type: toolType.value, ...folderId })
}

// 加载工具商店
Expand Down
8 changes: 4 additions & 4 deletions ui/src/views/tool/tool-store/ApplyStoreToolDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ function handleSubmit() {

const commonPayload = { folder_id: props.folderId || 'default', name }
const isSharedResource = isSystemSharedResource()
const toolApi = isSharedResource ? SystemSharedToolApi : ToolApi
const toolStoreApi = isSharedResource ? SystemSharedToolStoreApi : WorkspaceToolStoreApi
let request: Promise<ToolItem>

if (tool.label === 'workflow_template') {
request = toolApi.postTool({ ...commonPayload, code: '{}', tool_type: TOOL_TYPE.WORKFLOW, work_flow_template: tool })
const requestApi = isSharedResource ? SystemSharedToolApi : ToolApi
request = requestApi.postTool({ ...commonPayload, code: '{}', tool_type: TOOL_TYPE.WORKFLOW, work_flow_template: tool })
} else {
request = toolStoreApi.postStoreTool(tool.id, {
const requestApi = isSharedResource ? SystemSharedToolStoreApi : WorkspaceToolStoreApi
request = requestApi.postStoreTool(tool.id, {
...commonPayload,
download_callback_url: tool.downloadCallbackUrl ?? '',
download_url: tool.downloadUrl ?? '',
Expand Down
30 changes: 15 additions & 15 deletions ui/src/views/workflow/tool/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ import { goBack } from './navigation'
defineOptions({ name: 'ToolWorkflowView' })

// 保存、调试与版本历史保持进入页面时的资源范围。
const ModelApi = isSystemResource() ? SystemModelApi : isSystemSharedResource() ? SharedModelApi : WorkspaceModelApi
const ToolApi = isSystemResource() ? SystemToolApi : isSystemSharedResource() ? SharedToolApi : WorkspaceToolApi
const ToolWorkflowApi = isSystemResource() ? SystemToolWorkflowApi : isSystemSharedResource() ? SharedToolWorkflowApi : WorkspaceToolWorkflowApi
const requestModelApi = isSystemResource() ? SystemModelApi : isSystemSharedResource() ? SharedModelApi : WorkspaceModelApi
const requestToolApi = isSystemResource() ? SystemToolApi : isSystemSharedResource() ? SharedToolApi : WorkspaceToolApi
const requestApi = isSystemResource() ? SystemToolWorkflowApi : isSystemSharedResource() ? SharedToolWorkflowApi : WorkspaceToolWorkflowApi
provide('resourceScope', getResourceScope())

// 为画布节点中的 SelectModel 提供参数表单接口。
provide('getModelParamsForm', ModelApi.getModelParamsForm)
provide('getModelParamsForm', requestModelApi.getModelParamsForm)

const DEFAULT_WORKFLOW: LogicFlow.GraphConfigData = {
nodes: cloneDeep(defaultToolNodes),
Expand Down Expand Up @@ -75,15 +75,15 @@ function saveToolWorkflow(graphData = getGraphData(), showMessage = false) {

const workflowSnapshot = cloneDeep(graphData)

return ToolWorkflowApi.putToolWorkflow(toolId, { work_flow: workflowSnapshot, default_model_setting: cloneDeep(defaultModelSetting.value) }).then(
(toolWorkflow) => {
return requestApi
.putToolWorkflow(toolId, { work_flow: workflowSnapshot, default_model_setting: cloneDeep(defaultModelSetting.value) })
.then((toolWorkflow) => {
defaultModelSetting.value = cloneDeep(toolWorkflow.default_model_setting ?? {})
saveTime.value = toolWorkflow.update_time || new Date()
setSavedWorkflow(workflowSnapshot)
if (showMessage) MsgSuccess('保存成功')
return toolWorkflow
},
)
})
}

/* 自动保存:一分钟周期,按资源类型和工具独立记录开关。 */
Expand Down Expand Up @@ -156,7 +156,7 @@ function handleUseTemplate(template: WorkflowStoreTemplate) {
})
.then(() => {
loading.value = true
return ToolWorkflowApi.putToolWorkflow(toolId, { work_flow_template: cloneDeep(template) }).then(() => {
return requestApi.putToolWorkflow(toolId, { work_flow_template: cloneDeep(template) }).then(() => {
return loadToolWorkflow().then(() => {
templateStoreButtonRef.value?.close()
MsgSuccess('应用成功')
Expand Down Expand Up @@ -226,7 +226,7 @@ function handlePublish() {
return workflowRef.value
.validate()
.then(() => saveToolWorkflow())
.then(() => ToolWorkflowApi.putToolWorkflowPublish(toolId))
.then(() => requestApi.putToolWorkflowPublish(toolId))
.then(() => MsgSuccess('发布成功'))
.catch(() => {
MsgError('发布失败')
Expand All @@ -242,7 +242,7 @@ async function handleExportWorkflow() {
loading.value = true
try {
if (hasUnsavedChanges()) await saveToolWorkflow()
await ToolApi.exportTool(toolId, toolDetail.value.name)
await requestToolApi.exportTool(toolId, toolDetail.value.name)
} catch {
MsgError('导出工作流失败')
} finally {
Expand All @@ -251,7 +251,7 @@ async function handleExportWorkflow() {
}

function loadToolWorkflow() {
return Promise.all([ToolApi.getToolDetail(toolId), ToolWorkflowApi.getToolWorkflow(toolId)]).then(([tool, toolWorkflow]) => {
return Promise.all([requestToolApi.getToolDetail(toolId), requestApi.getToolWorkflow(toolId)]).then(([tool, toolWorkflow]) => {
toolDetail.value = tool
defaultModelSetting.value = cloneDeep(toolWorkflow.default_model_setting ?? {})
saveTime.value = toolWorkflow.update_time
Expand Down Expand Up @@ -331,7 +331,7 @@ onBeforeUnmount(() => stopAutoSave())
<!-- 默认模型设置 -->
<ButtonDefaultModelSetting
:model-value="defaultModelSetting"
:model-api="ModelApi"
:model-api="requestModelApi"
:get-graph-data="getGraphData"
:disabled="loading"
@open="closeDebug"
Expand Down Expand Up @@ -365,7 +365,7 @@ onBeforeUnmount(() => stopAutoSave())
</MkDropdownItem>
<!-- 发布历史 -->
<ButtonPublishHistory
:api="ToolWorkflowApi"
:api="requestApi"
v-model:visible="historyVisible"
:tool-id="toolId"
:selected-id="previewVersion?.id"
Expand Down Expand Up @@ -396,6 +396,6 @@ onBeforeUnmount(() => stopAutoSave())
/>
</div>
<!-- 调试抽屉 -->
<DebugDrawer :api="ToolWorkflowApi" ref="debugDrawerRef" :tool-id="toolId" />
<DebugDrawer :api="requestApi" ref="debugDrawerRef" :tool-id="toolId" />
</WorkflowViewLayout>
</template>
6 changes: 4 additions & 2 deletions ui/src/workflow-canvas/WORKFLOW_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,10 @@ AI 对话节点的提示词、历史记录、视觉理解和输出思考表单
重新生成复用上次请求消息,关闭时终止请求并在关闭动画结束后清理会话;点击替换后通过 `replace` 交由节点回写系统提示词。
生成接口沿用智能体已保存的参数,弹窗不提供独立模型参数设置。
主题输入直接在 `PromptGenerate.vue` 内使用 Element Plus 自适应文本域与底部发送/停止按钮,
通过本地输入值、模型和智能体状态控制提交;Enter 发送、Shift+Enter 换行,输入法组合期间不提交。
长文本使用原生纯文本粘贴,输入上限为 100000 字符,不转为附件事件。
通过本地输入值、模型和智能体状态控制提交;Enter 发送,Ctrl/Shift/Alt/Meta + Enter 在光标处换行,
输入法组合期间不提交,纯空白内容不可发送。
长文本使用原生纯文本粘贴,输入上限为 100000 字符,不转为附件事件;输入框的键盘和粘贴事件
停止冒泡,避免触发画布快捷键或节点粘贴。
AI 对话、图片理解和视频理解统一复用 `component/ThinkingSetting.vue`,后续同类入口也应复用。
组件通过 `v-model` 接收 `types.ts` 的 `ReasoningSettingData`,由节点的输出思考开关以 `v-if` 挂载,
遵循通用设置弹窗规则;开始、结束标签当前不设必填。
Expand Down
Loading
Loading