From 845753984f0ff93a7253b0affae2c091dfe987ef Mon Sep 17 00:00:00 2001 From: Sai Nikhil Date: Thu, 10 Jul 2025 12:46:55 +0530 Subject: [PATCH] fix: o2 ai addtional info main (#7520) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### **User description** This PR fixes 1. if user clicks on ai shortcut to add a log line and user removes that and again tries to add same line it should add 2. if user have filtered columns then user should get only those columns in the input ai when clicks on shortcut ___ ### **PR Type** Enhancement ___ ### **Description** - Reset AI chat input before setting context - Include timestamp and all fields for UDS schemas - Deep copy schemas to prevent mutation - Filter rows by selected columns when sending ___ ### **Changes diagram** ```mermaid flowchart LR A["User clicks AI chat"] --> B["Reset aiChatInputContext"] B --> C["nextTick callback"] C --> D["Set aiChatInputContext"] D --> E["Dispatch enable AI chat"] ``` ___ ### **Changes walkthrough** 📝
Relevant files
Enhancement
AddFunction.vue
Reset aiChatInputContext to trigger watcher                           

web/src/components/functions/AddFunction.vue
  • Imported nextTick for async updates
  • Reset aiChatInputContext before setting
  • Used nextTick to trigger watcher on same value
  • +7/-1     
    ScheduledPipeline.vue
    Add UDS timestamp and all_fields to schema                             

    web/src/components/pipeline/NodeForm/ScheduledPipeline.vue
  • Typed userDefinedFields as any[]
  • Annotated payload as any
  • Added UDS logic: push timestamp and all_fields
  • +14/-2   
    MainLayout.vue
    Reset chat context for watcher trigger                                     

    web/src/layouts/MainLayout.vue
  • Reset aiChatInputContext before setting
  • Wrapped setting in nextTick callback
  • +6/-1     
    Index.vue
    Deep copy and extend UDS schema                                                   

    web/src/plugins/logs/Index.vue
  • Imported deepCopy utility
  • Deep-copied schema to avoid mutations
  • Added timestamp and all_fields only if UDS enabled
  • +20/-3   
    JsonPreview.vue
    Simplify sendToAiChat parameters                                                 

    web/src/plugins/logs/JsonPreview.vue
  • Simplified sendToAiChat signature
  • Removed unused key argument
  • Emit only value to parent
  • +2/-2     
    TenstackTable.vue
    Filter table row before AI chat send                                         

    web/src/plugins/logs/TenstackTable.vue
  • Enhanced sendToAiChat to handle full row flag
  • Filtered row based on selected columns
  • Added helper functions for filtering
  • +38/-3   
    ___ >
    Need help?
  • Type /help how to ... in the comments thread for any questions about PR-Agent usage.
  • Check out the documentation for more information.
  • --- web/src/components/functions/AddFunction.vue | 8 +++- .../pipeline/NodeForm/ScheduledPipeline.vue | 22 +++++++++- web/src/layouts/MainLayout.vue | 7 +++- web/src/plugins/logs/Index.vue | 23 +++++++++-- web/src/plugins/logs/JsonPreview.vue | 4 +- web/src/plugins/logs/TenstackTable.vue | 41 +++++++++++++++++-- 6 files changed, 93 insertions(+), 12 deletions(-) diff --git a/web/src/components/functions/AddFunction.vue b/web/src/components/functions/AddFunction.vue index 75d838647f..add3b9e27b 100644 --- a/web/src/components/functions/AddFunction.vue +++ b/web/src/components/functions/AddFunction.vue @@ -141,6 +141,7 @@ import { watch, onUnmounted, defineAsyncComponent, + nextTick, } from "vue"; import jsTransformService from "../../services/jstransform"; @@ -466,7 +467,12 @@ end`; const sendToAiChat = (value: any) => { //this is for when user in pipeline add function page and click on ai chat button - aiChatInputContext.value = value; + //here we reset the value befoere setting it because if user clears the input then again click on the same value it wont trigger the watcher that is there in the child component + //so to force trigger we do this + aiChatInputContext.value = ''; + nextTick(() => { + aiChatInputContext.value = value; + }); store.dispatch("setIsAiChatEnabled", true); //this is for when user in functions page and click on ai chat button emit("sendToAiChat", value); diff --git a/web/src/components/pipeline/NodeForm/ScheduledPipeline.vue b/web/src/components/pipeline/NodeForm/ScheduledPipeline.vue index 42582a7b9e..f80df04a21 100644 --- a/web/src/components/pipeline/NodeForm/ScheduledPipeline.vue +++ b/web/src/components/pipeline/NodeForm/ScheduledPipeline.vue @@ -1349,7 +1349,7 @@ const loading = ref(false); const aiChatInputContext = ref(""); -const userDefinedFields = ref([]); +const userDefinedFields = ref([]); const selectedStreamType = ref(props.streamType || "logs"); @@ -2138,7 +2138,7 @@ const getBtnLogo = computed(() => { const getContext = async () => { return new Promise(async (resolve, reject) => { try { - const payload = {}; + const payload : any = {}; if (!selectedStreamType.value || !selectedStreamName.value) { @@ -2153,6 +2153,24 @@ const getBtnLogo = computed(() => { } }) + //if uds is enabled we need to push the timestamp and all fields name in the schema + const hasTimestampColumn = userDefinedFields.value.some((field: any) => field.name === store.state.zoConfig.timestamp_column); + const hasAllFieldsName = userDefinedFields.value.some((field: any) => field.name === store.state.zoConfig.all_fields_name); + if(userDefinedFields.value.length > 0){ + if(!hasTimestampColumn){ + userDefinedFields.value.push({ + name:store.state.zoConfig.timestamp_column, + type:'Int64' + }) + } + if(!hasAllFieldsName){ + userDefinedFields.value.push({ + name:store.state.zoConfig.all_fields_name, + type:'Utf8' + }) + } + } + payload["stream_name"] = selectedStreamName.value; payload["schema_"] = userDefinedFields.value.length > 0 ? userDefinedFields.value : schema; diff --git a/web/src/layouts/MainLayout.vue b/web/src/layouts/MainLayout.vue index 90cdcd2d17..8f50951d2d 100644 --- a/web/src/layouts/MainLayout.vue +++ b/web/src/layouts/MainLayout.vue @@ -1256,7 +1256,12 @@ export default defineComponent({ }) const sendToAiChat = (value: any) => { store.dispatch("setIsAiChatEnabled", true); - aiChatInputContext.value = value; + //here we reset the value befoere setting it because if user clears the input then again click on the same value it wont trigger the watcher that is there in the child component + //so to force trigger we do this + aiChatInputContext.value = ''; + nextTick(() => { + aiChatInputContext.value = value; + }); } return { diff --git a/web/src/plugins/logs/Index.vue b/web/src/plugins/logs/Index.vue index be89d81340..75d72028ad 100644 --- a/web/src/plugins/logs/Index.vue +++ b/web/src/plugins/logs/Index.vue @@ -370,6 +370,7 @@ import config from "@/aws-exports"; import { verifyOrganizationStatus, useLocalInterestingFields, + deepCopy, } from "@/utils/zincutils"; import MainLayoutCloudMixin from "@/enterprise/mixins/mainLayout.mixin"; import SanitizedHtmlRenderer from "@/components/SanitizedHtmlRenderer.vue"; @@ -1651,11 +1652,27 @@ export default defineComponent({ } for (let i = 0; i < streams.length; i++) { - const schema = await getStream(streams[i], streamType, true); + const schema = await getStream(streams[i], streamType, true); + //here we are deep copying the schema before assiging it to schemaData so that we dont mutatat the orginial data + //if we do this we dont get duplicate fields in the schema + let schemaData = deepCopy(schema.uds_schema || schema.schema || []); + let isUdsEnabled = schema.uds_schema?.length > 0; + //we only push the timestamp and all fields name in the schema if uds is enabled for that stream + if(isUdsEnabled){ + let timestampColumn = store.state.zoConfig.timestamp_column; + let allFieldsName = store.state.zoConfig.all_fields_name; + schemaData.push({ + name:timestampColumn, + type:'Int64' + }) + schemaData.push({ + name:allFieldsName, + type:'Utf8' + }) + } payload["stream_name_" + (i + 1)] = streams[i]; - payload["schema_" + (i + 1)] = - schema.uds_schema || schema.schema || []; + payload["schema_" + (i + 1)] = schemaData; } resolve(payload); diff --git a/web/src/plugins/logs/JsonPreview.vue b/web/src/plugins/logs/JsonPreview.vue index 6903859cd0..93e4006ab6 100644 --- a/web/src/plugins/logs/JsonPreview.vue +++ b/web/src/plugins/logs/JsonPreview.vue @@ -504,9 +504,9 @@ export default { return t("common.addFieldToTable"); }; - const sendToAiChat = (key: string, value: string) => { + const sendToAiChat = (value: string) => { emit("closeTable"); - emit("sendToAiChat", key, value); + emit("sendToAiChat", value); }; const getBtnLogo = computed(() => { diff --git a/web/src/plugins/logs/TenstackTable.vue b/web/src/plugins/logs/TenstackTable.vue index 287ea9c8c7..2eee008f79 100644 --- a/web/src/plugins/logs/TenstackTable.vue +++ b/web/src/plugins/logs/TenstackTable.vue @@ -350,7 +350,7 @@ along with this program. If not, see . { ? getImageURL('images/common/ai_icon_dark.svg') : getImageURL('images/common/ai_icon.svg') }) -const sendToAiChat = (value: any) => { - emits("sendToAiChat", value); +const sendToAiChat = (value: any,isEntireRow: boolean = false) => { + if(isEntireRow){ + //here we will get the original value of the row + //and we need to filter the row if props.columns have any filtered cols that user applied + //the format of the props.columns is like this: + //if user have not applied any filter then the props.columns will be like this: + //it contains _timestamp column and source column + //else we get _timestamp column and other filter columns so if user have applied any filter then we need to filter the row based on the filter columns + const row = JSON.parse(value); + //lets filter based on props.columns so lets ignore _timestamp column as it is always present and now we want to check if source is present we can directly send the row + //otherwise we need to filter the row based on the columns that user have applied + if(checkIfSourceColumnPresent(props.columns)){ + emits("sendToAiChat", JSON.stringify(row)); + }else{ + //we need to filter the row based on the columns that user have applied + const filteredRow = filterRowBasedOnColumns(row,props.columns); + emits("sendToAiChat", JSON.stringify(filteredRow)); + } + }else{ + emits("sendToAiChat", value); + } }; +const checkIfSourceColumnPresent = (columns: any) => { + //we need to check if source column is present in the columns + //if present then we need to return true else false + return columns.some((column: any) => column.id === 'source'); +} + +const filterRowBasedOnColumns = (row: any,columns: any) => { + //we need to filter the row based on the columns that user have applied + //here we need to filter row not columns based on the columns that user have applied + const columnsToFilter = columns.filter((column: any) => column.id !== 'source'); + return columnsToFilter.reduce((acc: any, column: any) => { + acc[column.id] = row[column.id]; + return acc; + }, {}); +} + defineExpose({ parentRef,