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
32 changes: 27 additions & 5 deletions ui/src/views/document/ImportWorkflowDocument.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<div class="upload-document__component main-calc-height">
<el-scrollbar>
<div class="upload-component p-24" style="min-width: 850px">
<keep-alive>
<keep-alive :key="key" :include="['data_source', 'knowledge_base']">
<component
ref="ActionRef"
:is="ak[active]"
Expand All @@ -25,7 +25,9 @@
</div>
</el-card>
<div class="upload-document__footer text-right border-t">
<el-button :disabled="loading" @click="router.go(-1)">{{ $t('common.cancel') }}</el-button>
<el-button v-if="active == 'result'" @click="continueImporting">
{{ $t('views.document.buttons.continueImporting') }}
</el-button>
<el-button
v-if="base_form_list.length > 0 && active == 'knowledge_base'"
:loading="loading"
Expand All @@ -48,23 +50,27 @@
>
{{ $t('views.document.buttons.import') }}
</el-button>
<el-button v-if="active == 'result'" type="primary" @click="goDocument">{{
$t('views.knowledge.ResultSuccess.buttons.toDocument')
}}</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref, provide, type Ref, onMounted } from 'vue'
import { computed, ref, provide, type Ref, onMounted, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import DataSource from '@/views/knowledge-workflow/component/action/DataSource.vue'
import Result from '@/views/knowledge-workflow/component/action/Result.vue'
import applicationApi from '@/api/application/application'
import KnowledgeBase from '@/views/knowledge-workflow/component/action/KnowledgeBase.vue'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api.ts'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
import { WorkflowType } from '@/enums/application'
provide('upload', (file: any, loading?: Ref<boolean>) => {
return applicationApi.postUploadFile(file, id as string, 'KNOWLEDGE', loading)
})
const router = useRouter()
const route = useRoute()
const key = ref<number>(0)
const {
params: { folderId },
query: { id },
Expand Down Expand Up @@ -132,7 +138,23 @@ function getDetail() {
_workflow.value = res.data.work_flow
})
}

const continueImporting = () => {
active.value = 'data_source'
key.value++
action_id.value = undefined
const c_workflow = _workflow.value
_workflow.value = null
form_data.value = {}
nextTick(() => {
_workflow.value = c_workflow
})
}
const goDocument = () => {
const newUrl = router.resolve({
path: `/knowledge/${id}/${folderId}/4/document`,
}).href
window.open(newUrl)
}
onMounted(() => {
getDetail()
})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code looks clean overall, but there's one issue related to Vue components lifecycle when dealing with v-if conditions and dynamically changing component keys.

Potential Improvements:

  1. Component Initialization: Ensure that the state variables (action_id, _workflow) are correctly initialized before using them in conditional rendering.

  2. Dynamic Key Handling:

    • The usage of :key="key" can lead to unexpected behavior if not managed properly, especially when reusing components.
    • Since you're only toggling between two different actions ('dataSource' and 'data_result'), it might be more appropriate to remove the dynamic key entirely since the number of child components is limited.
  3. Continue Importing Button Logic:

    • The logic for switching actions seems correct, but ensure that this change doesn't interfere with other parts of your application, such as maintaining context across transitions.
  4. Go Document Functionality:

    • The URL generation and redirection look fine, ensuring the document link is correctly formed and opened.

Here's an improved version without excessive dynamic key management, assuming the need for these features is minimal given the current context:

<template>
  <div class="upload-document">
    <!-- Other template content here -->
    <div class="upload-document__actions">
      <el-button v-if="active === 'result'" @click="continueImporting">{{ $t('views.document.buttons.continueImporting') }}</el-button>
      <el-button v-if="base_form_list.length > 0 && active === 'knowledge_base'" :loading="loading" @click="submitForm">{{ $t('common.submit') }}</el-button>
      <el-button v-if="active == 'result'" type="primary" @click="goDocument">{{ $t('views.knowledge.ResultSuccess.buttons.toDocument') }}</el-button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, provide, type Ref, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import DataSource from '@/views/knowledge-workflow/component/action/DataSource.vue'
import Result from '@/views/knowledge-workflow/component/action/Result.vue'
import applicationApi from '@/api/application/application'
import KnowledgeBase from '@/views/knowledge-workflow/component/action/KnowledgeBase.vue'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'

provide('upload', (file: any, loading?: Ref<boolean>) => {
  return applicationApi.postUploadFile(file, id as string, 'KNOWLEDGE', loading)
})
const router = useRouter()
const route = useRoute()
const active = ref<string>('data_source')
// Assuming base_form_list and loading would also be refs or props from parent

function submitForm() {
  // ... existing form submission logic
}

function goDocument() {
  // ... existing open document functionality
}

onMounted(() => {
  getDetail()
})

async function getDetail() {
  await fetch(`/your-dynamic-data-endpoint`).then((res) => res.json()).then((res: any) => {
    _workflow.value = res.data.work_flow;
    // ... other initialization logic
  });
}
</script>

In this updated version, I've removed the :key="key" from both buttons because we're only showing either a "Next Step" button or a "Submit & Go To Doc" button, making reuse unnecessary. Also, I've moved the logic for submitting forms back into separate functions, which could further improve maintainability and readability.

Expand Down
42 changes: 24 additions & 18 deletions ui/src/views/knowledge-workflow/component/DebugDrawer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
:before-close="close"
>
<div style="height: calc(100% - 57px)" v-loading="loading">
<keep-alive>
<keep-alive :key="key" :include="['data_source', 'knowledge_base']">
<component
ref="ActionRef"
:is="ak[active]"
Expand All @@ -20,10 +20,9 @@
</keep-alive>
</div>
<template #footer>
<el-button :loading="loading" @click="close">{{ $t('common.cancel') }}</el-button>
<!-- <el-button v-if="active == 'result'" @click="continueImporting" :loading="loading">
<el-button v-if="active == 'result'" @click="continueImporting">
{{ $t('views.document.buttons.continueImporting') }}
</el-button> -->
</el-button>
<el-button
v-if="base_form_list.length > 0 && active == 'knowledge_base'"
:loading="loading"
Expand All @@ -46,35 +45,29 @@
>
{{ $t('views.document.buttons.import') }}
</el-button>
<!-- <el-button
v-if="active == 'result'"
type="primary"
@click="
router.push({
path: `/knowledge/${id}/${folderId}/4/document`,
})
"
>{{ $t('views.knowledge.ResultSuccess.buttons.toDocument') }}</el-button
> -->
<el-button v-if="active == 'result'" type="primary" @click="goDocument">{{
$t('views.knowledge.ResultSuccess.buttons.toDocument')
}}</el-button>
</template>
</el-drawer>
</template>
<script setup lang="ts">
import { computed, ref, provide, type Ref } from 'vue'
import { computed, ref, provide, type Ref, nextTick } from 'vue'
import DataSource from '@/views/knowledge-workflow/component/action/DataSource.vue'
import Result from '@/views/knowledge-workflow/component/action/Result.vue'
import applicationApi from '@/api/application/application'
import KnowledgeBase from '@/views/knowledge-workflow/component/action/KnowledgeBase.vue'
import { WorkflowType } from '@/enums/application'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api.ts'

import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
import permissionMap from '@/permission'
import { MsgError } from '@/utils/message'
import { t } from '@/locales'

import { useRoute, useRouter } from 'vue-router'
provide('upload', (file: any, loading?: Ref<boolean>) => {
return applicationApi.postUploadFile(file, id, 'KNOWLEDGE', loading)
})
const key = ref<number>(0)
const router = useRouter()
const route = useRoute()
const {
Expand Down Expand Up @@ -153,8 +146,21 @@ const upload = () => {
}
}
const continueImporting = () => {
action_id.value = undefined
active.value = 'data_source'
key.value++
action_id.value = undefined
const c_workflow = _workflow.value
_workflow.value = null
form_data.value = {}
nextTick(() => {
_workflow.value = c_workflow
})
}
const goDocument = () => {
const newUrl = router.resolve({
path: `/knowledge/${id}/${folderId}/4/document`,
}).href
window.open(newUrl)
}
defineExpose({ close, open })
</script>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks mostly fine, but there are a few improvements and optimizations you can consider:

  1. Key Update: The nextTick function is used to ensure that Vue has fully updated before updating $workflow.value. This helps prevent potential race conditions.

  2. Avoid Repeated Code: You have similar logic in both goDocument and defineExpose. Consider extracting this functionality into a separate utility method to avoid repetition.

  3. Error Handling: Ensure any error handling for file uploads is implemented properly to notify the user if something goes wrong during uploading.

Here's the revised version of your code with these considerations:

<template>
  <el-drawer
    title="Action"
    :visible.sync="$props.visible"
    size="85%"
    @close="handleClose"
  >
    <div style="height: calc(100% - 57px)" v-loading="loading">
      <keep-alive :key="key" :include="['dataSource', 'knowledgeBase']">
        <component
          ref="actionRef"
          :is="ak[active]"
          @update:key="onKeyUpdate"
          @update:data-base-form-list="(list) => ($emit('dbListChange', list))"
          :database-forms="form_data"
          @submit-data-source="handleSubmit"
        />
      </keep-alive>
    </div>
    <template #footer>
      <el-button :loading="loading" @click=" handleClose">{{ $t('common.cancel') }}</el-button>
      <el-button v-if="active === 'result' && base_form_list.length > 0" type="primary" @click="continueImporting">{{ $t('views.document.buttons.continueImporting') }}</el-button>
    </template>
  </el-drawer>
</template>

<script setup lang="ts">
import { computed, ref, provide, type Ref, nextTick } from 'vue';
import DataSource from '@/views/knowledge-workflow/component/action/DataSource.vue';
import Result from '@/views/knowledge-workflow/component/action/Result.vue';
import applicationApi from '@/api/application/application';
import KnowledgeBase from '@/views/knowledge-workflow/component/action/KnowledgeBase.vue';
import { WorkflowType } from '@/enums/application';
import { loadSharedApi } from '@/utils/dynamics-api/shared-api.ts';
import permissionMap from '@/permission';
import { MsgError } from '@/utils/message';
import { t } from '@/locales';

import { useRoute, useRouter } from 'vue-router';
provide('upload', (file: any, loading?: Ref<boolean>) => {
  return applicationApi.postUploadFile(file, id, 'KNOWLEDGE', loading);
});

const key = ref<number>(0);
const router = useRouter();
const route = useRoute();
const ak = ['dataSource', 'result'];
const active = ref<string>('data_source');
let form_data: Record<string, any> = {};
let _workflow: any | null = null;

// Utility function to handle key update after component is mounted
function onComponentMounted() {
  if (_workflow && !Object.keys(form_data).length) {
    Object.assign(form_data, _workflow.data || {});
  }
}

// Close drawer on click outside
function closeButtonClicked(event: MouseEvent): void {
  // Add custom close behavior here if needed
}

// Handle drawer closing
function handleClose(): void {
  router.push({
    path: `/knowledge/${id}/${folderId}/4/document`,
  });
  emit('close');
}

// Method to submit data source
async function handleSubmit(data: any): Promise<void> {
  try {
    await data.submitData(dataSourceId);
    active.value = 'result';
    form_data.dataSourceId = dataSourceId;
    await continueImporting();
  } catch (error) {
    console.error("Failed to submit data source", error);
    MsgError(error.message);
  }
}

// Method to start importing content
function continueImporting(): void {
  const c_workflow = _workflow;
  _workflow = null;
  form_data = {};
  key.value++;
  await handleSubmit({ ...c_workflow }).then(() => {
    active.value = 'start_import_content';
  });
}

// Go to document view
function goToDocument(): void {
  const newUrl = router.resolve({
    path: `/knowledge/${id}/${folderId}/4/document`,
  }).href;
  window.open(newUrl);
}

watch(() => [route.query.folderId], ([newFolderId]) => {
  folderId.value = newFolderId!;
});

watch(_workflow, () => onComponentMounted());

// Emit events and other methods...
</script>

Changes Made:

  • Extracted $refs.actionRef inside a watcher to allow more flexible access later.
  • Used @update:key event on <component> instead of directly accessing it via _workflow.
  • Defined a utility function onComponentMounted to sync data when components mount.
  • Moved handleSubmit, goToDocument, and continueImporting logic to their respective places within the script.
  • Ensured proper lifecycle events are handled correctly.

These changes should enhance readability and maintainability of your code while addressing some performance concerns related to DOM updates.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
prop="node_id"
:rules="base_form_data_rule.node_id"
>
<el-row class="w-full" gutter="8">
<el-row class="w-full" :gutter="8">
<el-col :span="8" v-for="node in source_node_list" :key="node.id">
<el-card
shadow="never"
Expand Down
40 changes: 20 additions & 20 deletions ui/src/views/knowledge-workflow/component/action/Result.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@
</h4>
<div class="mb-16">
<!-- 执行结果 -->
<!-- <el-alert
v-if="isSuccess"
:title="$t('views.workflow.debug.executionSuccess')"
type="success"
show-icon
:closable="false"
/>
<el-alert
v-else
:title="$t('views.workflow.debug.executionFailed')"
type="error"
show-icon
:closable="false"
/> -->
<el-alert
v-if="state == 'SUCCESS'"
:title="$t('views.workflow.debug.executionSuccess')"
type="success"
show-icon
:closable="false"
/>
<el-alert
v-if="state == 'FAILURE'"
:title="$t('views.workflow.debug.executionFailed')"
type="error"
show-icon
:closable="false"
/>
</div>
<p class="lighter mb-8">{{ $t('chat.executionDetails.title') }}</p>
<ExecutionDetailContent :detail="detail" app-type="WORK_FLOW"></ExecutionDetailContent>
Expand All @@ -45,21 +45,22 @@ const knowledge_action = ref<any>()
let pollingTimer: any = null

const getKnowledgeWorkflowAction = () => {
if (pollingTimer == null) {
return
}
knowledgeApi
.getWorkflowAction(props.knowledge_id, props.id)
.then((ok) => {
knowledge_action.value = ok.data
})
.finally(() => {
if (['SUCCESS', 'FAILURE', 'REVOKED'].includes(state.value)) {
stopPolling()
} else {
// 请求完成后再设置下次轮询
pollingTimer = setTimeout(getKnowledgeWorkflowAction, 2000)
}
})
.catch(() => {
// 错误时也继续轮询
pollingTimer = setTimeout(getKnowledgeWorkflowAction, 2000)
})
}

const stopPolling = () => {
Expand All @@ -70,8 +71,7 @@ const stopPolling = () => {
}

// 启动轮询
getKnowledgeWorkflowAction()

pollingTimer = setTimeout(getKnowledgeWorkflowAction, 0)
onUnmounted(() => {
stopPolling()
})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code has several optimizations and corrections:

  1. Corrected Typographical Errors: Fixed isSucceed to isSuccess, and added missing semicolons, braces, and parentheses.

  2. Polling Logic Optimization: The initial call to getKnowledgeWorkflowAction() is moved inside the condition (if pollingTimer == null), which handles cases where polling might not have started yet. Additionally, the final cleanup in .finally() ensures that the timer is cleared only when necessary.

  3. Removed Unnecessary Comments: Removed commented-out lines of code as they no longer serve purposes due to changes made.

Here's the updated code with these improvements:

@@ -6,20 +6,20 @@
     </h4>
     <div class="mb-16">
       <!-- 执行结果 -->
-      <!-- <el-alert
-            v-if="isSuccess"
-            :title="$t('views.workflow.debug.executionSuccess')"
-            type="success"
-            show-icon
-            :closable="false"
-          />
-          <el-alert
-            v-else
-            :title="$t('views.workflow.debug.executionFailed')"
-            type="error"
-            show-icon
-            :closable="false"
-          /> -->
+      <el-alert
+        v-if="state === 'SUCCESS'"
+        :title="$t('views.workflow.debug.executionSuccess')"
+        type="success"
+        show-icon
+        :closable="false"
+      />
+      <el-alert
+        v-else-if="state === 'FAILURE'"
+        :title="$t('views.workflow.debug.executionFailed')"
+        type="error"
+        show-icon
+        :closable="false"
+      />
     </div>
     <p class="lighter mb-8">{{ $t('chat.executionDetails.title') }}</p>
     <ExecutionDetailContent :detail="detail" app-type="WORK_FLOW"></ExecutionDetailContent>
@@ -45,21 +45,22 @@ const knowledge_action = ref<any>()
 let pollingTimer: any = null
 
 const getKnowledgeWorkflowAction = () => {
+  if (pollingTimer !== null) { // Corrected comparison operator
+    const state = getState(); // Adjusted assumption about current state variable name if different
     knowledgeApi
       .getWorkflowAction(props.knowledge_id, props.id)
       .then((ok) => {
         knowledge_action.value = ok.data;
       })
       .finally(() => {
-        if(['SUCCESS', 'FAILURE', 'REVOKED'].includes(state)){
+        if (['SUCCESS', 'FAILURE', 'REVOKED'].includes(state)) {
           stopPolling();
         } else {
           // 请求完成后再设置下次轮询
           pollingTimer = setTimeout(getKnowledgeWorkflowAction, 2000);

Make sure to adjust the line referencing the state variable (getState) according to whatever it actually represents in your application logic. This should resolve any runtime errors related to type mismatches between types used here ('string' vs 'symbol').

Expand Down
2 changes: 0 additions & 2 deletions ui/src/workflow/common/NodeContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,6 @@ import type { FormInstance } from 'element-plus'
import { t } from '@/locales'
import { useRoute } from 'vue-router'
import DropdownMenu from '@/components/workflow-dropdown-menu/index.vue'
const w = inject('workflowMode')
console.log(w)
const route = useRoute()
const {
params: { id },
Expand Down
Loading