From 6578e68227f09dd9e5c702f0ede670985739e253 Mon Sep 17 00:00:00 2001 From: Aldrin Jenson Date: Wed, 6 Sep 2023 13:45:05 +0530 Subject: [PATCH 1/6] Add AI based SQL generator from natural laguage --- .env.example | 1 + src/pages/Query/QueryCodeEditor.tsx | 122 ++++++++++++++++++++++------ src/utils/index.ts | 26 ++++++ src/vite-env.d.ts | 1 + 4 files changed, 126 insertions(+), 24 deletions(-) diff --git a/.env.example b/.env.example index 6cc5dc73..fdf29a3d 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,2 @@ VITE_PARSEABLE_URL="https://demo.parseable.io" +VITE_OPENAI_API_KEY='sk-...' diff --git a/src/pages/Query/QueryCodeEditor.tsx b/src/pages/Query/QueryCodeEditor.tsx index f7ba36d2..bdac45d6 100644 --- a/src/pages/Query/QueryCodeEditor.tsx +++ b/src/pages/Query/QueryCodeEditor.tsx @@ -2,7 +2,7 @@ import React, { FC, useEffect } from 'react'; import Editor from '@monaco-editor/react'; import { useQueryPageContext } from './Context'; import { useHeaderContext } from '@/layouts/MainLayout/Context'; -import { Box, Button, Text, Tooltip, px } from '@mantine/core'; +import { Box, Button, Input, Text, Tooltip, px } from '@mantine/core'; import { useQueryResult } from '@/hooks/useQueryResult'; import { ErrorMarker, errChecker } from './ErrorMarker'; import { notifications } from '@mantine/notifications'; @@ -10,6 +10,8 @@ import { IconPlayerPlayFilled, IconCheck, IconFileAlert, IconFileInfo } from '@t import useMountedState from '@/hooks/useMountedState'; import { useQueryCodeEditorStyles } from './styles'; import dayjs from 'dayjs'; +import { useGetLogStreamSchema } from '@/hooks/useGetLogStreamSchema'; +import { makeAPIRequest } from '@/utils'; const QueryCodeEditor: FC = () => { const { @@ -25,7 +27,51 @@ const QueryCodeEditor: FC = () => { const [isSchemaOpen, setIsSchemaOpen] = useMountedState(false); const [refreshInterval, setRefreshInterval] = useMountedState(null); const [currentStreamName, setCurrentStreamName] = useMountedState(subLogQuery.get().streamName); - const [query, setQuery] = useMountedState(""); + const [query, setQuery] = useMountedState(''); + const [aiQuery, setAiQuery] = useMountedState('Show all records'); + const { data: querySchema, getDataSchema } = useGetLogStreamSchema(); + + const filterUnnecessaryFieldsFromRecord = (objArray = []) => { + return objArray.map((obj) => { + const { name, data_type } = obj; + return { name, data_type }; + }); + }; + + const handleAIGenerate = async () => { + if (!aiQuery?.length) { + alert('Please enter a valid query'); + return; + } + + notifications.show({ + id: 'ai-suggest', + loading: true, + color: '#545BEB', + title: 'Getting suggestions', + message: 'AI based SQL being generated.', + autoClose: true, + withCloseButton: false, + }); + + const columnData = querySchema?.fields; + const usefulCols = filterUnnecessaryFieldsFromRecord(columnData); + const stringified = JSON.stringify(usefulCols); + + const prompt = `I have a table called ${currentStreamName}. It has the columns:\n${stringified} +Based on this, please generate valid SQL for the query: "${aiQuery}" +Generate only the SQL as output. Also add comments in SQL syntax to explain your action. Don't output anything else. +If it is not possible to generate valid SQL, output as an SQL comment saying so.`; + const resp = await makeAPIRequest(prompt); + + const warningMsg = + '-- Parseable AI is experimental and may produce incorrect answers\n-- Always verify the generated SQL before executing\n\n'; + setQuery(warningMsg + resp); + }; + + useEffect(() => { + getDataSchema(currentStreamName); + }, [currentStreamName]); const handleEditorChange = (code: any) => { setQuery(code); @@ -59,14 +105,13 @@ const QueryCodeEditor: FC = () => { refreshIntervalListener(); subQueryListener(); }; - }, [subLogQuery.get(), subSchemaToggle.get(), subRefreshInterval.get()]); - -useEffect(() => { - if(subLogQuery.get().streamName){ - setQuery(`SELECT * FROM ${subLogQuery.get().streamName} LIMIT 100 ; `); - } -}, []); + }, [subLogQuery.get(), subSchemaToggle.get(), subRefreshInterval.get(), querySchema]); + useEffect(() => { + if (subLogQuery.get().streamName) { + setQuery(`SELECT * FROM ${subLogQuery.get().streamName} LIMIT 100 ; `); + } + }, []); function handleEditorDidMount(editor: any, monaco: any) { editorRef.current = editor; @@ -75,7 +120,17 @@ useEffect(() => { runQuery(editor.getValue()); }); } - const runQuery = (query:string) => { + + const sanitseSqlString = (sqlString: string): string => { + const withoutComments = sqlString.replace(/--.*$/gm, ''); + const withoutNewLines = withoutComments.replace(/\n/g, ' '); + const withoutTrailingSemicolon = withoutNewLines.replace(/;/, ''); + return withoutTrailingSemicolon; + }; + + const runQuery = (inputQuery: string) => { + const query = sanitseSqlString(inputQuery); + resetData(); notifications.show({ id: 'load-data', @@ -86,21 +141,21 @@ useEffect(() => { autoClose: false, withCloseButton: false, }); - let LogQuery ={ - startTime : subLogQuery.get().startTime, - endTime :subLogQuery.get().endTime, - streamName : currentStreamName, - access:[] - } - if (subLogSelectedTimeRange.get().state==='fixed') { + let LogQuery = { + startTime: subLogQuery.get().startTime, + endTime: subLogQuery.get().endTime, + streamName: currentStreamName, + access: [], + }; + if (subLogSelectedTimeRange.get().state === 'fixed') { const now = dayjs(); const timeDiff = subLogQuery.get().endTime.getTime() - subLogQuery.get().startTime.getTime(); - LogQuery ={ - startTime : now.subtract(timeDiff).toDate(), - endTime :now.toDate(), - streamName : currentStreamName, - access:[] - } + LogQuery = { + startTime: now.subtract(timeDiff).toDate(), + endTime: now.toDate(), + streamName: currentStreamName, + access: [], + }; } const parsedQuery = query.replace(/(\r\n|\n|\r)/gm, ''); getQueryData(LogQuery, parsedQuery); @@ -158,13 +213,32 @@ useEffect(() => { sx={{ color: 'white', backgroundColor: 'black' }} withArrow position="right"> - + + setAiQuery(e.target.value)} + placeholder="Ask Parseable AI" + /> + + new Promise((res) => setTimeout(res, sec * 1000)); @@ -33,3 +34,28 @@ export const parseLogData = (value?: any, columnName?: string) => { return 'N/A'; }; + +export const makeAPIRequest = async (promptContent: string) => { + const data = { + model: 'gpt-3.5-turbo', + messages: [{ role: 'user', content: promptContent }], + temperature: 0.5, + }; + + const apiKey = import.meta.env.VITE_OPENAI_API_KEY; + + const headers = { + 'Content-Type': 'application/json', + Authorization: `Bearer ${apiKey}`, + }; + + try { + const response = await axios.post('https://api.openai.com/v1/chat/completions', data, { headers }); + const { + choices: [choice], + } = response.data; + return choice.message.content; + } catch (error) { + console.error(error); + } +}; diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 2864218c..1314948b 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -2,6 +2,7 @@ interface ImportMetaEnv { readonly VITE_PARSEABLE_URL?: string; + readonly VITE_OPENAI_API_KEY?: string; } interface ImportMeta { From 07789bfe567390d44aa34a7c62e4830694577324 Mon Sep 17 00:00:00 2001 From: Aldrin Jenson Date: Thu, 7 Sep 2023 13:54:02 +0530 Subject: [PATCH 2/6] make llm query from backend api instead of env --- .env.example | 1 - src/api/constants.ts | 6 +++-- src/pages/Query/QueryCodeEditor.tsx | 38 ++++++++++++----------------- src/utils/index.ts | 26 -------------------- src/vite-env.d.ts | 1 - 5 files changed, 19 insertions(+), 53 deletions(-) diff --git a/.env.example b/.env.example index fdf29a3d..6cc5dc73 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1 @@ VITE_PARSEABLE_URL="https://demo.parseable.io" -VITE_OPENAI_API_KEY='sk-...' diff --git a/src/api/constants.ts b/src/api/constants.ts index a05a26b9..75aa334b 100644 --- a/src/api/constants.ts +++ b/src/api/constants.ts @@ -1,6 +1,5 @@ const API_V1 = 'api/v1'; - // Streams Management export const LOG_STREAM_LIST_URL = `${API_V1}/logstream`; export const LOG_STREAMS_SCHEMA_URL = (streamName: string) => `${LOG_STREAM_LIST_URL}/${streamName}/schema`; @@ -17,4 +16,7 @@ export const ABOUT_URL = `${API_V1}/about`; export const USERS_LIST_URL = `${API_V1}/user`; export const USER_URL = (username: string) => `${USERS_LIST_URL}/${username}`; export const USER_ROLES_URL = (username: string) => `${USER_URL(username)}/role`; -export const USER_PASSWORD_URL = (username: string) => `${USER_URL(username)}/generate-new-password`; \ No newline at end of file +export const USER_PASSWORD_URL = (username: string) => `${USER_URL(username)}/generate-new-password`; + +// LLM queries +export const LLM_QUERY_URL = `${API_V1}/llm`; diff --git a/src/pages/Query/QueryCodeEditor.tsx b/src/pages/Query/QueryCodeEditor.tsx index bdac45d6..4e79f4b8 100644 --- a/src/pages/Query/QueryCodeEditor.tsx +++ b/src/pages/Query/QueryCodeEditor.tsx @@ -11,7 +11,9 @@ import useMountedState from '@/hooks/useMountedState'; import { useQueryCodeEditorStyles } from './styles'; import dayjs from 'dayjs'; import { useGetLogStreamSchema } from '@/hooks/useGetLogStreamSchema'; -import { makeAPIRequest } from '@/utils'; +import { notify } from '@/utils/notification'; +import { Axios } from '@/api/axios'; +import { LLM_QUERY_URL } from '@/api/constants'; const QueryCodeEditor: FC = () => { const { @@ -40,19 +42,10 @@ const QueryCodeEditor: FC = () => { const handleAIGenerate = async () => { if (!aiQuery?.length) { - alert('Please enter a valid query'); + notify({ message: 'Please enter a valid query' }); return; } - - notifications.show({ - id: 'ai-suggest', - loading: true, - color: '#545BEB', - title: 'Getting suggestions', - message: 'AI based SQL being generated.', - autoClose: true, - withCloseButton: false, - }); + notify({ message: 'AI based SQL being generated.', title: 'Getting suggestions', autoClose: 3000, color: 'blue' }); const columnData = querySchema?.fields; const usefulCols = filterUnnecessaryFieldsFromRecord(columnData); @@ -62,11 +55,19 @@ const QueryCodeEditor: FC = () => { Based on this, please generate valid SQL for the query: "${aiQuery}" Generate only the SQL as output. Also add comments in SQL syntax to explain your action. Don't output anything else. If it is not possible to generate valid SQL, output as an SQL comment saying so.`; - const resp = await makeAPIRequest(prompt); + const resp = await Axios().post(LLM_QUERY_URL, { prompt }); + if (resp.status !== 200) { + notify({ + message: 'Please check your internet connection and add a valid OpenAI API key', + title: 'Error getting suggestions', + color: 'red', + }); + return; + } const warningMsg = '-- Parseable AI is experimental and may produce incorrect answers\n-- Always verify the generated SQL before executing\n\n'; - setQuery(warningMsg + resp); + setQuery(warningMsg + resp.data); }; useEffect(() => { @@ -132,15 +133,6 @@ If it is not possible to generate valid SQL, output as an SQL comment saying so. const query = sanitseSqlString(inputQuery); resetData(); - notifications.show({ - id: 'load-data', - loading: true, - color: '#545BEB', - title: 'Running Query', - message: 'Data will be loaded.', - autoClose: false, - withCloseButton: false, - }); let LogQuery = { startTime: subLogQuery.get().startTime, endTime: subLogQuery.get().endTime, diff --git a/src/utils/index.ts b/src/utils/index.ts index 3f325099..3b739354 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,5 +1,4 @@ import dayjs from 'dayjs'; -import axios from 'axios'; export const wait = (sec = 1) => new Promise((res) => setTimeout(res, sec * 1000)); @@ -34,28 +33,3 @@ export const parseLogData = (value?: any, columnName?: string) => { return 'N/A'; }; - -export const makeAPIRequest = async (promptContent: string) => { - const data = { - model: 'gpt-3.5-turbo', - messages: [{ role: 'user', content: promptContent }], - temperature: 0.5, - }; - - const apiKey = import.meta.env.VITE_OPENAI_API_KEY; - - const headers = { - 'Content-Type': 'application/json', - Authorization: `Bearer ${apiKey}`, - }; - - try { - const response = await axios.post('https://api.openai.com/v1/chat/completions', data, { headers }); - const { - choices: [choice], - } = response.data; - return choice.message.content; - } catch (error) { - console.error(error); - } -}; diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 1314948b..2864218c 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -2,7 +2,6 @@ interface ImportMetaEnv { readonly VITE_PARSEABLE_URL?: string; - readonly VITE_OPENAI_API_KEY?: string; } interface ImportMeta { From 2f520ea3986e154b9a54691063ee6676b0a6cee0 Mon Sep 17 00:00:00 2001 From: Aldrin Jenson Date: Thu, 7 Sep 2023 14:02:07 +0530 Subject: [PATCH 3/6] =?UTF-8?q?deepsource=20fix=F0=9F=A4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Query/QueryCodeEditor.tsx | 19 +++++++++++-------- src/utils/index.ts | 9 +++++++++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/pages/Query/QueryCodeEditor.tsx b/src/pages/Query/QueryCodeEditor.tsx index 4e79f4b8..fae95b41 100644 --- a/src/pages/Query/QueryCodeEditor.tsx +++ b/src/pages/Query/QueryCodeEditor.tsx @@ -14,6 +14,7 @@ import { useGetLogStreamSchema } from '@/hooks/useGetLogStreamSchema'; import { notify } from '@/utils/notification'; import { Axios } from '@/api/axios'; import { LLM_QUERY_URL } from '@/api/constants'; +import { filterUnnecessaryFieldsFromRecord } from '@/utils'; const QueryCodeEditor: FC = () => { const { @@ -33,13 +34,6 @@ const QueryCodeEditor: FC = () => { const [aiQuery, setAiQuery] = useMountedState('Show all records'); const { data: querySchema, getDataSchema } = useGetLogStreamSchema(); - const filterUnnecessaryFieldsFromRecord = (objArray = []) => { - return objArray.map((obj) => { - const { name, data_type } = obj; - return { name, data_type }; - }); - }; - const handleAIGenerate = async () => { if (!aiQuery?.length) { notify({ message: 'Please enter a valid query' }); @@ -47,7 +41,7 @@ const QueryCodeEditor: FC = () => { } notify({ message: 'AI based SQL being generated.', title: 'Getting suggestions', autoClose: 3000, color: 'blue' }); - const columnData = querySchema?.fields; + const columnData = querySchema?.fields || []; const usefulCols = filterUnnecessaryFieldsFromRecord(columnData); const stringified = JSON.stringify(usefulCols); @@ -133,6 +127,15 @@ If it is not possible to generate valid SQL, output as an SQL comment saying so. const query = sanitseSqlString(inputQuery); resetData(); + notifications.show({ + id: 'load-data', + loading: true, + color: '#545BEB', + title: 'Running Query', + message: 'Data will be loaded.', + autoClose: false, + withCloseButton: false, + }); let LogQuery = { startTime: subLogQuery.get().startTime, endTime: subLogQuery.get().endTime, diff --git a/src/utils/index.ts b/src/utils/index.ts index 3b739354..a7b94eb3 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,3 +1,4 @@ +import { Field } from '@/@types/parseable/dataType'; import dayjs from 'dayjs'; export const wait = (sec = 1) => new Promise((res) => setTimeout(res, sec * 1000)); @@ -33,3 +34,11 @@ export const parseLogData = (value?: any, columnName?: string) => { return 'N/A'; }; + +export const filterUnnecessaryFieldsFromRecord = (objArray: Field[] = []) => { + // For selecting only the necessary parts of schema to pass on to llm query + return objArray.map((obj) => { + const { name, data_type } = obj; + return { name, data_type }; + }); +}; From 5c8948ae6f6db7aa39bbe38103141bd598c43785 Mon Sep 17 00:00:00 2001 From: Aldrin Jenson Date: Thu, 7 Sep 2023 13:54:02 +0530 Subject: [PATCH 4/6] make llm query from backend api instead of env --- src/api/constants.ts | 6 +++--- src/pages/Query/QueryCodeEditor.tsx | 9 --------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/api/constants.ts b/src/api/constants.ts index ef3aa67e..59c9e00f 100644 --- a/src/api/constants.ts +++ b/src/api/constants.ts @@ -20,12 +20,12 @@ export const USER_URL = (username: string) => `${USERS_LIST_URL}/${username}`; export const USER_ROLES_URL = (username: string) => `${USER_URL(username)}/role`; export const USER_PASSWORD_URL = (username: string) => `${USER_URL(username)}/generate-new-password`; -// LLM queries -export const LLM_QUERY_URL = `${API_V1}/llm`; - // Roles Management export const ROLES_LIST_URL = `${API_V1}/role`; export const ROLE_URL = (roleName: string) => `${ROLES_LIST_URL}/${roleName}`; //USERS LOGIN export const LOGIN_URL = `${API_V1}/o/login?redirect=${window.location.origin}`; + +// LLM queries +export const LLM_QUERY_URL = `${API_V1}/llm`; diff --git a/src/pages/Query/QueryCodeEditor.tsx b/src/pages/Query/QueryCodeEditor.tsx index fae95b41..9cffda86 100644 --- a/src/pages/Query/QueryCodeEditor.tsx +++ b/src/pages/Query/QueryCodeEditor.tsx @@ -127,15 +127,6 @@ If it is not possible to generate valid SQL, output as an SQL comment saying so. const query = sanitseSqlString(inputQuery); resetData(); - notifications.show({ - id: 'load-data', - loading: true, - color: '#545BEB', - title: 'Running Query', - message: 'Data will be loaded.', - autoClose: false, - withCloseButton: false, - }); let LogQuery = { startTime: subLogQuery.get().startTime, endTime: subLogQuery.get().endTime, From 34066ad20652ca47dac9358c3f5ef5a947c5aaf9 Mon Sep 17 00:00:00 2001 From: Aldrin Jenson Date: Fri, 8 Sep 2023 19:48:05 +0530 Subject: [PATCH 5/6] move llm query to backend --- src/pages/Query/QueryCodeEditor.tsx | 20 +++----------------- src/utils/index.ts | 8 -------- 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/src/pages/Query/QueryCodeEditor.tsx b/src/pages/Query/QueryCodeEditor.tsx index 9cffda86..09d44153 100644 --- a/src/pages/Query/QueryCodeEditor.tsx +++ b/src/pages/Query/QueryCodeEditor.tsx @@ -10,11 +10,9 @@ import { IconPlayerPlayFilled, IconCheck, IconFileAlert, IconFileInfo } from '@t import useMountedState from '@/hooks/useMountedState'; import { useQueryCodeEditorStyles } from './styles'; import dayjs from 'dayjs'; -import { useGetLogStreamSchema } from '@/hooks/useGetLogStreamSchema'; import { notify } from '@/utils/notification'; import { Axios } from '@/api/axios'; import { LLM_QUERY_URL } from '@/api/constants'; -import { filterUnnecessaryFieldsFromRecord } from '@/utils'; const QueryCodeEditor: FC = () => { const { @@ -32,7 +30,6 @@ const QueryCodeEditor: FC = () => { const [currentStreamName, setCurrentStreamName] = useMountedState(subLogQuery.get().streamName); const [query, setQuery] = useMountedState(''); const [aiQuery, setAiQuery] = useMountedState('Show all records'); - const { data: querySchema, getDataSchema } = useGetLogStreamSchema(); const handleAIGenerate = async () => { if (!aiQuery?.length) { @@ -41,15 +38,7 @@ const QueryCodeEditor: FC = () => { } notify({ message: 'AI based SQL being generated.', title: 'Getting suggestions', autoClose: 3000, color: 'blue' }); - const columnData = querySchema?.fields || []; - const usefulCols = filterUnnecessaryFieldsFromRecord(columnData); - const stringified = JSON.stringify(usefulCols); - - const prompt = `I have a table called ${currentStreamName}. It has the columns:\n${stringified} -Based on this, please generate valid SQL for the query: "${aiQuery}" -Generate only the SQL as output. Also add comments in SQL syntax to explain your action. Don't output anything else. -If it is not possible to generate valid SQL, output as an SQL comment saying so.`; - const resp = await Axios().post(LLM_QUERY_URL, { prompt }); + const resp = await Axios().post(LLM_QUERY_URL, { prompt: aiQuery, stream: currentStreamName }); if (resp.status !== 200) { notify({ message: 'Please check your internet connection and add a valid OpenAI API key', @@ -64,10 +53,6 @@ If it is not possible to generate valid SQL, output as an SQL comment saying so. setQuery(warningMsg + resp.data); }; - useEffect(() => { - getDataSchema(currentStreamName); - }, [currentStreamName]); - const handleEditorChange = (code: any) => { setQuery(code); errChecker(code, subLogQuery.get().streamName); @@ -100,7 +85,7 @@ If it is not possible to generate valid SQL, output as an SQL comment saying so. refreshIntervalListener(); subQueryListener(); }; - }, [subLogQuery.get(), subSchemaToggle.get(), subRefreshInterval.get(), querySchema]); + }, [subLogQuery.get(), subSchemaToggle.get(), subRefreshInterval.get()]); useEffect(() => { if (subLogQuery.get().streamName) { @@ -146,6 +131,7 @@ If it is not possible to generate valid SQL, output as an SQL comment saying so. const parsedQuery = query.replace(/(\r\n|\n|\r)/gm, ''); getQueryData(LogQuery, parsedQuery); }; + useEffect(() => { if (error) { notifications.update({ diff --git a/src/utils/index.ts b/src/utils/index.ts index a7b94eb3..ed3e529d 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -34,11 +34,3 @@ export const parseLogData = (value?: any, columnName?: string) => { return 'N/A'; }; - -export const filterUnnecessaryFieldsFromRecord = (objArray: Field[] = []) => { - // For selecting only the necessary parts of schema to pass on to llm query - return objArray.map((obj) => { - const { name, data_type } = obj; - return { name, data_type }; - }); -}; From d446e7b75349086920f9b1c566338c2ba9f7c99b Mon Sep 17 00:00:00 2001 From: Aldrin Jenson Date: Fri, 8 Sep 2023 19:59:09 +0530 Subject: [PATCH 6/6] refactoring --- src/api/constants.ts | 9 --------- src/pages/Query/QueryCodeEditor.tsx | 9 +++++++++ src/utils/index.ts | 1 - 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/api/constants.ts b/src/api/constants.ts index 59c9e00f..75aa334b 100644 --- a/src/api/constants.ts +++ b/src/api/constants.ts @@ -1,7 +1,5 @@ const API_V1 = 'api/v1'; -// const baseURL = process.env.REACT_APP_API_URL || '/'; - // Streams Management export const LOG_STREAM_LIST_URL = `${API_V1}/logstream`; export const LOG_STREAMS_SCHEMA_URL = (streamName: string) => `${LOG_STREAM_LIST_URL}/${streamName}/schema`; @@ -20,12 +18,5 @@ export const USER_URL = (username: string) => `${USERS_LIST_URL}/${username}`; export const USER_ROLES_URL = (username: string) => `${USER_URL(username)}/role`; export const USER_PASSWORD_URL = (username: string) => `${USER_URL(username)}/generate-new-password`; -// Roles Management -export const ROLES_LIST_URL = `${API_V1}/role`; -export const ROLE_URL = (roleName: string) => `${ROLES_LIST_URL}/${roleName}`; - -//USERS LOGIN -export const LOGIN_URL = `${API_V1}/o/login?redirect=${window.location.origin}`; - // LLM queries export const LLM_QUERY_URL = `${API_V1}/llm`; diff --git a/src/pages/Query/QueryCodeEditor.tsx b/src/pages/Query/QueryCodeEditor.tsx index 09d44153..832aa3b4 100644 --- a/src/pages/Query/QueryCodeEditor.tsx +++ b/src/pages/Query/QueryCodeEditor.tsx @@ -112,6 +112,15 @@ const QueryCodeEditor: FC = () => { const query = sanitseSqlString(inputQuery); resetData(); + notifications.show({ + id: 'load-data', + loading: true, + color: '#545BEB', + title: 'Running Query', + message: 'Data will be loaded.', + autoClose: false, + withCloseButton: false, + }); let LogQuery = { startTime: subLogQuery.get().startTime, endTime: subLogQuery.get().endTime, diff --git a/src/utils/index.ts b/src/utils/index.ts index ed3e529d..3b739354 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,4 +1,3 @@ -import { Field } from '@/@types/parseable/dataType'; import dayjs from 'dayjs'; export const wait = (sec = 1) => new Promise((res) => setTimeout(res, sec * 1000));