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..6efdee684 --- /dev/null +++ b/src/Explorer/Tabs/QueryTablesTab/QueryTableTabUtils.tsx @@ -0,0 +1,110 @@ +import { IColumn } from "@fluentui/react"; +import * as ViewModels from "../../../Contracts/ViewModels"; +import Explorer from "../../Explorer"; +import TableEntityListViewModel from "../../Tables/DataTable/TableEntityListViewModel"; +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; + 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 2f8e6677e..e6fe80e73 100644 --- a/src/Explorer/Tabs/QueryTablesTab/QueryTablesTabComponent.tsx +++ b/src/Explorer/Tabs/QueryTablesTab/QueryTablesTabComponent.tsx @@ -1,4 +1,4 @@ -import { DetailsList, DetailsListLayoutMode, IColumn, SelectionMode } from "@fluentui/react"; +import { DetailsList, DetailsListLayoutMode, IColumn, IDropdownOption, SelectionMode } from "@fluentui/react"; import * as ko from "knockout"; import React, { Component } from "react"; import QueryInformation from "../../../../images//QueryBuilder/QueryInformation_16x.png"; @@ -26,47 +26,18 @@ import TableCommands from "../../Tables/DataTable/TableCommands"; import TableEntityListViewModel from "../../Tables/DataTable/TableEntityListViewModel"; import QueryViewModel from "../../Tables/QueryBuilder/QueryViewModel"; import { CassandraAPIDataClient, TableDataClient } from "../../Tables/TableDataClient"; -import TabsBase from "../TabsBase"; -import NewQueryTablesTab from "./QueryTablesTab"; - -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; -} - -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; -} +import { QueryTableEntityClause } from "./QueryTableEntityClause"; +import { + entityTypeOptions, + fieldOptions, + IDocument, + IQueryTableRowsType, + IQueryTablesTabComponentProps, + IQueryTablesTabComponentStates, + opertionOptions, + opertorOptions, + timestampOptions, +} from "./QueryTableTabUtils"; class QueryTablesTabComponent extends Component { // public readonly html = template; @@ -186,6 +157,24 @@ 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 (
@@ -476,30 +525,57 @@ class QueryTablesTabComponent extends Component - {this.andLabel} + {this.andLabel} - {this.fieldLabel} + {this.fieldLabel} - {this.dataTypeLabel} + {this.dataTypeLabel} - {this.operatorLabel} + {this.operatorLabel} - {this.valueLabel} + {this.valueLabel}
+ <> + {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 + + +