diff --git a/less/TableStyles/queryBuilder.less b/less/TableStyles/queryBuilder.less index 2d2a1224e..0c38f9934 100644 --- a/less/TableStyles/queryBuilder.less +++ b/less/TableStyles/queryBuilder.less @@ -295,7 +295,25 @@ input::-webkit-inner-spin-button { .and-or-svg { margin-top: -8px; - margin-right: -5px; + margin-right: -26px; +} + +.and-or-label { + margin-left: 52px; +} + +.field-label { + margin-left: 69px; +} +.data-type-label { + margin-left: 54px; +} + +.operator-label { + margin-left: 80px; +} +.value-label{ + margin-left: 62px; } .scroll-box { diff --git a/src/Explorer/Tabs/QueryTablesTab/QueryTableEntityClause.tsx b/src/Explorer/Tabs/QueryTablesTab/QueryTableEntityClause.tsx new file mode 100644 index 000000000..057b0da2f --- /dev/null +++ b/src/Explorer/Tabs/QueryTablesTab/QueryTableEntityClause.tsx @@ -0,0 +1,150 @@ +import { + Checkbox, + Dropdown, + IDropdownOption, + IDropdownStyles, + IImageProps, + Image, + IStackTokens, + Stack, + TextField, + TooltipHost +} from "@fluentui/react"; +import React, { FunctionComponent } from "react"; +import AddIcon from "../../../../images/Add.svg"; +import CancelIcon from "../../../../images/cancel.svg"; +import { IOption } from "./QueryTableTabUtils"; +const dropdownStyles: Partial = { dropdown: { width: 100 } }; + +export interface IQueryTableEntityClauseProps { + entityValue: string; + entityValuePlaceHolder?: string; + selectedOperator: string; + selectedOperation: string; + opertorOptions: IOption[]; + opertationOptions: IOption[]; + isQueryTableEntityChecked: boolean; + selectedField: string; + fieldOptions: IOption[]; + entityTypeOptions: IOption[]; + selectedEntityType: string; + isTimeStampSelected?: boolean; + selectedTimestamp: string; + timestampOptions: IOption[]; + onAddNewClause?: () => void; + onDeleteClause?: () => void; + onQueryTableEntityCheck: (ev?: React.FormEvent, checked?: boolean) => void; + onDropdownChange: (selectedOption: IDropdownOption, selectedOptionType: string) => void; + onEntityValueChange: (event: React.FormEvent, newInput?: string) => void; +} + +export const QueryTableEntityClause: FunctionComponent = ({ + entityValue, + entityValuePlaceHolder, + selectedOperator, + opertorOptions, + selectedField, + isQueryTableEntityChecked, + fieldOptions, + entityTypeOptions, + selectedEntityType, + selectedOperation, + opertationOptions, + isTimeStampSelected, + selectedTimestamp, + timestampOptions, + onQueryTableEntityCheck, + onAddNewClause, + onDeleteClause, + onDropdownChange, + onEntityValueChange, +}: IQueryTableEntityClauseProps): JSX.Element => { + const cancelImageProps: IImageProps = { + width: 14, + height: 25, + }; + + const addImageProps: IImageProps = { + width: 18, + height: 25, + }; + + const sectionStackTokens: IStackTokens = { childrenGap: 12 }; + + return ( + <> + + + Add new clause + + + delete clause + + + , selectedOption: IDropdownOption) => + onDropdownChange(selectedOption, "selectedOperation") + } + options={opertationOptions} + id="operatorOptionId" + styles={dropdownStyles} + /> + , selectedOption: IDropdownOption) => + onDropdownChange(selectedOption, "selectedField") + } + options={fieldOptions} + id="fieldOptionId" + styles={dropdownStyles} + /> + , selectedOption: IDropdownOption) => + onDropdownChange(selectedOption, "selectedEntityType") + } + options={entityTypeOptions} + id="entityOptionId" + disabled={selectedField !== "t3PN"} + styles={dropdownStyles} + /> + , selectedOption: IDropdownOption) => + onDropdownChange(selectedOption, "selectedOperator") + } + options={opertorOptions} + id="operatorOptionId" + styles={dropdownStyles} + /> + {isTimeStampSelected ? ( + , selectedOption: IDropdownOption) => + onDropdownChange(selectedOption, "selectedTimestamp") + } + options={timestampOptions} + id="operatorOptionId" + styles={dropdownStyles} + /> + ) : ( + + )} + + + ); +}; diff --git a/src/Explorer/Tabs/QueryTablesTab/QueryTableTabUtils.tsx b/src/Explorer/Tabs/QueryTablesTab/QueryTableTabUtils.tsx new file mode 100644 index 000000000..01f742605 --- /dev/null +++ b/src/Explorer/Tabs/QueryTablesTab/QueryTableTabUtils.tsx @@ -0,0 +1,119 @@ +import { IColumn } from "@fluentui/react"; +import * as ViewModels from "../../../Contracts/ViewModels"; +import Explorer from "../../Explorer"; +import TableEntityListViewModel from "../../Tables/DataTable/TableEntityListViewModel"; +import * as Entities from "../../Tables/Entities"; +import QueryViewModel from "../../Tables/QueryBuilder/QueryViewModel"; +import TabsBase from "../TabsBase"; +import NewQueryTablesTab from "./QueryTablesTab"; + +export interface Button { + visible: boolean; + enabled: boolean; + isSelected?: boolean; +} + +export interface IOption { + key: string; + text: string; +} +export interface IDocument { + partitionKey: string; + rowKey: string; + timeStamp: string; +} +export interface IQueryTablesTabComponentProps { + tabKind: ViewModels.CollectionTabKind; + title: string; + tabPath: string; + collection: ViewModels.CollectionBase; + node: ViewModels.TreeNode; + onLoadStartKey: number; + container: Explorer; + tabsBaseInstance: TabsBase; + queryTablesTab: NewQueryTablesTab; +} + +export interface IQueryTablesTabComponentStates { + tableEntityListViewModel: TableEntityListViewModel; + queryViewModel: QueryViewModel; + queryText: string; + selectedQueryText: string; + executeQueryButton: Button; + queryBuilderButton: Button; + queryTextButton: Button; + addEntityButton: Button; + editEntityButton: Button; + deleteEntityButton: Button; + isHelperActive: boolean; + columns: IColumn[]; + items: IDocument[]; + isExpanded: boolean; + isEditorActive: boolean; + selectedItems: Entities.ITableEntity[]; + isValue: boolean; + isTimestamp: boolean; + isCustomLastTimestamp: boolean; + isCustomRangeTimestamp: boolean; + operators: string[]; + selectMessage: string; + queryTableRows: IQueryTableRowsType[]; +} + +export interface IQueryTableRowsType { + isQueryTableEntityChecked: boolean; + isTimeStampSelected: boolean; + selectedOperator: string; + selectedField: string; + entityValue: string; + selectedEntityType: string; + selectedOperation: string; + selectedTimestamp: string; + fieldOptions: IOption[]; + opertorOptions: IOption[]; + entityTypeOptions: IOption[]; + opertionOptions: IOption[]; + timestampOptions: IOption[]; + id: number; +} + +export const opertionOptions = [ + { key: "And", text: "And" }, + { key: "Or", text: "Or" }, +]; +export const opertorOptions = [ + { key: "=", text: "=" }, + { key: ">", text: ">" }, + { key: ">=", text: ">=" }, + { key: "<", text: "<" }, + { key: "<=", text: "<=" }, + { key: "<>", text: "<>" }, +]; + +export const fieldOptions = [ + { key: "PartitionKey", text: "PartitionKey" }, + { key: "RowKey", text: "RowKey" }, + { key: "Timestamp", text: "Timestamp" }, + { key: "t3PN", text: "t3PN" }, +]; + +export const entityTypeOptions = [ + { key: "String", text: "String" }, + { key: "Boolean", text: "Boolean" }, + { key: "Binary", text: "Binary" }, + { key: "DateTime", text: "DateTime" }, + { key: "Double", text: "Double" }, + { key: "Guid", text: "Guid" }, + { key: "Int32", text: "Int32" }, + { key: "Int64", text: "Int64" }, +]; + +export const timestampOptions = [ + { key: "Last hour", text: "Last hour" }, + { key: "Last 24 hours", text: "Last 24 hours" }, + { key: "Last 7 days", text: "Last 7 days" }, + { key: "Last 31 days", text: "Last 31 days" }, + { key: "Last 365 days", text: "Last 365 days" }, + { key: "Current month", text: "Current month" }, + { key: "Current year", text: "Current year" }, +]; diff --git a/src/Explorer/Tabs/QueryTablesTab/QueryTablesTabComponent.tsx b/src/Explorer/Tabs/QueryTablesTab/QueryTablesTabComponent.tsx index f72768a20..8e1a6c0eb 100644 --- a/src/Explorer/Tabs/QueryTablesTab/QueryTablesTabComponent.tsx +++ b/src/Explorer/Tabs/QueryTablesTab/QueryTablesTabComponent.tsx @@ -1,5 +1,12 @@ -import { DetailsList, DetailsListLayoutMode, IColumn, Selection, SelectionMode } from "@fluentui/react"; -import { Dropdown, IDropdownOption, IDropdownStyles } from "@fluentui/react/lib/Dropdown"; +import { + DetailsList, + DetailsListLayoutMode, + IColumn, + IDropdownOption, + IDropdownStyles, + Selection, + SelectionMode, +} from "@fluentui/react"; import * as ko from "knockout"; import React, { Component } from "react"; import QueryInformation from "../../../../images//QueryBuilder/QueryInformation_16x.png"; @@ -8,7 +15,6 @@ import AddEntityIcon from "../../../../images/AddEntity.svg"; import AndOr from "../../../../images/And-Or.svg"; import DeleteEntitiesIcon from "../../../../images/DeleteEntities.svg"; import EditEntityIcon from "../../../../images/Edit-entity.svg"; -import EntityCancel from "../../../../images/Entity_cancel.svg"; import ErrorRed from "../../../../images/error_red.svg"; import ExecuteQueryIcon from "../../../../images/ExecuteQuery.svg"; import QueryBuilderIcon from "../../../../images/Query-Builder.svg"; @@ -29,55 +35,67 @@ import TableEntityListViewModel from "../../Tables/DataTable/TableEntityListView import * as Entities from "../../Tables/Entities"; import QueryViewModel from "../../Tables/QueryBuilder/QueryViewModel"; import { CassandraAPIDataClient, TableDataClient } from "../../Tables/TableDataClient"; -import TabsBase from "../TabsBase"; -import NewQueryTablesTab from "./QueryTablesTab"; - +// import TabsBase from "../TabsBase"; +// import NewQueryTablesTab from "./QueryTablesTab"; +import { QueryTableEntityClause } from "./QueryTableEntityClause"; +import { + entityTypeOptions, + fieldOptions, + IDocument, + IQueryTableRowsType, + IQueryTablesTabComponentProps, + IQueryTablesTabComponentStates, + opertionOptions, + opertorOptions, + timestampOptions, +} from "./QueryTableTabUtils"; export interface Button { visible: boolean; enabled: boolean; isSelected?: boolean; } -export interface IDocument { - partitionKey: string; - rowKey: string; - timeStamp: string; -} -export interface IQueryTablesTabComponentProps { - tabKind: ViewModels.CollectionTabKind; - title: string; - tabPath: string; - collection: ViewModels.CollectionBase; - node: ViewModels.TreeNode; - onLoadStartKey: number; - container: Explorer; - tabsBaseInstance: TabsBase; - queryTablesTab: NewQueryTablesTab; -} +// export interface IDocument { +// partitionKey: string; +// rowKey: string; +// timeStamp: string; +// } +// export interface IQueryTablesTabComponentProps { +// tabKind: ViewModels.CollectionTabKind; +// title: string; +// tabPath: string; +// collection: ViewModels.CollectionBase; +// node: ViewModels.TreeNode; +// onLoadStartKey: number; +// container: Explorer; +// tabsBaseInstance: TabsBase; +// queryTablesTab: NewQueryTablesTab; +// } -interface IQueryTablesTabComponentStates { - tableEntityListViewModel: TableEntityListViewModel; - queryViewModel: QueryViewModel; - queryText: string; - selectedQueryText: string; - executeQueryButton: Button; - queryBuilderButton: Button; - queryTextButton: Button; - addEntityButton: Button; - editEntityButton: Button; - deleteEntityButton: Button; - isHelperActive: boolean; - columns: IColumn[]; - items: IDocument[]; - isExpanded: boolean; - isEditorActive: boolean; - selectedItems: Entities.ITableEntity[]; - isValue: boolean; - isTimestamp: boolean; - isCustomLastTimestamp: boolean; - isCustomRangeTimestamp: boolean; - operators: string[]; - selectMessage: string; -} +// interface IQueryTablesTabComponentStates { +// tableEntityListViewModel: TableEntityListViewModel; +// queryViewModel: QueryViewModel; +// queryText: string; +// selectedQueryText: string; +// executeQueryButton: Button; +// queryBuilderButton: Button; +// queryTextButton: Button; +// addEntityButton: Button; +// editEntityButton: Button; +// deleteEntityButton: Button; +// isHelperActive: boolean; +// columns: IColumn[]; +// items: IDocument[]; +// isExpanded: boolean; +// isEditorActive: boolean; +// selectedItems: Entities.ITableEntity[]; +// isValue: boolean; +// isTimestamp: boolean; +// isCustomLastTimestamp: boolean; +// isCustomRangeTimestamp: boolean; +// operators: string[]; +// selectMessage: string; +// queryTableRows: IQueryTableRowsType[]; +// } class QueryTablesTabComponent extends Component { // public readonly html = template; @@ -207,12 +225,31 @@ class QueryTablesTabComponent extends Component ", this.state.tableEntityListViewModel ); - const x = this.state.tableEntityListViewModel.items(); - console.log("🚀 ~ file: QueryTablesTabComponent.tsx ~ line 146 ~ QueryTablesTabComponent ~ constructor ~ x", x); + // const x = this.state.tableEntityListViewModel.items(); + // console.log("🚀 ~ file: QueryTablesTabComponent.tsx ~ line 146 ~ QueryTablesTabComponent ~ constructor ~ x", x); this.andLabel = this.state.queryViewModel.queryBuilderViewModel().andLabel; this.actionLabel = this.state.queryViewModel.queryBuilderViewModel().actionLabel; this.fieldLabel = this.state.queryViewModel.queryBuilderViewModel().fieldLabel; this.dataTypeLabel = this.state.queryViewModel.queryBuilderViewModel().dataTypeLabel; this.operatorLabel = this.state.queryViewModel.queryBuilderViewModel().operatorLabel; this.valueLabel = this.state.queryViewModel.queryBuilderViewModel().valueLabel; - console.log( - "🚀 ~ file: QueryTablesTabComponent.tsx ~ line 232 ~ QueryTablesTabComponent ~ constructor ~ this.state.queryViewModel.queryBuilderViewModel().operators", - this.state.queryViewModel.queryBuilderViewModel().operators() - ); + // console.log( + // "🚀 ~ file: QueryTablesTabComponent.tsx ~ line 232 ~ QueryTablesTabComponent ~ constructor ~ this.state.queryViewModel.queryBuilderViewModel().operators", + // this.state.queryViewModel.queryBuilderViewModel().operators() + // ); useCommandBar.getState().setContextButtons(this.getTabsButtons()); @@ -276,17 +313,14 @@ class QueryTablesTabComponent extends Component { - const abc = await this.state.tableEntityListViewModel.renderNextPageAndupdateCache(); - console.log( - "🚀 ~ file: QueryTablesTabComponent.tsx ~ line 249 ~ QueryTablesTabComponent ~ componentDidMount ~ abc", - abc - ); + componentDidMount(): void { + this.state.tableEntityListViewModel.renderNextPageAndupdateCache(); + setTimeout(() => { - console.log("items > ", this.state.tableEntityListViewModel.cache.data); - console.log("items > ", this.state.tableEntityListViewModel.items()); - console.log("items1 > ", this.state.tableEntityListViewModel.headers); - console.log("items1 > simple > ", this.tableEntityListViewModel1.items1); + // console.log("items > ", this.state.tableEntityListViewModel.cache.data); + // console.log("items > ", this.state.tableEntityListViewModel.items()); + // console.log("items1 > ", this.state.tableEntityListViewModel.headers); + // console.log("items1 > simple > ", this.tableEntityListViewModel1.items1); this.columns = []; this.state.tableEntityListViewModel.headers.map((header) => { this.columns.push({ @@ -309,10 +343,10 @@ class QueryTablesTabComponent extends Component { - console.log( - "🚀 ~ file: QueryTablesTabComponent.tsx ~ line 248 ~ QueryTablesTabComponent ~ setTimeout ~ columns", - this.state.columns - ); + // console.log( + // "🚀 ~ file: QueryTablesTabComponent.tsx ~ line 248 ~ QueryTablesTabComponent ~ setTimeout ~ columns", + // this.state.columns + // ); }, 1000); this.allItems = this.generateDetailsList(); this.setState({ @@ -329,10 +363,10 @@ class QueryTablesTabComponent extends Component 0) { const a = this.state.tableEntityListViewModel .items() .filter((item) => item["Timestamp"]._ === Object.values(this.selection.getSelection()[0])[2]); - console.log("🚀 ~ file: QueryTablesTabComponent.tsx ~ line 293 ~ QueryTablesTabComponent ~ a", a); + // console.log("🚀 ~ file: QueryTablesTabComponent.tsx ~ line 293 ~ QueryTablesTabComponent ~ a", a); this.setState({ // selectionCount: this._selection.getSelectedCount(), @@ -436,6 +470,7 @@ class QueryTablesTabComponent extends Component { return this.state.tableEntityListViewModel.removeEntitiesFromCache(entitiesToDelete).then(() => { // this.state.tableEntityListViewModel.redrawTableThrottled(); @@ -543,23 +578,23 @@ class QueryTablesTabComponent extends Component { - console.log("generateDetailsList > ", item["PartitionKey"]._); + // console.log("generateDetailsList > ", item["PartitionKey"]._); this.columns.map((col) => { // console.log( // "🚀 ~ file: QueryTablesTabComponent.tsx ~ line 403 ~ QueryTablesTabComponent ~ this.columns.map ~ col.name", // col.name // ); if (item[col.name]) { - console.log("Data > ", item[col.name]._); + // console.log("Data > ", item[col.name]._); obj = { ...obj, ...{ [col.name]: item[col.name]._ } }; } }); items.push(obj); }); - console.log( - "🚀 ~ file: QueryTablesTabComponent.tsx ~ line 383 ~ QueryTablesTabComponent ~ this.state.tableEntityListViewModel.items ~ items", - items - ); + // console.log( + // "🚀 ~ file: QueryTablesTabComponent.tsx ~ line 383 ~ QueryTablesTabComponent ~ this.state.tableEntityListViewModel.items ~ items", + // items + // ); return items; } @@ -584,9 +619,68 @@ class QueryTablesTabComponent extends Component { + const { queryTableRows } = this.state; + const cloneQueryTableRows: IQueryTableRowsType[] = [...queryTableRows]; + cloneQueryTableRows[index].isQueryTableEntityChecked = !cloneQueryTableRows[index].isQueryTableEntityChecked; + this.setState({ queryTableRows: cloneQueryTableRows }); + }; + + private onDropdownChange = (selectedOption: IDropdownOption, selectedOptionType: string, index: number): void => { + const { queryTableRows } = this.state; + const cloneQueryTableRows: IQueryTableRowsType[] = [...queryTableRows]; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + //@ts-ignore + cloneQueryTableRows[index][selectedOptionType] = selectedOption.text; + const { text } = selectedOption; + if (text === "DateTime" || text === "Timestamp") { + cloneQueryTableRows[index].isTimeStampSelected = true; + cloneQueryTableRows[index].selectedEntityType = "DateTime"; + } else if (selectedOptionType !== "selectedTimestamp") { + cloneQueryTableRows[index].isTimeStampSelected = false; + } + this.setState({ queryTableRows: cloneQueryTableRows }); + }; + + onDeleteClause = (indexToRemove: number): void => { + const { queryTableRows } = this.state; + const cloneQueryTableRows: IQueryTableRowsType[] = [...queryTableRows]; + cloneQueryTableRows.splice(indexToRemove, 1); + this.setState({ queryTableRows: cloneQueryTableRows }); + }; + + onAddNewClause = (): void => { + const { queryTableRows } = this.state; + const cloneQueryTableRows: IQueryTableRowsType[] = [...queryTableRows]; + cloneQueryTableRows.splice(cloneQueryTableRows.length, 0, { + isQueryTableEntityChecked: false, + selectedOperator: "=", + opertorOptions, + id: cloneQueryTableRows.length + 1, + selectedField: "PartitionKey", + fieldOptions, + entityTypeOptions, + selectedEntityType: "String", + opertionOptions, + selectedOperation: "And", + entityValue: "", + isTimeStampSelected: false, + timestampOptions, + selectedTimestamp: "Last hour", + }); + this.setState({ queryTableRows: cloneQueryTableRows }); + }; + + private onEntityValueChange = (newInput: string, index: number) => { + const { queryTableRows } = this.state; + const cloneQueryTableRows: IQueryTableRowsType[] = [...queryTableRows]; + cloneQueryTableRows[index].entityValue = newInput; + this.setState({ queryTableRows: cloneQueryTableRows }); + }; render(): JSX.Element { useCommandBar.getState().setContextButtons(this.getTabsButtons()); + const { queryTableRows } = this.state; return (
@@ -634,131 +728,56 @@ class QueryTablesTabComponent extends Component - {this.andLabel} + {this.andLabel} - {this.fieldLabel} + {this.fieldLabel} - {this.dataTypeLabel} + {this.dataTypeLabel} - {this.operatorLabel} + {this.operatorLabel} - {this.valueLabel} + {this.valueLabel} - - - {/* Add and Cancel */} - - - Add clause - - - Delete clause - - - {/* Group and unGroup */} - - - - - - - - -
- - {/* AndOr */} - - - - {/* Field */} - - - - {/* Type */} - - - - {/* Operator */} - - - - {/* Value */} - - - - - - - - - -
+ <> + {queryTableRows.map((queryTableRow, index) => ( + this.onDeleteClause(index)} + onQueryTableEntityCheck={() => this.onQueryTableEntityCheck(index)} + onEntityValueChange={(_event, newInput?: string) => this.onEntityValueChange(newInput, index)} + onDropdownChange={(selectedOption: IDropdownOption, selectedOptionType: string) => + this.onDropdownChange(selectedOption, selectedOptionType, index) + } + /> + ))} +
diff --git a/src/index.html b/src/index.html index bfbaf3672..5332ae673 100644 --- a/src/index.html +++ b/src/index.html @@ -1,13 +1,13 @@ - - - - - Azure Cosmos DB Emulator - - - + + + + + Azure Cosmos DB Emulator + + +