Migrate Add Table Entity Pane to React (#642)

Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
This commit is contained in:
Sunil Kumar Yadav 2021-04-21 22:03:29 +05:30 committed by GitHub
parent d5f3230f6f
commit 72ce5fc813
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 4343 additions and 744 deletions

View File

@ -128,7 +128,6 @@ src/Explorer/Panes/PaneComponents.ts
src/Explorer/Panes/RenewAdHocAccessPane.ts src/Explorer/Panes/RenewAdHocAccessPane.ts
src/Explorer/Panes/StringInputPane.ts src/Explorer/Panes/StringInputPane.ts
src/Explorer/Panes/SwitchDirectoryPane.ts src/Explorer/Panes/SwitchDirectoryPane.ts
src/Explorer/Panes/Tables/AddTableEntityPane.ts
src/Explorer/Panes/Tables/EditTableEntityPane.ts src/Explorer/Panes/Tables/EditTableEntityPane.ts
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
src/Explorer/Panes/Tables/TableEntityPane.ts src/Explorer/Panes/Tables/TableEntityPane.ts

View File

@ -0,0 +1,61 @@
import { DatePicker, TextField } from "office-ui-fabric-react";
import React, { FunctionComponent } from "react";
export interface TableEntityProps {
entityValueLabel?: string;
entityValuePlaceholder: string;
entityValue: string | Date;
isEntityTypeDate: boolean;
entityTimeValue: string;
entityValueType: string;
onEntityValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
onSelectDate: (date: Date | null | undefined) => void;
onEntityTimeValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
}
export const EntityValue: FunctionComponent<TableEntityProps> = ({
entityValueLabel,
entityValuePlaceholder,
entityValue,
isEntityTypeDate,
entityTimeValue,
entityValueType,
onEntityValueChange,
onSelectDate,
onEntityTimeValueChange,
}: TableEntityProps): JSX.Element => {
if (isEntityTypeDate) {
return (
<>
<DatePicker
className="addEntityDatePicker"
placeholder={entityValuePlaceholder}
value={entityValue && new Date(entityValue)}
ariaLabel={entityValuePlaceholder}
onSelectDate={onSelectDate}
/>
<TextField
label={entityValueLabel && entityValueLabel}
id="entityTimeId"
autoFocus
type="time"
value={entityTimeValue}
onChange={onEntityTimeValueChange}
/>
</>
);
}
return (
<TextField
label={entityValueLabel && entityValueLabel}
className="addEntityTextField"
id="entityValueId"
autoFocus
type={entityValueType}
placeholder={entityValuePlaceholder}
value={typeof entityValue === "string" && entityValue}
onChange={onEntityValueChange}
/>
);
};

136
src/Common/TableEntity.tsx Normal file
View File

@ -0,0 +1,136 @@
import {
Dropdown,
IDropdownOption,
IDropdownStyles,
IImageProps,
Image,
IStackTokens,
Stack,
TextField,
TooltipHost,
} from "office-ui-fabric-react";
import React, { FunctionComponent } from "react";
import DeleteIcon from "../../images/delete.svg";
import EditIcon from "../../images/Edit_entity.svg";
import { CassandraType, TableType } from "../Explorer/Tables/Constants";
import { userContext } from "../UserContext";
import { EntityValue } from "./EntityValue";
const dropdownStyles: Partial<IDropdownStyles> = { dropdown: { width: 100 } };
export interface TableEntityProps {
entityTypeLabel?: string;
entityPropertyLabel?: string;
entityValueLabel?: string;
isDeleteOptionVisible: boolean;
entityProperty: string;
entityPropertyPlaceHolder: string;
selectedKey: string | number;
entityValuePlaceholder: string;
entityValue: string | Date;
isEntityTypeDate: boolean;
options: { key: string; text: string }[];
isPropertyTypeDisable: boolean;
entityTimeValue: string;
onDeleteEntity?: () => void;
onEditEntity?: () => void;
onEntityPropertyChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
onEntityTypeChange: (event: React.FormEvent<HTMLElement>, selectedParam: IDropdownOption) => void;
onEntityValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
onSelectDate: (date: Date | null | undefined) => void;
onEntityTimeValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
}
export const TableEntity: FunctionComponent<TableEntityProps> = ({
entityTypeLabel,
entityPropertyLabel,
isDeleteOptionVisible,
entityProperty,
selectedKey,
entityPropertyPlaceHolder,
entityValueLabel,
entityValuePlaceholder,
entityValue,
options,
isPropertyTypeDisable,
isEntityTypeDate,
entityTimeValue,
onEditEntity,
onDeleteEntity,
onEntityPropertyChange,
onEntityTypeChange,
onEntityValueChange,
onSelectDate,
onEntityTimeValueChange,
}: TableEntityProps): JSX.Element => {
const imageProps: IImageProps = {
width: 16,
height: 30,
className: entityPropertyLabel ? "addRemoveIconLabel" : "addRemoveIcon",
};
const sectionStackTokens: IStackTokens = { childrenGap: 12 };
const getEntityValueType = (): string => {
const { Int, Smallint, Tinyint } = CassandraType;
const { Double, Int32, Int64 } = TableType;
if (
selectedKey === Double ||
selectedKey === Int32 ||
selectedKey === Int64 ||
selectedKey === Int ||
selectedKey === Smallint ||
selectedKey === Tinyint
) {
return "number";
}
return "string";
};
return (
<>
<Stack horizontal tokens={sectionStackTokens}>
<TextField
label={entityPropertyLabel && entityPropertyLabel}
id="entityPropertyId"
autoFocus
disabled={isPropertyTypeDisable}
placeholder={entityPropertyPlaceHolder}
value={entityProperty}
onChange={onEntityPropertyChange}
required
/>
<Dropdown
label={entityTypeLabel && entityTypeLabel}
selectedKey={selectedKey}
onChange={onEntityTypeChange}
options={options}
disabled={isPropertyTypeDisable}
id="entityTypeId"
styles={dropdownStyles}
/>
<EntityValue
entityValueLabel={entityValueLabel}
entityValueType={getEntityValueType()}
entityValuePlaceholder={entityValuePlaceholder}
entityValue={entityValue}
isEntityTypeDate={isEntityTypeDate}
entityTimeValue={entityTimeValue}
onEntityValueChange={onEntityValueChange}
onSelectDate={onSelectDate}
onEntityTimeValueChange={onEntityTimeValueChange}
/>
<TooltipHost content="Edit property" id="editTooltip">
<Image {...imageProps} src={EditIcon} alt="editEntity" id="editEntity" onClick={onEditEntity} />
</TooltipHost>
{isDeleteOptionVisible && userContext.apiType !== "Cassandra" && (
<TooltipHost content="Delete property" id="deleteTooltip">
<Image {...imageProps} src={DeleteIcon} alt="delete entity" id="deleteEntity" onClick={onDeleteEntity} />
</TooltipHost>
)}
</Stack>
</>
);
};

View File

@ -177,42 +177,6 @@ exports[`SettingsComponent renders 1`] = `
"title": [Function], "title": [Function],
"visible": [Function], "visible": [Function],
}, },
AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
EditTableEntityPane { EditTableEntityPane {
"addButtonLabel": "Add Property", "addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name", "attributeNameLabel": "Property Name",
@ -453,42 +417,6 @@ exports[`SettingsComponent renders 1`] = `
"visible": [Function], "visible": [Function],
}, },
"addDatabaseText": [Function], "addDatabaseText": [Function],
"addTableEntityPane": AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
"arcadiaToken": [Function], "arcadiaToken": [Function],
"canExceedMaximumValue": [Function], "canExceedMaximumValue": [Function],
"canSaveQueries": [Function], "canSaveQueries": [Function],
@ -911,42 +839,6 @@ exports[`SettingsComponent renders 1`] = `
"title": [Function], "title": [Function],
"visible": [Function], "visible": [Function],
}, },
AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
EditTableEntityPane { EditTableEntityPane {
"addButtonLabel": "Add Property", "addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name", "attributeNameLabel": "Property Name",
@ -1187,42 +1079,6 @@ exports[`SettingsComponent renders 1`] = `
"visible": [Function], "visible": [Function],
}, },
"addDatabaseText": [Function], "addDatabaseText": [Function],
"addTableEntityPane": AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
"arcadiaToken": [Function], "arcadiaToken": [Function],
"canExceedMaximumValue": [Function], "canExceedMaximumValue": [Function],
"canSaveQueries": [Function], "canSaveQueries": [Function],
@ -1658,42 +1514,6 @@ exports[`SettingsComponent renders 1`] = `
"title": [Function], "title": [Function],
"visible": [Function], "visible": [Function],
}, },
AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
EditTableEntityPane { EditTableEntityPane {
"addButtonLabel": "Add Property", "addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name", "attributeNameLabel": "Property Name",
@ -1934,42 +1754,6 @@ exports[`SettingsComponent renders 1`] = `
"visible": [Function], "visible": [Function],
}, },
"addDatabaseText": [Function], "addDatabaseText": [Function],
"addTableEntityPane": AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
"arcadiaToken": [Function], "arcadiaToken": [Function],
"canExceedMaximumValue": [Function], "canExceedMaximumValue": [Function],
"canSaveQueries": [Function], "canSaveQueries": [Function],
@ -2392,42 +2176,6 @@ exports[`SettingsComponent renders 1`] = `
"title": [Function], "title": [Function],
"visible": [Function], "visible": [Function],
}, },
AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
EditTableEntityPane { EditTableEntityPane {
"addButtonLabel": "Add Property", "addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name", "attributeNameLabel": "Property Name",
@ -2668,42 +2416,6 @@ exports[`SettingsComponent renders 1`] = `
"visible": [Function], "visible": [Function],
}, },
"addDatabaseText": [Function], "addDatabaseText": [Function],
"addTableEntityPane": AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
"arcadiaToken": [Function], "arcadiaToken": [Function],
"canExceedMaximumValue": [Function], "canExceedMaximumValue": [Function],
"canSaveQueries": [Function], "canSaveQueries": [Function],

View File

@ -63,14 +63,16 @@ import { SaveQueryPanel } from "./Panes/SaveQueryPanel";
import { SettingsPane } from "./Panes/SettingsPane"; import { SettingsPane } from "./Panes/SettingsPane";
import { SetupNoteBooksPanel } from "./Panes/SetupNotebooksPanel/SetupNotebooksPanel"; import { SetupNoteBooksPanel } from "./Panes/SetupNotebooksPanel/SetupNotebooksPanel";
import { StringInputPane } from "./Panes/StringInputPane"; import { StringInputPane } from "./Panes/StringInputPane";
import AddTableEntityPane from "./Panes/Tables/AddTableEntityPane"; import { AddTableEntityPanel } from "./Panes/Tables/AddTableEntityPanel";
import EditTableEntityPane from "./Panes/Tables/EditTableEntityPane"; import EditTableEntityPane from "./Panes/Tables/EditTableEntityPane";
import { TableQuerySelectPanel } from "./Panes/Tables/TableQuerySelectPanel"; import { TableQuerySelectPanel } from "./Panes/Tables/TableQuerySelectPanel";
import { UploadFilePane } from "./Panes/UploadFilePane"; import { UploadFilePane } from "./Panes/UploadFilePane";
import { UploadItemsPane } from "./Panes/UploadItemsPane"; import { UploadItemsPane } from "./Panes/UploadItemsPane";
import TableListViewModal from "./Tables/DataTable/TableEntityListViewModel";
import QueryViewModel from "./Tables/QueryBuilder/QueryViewModel"; import QueryViewModel from "./Tables/QueryBuilder/QueryViewModel";
import { CassandraAPIDataClient, TableDataClient, TablesAPIDataClient } from "./Tables/TableDataClient"; import { CassandraAPIDataClient, TableDataClient, TablesAPIDataClient } from "./Tables/TableDataClient";
import NotebookV2Tab, { NotebookTabOptions } from "./Tabs/NotebookV2Tab"; import NotebookV2Tab, { NotebookTabOptions } from "./Tabs/NotebookV2Tab";
import QueryTablesTab from "./Tabs/QueryTablesTab";
import TabsBase from "./Tabs/TabsBase"; import TabsBase from "./Tabs/TabsBase";
import { TabsManager } from "./Tabs/TabsManager"; import { TabsManager } from "./Tabs/TabsManager";
import TerminalTab from "./Tabs/TerminalTab"; import TerminalTab from "./Tabs/TerminalTab";
@ -177,7 +179,6 @@ export default class Explorer {
public addDatabasePane: AddDatabasePane; public addDatabasePane: AddDatabasePane;
public addCollectionPane: AddCollectionPane; public addCollectionPane: AddCollectionPane;
public graphStylingPane: GraphStylingPane; public graphStylingPane: GraphStylingPane;
public addTableEntityPane: AddTableEntityPane;
public editTableEntityPane: EditTableEntityPane; public editTableEntityPane: EditTableEntityPane;
public newVertexPane: NewVertexPane; public newVertexPane: NewVertexPane;
public cassandraAddCollectionPane: CassandraAddCollectionPane; public cassandraAddCollectionPane: CassandraAddCollectionPane;
@ -514,13 +515,6 @@ export default class Explorer {
container: this, container: this,
}); });
this.addTableEntityPane = new AddTableEntityPane({
id: "addtableentitypane",
visible: ko.observable<boolean>(false),
container: this,
});
this.editTableEntityPane = new EditTableEntityPane({ this.editTableEntityPane = new EditTableEntityPane({
id: "edittableentitypane", id: "edittableentitypane",
visible: ko.observable<boolean>(false), visible: ko.observable<boolean>(false),
@ -561,7 +555,6 @@ export default class Explorer {
this.addDatabasePane, this.addDatabasePane,
this.addCollectionPane, this.addCollectionPane,
this.graphStylingPane, this.graphStylingPane,
this.addTableEntityPane,
this.editTableEntityPane, this.editTableEntityPane,
this.newVertexPane, this.newVertexPane,
this.cassandraAddCollectionPane, this.cassandraAddCollectionPane,
@ -634,7 +627,6 @@ export default class Explorer {
this.addCollectionPane.collectionIdTitle("Table id"); this.addCollectionPane.collectionIdTitle("Table id");
this.addCollectionPane.collectionWithThroughputInSharedTitle("Provision dedicated throughput for this table"); this.addCollectionPane.collectionWithThroughputInSharedTitle("Provision dedicated throughput for this table");
this.refreshTreeTitle("Refresh tables"); this.refreshTreeTitle("Refresh tables");
this.addTableEntityPane.title("Add Table Entity");
this.editTableEntityPane.title("Edit Table Entity"); this.editTableEntityPane.title("Edit Table Entity");
this.tableDataClient = new TablesAPIDataClient(); this.tableDataClient = new TablesAPIDataClient();
break; break;
@ -649,7 +641,6 @@ export default class Explorer {
this.addCollectionPane.collectionIdTitle("Table id"); this.addCollectionPane.collectionIdTitle("Table id");
this.addCollectionPane.collectionWithThroughputInSharedTitle("Provision dedicated throughput for this table"); this.addCollectionPane.collectionWithThroughputInSharedTitle("Provision dedicated throughput for this table");
this.refreshTreeTitle("Refresh tables"); this.refreshTreeTitle("Refresh tables");
this.addTableEntityPane.title("Add Table Row");
this.editTableEntityPane.title("Edit Table Row"); this.editTableEntityPane.title("Edit Table Row");
this.tableDataClient = new CassandraAPIDataClient(); this.tableDataClient = new CassandraAPIDataClient();
break; break;
@ -2263,6 +2254,18 @@ export default class Explorer {
); );
} }
public openAddTableEntityPanel(queryTablesTab: QueryTablesTab, tableEntityListViewModel: TableListViewModal): void {
this.openSidePanel(
"Add Table Entity",
<AddTableEntityPanel
explorer={this}
closePanel={this.closeSidePanel}
queryTablesTab={queryTablesTab}
tableEntityListViewModel={tableEntityListViewModel}
cassandraApiClient={new CassandraAPIDataClient()}
/>
);
}
public openSetupNotebooksPanel(title: string, description: string): void { public openSetupNotebooksPanel(title: string, description: string): void {
this.openSidePanel( this.openSidePanel(
title, title,

View File

@ -152,6 +152,21 @@
.removeIcon { .removeIcon {
color: @InfoIconColor; color: @InfoIconColor;
} }
.backImageIcon {
margin-top: 8px;
}
.entityValueTextField {
margin: 24px;
}
.addEntityDatePicker {
max-width: 145px;
}
.addEntityTextField {
width: 237px;
}
.addButtonEntiy {
width: 25%;
}
.column-select-view { .column-select-view {
margin: 20px 0px 0px 0px; margin: 20px 0px 0px 0px;
} }

View File

@ -1,5 +1,5 @@
import { IPanelProps, IRenderFunction, Panel, PanelType } from "office-ui-fabric-react";
import * as React from "react"; import * as React from "react";
import { Panel, PanelType } from "office-ui-fabric-react";
export interface PanelContainerProps { export interface PanelContainerProps {
headerText: string; headerText: string;
@ -7,6 +7,8 @@ export interface PanelContainerProps {
isConsoleExpanded: boolean; isConsoleExpanded: boolean;
isOpen: boolean; isOpen: boolean;
closePanel: () => void; closePanel: () => void;
panelWidth?: string;
onRenderNavigationContent?: IRenderFunction<IPanelProps>;
} }
export interface PanelContainerState { export interface PanelContainerState {
@ -46,8 +48,9 @@ export class PanelContainerComponent extends React.Component<PanelContainerProps
isLightDismiss isLightDismiss
type={PanelType.custom} type={PanelType.custom}
closeButtonAriaLabel="Close" closeButtonAriaLabel="Close"
customWidth="440px" customWidth={this.props.panelWidth ? this.props.panelWidth : "440px"}
headerClassName="panelHeader" headerClassName="panelHeader"
onRenderNavigationContent={this.props.onRenderNavigationContent}
styles={{ styles={{
navigation: { borderBottom: "1px solid #cccccc" }, navigation: { borderBottom: "1px solid #cccccc" },
content: { padding: 0, height: "100%" }, content: { padding: 0, height: "100%" },

View File

@ -153,42 +153,6 @@ exports[`Settings Pane should render Default properly 1`] = `
"title": [Function], "title": [Function],
"visible": [Function], "visible": [Function],
}, },
AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
EditTableEntityPane { EditTableEntityPane {
"addButtonLabel": "Add Property", "addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name", "attributeNameLabel": "Property Name",
@ -429,42 +393,6 @@ exports[`Settings Pane should render Default properly 1`] = `
"visible": [Function], "visible": [Function],
}, },
"addDatabaseText": [Function], "addDatabaseText": [Function],
"addTableEntityPane": AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
"arcadiaToken": [Function], "arcadiaToken": [Function],
"canExceedMaximumValue": [Function], "canExceedMaximumValue": [Function],
"canSaveQueries": [Function], "canSaveQueries": [Function],
@ -1010,42 +938,6 @@ exports[`Settings Pane should render Gremlin properly 1`] = `
"title": [Function], "title": [Function],
"visible": [Function], "visible": [Function],
}, },
AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
EditTableEntityPane { EditTableEntityPane {
"addButtonLabel": "Add Property", "addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name", "attributeNameLabel": "Property Name",
@ -1286,42 +1178,6 @@ exports[`Settings Pane should render Gremlin properly 1`] = `
"visible": [Function], "visible": [Function],
}, },
"addDatabaseText": [Function], "addDatabaseText": [Function],
"addTableEntityPane": AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
"arcadiaToken": [Function], "arcadiaToken": [Function],
"canExceedMaximumValue": [Function], "canExceedMaximumValue": [Function],
"canSaveQueries": [Function], "canSaveQueries": [Function],

View File

@ -1,150 +0,0 @@
import * as ko from "knockout";
import * as _ from "underscore";
import * as ViewModels from "../../../Contracts/ViewModels";
import { userContext } from "../../../UserContext";
import * as TableConstants from "../../Tables/Constants";
import * as DataTableUtilities from "../../Tables/DataTable/DataTableUtilities";
import * as Entities from "../../Tables/Entities";
import { CassandraAPIDataClient, CassandraTableKey } from "../../Tables/TableDataClient";
import * as Utilities from "../../Tables/Utilities";
import EntityPropertyViewModel from "./EntityPropertyViewModel";
import TableEntityPane from "./TableEntityPane";
export default class AddTableEntityPane extends TableEntityPane {
private static _excludedFields: string[] = [TableConstants.EntityKeyNames.Timestamp];
private static _readonlyFields: string[] = [
TableConstants.EntityKeyNames.PartitionKey,
TableConstants.EntityKeyNames.RowKey,
TableConstants.EntityKeyNames.Timestamp,
];
public enterRequiredValueLabel = "Enter identifier value."; // localize
public enterValueLabel = "Enter value to keep property."; // localize
constructor(options: ViewModels.PaneOptions) {
super(options);
this.submitButtonText("Add Entity");
if (userContext.apiType === "Cassandra") {
this.submitButtonText("Add Row");
}
this.scrollId = ko.observable<string>("addEntityScroll");
}
public submit() {
if (!this.canApply()) {
return;
}
let entity: Entities.ITableEntity = this.entityFromAttributes(this.displayedAttributes());
this.container.tableDataClient
.createDocument(this.tableViewModel.queryTablesTab.collection, entity)
.then((newEntity: Entities.ITableEntity) => {
this.tableViewModel.addEntityToCache(newEntity).then(() => {
if (!this.tryInsertNewHeaders(this.tableViewModel, newEntity)) {
this.tableViewModel.redrawTableThrottled();
}
});
this.close();
});
}
public open() {
var headers = this.tableViewModel.headers;
if (DataTableUtilities.checkForDefaultHeader(headers)) {
headers = [];
if (this.container.isPreferredApiTable()) {
headers = [TableConstants.EntityKeyNames.PartitionKey, TableConstants.EntityKeyNames.RowKey];
}
}
if (userContext.apiType === "Cassandra") {
(<CassandraAPIDataClient>this.container.tableDataClient)
.getTableSchema(this.tableViewModel.queryTablesTab.collection)
.then((columns: CassandraTableKey[]) => {
this.displayedAttributes(
this.constructDisplayedAttributes(
columns.map((col) => col.property),
Utilities.getDataTypesFromCassandraSchema(columns)
)
);
this.updateIsActionEnabled();
super.open();
this.focusValueElement();
});
} else {
this.displayedAttributes(
this.constructDisplayedAttributes(
headers,
Utilities.getDataTypesFromEntities(headers, this.tableViewModel.items())
)
);
this.updateIsActionEnabled();
super.open();
this.focusValueElement();
}
}
private focusValueElement() {
const focusElement = document.getElementById("addTableEntityValue");
focusElement && focusElement.focus();
}
private constructDisplayedAttributes(headers: string[], dataTypes: any): EntityPropertyViewModel[] {
var displayedAttributes: EntityPropertyViewModel[] = [];
headers &&
headers.forEach((key: string) => {
if (!_.contains<string>(AddTableEntityPane._excludedFields, key)) {
if (userContext.apiType === "Cassandra") {
const cassandraKeys = this.tableViewModel.queryTablesTab.collection.cassandraKeys.partitionKeys
.concat(this.tableViewModel.queryTablesTab.collection.cassandraKeys.clusteringKeys)
.map((key) => key.property);
var isRequired: boolean = _.contains<string>(cassandraKeys, key);
var editable: boolean = false;
var placeholderLabel: string = isRequired ? this.enterRequiredValueLabel : this.enterValueLabel;
var entityAttributeType: string = dataTypes[key] || TableConstants.CassandraType.Text; // Default to String if there is no type specified.
// TODO figure out validation story for blob and Inet so we can allow adding/editing them
const nonEditableType: boolean =
entityAttributeType === TableConstants.CassandraType.Blob ||
entityAttributeType === TableConstants.CassandraType.Inet;
var entity: EntityPropertyViewModel = new EntityPropertyViewModel(
this,
key,
entityAttributeType,
"", // default to empty string
/* namePlaceholder */ undefined,
nonEditableType ? "Type is not editable via DataExplorer." : placeholderLabel,
editable,
/* default valid name */ true,
/* default valid value */ true,
/* required value */ isRequired,
/* removable */ false,
/* valueEditable */ !nonEditableType,
/* ignoreEmptyValue */ true
);
} else {
var isRequired: boolean = _.contains<string>(AddTableEntityPane.requiredFieldsForTablesAPI, key);
var editable: boolean = !_.contains<string>(AddTableEntityPane._readonlyFields, key);
var placeholderLabel: string = isRequired ? this.enterRequiredValueLabel : this.enterValueLabel;
var entityAttributeType: string = dataTypes[key] || TableConstants.TableType.String; // Default to String if there is no type specified.
var entity: EntityPropertyViewModel = new EntityPropertyViewModel(
this,
key,
entityAttributeType,
"", // default to empty string
/* namePlaceholder */ undefined,
placeholderLabel,
editable,
/* default valid name */ true,
/* default valid value */ true,
/* required value */ isRequired,
/* removable */ editable,
/* valueEditable */ true,
/* ignoreEmptyValue */ true
);
}
displayedAttributes.push(entity);
}
});
return displayedAttributes;
}
}

View File

@ -0,0 +1,49 @@
import { mount } from "enzyme";
import * as ko from "knockout";
import React from "react";
import Explorer from "../../Explorer";
import TableListViewModal from "../../Tables/DataTable/TableEntityListViewModel";
import * as Entities from "../../Tables/Entities";
import { CassandraAPIDataClient } from "../../Tables/TableDataClient";
import QueryTablesTab from "../../Tabs/QueryTablesTab";
import { AddTableEntityPanel } from "./AddTableEntityPanel";
describe("Excute Add Table Entity Pane", () => {
const fakeExplorer = {} as Explorer;
const fakeQueryTablesTab = {} as QueryTablesTab;
const fakeTableEntityListViewModel = {} as TableListViewModal;
const fakeCassandraApiClient = {} as CassandraAPIDataClient;
fakeTableEntityListViewModel.items = ko.observableArray<Entities.ITableEntity>();
fakeTableEntityListViewModel.headers = [];
const props = {
explorer: fakeExplorer,
closePanel: (): void => undefined,
queryTablesTab: fakeQueryTablesTab,
tableEntityListViewModel: fakeTableEntityListViewModel,
cassandraApiClient: fakeCassandraApiClient,
};
it("should render Default properly", () => {
const wrapper = mount(<AddTableEntityPanel {...props} />);
expect(wrapper).toMatchSnapshot();
});
it("initially display 4 input field, 2 properties and 2 entity values", () => {
const wrapper = mount(<AddTableEntityPanel {...props} />);
expect(wrapper.find("input[type='text']")).toHaveLength(0);
});
it("add a new entity row", () => {
const wrapper = mount(<AddTableEntityPanel {...props} />);
wrapper.find(".addButtonEntiy").last().simulate("click");
expect(wrapper.find("input[type='text']")).toHaveLength(1);
});
it("remove a entity field", () => {
const wrapper = mount(<AddTableEntityPanel {...props} />);
// Since default entity row doesn't have delete option, so added row then delete for test cases.
wrapper.find(".addButtonEntiy").last().simulate("click");
wrapper.find("#deleteEntity").last().simulate("click");
expect(wrapper.find("input[type='text']")).toHaveLength(0);
});
});

View File

@ -0,0 +1,324 @@
import { useBoolean } from "@uifabric/react-hooks";
import {
IDropdownOption,
Image,
IPanelProps,
IRenderFunction,
Label,
Stack,
Text,
TextField,
} from "office-ui-fabric-react";
import React, { FunctionComponent, useEffect, useState } from "react";
import * as _ from "underscore";
import AddPropertyIcon from "../../../../images/Add-property.svg";
import RevertBackIcon from "../../../../images/RevertBack.svg";
import { TableEntity } from "../../../Common/TableEntity";
import { userContext } from "../../../UserContext";
import Explorer from "../../Explorer";
import * as TableConstants from "../../Tables/Constants";
import * as DataTableUtilities from "../../Tables/DataTable/DataTableUtilities";
import TableEntityListViewModel from "../../Tables/DataTable/TableEntityListViewModel";
import * as Entities from "../../Tables/Entities";
import { CassandraAPIDataClient, CassandraTableKey } from "../../Tables/TableDataClient";
import * as TableEntityProcessor from "../../Tables/TableEntityProcessor";
import * as Utilities from "../../Tables/Utilities";
import QueryTablesTab from "../../Tabs/QueryTablesTab";
import { PanelContainerComponent } from "../PanelContainerComponent";
import {
attributeNameLabel,
attributeValueLabel,
backImageProps,
cassandraOptions,
columnProps,
dataTypeLabel,
detailedHelp,
entityFromAttributes,
getAddButtonLabel,
getButtonLabel,
getCassandraDefaultEntities,
getDefaultEntities,
getEntityValuePlaceholder,
getPanelTitle,
imageProps,
isValidEntities,
options,
} from "./Validators/EntityTableHelper";
interface AddTableEntityPanelProps {
explorer: Explorer;
closePanel: () => void;
queryTablesTab: QueryTablesTab;
tableEntityListViewModel: TableEntityListViewModel;
cassandraApiClient: CassandraAPIDataClient;
}
interface EntityRowType {
property: string;
type: string;
value: string;
isPropertyTypeDisable: boolean;
isDeleteOptionVisible: boolean;
id: number;
entityValuePlaceholder: string;
isEntityTypeDate: boolean;
entityTimeValue?: string;
}
export const AddTableEntityPanel: FunctionComponent<AddTableEntityPanelProps> = ({
explorer,
closePanel,
queryTablesTab,
tableEntityListViewModel,
cassandraApiClient,
}: AddTableEntityPanelProps): JSX.Element => {
const [entities, setEntities] = useState<EntityRowType[]>([]);
const [selectedRow, setSelectedRow] = useState<number>(0);
const [entityAttributeValue, setEntityAttributeValue] = useState<string>("");
const [entityAttributeProperty, setEntityAttributeProperty] = useState<string>("");
const [
isEntityValuePanelOpen,
{ setTrue: setIsEntityValuePanelTrue, setFalse: setIsEntityValuePanelFalse },
] = useBoolean(false);
/* Get default and previous saved entity headers */
useEffect(() => {
getDefaultEntitiesAttribute();
}, []);
const getDefaultEntitiesAttribute = async (): Promise<void> => {
let headers = tableEntityListViewModel.headers;
if (DataTableUtilities.checkForDefaultHeader(headers)) {
headers = [];
if (userContext.apiType === "Tables") {
headers = [TableConstants.EntityKeyNames.PartitionKey, TableConstants.EntityKeyNames.RowKey];
}
}
if (userContext.apiType === "Cassandra") {
const columns: CassandraTableKey[] = await cassandraApiClient.getTableSchema(queryTablesTab.collection);
const cassandraEntities = Utilities.getDataTypesFromCassandraSchema(columns);
const cassandraDefaultEntities: EntityRowType[] = getCassandraDefaultEntities(headers, cassandraEntities);
setEntities(cassandraDefaultEntities);
} else {
const entityItems = tableEntityListViewModel.items();
const entityTypes = Utilities.getDataTypesFromEntities(headers, entityItems);
const defaultEntities: EntityRowType[] = getDefaultEntities(headers, entityTypes);
setEntities(defaultEntities);
}
};
/* Add new entity attribute */
const submit = async (event: React.FormEvent<HTMLInputElement>): Promise<void> => {
if (!isValidEntities(entities)) {
return undefined;
}
event.preventDefault();
const entity: Entities.ITableEntity = entityFromAttributes(entities);
const newEntity: Entities.ITableEntity = await explorer.tableDataClient.createDocument(
queryTablesTab.collection,
entity
);
await tableEntityListViewModel.addEntityToCache(newEntity);
if (!tryInsertNewHeaders(tableEntityListViewModel, newEntity)) {
tableEntityListViewModel.redrawTableThrottled();
}
closePanel();
};
const tryInsertNewHeaders = (viewModel: TableEntityListViewModel, newEntity: Entities.ITableEntity): boolean => {
let newHeaders: string[] = [];
const keys = Object.keys(newEntity);
keys &&
keys.forEach((key: string) => {
if (
!_.contains(viewModel.headers, key) &&
key !== TableEntityProcessor.keyProperties.attachments &&
key !== TableEntityProcessor.keyProperties.etag &&
key !== TableEntityProcessor.keyProperties.resourceId &&
key !== TableEntityProcessor.keyProperties.self &&
(!(userContext.apiType === "Cassandra") || key !== TableConstants.EntityKeyNames.RowKey)
) {
newHeaders.push(key);
}
});
let newHeadersInserted = false;
if (newHeaders.length) {
if (!DataTableUtilities.checkForDefaultHeader(viewModel.headers)) {
newHeaders = viewModel.headers.concat(newHeaders);
}
viewModel.updateHeaders(newHeaders, /* notifyColumnChanges */ true, /* enablePrompt */ false);
newHeadersInserted = true;
}
return newHeadersInserted;
};
/* Add new entity row */
const addNewEntity = (): void => {
const cloneEntities: EntityRowType[] = [...entities];
cloneEntities.splice(cloneEntities.length, 0, {
property: "",
type: "String",
value: "",
isPropertyTypeDisable: false,
isDeleteOptionVisible: true,
id: cloneEntities.length + 1,
entityValuePlaceholder: "",
isEntityTypeDate: false,
});
setEntities(cloneEntities);
};
/* Delete entity row */
const deleteEntityAtIndex = (indexToRemove: number): void => {
const cloneEntities: EntityRowType[] = [...entities];
cloneEntities.splice(indexToRemove, 1);
setEntities(cloneEntities);
};
/* handle Entity change */
const entityChange = (value: string | Date, indexOfInput: number, key: string): void => {
const cloneEntities: EntityRowType[] = [...entities];
if (key === "property") {
cloneEntities[indexOfInput].property = value.toString();
} else if (key === "time") {
cloneEntities[indexOfInput].entityTimeValue = value.toString();
} else {
cloneEntities[indexOfInput].value = value.toString();
}
setEntities(cloneEntities);
};
/* handle Entity type */
const entityTypeChange = (
_event: React.FormEvent<HTMLDivElement>,
selectedType: IDropdownOption,
indexOfEntity: number
): void => {
const entityValuePlaceholder: string = getEntityValuePlaceholder(selectedType.key);
const cloneEntities: EntityRowType[] = [...entities];
cloneEntities[indexOfEntity].type = selectedType.key.toString();
cloneEntities[indexOfEntity].entityValuePlaceholder = entityValuePlaceholder;
cloneEntities[indexOfEntity].isEntityTypeDate = selectedType.key === "DateTime";
setEntities(cloneEntities);
};
/* Open edit entity value modal */
const editEntity = (rowEndex: number): void => {
const entityAttribute: EntityRowType = entities[rowEndex] && entities[rowEndex];
setEntityAttributeValue(entityAttribute.value);
setEntityAttributeProperty(entityAttribute.property);
setSelectedRow(rowEndex);
setIsEntityValuePanelTrue();
};
const renderPanelContent = (): JSX.Element => {
return (
<form className="panelFormWrapper">
<div className="panelFormWrapper">
<div className="panelMainContent">
{entities.map((entity, index) => {
return (
<TableEntity
key={"" + entity.id + index}
isDeleteOptionVisible={entity.isDeleteOptionVisible}
entityTypeLabel={index === 0 && dataTypeLabel}
entityPropertyLabel={index === 0 && attributeNameLabel}
entityValueLabel={index === 0 && attributeValueLabel}
options={userContext.apiType === "Cassandra" ? cassandraOptions : options}
isPropertyTypeDisable={entity.isPropertyTypeDisable}
entityProperty={entity.property}
selectedKey={entity.type}
entityPropertyPlaceHolder={detailedHelp}
entityValuePlaceholder={entity.entityValuePlaceholder}
entityValue={entity.value}
isEntityTypeDate={entity.isEntityTypeDate}
entityTimeValue={entity.entityTimeValue}
onEditEntity={() => editEntity(index)}
onSelectDate={(date: Date) => {
entityChange(date, index, "value");
}}
onDeleteEntity={() => deleteEntityAtIndex(index)}
onEntityPropertyChange={(event, newInput?: string) => {
entityChange(newInput, index, "property");
}}
onEntityTypeChange={(event: React.FormEvent<HTMLDivElement>, selectedParam: IDropdownOption) => {
entityTypeChange(event, selectedParam, index);
}}
onEntityValueChange={(event, newInput?: string) => {
entityChange(newInput, index, "value");
}}
onEntityTimeValueChange={(event, newInput?: string) => {
entityChange(newInput, index, "time");
}}
/>
);
})}
{userContext.apiType !== "Cassandra" && (
<Stack horizontal onClick={addNewEntity} className="addButtonEntiy">
<Image {...imageProps} src={AddPropertyIcon} alt="Add Entity" />
<Text className="addNewParamStyle">{getAddButtonLabel(userContext.apiType)}</Text>
</Stack>
)}
</div>
<div className="paneFooter">
<div className="leftpanel-okbut">
<input
type="submit"
onClick={submit}
className="genericPaneSubmitBtn"
value={getButtonLabel(userContext.apiType)}
/>
</div>
</div>
</div>
</form>
);
};
const onRenderNavigationContent: IRenderFunction<IPanelProps> = () => {
return (
<Stack horizontal {...columnProps}>
<Image {...backImageProps} src={RevertBackIcon} alt="back" onClick={() => setIsEntityValuePanelFalse()} />
<Label>{entityAttributeProperty}</Label>
</Stack>
);
};
if (isEntityValuePanelOpen) {
return (
<PanelContainerComponent
headerText=""
onRenderNavigationContent={onRenderNavigationContent}
panelWidth="700px"
isOpen={true}
panelContent={
<TextField
multiline
rows={5}
className="entityValueTextField"
value={entityAttributeValue}
onChange={(event, newInput?: string) => {
entityChange(newInput, selectedRow, "value");
setEntityAttributeValue(newInput);
}}
/>
}
closePanel={() => closePanel()}
isConsoleExpanded={false}
/>
);
}
return (
<PanelContainerComponent
headerText={getPanelTitle(userContext.apiType)}
panelWidth="700px"
isOpen={true}
panelContent={renderPanelContent()}
closePanel={() => closePanel()}
isConsoleExpanded={false}
/>
);
};

View File

@ -0,0 +1,247 @@
import { IImageProps, IStackProps } from "office-ui-fabric-react";
import * as _ from "underscore";
import * as TableConstants from "../../../Tables/Constants";
import * as Entities from "../../../Tables/Entities";
import * as Utilities from "../../../Tables/Utilities";
export const defaultStringPlaceHolder = "Enter identifier value.";
export const defaultEntities = [
{
property: "PartitionKey",
type: "String",
value: "",
isPropertyTypeDisable: true,
isDeleteOptionVisible: false,
id: 1,
entityValuePlaceholder: defaultStringPlaceHolder,
isEntityTypeDate: false,
},
{
property: "RowKey",
type: "String",
value: "",
isPropertyTypeDisable: true,
isDeleteOptionVisible: false,
id: 2,
entityValuePlaceholder: defaultStringPlaceHolder,
isEntityTypeDate: false,
},
];
// Dropdown options
const { String, Boolean, Binary, DateTime, Double, Guid, Int32, Int64 } = TableConstants.TableType;
export const options = [
{ key: String, text: String },
{ key: Boolean, text: Boolean },
{ key: Binary, text: Binary, disabled: true },
{ key: DateTime, text: DateTime },
{ key: Double, text: Double },
{ key: Guid, text: Guid },
{ key: Int32, text: Int32 },
{ key: Int64, text: Int64 },
];
const {
Text,
Ascii,
Bigint,
Blob,
Decimal,
Float,
Int,
Uuid,
Varchar,
Varint,
Inet,
Smallint,
Tinyint,
} = TableConstants.CassandraType;
export const cassandraOptions = [
{ key: Text, text: Text },
{ key: Ascii, text: Ascii },
{ key: Bigint, text: Bigint },
{ key: Blob, text: Blob },
{ key: Boolean, text: Boolean },
{ key: Decimal, text: Decimal },
{ key: Double, text: Double },
{ key: Float, text: Float },
{ key: Int, text: Int },
{ key: Uuid, text: Uuid },
{ key: Varchar, text: Varchar },
{ key: Varint, text: Varint },
{ key: Inet, text: Inet },
{ key: Smallint, text: Smallint },
{ key: Tinyint, text: Tinyint },
];
export const imageProps: IImageProps = {
width: 16,
height: 30,
};
export const backImageProps: IImageProps = {
width: 16,
height: 16,
className: "backImageIcon",
};
/* Labels */
export const attributeNameLabel = "Property Name";
export const dataTypeLabel = "Type";
export const attributeValueLabel = "Value";
export const addButtonLabel = "Add Property";
// add table entity placeholders
export const detailedHelp = "Enter a name up to 255 characters in size. Most valid C# identifiers are allowed.";
export const booleanPlaceHolder = "Enter true or false.";
export const stringPlaceholder = "Enter a value up to 64 KB in size.";
export const datePlaceholder = "Enter a date and time.";
export const doublePlaceholder = "Enter a 64-bit floating point value.";
export const guidPlaceholder = "Enter a 16-byte (128-bit) GUID value.";
export const intPlaceholder = "Enter a signed 32-bit integer.";
export const int64Placeholder = "Enter a signed 64-bit integer, in the range (-2^53 - 1, 2^53 - 1).";
export const columnProps: Partial<IStackProps> = {
tokens: { childrenGap: 10 },
styles: { root: { width: 680 } },
};
// helper functions
export const entityFromAttributes = (entities: EntityRowType[]): Entities.ITableEntity => {
const entity: { [key: string]: { _: string; $: string } } = {};
entities.forEach((entityRow: EntityRowType) => {
if (entityRow) {
let value = entityRow.value;
if (entityRow.type === TableConstants.TableType.DateTime && entityRow.entityTimeValue) {
// Add time in date as time has seperate textfield
const [hours, minuntes] = entityRow.entityTimeValue.split(":");
const entityDate = new Date(value);
entityDate.setHours(+hours);
entityDate.setMinutes(+minuntes);
value = entityDate.toString();
}
if (entityRow.type === TableConstants.TableType.Int64) {
value = Utilities.padLongWithZeros(value);
}
entity[entityRow.property] = {
_: value,
$: entityRow.type,
};
}
});
return entity;
};
// GetPlaceholder according to entity type
export const getEntityValuePlaceholder = (entityType: string | number): string => {
switch (entityType) {
case "String":
return stringPlaceholder;
case "Boolean":
return booleanPlaceHolder;
case "DateTime":
return datePlaceholder;
case "Double":
return doublePlaceholder;
case "Guid":
return guidPlaceholder;
case "Int32":
return intPlaceholder;
case "Int64":
return int64Placeholder;
default:
return "";
}
};
export const isValidEntities = (entities: EntityRowType[]): boolean => {
for (let i = 0; i < entities.length; i++) {
const { property } = entities[i];
if (property === "" || property === undefined) {
return false;
}
}
return true;
};
const isEntityPropertyTypeDisable = (header: string): boolean => {
if (header === "PartitionKey" || header === "RowKey") {
return true;
}
return false;
};
export const getDefaultEntities = (headers: string[], entityTypes: { [key: string]: string }): EntityRowType[] => {
const defaultEntities: EntityRowType[] = [];
headers.forEach((header: string) => {
if (header !== "Timestamp") {
const entityType = !_.isEmpty(entityTypes) ? entityTypes[header] : "String";
const entityRow = {
property: header,
type: entityType,
value: "",
isPropertyTypeDisable: isEntityPropertyTypeDisable(header),
isDeleteOptionVisible: !isEntityPropertyTypeDisable(header),
id: 1,
entityValuePlaceholder: defaultStringPlaceHolder,
isEntityTypeDate: entityType === "DateTime",
};
defaultEntities.push(entityRow);
}
});
return defaultEntities;
};
export const getPanelTitle = (apiType: string): string => {
if (apiType === "Cassandra") {
return "Add Table Row";
}
return "Add Table Row";
};
export const getAddButtonLabel = (apiType: string): string => {
if (apiType === "Cassandra") {
return "Add Row";
}
return addButtonLabel;
};
export const getButtonLabel = (apiType: string): string => {
if (apiType === "Cassandra") {
return "Add Row";
}
return "Add Entity";
};
export const getCassandraDefaultEntities = (
headers: string[],
entityTypes: { [key: string]: string }
): EntityRowType[] => {
const defaultEntities: EntityRowType[] = [];
headers.forEach((header: string) => {
const entityRow = {
property: header,
type: entityTypes[header],
value: "",
isPropertyTypeDisable: true,
isDeleteOptionVisible: true,
id: 1,
entityValuePlaceholder: defaultStringPlaceHolder,
isEntityTypeDate: entityTypes[header] === "DateTime",
};
defaultEntities.push(entityRow);
});
return defaultEntities;
};
// Type of entity row
export interface EntityRowType {
property: string;
type: string;
value: string;
isPropertyTypeDisable: boolean;
isDeleteOptionVisible: boolean;
id: number;
entityValuePlaceholder: string;
isEntityTypeDate: boolean;
entityTimeValue?: string;
}

File diff suppressed because it is too large Load Diff

View File

@ -153,42 +153,6 @@ exports[`Upload Items Pane should render Default properly 1`] = `
"title": [Function], "title": [Function],
"visible": [Function], "visible": [Function],
}, },
AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
EditTableEntityPane { EditTableEntityPane {
"addButtonLabel": "Add Property", "addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name", "attributeNameLabel": "Property Name",
@ -429,42 +393,6 @@ exports[`Upload Items Pane should render Default properly 1`] = `
"visible": [Function], "visible": [Function],
}, },
"addDatabaseText": [Function], "addDatabaseText": [Function],
"addTableEntityPane": AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
"arcadiaToken": [Function], "arcadiaToken": [Function],
"canExceedMaximumValue": [Function], "canExceedMaximumValue": [Function],
"canSaveQueries": [Function], "canSaveQueries": [Function],

View File

@ -154,42 +154,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
"title": [Function], "title": [Function],
"visible": [Function], "visible": [Function],
}, },
AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
EditTableEntityPane { EditTableEntityPane {
"addButtonLabel": "Add Property", "addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name", "attributeNameLabel": "Property Name",
@ -430,42 +394,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
"visible": [Function], "visible": [Function],
}, },
"addDatabaseText": [Function], "addDatabaseText": [Function],
"addTableEntityPane": AddTableEntityPane {
"addButtonLabel": "Add Property",
"attributeNameLabel": "Property Name",
"attributeValueLabel": "Value",
"canAdd": [Function],
"canApply": [Function],
"container": [Circular],
"dataTypeLabel": "Type",
"displayedAttributes": [Function],
"editAttribute": [Function],
"editButtonLabel": "Edit",
"editingProperty": [Function],
"edmTypes": [Function],
"enterRequiredValueLabel": "Enter identifier value.",
"enterValueLabel": "Enter value to keep property.",
"finishEditingAttribute": [Function],
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"id": "addtableentitypane",
"insertAttribute": [Function],
"isEditing": [Function],
"isExecuting": [Function],
"isTemplateReady": [Function],
"onAddPropertyKeyDown": [Function],
"onBackButtonKeyDown": [Function],
"onDeletePropertyKeyDown": [Function],
"onEditPropertyKeyDown": [Function],
"onKeyUp": [Function],
"removeAttribute": [Function],
"removeButtonLabel": "Remove",
"scrollId": [Function],
"submitButtonText": [Function],
"title": [Function],
"visible": [Function],
},
"arcadiaToken": [Function], "arcadiaToken": [Function],
"canExceedMaximumValue": [Function], "canExceedMaximumValue": [Function],
"canSaveQueries": [Function], "canSaveQueries": [Function],

View File

@ -146,8 +146,7 @@ export default class QueryTablesTab extends TabsBase {
}; };
public onAddEntityClick = (): Q.Promise<any> => { public onAddEntityClick = (): Q.Promise<any> => {
this.container.addTableEntityPane.tableViewModel = this.tableEntityListViewModel(); this.container.openAddTableEntityPanel(this, this.tableEntityListViewModel());
this.container.addTableEntityPane.open();
return null; return null;
}; };

View File

@ -234,7 +234,6 @@ const App: React.FunctionComponent = () => {
<div data-bind='component: { name: "add-collection-pane", params: { data: addCollectionPane} }' /> <div data-bind='component: { name: "add-collection-pane", params: { data: addCollectionPane} }' />
<div data-bind='component: { name: "graph-new-vertex-pane", params: { data: newVertexPane} }' /> <div data-bind='component: { name: "graph-new-vertex-pane", params: { data: newVertexPane} }' />
<div data-bind='component: { name: "graph-styling-pane", params: { data: graphStylingPane} }' /> <div data-bind='component: { name: "graph-styling-pane", params: { data: graphStylingPane} }' />
<div data-bind='component: { name: "table-add-entity-pane", params: { data: addTableEntityPane} }' />
<div data-bind='component: { name: "table-edit-entity-pane", params: { data: editTableEntityPane} }' /> <div data-bind='component: { name: "table-edit-entity-pane", params: { data: editTableEntityPane} }' />
<div data-bind='component: { name: "cassandra-add-collection-pane", params: { data: cassandraAddCollectionPane} }' /> <div data-bind='component: { name: "cassandra-add-collection-pane", params: { data: cassandraAddCollectionPane} }' />
<div data-bind='component: { name: "string-input-pane", params: { data: stringInputPane} }' /> <div data-bind='component: { name: "string-input-pane", params: { data: stringInputPane} }' />