diff --git a/src/Common/EntityValue.tsx b/src/Common/EntityValue.tsx index 16d95a007..14a7af964 100644 --- a/src/Common/EntityValue.tsx +++ b/src/Common/EntityValue.tsx @@ -6,6 +6,7 @@ export interface TableEntityProps { entityValuePlaceholder: string; entityValue: string | Date; isEntityTypeDate: boolean; + isEntityValueDisable?: boolean; entityTimeValue: string; entityValueType: string; onEntityValueChange: (event: React.FormEvent, newInput?: string) => void; @@ -22,6 +23,7 @@ export const EntityValue: FunctionComponent = ({ entityValueType, onEntityValueChange, onSelectDate, + isEntityValueDisable, onEntityTimeValueChange, }: TableEntityProps): JSX.Element => { if (isEntityTypeDate) { @@ -33,6 +35,7 @@ export const EntityValue: FunctionComponent = ({ value={entityValue && new Date(entityValue)} ariaLabel={entityValuePlaceholder} onSelectDate={onSelectDate} + disabled={isEntityValueDisable} /> = ({ type="time" value={entityTimeValue} onChange={onEntityTimeValueChange} + disabled={isEntityValueDisable} /> ); @@ -52,6 +56,7 @@ export const EntityValue: FunctionComponent = ({ className="addEntityTextField" id="entityValueId" autoFocus + disabled={isEntityValueDisable} type={entityValueType} placeholder={entityValuePlaceholder} value={typeof entityValue === "string" && entityValue} diff --git a/src/Common/TableEntity.tsx b/src/Common/TableEntity.tsx index 864929752..469a1b938 100644 --- a/src/Common/TableEntity.tsx +++ b/src/Common/TableEntity.tsx @@ -32,6 +32,7 @@ export interface TableEntityProps { options: { key: string; text: string }[]; isPropertyTypeDisable: boolean; entityTimeValue: string; + isEntityValueDisable?: boolean; onDeleteEntity?: () => void; onEditEntity?: () => void; onEntityPropertyChange: (event: React.FormEvent, newInput?: string) => void; @@ -55,6 +56,7 @@ export const TableEntity: FunctionComponent = ({ isPropertyTypeDisable, isEntityTypeDate, entityTimeValue, + isEntityValueDisable, onEditEntity, onDeleteEntity, onEntityPropertyChange, @@ -113,6 +115,7 @@ export const TableEntity: FunctionComponent = ({ = ({ onSelectDate={onSelectDate} onEntityTimeValueChange={onEntityTimeValueChange} /> - - editEntity - - + {!isEntityValueDisable && ( + + editEntity + + )} {isDeleteOptionVisible && userContext.apiType !== "Cassandra" && ( delete entity diff --git a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap index 4fde12349..790b14b95 100644 --- a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap +++ b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap @@ -177,40 +177,6 @@ exports[`SettingsComponent renders 1`] = ` "title": [Function], "visible": [Function], }, - EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, CassandraAddCollectionPane { "autoPilotUsageCost": [Function], "canConfigureThroughput": [Function], @@ -479,40 +445,6 @@ exports[`SettingsComponent renders 1`] = ` "defaultExperience": [Function], "deleteCollectionText": [Function], "deleteDatabaseText": [Function], - "editTableEntityPane": EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, "graphStylingPane": GraphStylingPane { "container": [Circular], "firstFieldHasFocus": [Function], @@ -805,40 +737,6 @@ exports[`SettingsComponent renders 1`] = ` "title": [Function], "visible": [Function], }, - EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, CassandraAddCollectionPane { "autoPilotUsageCost": [Function], "canConfigureThroughput": [Function], @@ -1107,40 +1005,6 @@ exports[`SettingsComponent renders 1`] = ` "defaultExperience": [Function], "deleteCollectionText": [Function], "deleteDatabaseText": [Function], - "editTableEntityPane": EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, "graphStylingPane": GraphStylingPane { "container": [Circular], "firstFieldHasFocus": [Function], @@ -1446,40 +1310,6 @@ exports[`SettingsComponent renders 1`] = ` "title": [Function], "visible": [Function], }, - EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, CassandraAddCollectionPane { "autoPilotUsageCost": [Function], "canConfigureThroughput": [Function], @@ -1748,40 +1578,6 @@ exports[`SettingsComponent renders 1`] = ` "defaultExperience": [Function], "deleteCollectionText": [Function], "deleteDatabaseText": [Function], - "editTableEntityPane": EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, "graphStylingPane": GraphStylingPane { "container": [Circular], "firstFieldHasFocus": [Function], @@ -2074,40 +1870,6 @@ exports[`SettingsComponent renders 1`] = ` "title": [Function], "visible": [Function], }, - EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, CassandraAddCollectionPane { "autoPilotUsageCost": [Function], "canConfigureThroughput": [Function], @@ -2376,40 +2138,6 @@ exports[`SettingsComponent renders 1`] = ` "defaultExperience": [Function], "deleteCollectionText": [Function], "deleteDatabaseText": [Function], - "editTableEntityPane": EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, "graphStylingPane": GraphStylingPane { "container": [Circular], "firstFieldHasFocus": [Function], diff --git a/src/Explorer/Explorer.tsx b/src/Explorer/Explorer.tsx index 32fb23038..09bf3c433 100644 --- a/src/Explorer/Explorer.tsx +++ b/src/Explorer/Explorer.tsx @@ -66,7 +66,7 @@ import { SettingsPane } from "./Panes/SettingsPane/SettingsPane"; import { SetupNoteBooksPanel } from "./Panes/SetupNotebooksPanel/SetupNotebooksPanel"; import { StringInputPane } from "./Panes/StringInputPane"; import { AddTableEntityPanel } from "./Panes/Tables/AddTableEntityPanel"; -import EditTableEntityPane from "./Panes/Tables/EditTableEntityPane"; +import { EditTableEntityPanel } from "./Panes/Tables/EditTableEntityPanel"; import { TableQuerySelectPanel } from "./Panes/Tables/TableQuerySelectPanel"; import { UploadFilePane } from "./Panes/UploadFilePane/UploadFilePane"; import { UploadItemsPane } from "./Panes/UploadItemsPane/UploadItemsPane"; @@ -173,7 +173,6 @@ export default class Explorer { public addDatabasePane: AddDatabasePane; public addCollectionPane: AddCollectionPane; public graphStylingPane: GraphStylingPane; - public editTableEntityPane: EditTableEntityPane; public cassandraAddCollectionPane: CassandraAddCollectionPane; public stringInputPane: StringInputPane; public gitHubReposPane: ContextualPaneBase; @@ -500,13 +499,6 @@ export default class Explorer { container: this, }); - this.editTableEntityPane = new EditTableEntityPane({ - id: "edittableentitypane", - visible: ko.observable(false), - - container: this, - }); - this.cassandraAddCollectionPane = new CassandraAddCollectionPane({ id: "cassandraaddcollectionpane", visible: ko.observable(false), @@ -533,7 +525,6 @@ export default class Explorer { this.addDatabasePane, this.addCollectionPane, this.graphStylingPane, - this.editTableEntityPane, this.cassandraAddCollectionPane, this.stringInputPane, ]; @@ -604,7 +595,6 @@ export default class Explorer { this.addCollectionPane.collectionIdTitle("Table id"); this.addCollectionPane.collectionWithThroughputInSharedTitle("Provision dedicated throughput for this table"); this.refreshTreeTitle("Refresh tables"); - this.editTableEntityPane.title("Edit Table Entity"); this.tableDataClient = new TablesAPIDataClient(); break; case "Cassandra": @@ -618,7 +608,6 @@ export default class Explorer { this.addCollectionPane.collectionIdTitle("Table id"); this.addCollectionPane.collectionWithThroughputInSharedTitle("Provision dedicated throughput for this table"); this.refreshTreeTitle("Refresh tables"); - this.editTableEntityPane.title("Edit Table Row"); this.tableDataClient = new CassandraAPIDataClient(); break; } @@ -2211,6 +2200,19 @@ export default class Explorer { ); } + public openEditTableEntityPanel(queryTablesTab: QueryTablesTab, tableEntityListViewModel: TableListViewModal): void { + this.openSidePanel( + "Edit Table Entity", + + ); + } + public openTableSelectQueryPanel(queryViewModal: QueryViewModel): void { this.openSidePanel( "Select Column", diff --git a/src/Explorer/Panes/SettingsPane/__snapshots__/SettingsPane.test.tsx.snap b/src/Explorer/Panes/SettingsPane/__snapshots__/SettingsPane.test.tsx.snap index 5602cffff..7d961e918 100644 --- a/src/Explorer/Panes/SettingsPane/__snapshots__/SettingsPane.test.tsx.snap +++ b/src/Explorer/Panes/SettingsPane/__snapshots__/SettingsPane.test.tsx.snap @@ -153,40 +153,6 @@ exports[`Settings Pane should render Default properly 1`] = ` "title": [Function], "visible": [Function], }, - EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, CassandraAddCollectionPane { "autoPilotUsageCost": [Function], "canConfigureThroughput": [Function], @@ -455,40 +421,6 @@ exports[`Settings Pane should render Default properly 1`] = ` "defaultExperience": [Function], "deleteCollectionText": [Function], "deleteDatabaseText": [Function], - "editTableEntityPane": EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, "graphStylingPane": GraphStylingPane { "container": [Circular], "firstFieldHasFocus": [Function], @@ -904,40 +836,6 @@ exports[`Settings Pane should render Gremlin properly 1`] = ` "title": [Function], "visible": [Function], }, - EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, CassandraAddCollectionPane { "autoPilotUsageCost": [Function], "canConfigureThroughput": [Function], @@ -1206,40 +1104,6 @@ exports[`Settings Pane should render Gremlin properly 1`] = ` "defaultExperience": [Function], "deleteCollectionText": [Function], "deleteDatabaseText": [Function], - "editTableEntityPane": EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, "graphStylingPane": GraphStylingPane { "container": [Circular], "firstFieldHasFocus": [Function], diff --git a/src/Explorer/Panes/Tables/EditTableEntityPanel.test.tsx b/src/Explorer/Panes/Tables/EditTableEntityPanel.test.tsx new file mode 100644 index 000000000..fa5a26885 --- /dev/null +++ b/src/Explorer/Panes/Tables/EditTableEntityPanel.test.tsx @@ -0,0 +1,51 @@ +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 { EditTableEntityPanel } from "./EditTableEntityPanel"; + +describe("Excute Edit Table Entity Pane", () => { + const fakeExplorer = {} as Explorer; + const fakeQueryTablesTab = {} as QueryTablesTab; + const fakeTableEntityListViewModel = {} as TableListViewModal; + fakeTableEntityListViewModel.items = ko.observableArray(); + const fakeCassandraApiClient = {} as CassandraAPIDataClient; + fakeTableEntityListViewModel.headers = []; + fakeTableEntityListViewModel.selected = ko.observableArray([{}]); + + const props = { + explorer: fakeExplorer, + closePanel: (): void => undefined, + queryTablesTab: fakeQueryTablesTab, + tableEntityListViewModel: fakeTableEntityListViewModel, + cassandraApiClient: fakeCassandraApiClient, + }; + + it("should render Default properly", () => { + const wrapper = mount(); + expect(wrapper).toMatchSnapshot(); + }); + + it("initially display 4 input field, 2 properties and 1 entity values", () => { + const wrapper = mount(); + expect(wrapper.find("input[type='text']")).toHaveLength(0); + }); + + it("add a new entity row", () => { + const wrapper = mount(); + wrapper.find(".addButtonEntiy").last().simulate("click"); + expect(wrapper.find("input[type='text']")).toHaveLength(1); + }); + + it("remove a entity field", () => { + const wrapper = mount(); + // 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); + }); +}); diff --git a/src/Explorer/Panes/Tables/EditTableEntityPanel.tsx b/src/Explorer/Panes/Tables/EditTableEntityPanel.tsx new file mode 100644 index 000000000..f34ef865e --- /dev/null +++ b/src/Explorer/Panes/Tables/EditTableEntityPanel.tsx @@ -0,0 +1,419 @@ +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 } from "../../Tables/TableDataClient"; +import * as TableEntityProcessor from "../../Tables/TableEntityProcessor"; +import QueryTablesTab from "../../Tabs/QueryTablesTab"; +import { PanelContainerComponent } from "../PanelContainerComponent"; +import { + attributeNameLabel, + attributeValueLabel, + backImageProps, + cassandraOptions, + columnProps, + dataTypeLabel, + defaultStringPlaceHolder, + detailedHelp, + entityFromAttributes, + getAddButtonLabel, + getEntityValuePlaceholder, + getFormattedTime, + imageProps, + isValidEntities, + options, +} from "./Validators/EntityTableHelper"; + +interface EditTableEntityPanelProps { + 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; + isEntityValueDisable?: boolean; +} + +export const EditTableEntityPanel: FunctionComponent = ({ + explorer, + closePanel, + queryTablesTab, + tableEntityListViewModel, + cassandraApiClient, +}: EditTableEntityPanelProps): JSX.Element => { + const [entities, setEntities] = useState([]); + const [selectedRow, setSelectedRow] = useState(0); + const [entityAttributeValue, setEntityAttributeValue] = useState(""); + const [originalDocument, setOriginalDocument] = useState({}); + const [entityAttributeProperty, setEntityAttributeProperty] = useState(""); + + const [ + isEntityValuePanelOpen, + { setTrue: setIsEntityValuePanelTrue, setFalse: setIsEntityValuePanelFalse }, + ] = useBoolean(false); + + useEffect(() => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let originalDocument: { [key: string]: any } = {}; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const entityAttribute: any = tableEntityListViewModel.selected(); + const entityFormattedAttribute = constructDisplayedAttributes(entityAttribute[0]); + setEntities(entityFormattedAttribute); + + if (userContext.apiType === "Tables") { + originalDocument = TableEntityProcessor.convertEntitiesToDocuments(entityAttribute, queryTablesTab.collection)[0]; + originalDocument.id = (): string => originalDocument.$id; + } else { + originalDocument = entityAttribute; + } + setOriginalDocument(originalDocument); + }, []); + + const constructDisplayedAttributes = (entity: Entities.ITableEntity): EntityRowType[] => { + const displayedAttributes: EntityRowType[] = []; + const keys = Object.keys(entity); + keys.length && + keys.forEach((key: string) => { + if ( + key !== TableEntityProcessor.keyProperties.attachments && + key !== TableEntityProcessor.keyProperties.etag && + key !== TableEntityProcessor.keyProperties.resourceId && + key !== TableEntityProcessor.keyProperties.self && + (userContext.apiType !== "Cassandra" || key !== TableConstants.EntityKeyNames.RowKey) + ) { + if (userContext.apiType === "Cassandra") { + const cassandraKeys = queryTablesTab.collection.cassandraKeys.partitionKeys + .concat(queryTablesTab.collection.cassandraKeys.clusteringKeys) + .map((key) => key.property); + const entityAttribute: Entities.ITableEntityAttribute = entity[key]; + const entityAttributeType: string = entityAttribute.$; + const displayValue: string = getPropertyDisplayValue(entity, key, entityAttributeType); + const nonEditableType: boolean = + entityAttributeType === TableConstants.CassandraType.Blob || + entityAttributeType === TableConstants.CassandraType.Inet; + const isDisable = !_.contains(cassandraKeys, key) && !nonEditableType; + const time = + entityAttributeType === TableConstants.TableType.DateTime ? getFormattedTime(displayValue) : ""; + displayedAttributes.push({ + property: key, + type: entityAttributeType, + value: displayValue, + isPropertyTypeDisable: !nonEditableType, + isDeleteOptionVisible: isDisable, + id: displayedAttributes.length, + entityValuePlaceholder: defaultStringPlaceHolder, + isEntityTypeDate: entityAttributeType === "DateTime", + isEntityValueDisable: !isDisable, + entityTimeValue: time, + }); + } else { + const entityAttribute: Entities.ITableEntityAttribute = entity[key]; + const entityAttributeType: string = entityAttribute.$; + const displayValue: string = getPropertyDisplayValue(entity, key, entityAttributeType); + const editable: boolean = isAttributeEditable(key, entityAttributeType); + // As per VSO:189935, Binary properties are read-only, we still want to be able to remove them. + const removable: boolean = editable || entityAttributeType === TableConstants.TableType.Binary; + const time = + entityAttributeType === TableConstants.TableType.DateTime ? getFormattedTime(displayValue) : ""; + displayedAttributes.push({ + property: key, + type: entityAttributeType, + value: displayValue, + isPropertyTypeDisable: !editable, + isDeleteOptionVisible: removable, + id: displayedAttributes.length, + entityValuePlaceholder: defaultStringPlaceHolder, + isEntityTypeDate: entityAttributeType === "DateTime", + isEntityValueDisable: !editable, + entityTimeValue: time, + }); + } + } + }); + return displayedAttributes; + }; + + const isAttributeEditable = (attributeName: string, entityAttributeType: string) => { + return !( + attributeName === TableConstants.EntityKeyNames.PartitionKey || + attributeName === TableConstants.EntityKeyNames.RowKey || + attributeName === TableConstants.EntityKeyNames.Timestamp || + // As per VSO:189935, Making Binary properties read-only in Edit Entity dialog until we have a full story for it. + entityAttributeType === TableConstants.TableType.Binary + ); + }; + + const getPropertyDisplayValue = (entity: Entities.ITableEntity, name: string, type: string): string => { + const attribute: Entities.ITableEntityAttribute = entity[name]; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let displayValue: any = attribute._; + const isBinary: boolean = type === TableConstants.TableType.Binary; + + // Showing the value in base64 for binary properties since that is what the Azure Storage Client Library expects. + // This means that, even if the Azure Storage API returns a byte[] of binary content, it needs that same array + // *base64 - encoded * as the value for the updated property or the whole update operation will fail. + if (isBinary && displayValue && $.isArray(displayValue.data)) { + const bytes: number[] = displayValue.data; + displayValue = getBase64DisplayValue(bytes); + } + return displayValue; + }; + + const getBase64DisplayValue = (bytes: number[]): string => { + let displayValue = ""; + try { + const chars: string[] = bytes.map((byte: number) => String.fromCharCode(byte)); + const toEncode: string = chars.join(""); + displayValue = window.btoa(toEncode); + } catch (error) { + console.error(error); + } + return displayValue; + }; + + const submit = async (event: React.FormEvent): Promise => { + if (!isValidEntities(entities)) { + return undefined; + } + event.preventDefault(); + const entity: Entities.ITableEntity = entityFromAttributes(entities); + const tableDataClient = userContext.apiType === "Cassandra" ? cassandraApiClient : explorer.tableDataClient; + const originalDocumentData = userContext.apiType === "Cassandra" ? originalDocument[0] : originalDocument; + const newEntity: Entities.ITableEntity = await tableDataClient.updateDocument( + queryTablesTab.collection, + originalDocumentData, + entity + ); + await tableEntityListViewModel.updateCachedEntity(newEntity); + if (!tryInsertNewHeaders(tableEntityListViewModel, newEntity)) { + tableEntityListViewModel.redrawTableThrottled(); + } + tableEntityListViewModel.selected.removeAll(); + tableEntityListViewModel.selected.push(newEntity); + 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 = [...entities]; + cloneEntities.splice(cloneEntities.length, 0, { + property: "", + type: TableConstants.TableType.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 = [...entities]; + cloneEntities.splice(indexToRemove, 1); + setEntities(cloneEntities); + }; + + // handle Entity change + const entityChange = (value: string | Date, indexOfInput: number, key: string): void => { + const cloneEntities = [...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, + selectedType: IDropdownOption, + indexOfEntity: number + ): void => { + const entityValuePlaceholder = getEntityValuePlaceholder(selectedType.key); + const cloneEntities = [...entities]; + cloneEntities[indexOfEntity].type = selectedType.key.toString(); + cloneEntities[indexOfEntity].entityValuePlaceholder = entityValuePlaceholder; + cloneEntities[indexOfEntity].isEntityTypeDate = selectedType.key === TableConstants.TableType.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 ( +
+
+
+ {entities.map((entity, index) => { + return ( + editEntity(index)} + onSelectDate={(date: Date) => { + entityChange(date, index, "value"); + }} + onDeleteEntity={() => deleteEntityAtIndex(index)} + onEntityPropertyChange={(event, newInput?: string) => { + entityChange(newInput, index, "property"); + }} + onEntityTypeChange={(event: React.FormEvent, 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" && ( + + Add Entity + {getAddButtonLabel(userContext.apiType)} + + )} +
+ {renderPanelFooter()} +
+
+ ); + }; + + const renderPanelFooter = (): JSX.Element => { + return ( +
+
+ +
+
+ ); + }; + + const onRenderNavigationContent: IRenderFunction = () => ( + + back setIsEntityValuePanelFalse()} /> + + + ); + if (isEntityValuePanelOpen) { + return ( + { + setEntityAttributeValue(newInput); + entityChange(newInput, selectedRow, "value"); + }} + /> + } + closePanel={() => closePanel()} + isConsoleExpanded={false} + /> + ); + } + + return ( + closePanel()} + isConsoleExpanded={false} + /> + ); +}; diff --git a/src/Explorer/Panes/Tables/Validators/EntityTableHelper.tsx b/src/Explorer/Panes/Tables/Validators/EntityTableHelper.tsx index 4f08ba83e..985276944 100644 --- a/src/Explorer/Panes/Tables/Validators/EntityTableHelper.tsx +++ b/src/Explorer/Panes/Tables/Validators/EntityTableHelper.tsx @@ -5,28 +5,6 @@ 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; @@ -133,20 +111,21 @@ export const entityFromAttributes = (entities: EntityRowType[]): Entities.ITable // GetPlaceholder according to entity type export const getEntityValuePlaceholder = (entityType: string | number): string => { + const { String, Boolean, DateTime, Double, Guid, Int32, Int64 } = TableConstants.TableType; switch (entityType) { - case "String": + case String: return stringPlaceholder; - case "Boolean": + case Boolean: return booleanPlaceHolder; - case "DateTime": + case DateTime: return datePlaceholder; - case "Double": + case Double: return doublePlaceholder; - case "Guid": + case Guid: return guidPlaceholder; - case "Int32": + case Int32: return intPlaceholder; - case "Int64": + case Int64: return int64Placeholder; default: return ""; @@ -164,13 +143,13 @@ export const isValidEntities = (entities: EntityRowType[]): boolean => { }; const isEntityPropertyTypeDisable = (header: string): boolean => { - if (header === "PartitionKey" || header === "RowKey") { + if (header === TableConstants.EntityKeyNames.PartitionKey || header === TableConstants.EntityKeyNames.RowKey) { return true; } return false; }; -export const getDefaultEntities = (headers: string[], entityTypes: { [key: string]: string }): EntityRowType[] => { +export const getDefaultEntities = (headers: string[], entityTypes: EntityType): EntityRowType[] => { const defaultEntities: EntityRowType[] = []; headers.forEach((header: string) => { if (header !== "Timestamp") { @@ -183,7 +162,7 @@ export const getDefaultEntities = (headers: string[], entityTypes: { [key: strin isDeleteOptionVisible: !isEntityPropertyTypeDisable(header), id: 1, entityValuePlaceholder: defaultStringPlaceHolder, - isEntityTypeDate: entityType === "DateTime", + isEntityTypeDate: entityType === TableConstants.TableType.DateTime, }; defaultEntities.push(entityRow); } @@ -212,6 +191,13 @@ export const getButtonLabel = (apiType: string): string => { return "Add Entity"; }; +export const getFormattedTime = (displayValue: string): string => { + const date = new Date(displayValue); + const minutes = date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes(); + const hours = date.getHours() < 10 ? `0${date.getHours()}` : date.getHours(); + return `${hours}:${minutes}`; +}; + export const getCassandraDefaultEntities = ( headers: string[], entityTypes: { [key: string]: string } @@ -244,4 +230,9 @@ export interface EntityRowType { entityValuePlaceholder: string; isEntityTypeDate: boolean; entityTimeValue?: string; + isEntityValueDisable?: boolean; +} + +export interface EntityType { + [key: string]: string; } diff --git a/src/Explorer/Panes/Tables/__snapshots__/EditTableEntityPanel.test.tsx.snap b/src/Explorer/Panes/Tables/__snapshots__/EditTableEntityPanel.test.tsx.snap new file mode 100644 index 000000000..114e84dff --- /dev/null +++ b/src/Explorer/Panes/Tables/__snapshots__/EditTableEntityPanel.test.tsx.snap @@ -0,0 +1,3491 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Excute Edit Table Entity Pane should render Default properly 1`] = ` + + +
+
+ + + + Add Property + + +
+
+
+ +
+
+
+ + } + panelWidth="700px" + > + + + + + + + +
+
+
+
+
+ +
+
+
+ } + > + + +
+ +
+
+ + +
+ + + +
+
+
+
+
+
+ Edit Table Entity +
+
+ + + *": Object { + "left": 0, + "position": "relative", + "top": 0, + }, + }, + "textAlign": "center", + "textDecoration": "none", + "userSelect": "none", + }, + Object { + "backgroundColor": "transparent", + "border": "none", + "color": "#0078d4", + "height": "32px", + "padding": "0 4px", + "width": "32px", + }, + "ms-Panel-closeButton ms-PanelAction-close", + Object { + "color": "#605e5c", + "fontSize": "20px", + "marginRight": 14, + }, + false, + ], + "rootChecked": Object { + "backgroundColor": "#edebe9", + "color": "#005a9e", + }, + "rootCheckedHovered": Object { + "backgroundColor": "#e1dfdd", + "color": "#005a9e", + }, + "rootDisabled": Array [ + Object { + "outline": "transparent", + "position": "relative", + "selectors": Object { + ".ms-Fabric--isFocusVisible &:focus:after": Object { + "border": "1px solid transparent", + "bottom": 2, + "content": "\\"\\"", + "left": 2, + "outline": "1px solid #605e5c", + "position": "absolute", + "right": 2, + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "bottom": -2, + "left": -2, + "outlineColor": "ButtonText", + "right": -2, + "top": -2, + }, + }, + "top": 2, + "zIndex": 1, + }, + "::-moz-focus-inner": Object { + "border": "0", + }, + }, + }, + Object { + "backgroundColor": "#f3f2f1", + "borderColor": "#f3f2f1", + "color": "#a19f9d", + "cursor": "default", + "pointerEvents": "none", + "selectors": Object { + ":focus": Object { + "outline": 0, + }, + ":hover": Object { + "outline": 0, + }, + }, + }, + Object { + "color": "#c8c6c4", + }, + ], + "rootExpanded": Object { + "backgroundColor": "#edebe9", + "color": "#005a9e", + }, + "rootHasMenu": Object { + "width": "auto", + }, + "rootHovered": Array [ + Object { + "backgroundColor": "#f3f2f1", + "color": "#106ebe", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "borderColor": "Highlight", + "color": "Highlight", + }, + }, + }, + Object { + "color": "#323130", + }, + ], + "rootPressed": Object { + "backgroundColor": "#edebe9", + "color": "#005a9e", + }, + "screenReaderText": Object { + "border": 0, + "height": 1, + "margin": -1, + "overflow": "hidden", + "padding": 0, + "position": "absolute", + "width": 1, + }, + "splitButtonContainer": Array [ + Object { + "outline": "transparent", + "position": "relative", + "selectors": Object { + ".ms-Fabric--isFocusVisible &:focus:after": Object { + "border": "1px solid #ffffff", + "bottom": 3, + "content": "\\"\\"", + "left": 3, + "outline": "1px solid #605e5c", + "position": "absolute", + "right": 3, + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "border": "none", + "bottom": -2, + "left": -2, + "right": -2, + "top": -2, + }, + }, + "top": 3, + "zIndex": 1, + }, + "::-moz-focus-inner": Object { + "border": "0", + }, + }, + }, + Object { + "display": "inline-flex", + "selectors": Object { + ".ms-Button--default": Object { + "borderBottomRightRadius": "0", + "borderRight": "none", + "borderTopRightRadius": "0", + }, + ".ms-Button--primary": Object { + "border": "none", + "borderBottomRightRadius": "0", + "borderTopRightRadius": "0", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "MsHighContrastAdjust": "none", + "backgroundColor": "Window", + "border": "1px solid WindowText", + "borderRightWidth": "0", + "color": "WindowText", + "forcedColorAdjust": "none", + }, + }, + }, + ".ms-Button--primary + .ms-Button": Object { + "border": "none", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "border": "1px solid WindowText", + "borderLeftWidth": "0", + }, + }, + }, + }, + }, + ], + "splitButtonContainerChecked": Object { + "selectors": Object { + ".ms-Button--primary": Object { + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "MsHighContrastAdjust": "none", + "backgroundColor": "WindowText", + "color": "Window", + "forcedColorAdjust": "none", + }, + }, + }, + }, + }, + "splitButtonContainerCheckedHovered": Object { + "selectors": Object { + ".ms-Button--primary": Object { + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "MsHighContrastAdjust": "none", + "backgroundColor": "WindowText", + "color": "Window", + "forcedColorAdjust": "none", + }, + }, + }, + }, + }, + "splitButtonContainerDisabled": Object { + "border": "none", + "outline": "none", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "MsHighContrastAdjust": "none", + "backgroundColor": "Window", + "borderColor": "GrayText", + "color": "GrayText", + "forcedColorAdjust": "none", + }, + }, + }, + "splitButtonContainerFocused": Object { + "outline": "none!important", + }, + "splitButtonContainerHovered": Object { + "selectors": Object { + ".ms-Button--primary": Object { + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "Highlight", + "color": "Window", + }, + }, + }, + ".ms-Button.is-disabled": Object { + "color": "#a19f9d", + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "Window", + "borderColor": "GrayText", + "color": "GrayText", + }, + }, + }, + }, + }, + "splitButtonDivider": Object { + "bottom": 8, + "position": "absolute", + "right": 31, + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "WindowText", + }, + }, + "top": 8, + "width": 1, + }, + "splitButtonDividerDisabled": Object { + "bottom": 8, + "position": "absolute", + "right": 31, + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "GrayText", + }, + }, + "top": 8, + "width": 1, + }, + "splitButtonFlexContainer": Object { + "alignItems": "center", + "display": "flex", + "flexWrap": "nowrap", + "height": "100%", + "justifyContent": "center", + }, + "splitButtonMenuButton": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + ".ms-Button-menuIcon": Object { + "color": "WindowText", + }, + }, + "border": "1px solid #8a8886", + "borderBottomRightRadius": "2px", + "borderLeft": "none", + "borderRadius": 0, + "borderTopRightRadius": "2px", + "boxSizing": "border-box", + "cursor": "pointer", + "display": "inline-block", + "height": "auto", + "marginBottom": 0, + "marginLeft": -1, + "marginRight": 0, + "marginTop": 0, + "outline": "transparent", + "padding": 6, + "textAlign": "center", + "textDecoration": "none", + "userSelect": "none", + "verticalAlign": "top", + "width": 32, + }, + "splitButtonMenuButtonDisabled": Object { + "border": "none", + "pointerEvents": "none", + "selectors": Object { + ".ms-Button--primary": Object { + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "Window", + "borderColor": "GrayText", + "color": "GrayText", + }, + }, + }, + ".ms-Button-menuIcon": Object { + "selectors": Object { + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "color": "GrayText", + }, + }, + }, + ":hover": Object { + "cursor": "default", + }, + "@media screen and (-ms-high-contrast: active), (forced-colors: active)": Object { + "backgroundColor": "Window", + "border": "1px solid GrayText", + "color": "GrayText", + }, + }, + }, + "textContainer": Object { + "display": "block", + "flexGrow": 1, + }, + } + } + theme={ + Object { + "disableGlobalClassNames": false, + "effects": Object { + "elevation16": "0 6.4px 14.4px 0 rgba(0, 0, 0, 0.132), 0 1.2px 3.6px 0 rgba(0, 0, 0, 0.108)", + "elevation4": "0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)", + "elevation64": "0 25.6px 57.6px 0 rgba(0, 0, 0, 0.22), 0 4.8px 14.4px 0 rgba(0, 0, 0, 0.18)", + "elevation8": "0 3.2px 7.2px 0 rgba(0, 0, 0, 0.132), 0 0.6px 1.8px 0 rgba(0, 0, 0, 0.108)", + "roundedCorner2": "2px", + "roundedCorner4": "4px", + "roundedCorner6": "6px", + }, + "fonts": Object { + "large": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "18px", + "fontWeight": 400, + }, + "medium": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "14px", + "fontWeight": 400, + }, + "mediumPlus": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "16px", + "fontWeight": 400, + }, + "mega": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "68px", + "fontWeight": 600, + }, + "small": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "12px", + "fontWeight": 400, + }, + "smallPlus": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "12px", + "fontWeight": 400, + }, + "superLarge": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "42px", + "fontWeight": 600, + }, + "tiny": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "10px", + "fontWeight": 400, + }, + "xLarge": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "20px", + "fontWeight": 600, + }, + "xLargePlus": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "24px", + "fontWeight": 600, + }, + "xSmall": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "10px", + "fontWeight": 400, + }, + "xxLarge": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "28px", + "fontWeight": 600, + }, + "xxLargePlus": Object { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "32px", + "fontWeight": 600, + }, + }, + "isInverted": false, + "palette": Object { + "accent": "#0078d4", + "black": "#000000", + "blackTranslucent40": "rgba(0,0,0,.4)", + "blue": "#0078d4", + "blueDark": "#002050", + "blueLight": "#00bcf2", + "blueMid": "#00188f", + "green": "#107c10", + "greenDark": "#004b1c", + "greenLight": "#bad80a", + "magenta": "#b4009e", + "magentaDark": "#5c005c", + "magentaLight": "#e3008c", + "neutralDark": "#201f1e", + "neutralLight": "#edebe9", + "neutralLighter": "#f3f2f1", + "neutralLighterAlt": "#faf9f8", + "neutralPrimary": "#323130", + "neutralPrimaryAlt": "#3b3a39", + "neutralQuaternary": "#d2d0ce", + "neutralQuaternaryAlt": "#e1dfdd", + "neutralSecondary": "#605e5c", + "neutralSecondaryAlt": "#8a8886", + "neutralTertiary": "#a19f9d", + "neutralTertiaryAlt": "#c8c6c4", + "orange": "#d83b01", + "orangeLight": "#ea4300", + "orangeLighter": "#ff8c00", + "purple": "#5c2d91", + "purpleDark": "#32145a", + "purpleLight": "#b4a0ff", + "red": "#e81123", + "redDark": "#a4262c", + "teal": "#008272", + "tealDark": "#004b50", + "tealLight": "#00b294", + "themeDark": "#005a9e", + "themeDarkAlt": "#106ebe", + "themeDarker": "#004578", + "themeLight": "#c7e0f4", + "themeLighter": "#deecf9", + "themeLighterAlt": "#eff6fc", + "themePrimary": "#0078d4", + "themeSecondary": "#2b88d8", + "themeTertiary": "#71afe5", + "white": "#ffffff", + "whiteTranslucent40": "rgba(255,255,255,.4)", + "yellow": "#ffb900", + "yellowDark": "#d29200", + "yellowLight": "#fff100", + }, + "rtl": undefined, + "semanticColors": Object { + "accentButtonBackground": "#0078d4", + "accentButtonText": "#ffffff", + "actionLink": "#323130", + "actionLinkHovered": "#201f1e", + "blockingBackground": "#FDE7E9", + "blockingIcon": "#FDE7E9", + "bodyBackground": "#ffffff", + "bodyBackgroundChecked": "#edebe9", + "bodyBackgroundHovered": "#f3f2f1", + "bodyDivider": "#edebe9", + "bodyFrameBackground": "#ffffff", + "bodyFrameDivider": "#edebe9", + "bodyStandoutBackground": "#faf9f8", + "bodySubtext": "#605e5c", + "bodyText": "#323130", + "bodyTextChecked": "#000000", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#c8c6c4", + "buttonBackgroundCheckedHovered": "#edebe9", + "buttonBackgroundDisabled": "#f3f2f1", + "buttonBackgroundHovered": "#f3f2f1", + "buttonBackgroundPressed": "#edebe9", + "buttonBorder": "#8a8886", + "buttonBorderDisabled": "#f3f2f1", + "buttonText": "#323130", + "buttonTextChecked": "#201f1e", + "buttonTextCheckedHovered": "#000000", + "buttonTextDisabled": "#a19f9d", + "buttonTextHovered": "#201f1e", + "buttonTextPressed": "#201f1e", + "cardShadow": "0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)", + "cardShadowHovered": "0 3.2px 7.2px 0 rgba(0, 0, 0, 0.132), 0 0.6px 1.8px 0 rgba(0, 0, 0, 0.108)", + "cardStandoutBackground": "#ffffff", + "defaultStateBackground": "#faf9f8", + "disabledBackground": "#f3f2f1", + "disabledBodySubtext": "#c8c6c4", + "disabledBodyText": "#a19f9d", + "disabledBorder": "#c8c6c4", + "disabledSubtext": "#d2d0ce", + "disabledText": "#a19f9d", + "errorBackground": "#FDE7E9", + "errorIcon": "#A80000", + "errorText": "#a4262c", + "focusBorder": "#605e5c", + "infoBackground": "#f3f2f1", + "infoIcon": "#605e5c", + "inputBackground": "#ffffff", + "inputBackgroundChecked": "#0078d4", + "inputBackgroundCheckedHovered": "#005a9e", + "inputBorder": "#605e5c", + "inputBorderHovered": "#323130", + "inputFocusBorderAlt": "#0078d4", + "inputForegroundChecked": "#ffffff", + "inputIcon": "#0078d4", + "inputIconDisabled": "#a19f9d", + "inputIconHovered": "#005a9e", + "inputPlaceholderBackgroundChecked": "#deecf9", + "inputPlaceholderText": "#605e5c", + "inputText": "#323130", + "inputTextHovered": "#201f1e", + "link": "#0078d4", + "linkHovered": "#004578", + "listBackground": "#ffffff", + "listHeaderBackgroundHovered": "#f3f2f1", + "listHeaderBackgroundPressed": "#edebe9", + "listItemBackgroundChecked": "#edebe9", + "listItemBackgroundCheckedHovered": "#e1dfdd", + "listItemBackgroundHovered": "#f3f2f1", + "listText": "#323130", + "listTextColor": "#323130", + "menuBackground": "#ffffff", + "menuDivider": "#c8c6c4", + "menuHeader": "#0078d4", + "menuIcon": "#0078d4", + "menuItemBackgroundChecked": "#edebe9", + "menuItemBackgroundHovered": "#f3f2f1", + "menuItemBackgroundPressed": "#edebe9", + "menuItemText": "#323130", + "menuItemTextHovered": "#201f1e", + "messageLink": "#005A9E", + "messageLinkHovered": "#004578", + "messageText": "#323130", + "primaryButtonBackground": "#0078d4", + "primaryButtonBackgroundDisabled": "#f3f2f1", + "primaryButtonBackgroundHovered": "#106ebe", + "primaryButtonBackgroundPressed": "#005a9e", + "primaryButtonBorder": "transparent", + "primaryButtonText": "#ffffff", + "primaryButtonTextDisabled": "#d2d0ce", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "severeWarningBackground": "#FED9CC", + "severeWarningIcon": "#D83B01", + "smallInputBorder": "#605e5c", + "successBackground": "#DFF6DD", + "successIcon": "#107C10", + "successText": "#107C10", + "variantBorder": "#edebe9", + "variantBorderHovered": "#a19f9d", + "warningBackground": "#FFF4CE", + "warningHighlight": "#ffb900", + "warningIcon": "#797775", + "warningText": "#323130", + }, + "spacing": Object { + "l1": "20px", + "l2": "32px", + "m": "16px", + "s1": "8px", + "s2": "4px", + }, + } + } + title="Close" + variantClassName="ms-Button--icon" + > + + + + + +
+
+
+
+
+
+
+
+ +
+ + +
+ Add Entity +
+
+
+ + + Add Property + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+ +
+ +
+
+
+
+ +
+
, + } + } + /> + + + + + + + + + + + +`; diff --git a/src/Explorer/Panes/UploadItemsPane/__snapshots__/UploadItemsPane.test.tsx.snap b/src/Explorer/Panes/UploadItemsPane/__snapshots__/UploadItemsPane.test.tsx.snap index 6cfb1497e..084047ff8 100644 --- a/src/Explorer/Panes/UploadItemsPane/__snapshots__/UploadItemsPane.test.tsx.snap +++ b/src/Explorer/Panes/UploadItemsPane/__snapshots__/UploadItemsPane.test.tsx.snap @@ -153,40 +153,6 @@ exports[`Upload Items Pane should render Default properly 1`] = ` "title": [Function], "visible": [Function], }, - EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, CassandraAddCollectionPane { "autoPilotUsageCost": [Function], "canConfigureThroughput": [Function], @@ -455,40 +421,6 @@ exports[`Upload Items Pane should render Default properly 1`] = ` "defaultExperience": [Function], "deleteCollectionText": [Function], "deleteDatabaseText": [Function], - "editTableEntityPane": EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, "graphStylingPane": GraphStylingPane { "container": [Circular], "firstFieldHasFocus": [Function], diff --git a/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap b/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap index 81eab5178..f4e22d048 100644 --- a/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap +++ b/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap @@ -154,40 +154,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database "title": [Function], "visible": [Function], }, - EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, CassandraAddCollectionPane { "autoPilotUsageCost": [Function], "canConfigureThroughput": [Function], @@ -456,40 +422,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database "defaultExperience": [Function], "deleteCollectionText": [Function], "deleteDatabaseText": [Function], - "editTableEntityPane": EditTableEntityPane { - "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], - "finishEditingAttribute": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "edittableentitypane", - "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], - }, "graphStylingPane": GraphStylingPane { "container": [Circular], "firstFieldHasFocus": [Function], diff --git a/src/Explorer/Tables/DataTable/TableCommands.ts b/src/Explorer/Tables/DataTable/TableCommands.ts index c3641fe44..9da9746ee 100644 --- a/src/Explorer/Tables/DataTable/TableCommands.ts +++ b/src/Explorer/Tables/DataTable/TableCommands.ts @@ -58,10 +58,6 @@ export default class TableCommands { var entityToUpdate: Entities.ITableEntity = viewModel.selected()[0]; var originalNumberOfProperties = entityToUpdate ? 0 : Object.keys(entityToUpdate).length - 1; // .metadata is always a property for etag - this._container.editTableEntityPane.originEntity = entityToUpdate; - this._container.editTableEntityPane.tableViewModel = viewModel; - this._container.editTableEntityPane.originalNumberOfProperties = originalNumberOfProperties; - this._container.editTableEntityPane.open(); return null; } diff --git a/src/Explorer/Tabs/QueryTablesTab.ts b/src/Explorer/Tabs/QueryTablesTab.ts index 8ea6237c5..59bd01cc7 100644 --- a/src/Explorer/Tabs/QueryTablesTab.ts +++ b/src/Explorer/Tabs/QueryTablesTab.ts @@ -151,7 +151,7 @@ export default class QueryTablesTab extends TabsBase { }; public onEditEntityClick = (): Q.Promise => { - this.tableCommands.editEntityCommand(this.tableEntityListViewModel()); + this.container.openEditTableEntityPanel(this, this.tableEntityListViewModel()); return null; }; diff --git a/src/Main.tsx b/src/Main.tsx index 901acda5e..43ca92976 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -231,7 +231,6 @@ const App: React.FunctionComponent = () => {
-