From a23817769d3df5e58eaca6daf570d47a1e74497a Mon Sep 17 00:00:00 2001 From: mmarkauskas Date: Fri, 5 Jan 2024 10:55:19 +0200 Subject: [PATCH 1/5] Change formatting to have a dropdown --- src/view/app/Query/query.tsx | 1608 ++++++++++++++++++---------------- 1 file changed, 862 insertions(+), 746 deletions(-) diff --git a/src/view/app/Query/query.tsx b/src/view/app/Query/query.tsx index 825bfb0b..3422a9d9 100644 --- a/src/view/app/Query/query.tsx +++ b/src/view/app/Query/query.tsx @@ -6,818 +6,934 @@ import { CommandAction, ICommand, ProcessAction } from "../model"; import ExportData from "./Export"; import UpdatePopup from "./Update"; import { ProBroButton } from "../assets/button"; -import RawOnTwoToneIcon from "@mui/icons-material/RawOnTwoTone"; -import RawOffTwoToneIcon from "@mui/icons-material/RawOffTwoTone"; +import CheckIcon from "@mui/icons-material/Check"; import PlayArrowTwoToneIcon from "@mui/icons-material/PlayArrowTwoTone"; import { Logger } from "../../../common/Logger"; import { ISettings } from "../../../common/IExtensionSettings"; +import { + Button, + ListItemIcon, + ListItemSecondaryAction, + ListItemText, + Menu, + MenuItem, +} from "@mui/material"; const filterCSS: React.CSSProperties = { - inlineSize: "100%", - padding: "4px", - fontSize: "14px", + inlineSize: "100%", + padding: "4px", + fontSize: "14px", }; interface IConfigProps { - vscode: any; - tableData: IOETableData; - tableName: string; - configuration: ISettings; - isReadOnly: boolean; + vscode: any; + tableData: IOETableData; + tableName: string; + configuration: ISettings; + isReadOnly: boolean; } interface IErrorObject { - error: string; - description: string; - trace?: string; + error: string; + description: string; + trace?: string; } interface IStatisticsObject { - recordsRetrieved: number; - recordsRetrievalTime: number; - connectTime: number; + recordsRetrieved: number; + recordsRetrievalTime: number; + connectTime: number; } -function QueryForm({ vscode, tableData, tableName, configuration, isReadOnly, ...props }: IConfigProps) { - const [wherePhrase, setWherePhrase] = React.useState(""); - const [isLoading, setIsLoading] = React.useState(false); - const [windowHeight, setWindowHeight] = React.useState(window.innerHeight); - const [isFormatted, setIsFormatted] = React.useState(false); - const [isError, setIsError] = React.useState(false); - const [isDataRetrieved, setIsDataRetrieved] = React.useState(false); - const [errorObject, setErrorObject] = React.useState(); - const [statisticsObject, setStatisticsObject] = - React.useState(); - - const [rawRows, setRawRows] = React.useState(() => tableData.data); - const [formattedRows, setFormattedRows] = React.useState( - () => tableData.data - ); - const [columns, setColumns] = React.useState(() => tableData.columns); - const [selectedColumns, setSelectedColumns] = React.useState([]); - const [columnsCRUD, setColumnsCRUD] = React.useState(() => []); - const [recordsCRUD, setRecordsCRUD] = React.useState(() => []); - const [loaded, setLoaded] = React.useState(() => 0); - const [rowID, setRowID] = React.useState(""); - const [scrollHeight, setScrollHeight] = React.useState(() => 0); - const [isWindowSmall, setIsWindowSmall] = React.useState(false); - - const [sortColumns, setSortColumns] = React.useState( - [] - ); - const [sortAction, setSortAction] = React.useState(false); - const [initialDataLoad, setInitialDataLoad] = React.useState(true); - const [recordColor, setRecordColor] = React.useState("red"); - const logger = new Logger(configuration.logging.react); - - window.addEventListener('contextmenu', e => { - e.stopImmediatePropagation(); - }, true); - - const [filters, _setFilters] = React.useState({ - columns: {}, - enabled: true, - }); - const filtersRef = React.useRef(filters); - const setFilters = (data) => { - filtersRef.current = data; - _setFilters(data); - }; +function QueryForm({ + vscode, + tableData, + tableName, + configuration, + isReadOnly, + ...props +}: IConfigProps) { + const [wherePhrase, setWherePhrase] = React.useState(""); + const [isLoading, setIsLoading] = React.useState(false); + const [windowHeight, setWindowHeight] = React.useState(window.innerHeight); + const [isFormatted, setIsFormatted] = React.useState(false); + const [isError, setIsError] = React.useState(false); + const [isDataRetrieved, setIsDataRetrieved] = React.useState(false); + const [errorObject, setErrorObject] = React.useState(); + const [statisticsObject, setStatisticsObject] = + React.useState(); + + const [rawRows, setRawRows] = React.useState(() => tableData.data); + const [formattedRows, setFormattedRows] = React.useState( + () => tableData.data + ); + const [columns, setColumns] = React.useState(() => tableData.columns); + const [selectedColumns, setSelectedColumns] = React.useState([]); + const [columnsCRUD, setColumnsCRUD] = React.useState(() => []); + const [recordsCRUD, setRecordsCRUD] = React.useState(() => []); + const [loaded, setLoaded] = React.useState(() => 0); + const [rowID, setRowID] = React.useState(""); + const [scrollHeight, setScrollHeight] = React.useState(() => 0); + const [isWindowSmall, setIsWindowSmall] = React.useState(false); + + const [sortColumns, setSortColumns] = React.useState( + [] + ); + const [sortAction, setSortAction] = React.useState(false); + const [initialDataLoad, setInitialDataLoad] = React.useState(true); + const [recordColor, setRecordColor] = React.useState("red"); + const [anchorEl, setAnchorEl] = React.useState(null); + const [selectedOption, setSelectedOption] = React.useState("OE"); + const logger = new Logger(configuration.logging.react); + + window.addEventListener( + "contextmenu", + (e) => { + e.stopImmediatePropagation(); + }, + true + ); + + const [filters, _setFilters] = React.useState({ + columns: {}, + enabled: true, + }); + const filtersRef = React.useRef(filters); + const setFilters = (data) => { + filtersRef.current = data; + _setFilters(data); + }; + + const [selectedRows, setSelectedRows] = React.useState( + (): ReadonlySet => new Set() + ); + + const getDataFormat = () => { + setIsFormatted(!isFormatted); + }; + + const windowResize = () => { + setWindowHeight(window.innerHeight); + }; + + let inputQuery: HTMLButtonElement = undefined; + React.useEffect(() => { + if (inputQuery) { + inputQuery.click(); + } + }, []); - const [selectedRows, setSelectedRows] = React.useState( - (): ReadonlySet => new Set() - ); + React.useEffect(() => { + window.addEventListener("resize", windowResize); - const getDataFormat = () => { - setIsFormatted(!isFormatted); + return () => { + window.removeEventListener("resize", windowResize); }; + }, []); - const windowResize = () => { - setWindowHeight(window.innerHeight); + React.useEffect(() => { + const handleResize = () => { + setIsWindowSmall(window.innerWidth <= 828); // Adjust the breakpoint value as needed }; - let inputQuery: HTMLButtonElement = undefined; - React.useEffect(() => { - if (inputQuery) { - inputQuery.click(); - } - }, []); - - React.useEffect(() => { - window.addEventListener("resize", windowResize); - - return () => { - window.removeEventListener("resize", windowResize); - }; - }, []); - - React.useEffect(() => { - const handleResize = () => { - setIsWindowSmall(window.innerWidth <= 828); // Adjust the breakpoint value as needed - }; - - window.addEventListener('resize', handleResize); - handleResize(); - - return () => { - window.removeEventListener('resize', handleResize); - }; - }, []); - - - const messageEvent = (event) => { - const message = event.data; - logger.log("got query data", message); - switch (message.command) { - case "columns": - setSelectedColumns([...message.columns]); - break; - case "submit": - if (message.data.error) { - // should be displayed in UpdatePopup window - setErrorObject({ - error: message.data.error, - description: message.data.description, - trace: message.data.trace, - }); - setIsError(true); - setIsDataRetrieved(false); - } else { - setSelectedRows(new Set()); - setOpen(false); - reloadData(loaded + (action === ProcessAction.Insert ? 1 : 0)); - } - break; - case "crud": - if (message.data.error) { - setErrorObject({ - error: message.data.error, - description: message.data.description, - trace: message.data.trace, - }); - setIsError(true); - setIsDataRetrieved(false); - } else { - setColumnsCRUD(message.data.columns); - setRecordsCRUD(message.data.rawData); - setOpen(true); - } - break; - case "data": - if (message.data.error) { - setErrorObject({ - error: message.data.error, - description: message.data.description, - trace: message.data.trace, - }); - setIsError(true); - setIsDataRetrieved(false); - } else { - if (message.data.columns.length !== columns.length) { - const fontSize = +window - .getComputedStyle( - document.getElementsByClassName("rdg-header-row")[0] - ) - .getPropertyValue("font-size") - .match(/\d+[.]?\d+/); - message.data.columns.forEach((column) => { - if (column.key !== "ROWID") { - column.headerRenderer = function ({ - column, - sortDirection, - priority, - onSort, - isCellSelected, - }) { - function handleKeyDown(event) { - if (event.key === " " || event.key === "Enter") { - event.preventDefault(); - onSort(event.ctrlKey || event.metaKey); - } - } - - function handleClick(event) { - onSort(event.ctrlKey || event.metaKey); - } - - var timer; - function handleKeyInputTimeout() { - clearTimeout(timer); - timer = setTimeout(() => { - reloadData(configuration.initialBatchSizeLoad); - }, 500); - } - function testKeyDown(event) { - if (event.key === "Enter") { - event.preventDefault(); - reloadData(configuration.initialBatchSizeLoad); - } - } - - function handleInputKeyDown(event) { - const tempFilters = filters; - tempFilters.columns[column.key] = event.target.value; - setFilters(tempFilters); - if (configuration.filterAsYouType === true) { - handleKeyInputTimeout(); - } - } - - return ( - -
- - - {column.name} - - - - {sortDirection === "ASC" && ( - - )} - {sortDirection === "DESC" && ( - - )} - - {priority} - - -
- {filters.enabled && ( -
- -
- )} -
- ); - }; - } - column.minWidth = column.name.length * (fontSize); - switch (column.type) { - case "integer": - case "decimal": - case "int64": - column.cellClass = "rightAlign"; - column.headerCellClass = "rightAlign"; - column.width = column.format.length * (fontSize - 3); - break; - case "character": - let dataLength = column.format.length; - if (/x\(\d+\)/.test(column.format)) { - dataLength = +column.format.match(/\d+/); - } - column.width = dataLength * (fontSize - 3); - break; - case "date": - case "datetime": - case "datetime-tz": - column.width = column.format.length * (fontSize - 3); - break; - case "logical": - column.width = column.name.length * (fontSize - 3); - break; - default: - break; - } - }); - setColumns([SelectColumn, ...message.data.columns]); - if (message.columns !== undefined) { - setSelectedColumns([...message.columns]); - } else { - setSelectedColumns([...message.data.columns.map(column => column.name)].filter(column => column !== "ROWID")); - } - } - const boolField = message.data.columns.filter( - (field) => field.type === "logical" - ); - if (boolField.length !== 0) { - message.data.rawData.forEach((row) => { - boolField.forEach((field) => { - if (row[field.name] !== null) { - row[field.name] = row[field.name].toString(); - } - }); - }); - } - setRawRows([...rawRows, ...message.data.rawData]); - setRowID( - message.data.rawData.length > 0 - ? message.data.rawData[message.data.rawData.length - 1].ROWID - : rowID - ); - setLoaded(loaded + message.data.rawData.length); - setFormattedRows([...formattedRows, ...message.data.formattedData]); - setLoaded(loaded + message.data.formattedData.length); - setIsError(false); - setIsDataRetrieved(true); - setStatisticsObject({ - recordsRetrieved: message.data.debug.recordsRetrieved, - recordsRetrievalTime: message.data.debug.recordsRetrievalTime, - connectTime: message.data.debug.timeConnect, - }); - allRecordsRetrieved(message.data.debug.recordsRetrieved, message.data.debug.recordsRetrievalTime); - } - } - setIsLoading(false); - }; - - React.useEffect(() => { - window.addEventListener("message", messageEvent); - return () => { - window.removeEventListener("message", messageEvent); - }; - }); + window.addEventListener("resize", handleResize); + handleResize(); - const prepareQuery = () => { - if (isLoading) { - return; - } - setIsLoading(true); - setLoaded(0); - setRawRows([]); - setFormattedRows([]); - setInitialDataLoad(true); - makeQuery( - 0, - configuration.initialBatchSizeLoad /*number of records for first load*/, - "", - sortColumns, - filters, - configuration.batchMaxTimeout, /*ms for data retrieval*/ - configuration.batchMinTimeout - ); + return () => { + window.removeEventListener("resize", handleResize); }; - - const onQueryClick = (event: React.MouseEvent) => { - event.preventDefault(); - prepareQuery(); - }; - - let input = document.getElementById('input'); - - const handleKeyDown = (e) => { - let selected = document.querySelector(".selected") as HTMLLIElement; - if (e.key === "Enter" && selected === null) { - e.preventDefault(); - prepareQuery(); + }, []); + + const messageEvent = (event) => { + const message = event.data; + logger.log("got query data", message); + switch (message.command) { + case "columns": + setSelectedColumns([...message.columns]); + break; + case "submit": + if (message.data.error) { + // should be displayed in UpdatePopup window + setErrorObject({ + error: message.data.error, + description: message.data.description, + trace: message.data.trace, + }); + setIsError(true); + setIsDataRetrieved(false); + } else { + setSelectedRows(new Set()); + setOpen(false); + reloadData(loaded + (action === ProcessAction.Insert ? 1 : 0)); } - - if (e.key === "Enter" && selected !== null) { - e.preventDefault(); - const selectedText = document.querySelector(".selected").textContent; - - addText(input, selectedText); - createListener(document.getElementById('input'), selectedColumns); - + break; + case "crud": + if (message.data.error) { + setErrorObject({ + error: message.data.error, + description: message.data.description, + trace: message.data.trace, + }); + setIsError(true); + setIsDataRetrieved(false); + } else { + setColumnsCRUD(message.data.columns); + setRecordsCRUD(message.data.rawData); + setOpen(true); } - - if (e.keyCode === 38) { - if (selected === null) { - document.querySelectorAll(".autocomplete-list li").item(0).classList.add("selected"); + break; + case "data": + if (message.data.error) { + setErrorObject({ + error: message.data.error, + description: message.data.description, + trace: message.data.trace, + }); + setIsError(true); + setIsDataRetrieved(false); + } else { + if (message.data.columns.length !== columns.length) { + const fontSize = +window + .getComputedStyle( + document.getElementsByClassName("rdg-header-row")[0] + ) + .getPropertyValue("font-size") + .match(/\d+[.]?\d+/); + message.data.columns.forEach((column) => { + if (column.key !== "ROWID") { + column.headerRenderer = function ({ + column, + sortDirection, + priority, + onSort, + isCellSelected, + }) { + function handleKeyDown(event) { + if (event.key === " " || event.key === "Enter") { + event.preventDefault(); + onSort(event.ctrlKey || event.metaKey); + } + } + + function handleClick(event) { + onSort(event.ctrlKey || event.metaKey); + } + + var timer; + function handleKeyInputTimeout() { + clearTimeout(timer); + timer = setTimeout(() => { + reloadData(configuration.initialBatchSizeLoad); + }, 500); + } + function testKeyDown(event) { + if (event.key === "Enter") { + event.preventDefault(); + reloadData(configuration.initialBatchSizeLoad); + } + } + + function handleInputKeyDown(event) { + const tempFilters = filters; + tempFilters.columns[column.key] = event.target.value; + setFilters(tempFilters); + if (configuration.filterAsYouType === true) { + handleKeyInputTimeout(); + } + } + + return ( + +
+ + + {column.name} + + + + {sortDirection === "ASC" && ( + + )} + {sortDirection === "DESC" && ( + + )} + + {priority} + + +
+ {filters.enabled && ( +
+ +
+ )} +
+ ); + }; + } + column.minWidth = column.name.length * fontSize; + switch (column.type) { + case "integer": + case "decimal": + case "int64": + column.cellClass = "rightAlign"; + column.headerCellClass = "rightAlign"; + column.width = column.format.length * (fontSize - 3); + break; + case "character": + let dataLength = column.format.length; + if (/x\(\d+\)/.test(column.format)) { + dataLength = +column.format.match(/\d+/); + } + column.width = dataLength * (fontSize - 3); + break; + case "date": + case "datetime": + case "datetime-tz": + column.width = column.format.length * (fontSize - 3); + break; + case "logical": + column.width = column.name.length * (fontSize - 3); + break; + default: + break; + } + }); + setColumns([SelectColumn, ...message.data.columns]); + if (message.columns !== undefined) { + setSelectedColumns([...message.columns]); + } else { + setSelectedColumns( + [...message.data.columns.map((column) => column.name)].filter( + (column) => column !== "ROWID" + ) + ); } - else { - document.querySelectorAll(".autocomplete-list li").forEach(function (item) { - item.classList.remove("selected"); - }); - if (selected.previousElementSibling === null) { - selected.parentElement.lastElementChild.classList.add("selected"); - } else { - selected.previousElementSibling.classList.add("selected"); + } + const boolField = message.data.columns.filter( + (field) => field.type === "logical" + ); + if (boolField.length !== 0) { + message.data.rawData.forEach((row) => { + boolField.forEach((field) => { + if (row[field.name] !== null) { + row[field.name] = row[field.name].toString(); } - } - selected = document.querySelector(".selected"); - selected.scrollIntoView(); - selected.focus(); + }); + }); + } + setRawRows([...rawRows, ...message.data.rawData]); + setRowID( + message.data.rawData.length > 0 + ? message.data.rawData[message.data.rawData.length - 1].ROWID + : rowID + ); + setLoaded(loaded + message.data.rawData.length); + setFormattedRows([...formattedRows, ...message.data.formattedData]); + setLoaded(loaded + message.data.formattedData.length); + setIsError(false); + setIsDataRetrieved(true); + setStatisticsObject({ + recordsRetrieved: message.data.debug.recordsRetrieved, + recordsRetrievalTime: message.data.debug.recordsRetrievalTime, + connectTime: message.data.debug.timeConnect, + }); + allRecordsRetrieved( + message.data.debug.recordsRetrieved, + message.data.debug.recordsRetrievalTime + ); } + } + setIsLoading(false); + }; - if (e.keyCode === 40) { - if (selected === null) { - document.querySelectorAll(".autocomplete-list li").item(0).classList.add("selected"); - } - else { - document.querySelectorAll(".autocomplete-list li").forEach(function (item) { - item.classList.remove("selected"); - }); - - if (selected.nextElementSibling === null) { - selected.parentElement.firstElementChild.classList.add("selected"); - - } else { - selected.nextElementSibling.classList.add("selected"); - } - } - selected = document.querySelector(".selected"); - selected.scrollIntoView(); - selected.focus(); - } + React.useEffect(() => { + window.addEventListener("message", messageEvent); + return () => { + window.removeEventListener("message", messageEvent); }; + }); - function reloadData(loaded: number) { - setLoaded(0); - setRawRows([]); - setFormattedRows([]); - makeQuery(0, loaded, "", sortColumns, filters, 0, 0); + const prepareQuery = () => { + if (isLoading) { + return; } + setIsLoading(true); + setLoaded(0); + setRawRows([]); + setFormattedRows([]); + setInitialDataLoad(true); + makeQuery( + 0, + configuration.initialBatchSizeLoad /*number of records for first load*/, + "", + sortColumns, + filters, + configuration.batchMaxTimeout /*ms for data retrieval*/, + configuration.batchMinTimeout + ); + }; - function makeQuery( - loaded, - pageLength, - lastRowID, - sortColumns, - inputFilters, - timeOut, - minTime - ) { - const command: ICommand = { - id: "Query", - action: CommandAction.Query, - params: { - wherePhrase: wherePhrase, - start: loaded, - pageLength: pageLength, - lastRowID: lastRowID, - sortColumns: sortColumns, - filters: inputFilters, - timeOut: timeOut, - minTime: minTime - }, - }; - logger.log("make query", command); - vscode.postMessage(command); - } + const onQueryClick = (event: React.MouseEvent) => { + event.preventDefault(); + prepareQuery(); + }; - function isAtBottom({ - currentTarget, - }: React.UIEvent): boolean { - return ( - currentTarget.scrollTop + 10 >= - currentTarget.scrollHeight - currentTarget.clientHeight - ); - } + let input = document.getElementById("input"); - function isHorizontalScroll({ - currentTarget, - }: React.UIEvent): boolean { - return currentTarget.scrollTop === scrollHeight; + const handleKeyDown = (e) => { + let selected = document.querySelector(".selected") as HTMLLIElement; + if (e.key === "Enter" && selected === null) { + e.preventDefault(); + prepareQuery(); } - async function handleScroll(event: React.UIEvent) { - if (isLoading || !isAtBottom(event) || isHorizontalScroll(event)) { - return; - } - setScrollHeight(event.currentTarget.scrollTop); - setIsLoading(true); - makeQuery(loaded, configuration.batchSize, rowID, sortColumns, filters, configuration.batchMaxTimeout, configuration.batchMinTimeout); - } + if (e.key === "Enter" && selected !== null) { + e.preventDefault(); + const selectedText = document.querySelector(".selected").textContent; - function onSortClick(inputSortColumns: SortColumn[]) { - if (isLoading) { - return; - } - setSortAction(true); - setSortColumns(inputSortColumns); - setLoaded(0); - setRawRows([]); - setFormattedRows([]); - makeQuery(0, loaded, "", inputSortColumns, filters, 0, 0); + addText(input, selectedText); + createListener(document.getElementById("input"), selectedColumns); } - function allRecordsRetrieved(recentRecords: number, recentRetrievalTime: number) { - if (!sortAction) { - const currentBatchSize: number = initialDataLoad ? configuration.initialBatchSizeLoad : configuration.batchSize; - setInitialDataLoad(false); - setRecordColor(recentRecords < currentBatchSize && recentRetrievalTime < configuration.batchMaxTimeout ? "green" : "red"); - } - else { - setSortAction(false); - } - } - - function getLoaded() { - if (recordColor === "red") { - return '> ' + loaded; - } - else { - return loaded; + if (e.keyCode === 38) { + if (selected === null) { + document + .querySelectorAll(".autocomplete-list li") + .item(0) + .classList.add("selected"); + } else { + document + .querySelectorAll(".autocomplete-list li") + .forEach(function (item) { + item.classList.remove("selected"); + }); + if (selected.previousElementSibling === null) { + selected.parentElement.lastElementChild.classList.add("selected"); + } else { + selected.previousElementSibling.classList.add("selected"); } + } + selected = document.querySelector(".selected"); + selected.scrollIntoView(); + selected.focus(); } - function getFooterTag() { - if (isError) { - return ( -
-
{`Error: ${errorObject.error}
-Description: ${errorObject.description}`}
-
- ); - } else if (isDataRetrieved) { - return ( -
-
{`Records in grid:`}
-                        {getLoaded()}
-                    
- {isWindowSmall ? null : ( -
-                            {`Recent records numbers: ${statisticsObject.recordsRetrieved}`}
-                        
- )} -
{`Recent retrieval time: ${statisticsObject.recordsRetrievalTime}`}
-
- - - - ); + if (e.keyCode === 40) { + if (selected === null) { + document + .querySelectorAll(".autocomplete-list li") + .item(0) + .classList.add("selected"); + } else { + document + .querySelectorAll(".autocomplete-list li") + .forEach(function (item) { + item.classList.remove("selected"); + }); + + if (selected.nextElementSibling === null) { + selected.parentElement.firstElementChild.classList.add("selected"); } else { - return <>; + selected.nextElementSibling.classList.add("selected"); } + } + selected = document.querySelector(".selected"); + selected.scrollIntoView(); + selected.focus(); } - - function rowKeyGetter(row: any) { - return row.ROWID; - } - - // CRUD operations - const [open, setOpen] = React.useState(false); - const [action, setAction] = React.useState(); - const [readRow, setReadRow] = React.useState([]); - - const readRecord = (row: string[]) => { - setAction(ProcessAction.Read); - setReadRow(row); - setOpen(true); + }; + + function reloadData(loaded: number) { + setLoaded(0); + setRawRows([]); + setFormattedRows([]); + makeQuery(0, loaded, "", sortColumns, filters, 0, 0); + } + + function makeQuery( + loaded, + pageLength, + lastRowID, + sortColumns, + inputFilters, + timeOut, + minTime + ) { + const command: ICommand = { + id: "Query", + action: CommandAction.Query, + params: { + wherePhrase: wherePhrase, + start: loaded, + pageLength: pageLength, + lastRowID: lastRowID, + sortColumns: sortColumns, + filters: inputFilters, + timeOut: timeOut, + minTime: minTime, + }, }; + logger.log("make query", command); + vscode.postMessage(command); + } - const insertRecord = () => { - processRecord(ProcessAction.Insert); - }; - const updateRecord = () => { - processRecord(ProcessAction.Update); - }; - const deleteRecord = () => { - processRecord(ProcessAction.Delete); - }; - const copyRecord = () => { - processRecord(ProcessAction.Copy); - }; + function isAtBottom({ + currentTarget, + }: React.UIEvent): boolean { + return ( + currentTarget.scrollTop + 10 >= + currentTarget.scrollHeight - currentTarget.clientHeight + ); + } - const processRecord = (mode: ProcessAction) => { - setAction(mode); - const rowids: string[] = []; - selectedRows.forEach((element) => { - rowids.push(element); - }); - - const command: ICommand = { - id: "CRUD", - action: CommandAction.CRUD, - params: { - start: 0, - pageLength: selectedRows.size, - timeOut: 1000, - minTime: 1000, - lastRowID: selectedRows.values().next().value, - crud: rowids, - mode: ProcessAction[mode], - }, - }; - logger.log("crud data request", command); - vscode.postMessage(command); - }; + function isHorizontalScroll({ + currentTarget, + }: React.UIEvent): boolean { + return currentTarget.scrollTop === scrollHeight; + } - function filterColumns() { - if (selectedColumns.length !== 0) { - const selection = columns.filter((column) => { - let testColumn = column.key; - if (/\[\d+\]$/.test(column.key)) { - testColumn = column.key.match(/[^[]+/)[0]; - } - return selectedColumns.includes(testColumn) || testColumn === "select-row"; - }); - return selection; - } else { - return []; - } - }; - const selected = filterColumns(); - - function handleCopy({ sourceRow, sourceColumnKey }: CopyEvent): void { - if (window.isSecureContext) { - navigator.clipboard.writeText(sourceRow[sourceColumnKey]); - } + async function handleScroll(event: React.UIEvent) { + if (isLoading || !isAtBottom(event) || isHorizontalScroll(event)) { + return; } + setScrollHeight(event.currentTarget.scrollTop); + setIsLoading(true); + makeQuery( + loaded, + configuration.batchSize, + rowID, + sortColumns, + filters, + configuration.batchMaxTimeout, + configuration.batchMinTimeout + ); + } - const suggestions = document.querySelector("#column-list"); + function onSortClick(inputSortColumns: SortColumn[]) { + if (isLoading) { + return; + } + setSortAction(true); + setSortColumns(inputSortColumns); + setLoaded(0); + setRawRows([]); + setFormattedRows([]); + makeQuery(0, loaded, "", inputSortColumns, filters, 0, 0); + } + + function allRecordsRetrieved( + recentRecords: number, + recentRetrievalTime: number + ) { + if (!sortAction) { + const currentBatchSize: number = initialDataLoad + ? configuration.initialBatchSizeLoad + : configuration.batchSize; + setInitialDataLoad(false); + setRecordColor( + recentRecords < currentBatchSize && + recentRetrievalTime < configuration.batchMaxTimeout + ? "green" + : "red" + ); + } else { + setSortAction(false); + } + } - function autocomplete(input, list) { - let lastWord = input.value.split(' ').pop(); + function getLoaded() { + if (recordColor === "red") { + return "> " + loaded; + } else { + return loaded; + } + } - suggestions.innerHTML = ""; + function getFooterTag() { + if (isError) { + return ( +
+
{`Error: ${errorObject.error}
+Description: ${errorObject.description}`}
+
+ ); + } else if (isDataRetrieved) { + return ( +
+
+            {`Records in grid:`}
+            {getLoaded()}
+          
+ {isWindowSmall ? null : ( +
+              {`Recent records numbers: ${statisticsObject.recordsRetrieved}`}
+            
+ )} +
{`Recent retrieval time: ${statisticsObject.recordsRetrievalTime}`}
+
+ ); + } else { + return <>; + } + } + + function rowKeyGetter(row: any) { + return row.ROWID; + } + + // CRUD operations + const [open, setOpen] = React.useState(false); + const [action, setAction] = React.useState(); + const [readRow, setReadRow] = React.useState([]); + + const readRecord = (row: string[]) => { + setAction(ProcessAction.Read); + setReadRow(row); + setOpen(true); + }; + + const insertRecord = () => { + processRecord(ProcessAction.Insert); + }; + const updateRecord = () => { + processRecord(ProcessAction.Update); + }; + const deleteRecord = () => { + processRecord(ProcessAction.Delete); + }; + const copyRecord = () => { + processRecord(ProcessAction.Copy); + }; + + const processRecord = (mode: ProcessAction) => { + setAction(mode); + const rowids: string[] = []; + selectedRows.forEach((element) => { + rowids.push(element); + }); - for (const item of list) { - if (item.toUpperCase().includes(lastWord.toUpperCase()) || lastWord === null) { - const suggestion = document.createElement('li'); - suggestion.innerHTML = item; - suggestion.style.cursor = 'pointer'; - suggestions.appendChild(suggestion); - } + const command: ICommand = { + id: "CRUD", + action: CommandAction.CRUD, + params: { + start: 0, + pageLength: selectedRows.size, + timeOut: 1000, + minTime: 1000, + lastRowID: selectedRows.values().next().value, + crud: rowids, + mode: ProcessAction[mode], + }, + }; + logger.log("crud data request", command); + vscode.postMessage(command); + }; + + function filterColumns() { + if (selectedColumns.length !== 0) { + const selection = columns.filter((column) => { + let testColumn = column.key; + if (/\[\d+\]$/.test(column.key)) { + testColumn = column.key.match(/[^[]+/)[0]; } + return ( + selectedColumns.includes(testColumn) || testColumn === "select-row" + ); + }); + return selection; + } else { + return []; } + } + const selected = filterColumns(); - function addText(input, newText) { - let wordArray = input.value.split(' '); - wordArray.pop(); - input.value = ''; - for (const word of wordArray) { - input.value += word; - input.value += ' '; - } - input.value += newText; - input.value += ' '; - setWherePhrase(input.value); + function handleCopy({ sourceRow, sourceColumnKey }: CopyEvent): void { + if (window.isSecureContext) { + navigator.clipboard.writeText(sourceRow[sourceColumnKey]); } + } - function mouseoverListener() { - document.querySelectorAll(".autocomplete-list li").forEach(function (item) { - item.addEventListener("mouseover", function () { - document.querySelectorAll(".autocomplete-list li").forEach(function (item) { - item.classList.remove("selected"); - }); - this.classList.add("selected"); - }); - item.addEventListener("click", function () { - addText(input, this.innerHTML); - document.getElementById('input').focus(); - setTimeout(() => { - createListener(document.getElementById('input'), selectedColumns); - }, 301); + const suggestions = document.querySelector("#column-list"); - }); - }); - } + function autocomplete(input, list) { + let lastWord = input.value.split(" ").pop(); - function createListener(input, list) { - input.addEventListener('input', autocomplete(input, list)); - mouseoverListener(); - } + suggestions.innerHTML = ""; - function hideSuggestions() { + for (const item of list) { + if ( + item.toUpperCase().includes(lastWord.toUpperCase()) || + lastWord === null + ) { + const suggestion = document.createElement("li"); + suggestion.innerHTML = item; + suggestion.style.cursor = "pointer"; + suggestions.appendChild(suggestion); + } + } + } + + function addText(input, newText) { + let wordArray = input.value.split(" "); + wordArray.pop(); + input.value = ""; + for (const word of wordArray) { + input.value += word; + input.value += " "; + } + input.value += newText; + input.value += " "; + setWherePhrase(input.value); + } + + function mouseoverListener() { + document.querySelectorAll(".autocomplete-list li").forEach(function (item) { + item.addEventListener("mouseover", function () { + document + .querySelectorAll(".autocomplete-list li") + .forEach(function (item) { + item.classList.remove("selected"); + }); + this.classList.add("selected"); + }); + item.addEventListener("click", function () { + addText(input, this.innerHTML); + document.getElementById("input").focus(); setTimeout(() => { - suggestions.innerHTML = ""; - }, 300); + createListener(document.getElementById("input"), selectedColumns); + }, 301); + }); + }); + } + + function createListener(input, list) { + input.addEventListener("input", autocomplete(input, list)); + mouseoverListener(); + } + + function hideSuggestions() { + setTimeout(() => { + suggestions.innerHTML = ""; + }, 300); + } + + const calculateHeight = () => { + const rowCount = isFormatted ? formattedRows.length : rawRows.length; + const minHeight = 35; + const startingHeight = 85; + const calculatedHeight = startingHeight + rowCount * minHeight; + return calculatedHeight; + }; + + const handleFormat = (format) => { + if (format === "OE") { + setIsFormatted(false); + } else if (format === "RAW") { + setIsFormatted(true); } - - const calculateHeight = () => { - const rowCount = isFormatted ? formattedRows.length : rawRows.length; - const minHeight = 35; - const startingHeight = 85; - const calculatedHeight = startingHeight + rowCount * minHeight; - return calculatedHeight; - }; - - return ( - -
-
Query
-
-
-
-
- { - createListener(document.getElementById('input'), selectedColumns); - }} - onBlur={hideSuggestions} - onChange={(event) => { - createListener(document.getElementById('input'), selectedColumns); - setWherePhrase(event.target.value); - }} - onKeyDown={handleKeyDown} - /> - {isWindowSmall ? ( - (inputQuery = input)} - startIcon={} - onClick={onQueryClick} - /> - ) : ( - (inputQuery = input)} - startIcon={} - onClick={onQueryClick} - > - Query - - )} -
-
-
    -
    -
    - - : } - > -
    -
    - -
    -
    -
    -
    - -
    -
    - {getFooterTag()} + setSelectedOption(format); + setAnchorEl(null); + }; + + return ( + +
    +
    Query
    +
    +
    +
    +
    + { + createListener( + document.getElementById("input"), + selectedColumns + ); + }} + onBlur={hideSuggestions} + onChange={(event) => { + createListener( + document.getElementById("input"), + selectedColumns + ); + setWherePhrase(event.target.value); + }} + onKeyDown={handleKeyDown} + /> + {isWindowSmall ? ( + (inputQuery = input)} + startIcon={} + onClick={onQueryClick} + /> + ) : ( + (inputQuery = input)} + startIcon={} + onClick={onQueryClick} + > + Query + + )} +
    - {isLoading &&
    Loading more rows...
    } - - ); +
      +
      +
      + +
      + <> + setAnchorEl(event.currentTarget)}> + FORMAT + + setAnchorEl(null)} + sx={{ + "& .MuiPaper-root": { + backgroundColor: "var(--vscode-input-background)", + maxWidth: "200px", + fontSize: "small", + }, + }} + > + handleFormat("OE")} + sx={{ + color: "var(--vscode-input-foreground)", + }} + > + + {selectedOption === "OE" && } + + + + handleFormat("RAW")} + sx={{ + color: "var(--vscode-input-foreground)", + }} + > + + {selectedOption === "RAW" && } + + + + + +
      + +
      +
      +
      +
      + +
      +
      {getFooterTag()}
      + {isLoading &&
      Loading more rows...
      } +
      + ); } export default QueryForm; From d0988201ab914f6acaa9b6c4c119dc8ee1720a45 Mon Sep 17 00:00:00 2001 From: mmarkauskas Date: Mon, 8 Jan 2024 09:54:48 +0200 Subject: [PATCH 2/5] remove unnecessary imports --- src/view/app/Query/query.tsx | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/view/app/Query/query.tsx b/src/view/app/Query/query.tsx index 3422a9d9..ac6f9031 100644 --- a/src/view/app/Query/query.tsx +++ b/src/view/app/Query/query.tsx @@ -10,14 +10,7 @@ import CheckIcon from "@mui/icons-material/Check"; import PlayArrowTwoToneIcon from "@mui/icons-material/PlayArrowTwoTone"; import { Logger } from "../../../common/Logger"; import { ISettings } from "../../../common/IExtensionSettings"; -import { - Button, - ListItemIcon, - ListItemSecondaryAction, - ListItemText, - Menu, - MenuItem, -} from "@mui/material"; +import { ListItemIcon, ListItemText, Menu, MenuItem } from "@mui/material"; const filterCSS: React.CSSProperties = { inlineSize: "100%", @@ -107,10 +100,6 @@ function QueryForm({ (): ReadonlySet => new Set() ); - const getDataFormat = () => { - setIsFormatted(!isFormatted); - }; - const windowResize = () => { setWindowHeight(window.innerHeight); }; From 9b38faca8758b76a1809cf106c67172b14de9606 Mon Sep 17 00:00:00 2001 From: mmarkauskas Date: Mon, 8 Jan 2024 10:20:10 +0200 Subject: [PATCH 3/5] test From 7c565468ae254f72d3a6a33f3530ea9cf6d04780 Mon Sep 17 00:00:00 2001 From: mmarkauskas Date: Mon, 8 Jan 2024 10:24:54 +0200 Subject: [PATCH 4/5] Remove unnecessary styling --- src/view/app/Query/query.tsx | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/view/app/Query/query.tsx b/src/view/app/Query/query.tsx index ab7e768d..51c5d71b 100644 --- a/src/view/app/Query/query.tsx +++ b/src/view/app/Query/query.tsx @@ -870,12 +870,7 @@ Description: ${errorObject.description}`} {selectedOption === "OE" && } - + handleFormat("RAW")} @@ -886,12 +881,7 @@ Description: ${errorObject.description}`} {selectedOption === "RAW" && } - + From f4e09d29536298a66456255b9e556e815b01e25e Mon Sep 17 00:00:00 2001 From: mmarkauskas Date: Mon, 8 Jan 2024 10:53:23 +0200 Subject: [PATCH 5/5] Edit text names. --- src/view/app/Query/query.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/view/app/Query/query.tsx b/src/view/app/Query/query.tsx index 51c5d71b..b24c16c1 100644 --- a/src/view/app/Query/query.tsx +++ b/src/view/app/Query/query.tsx @@ -75,7 +75,7 @@ function QueryForm({ const [initialDataLoad, setInitialDataLoad] = React.useState(true); const [recordColor, setRecordColor] = React.useState("red"); const [anchorEl, setAnchorEl] = React.useState(null); - const [selectedOption, setSelectedOption] = React.useState("OE"); + const [selectedOption, setSelectedOption] = React.useState("JSON"); const logger = new Logger(configuration.logging.react); window.addEventListener( @@ -749,9 +749,9 @@ Description: ${errorObject.description}`} } const handleFormat = (format) => { - if (format === "OE") { + if (format === "JSON") { setIsFormatted(false); - } else if (format === "RAW") { + } else if (format === "PROGRESS") { setIsFormatted(true); } setSelectedOption(format); @@ -862,26 +862,26 @@ Description: ${errorObject.description}`} }} > handleFormat("OE")} + onClick={() => handleFormat("JSON")} sx={{ color: "var(--vscode-input-foreground)", }} > - {selectedOption === "OE" && } + {selectedOption === "JSON" && } - + handleFormat("RAW")} + onClick={() => handleFormat("PROGRESS")} sx={{ color: "var(--vscode-input-foreground)", }} > - {selectedOption === "RAW" && } + {selectedOption === "PROGRESS" && } - +