fix: o2 ai addtional info main (#7520)

### **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** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>AddFunction.vue</strong><dd><code>Reset
aiChatInputContext to trigger watcher</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

web/src/components/functions/AddFunction.vue

<li>Imported <code>nextTick</code> for async updates<br> <li> Reset
<code>aiChatInputContext</code> before setting<br> <li> Used
<code>nextTick</code> to trigger watcher on same value


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7520/files#diff-ebfd6c538f3cd3ecb9ab17550fd76e2e89e7a1abccc83a7505077e4af3eee110">+7/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>ScheduledPipeline.vue</strong><dd><code>Add UDS
timestamp and all_fields to schema</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

web/src/components/pipeline/NodeForm/ScheduledPipeline.vue

<li>Typed <code>userDefinedFields</code> as <code>any[]</code><br> <li>
Annotated <code>payload</code> as <code>any</code><br> <li> Added UDS
logic: push timestamp and all_fields


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7520/files#diff-63d8f838bb880356e7804b4a57fd9223d4f2c189de7aadc7cf33cba723b29aaf">+14/-2</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>MainLayout.vue</strong><dd><code>Reset chat context for
watcher trigger</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

web/src/layouts/MainLayout.vue

<li>Reset <code>aiChatInputContext</code> before setting<br> <li>
Wrapped setting in <code>nextTick</code> callback


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7520/files#diff-91e4134141264c4624d4eb4cfa987b33ed31eb6f551e089c0b26f2610dd54362">+6/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>Index.vue</strong><dd><code>Deep copy and extend UDS
schema</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

web/src/plugins/logs/Index.vue

<li>Imported <code>deepCopy</code> utility<br> <li> Deep-copied schema
to avoid mutations<br> <li> Added timestamp and all_fields only if UDS
enabled


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7520/files#diff-0323c3da69b369843c5d72bf4df5b00ca6b5147192a213baf331659ecf92af62">+20/-3</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>JsonPreview.vue</strong><dd><code>Simplify sendToAiChat
parameters</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

web/src/plugins/logs/JsonPreview.vue

<li>Simplified <code>sendToAiChat</code> signature<br> <li> Removed
unused <code>key</code> argument<br> <li> Emit only <code>value</code>
to parent


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7520/files#diff-3985073134d35ff074742944b114d0905524038b42e6d2ac887fef2c8436fb16">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>TenstackTable.vue</strong><dd><code>Filter table row
before AI chat send</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

web/src/plugins/logs/TenstackTable.vue

<li>Enhanced <code>sendToAiChat</code> to handle full row flag<br> <li>
Filtered row based on selected columns<br> <li> Added helper functions
for filtering


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7520/files#diff-bc3c669f5ab65a42ae378df1f7d6b35014c9c220790bdcc72b47f55d1385dc22">+38/-3</a>&nbsp;
&nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>
This commit is contained in:
Sai Nikhil
2025-07-10 12:46:55 +05:30
committed by GitHub
parent 032273ac87
commit 845753984f
6 changed files with 93 additions and 12 deletions
+7 -1
View File
@@ -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);
@@ -1349,7 +1349,7 @@ const loading = ref(false);
const aiChatInputContext = ref("");
const userDefinedFields = ref([]);
const userDefinedFields = ref<any[]>([]);
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;
+6 -1
View File
@@ -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 {
+20 -3
View File
@@ -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);
+2 -2
View File
@@ -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(() => {
+38 -3
View File
@@ -350,7 +350,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<q-btn
v-if="cell.column.columnDef.id === store.state.zoConfig.timestamp_column"
:ripple="false"
@click.stop="sendToAiChat(JSON.stringify(cell.row.original))"
@click.stop="sendToAiChat(JSON.stringify(cell.row.original),true)"
data-test="menu-link-ai-item"
no-caps
:borderless="true"
@@ -852,10 +852,45 @@ const getBtnLogo = computed(() => {
? 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,