From a6b82c8340545e57123657a66b51d42b4bffed41 Mon Sep 17 00:00:00 2001 From: vaidankarswapnil <81285216+vaidankarswapnil@users.noreply.github.com> Date: Fri, 14 May 2021 02:15:00 +0530 Subject: [PATCH] Migrate graph style panel to react (#619) Co-authored-by: Steve Faulkner --- .eslintignore | 7 +- src/Contracts/ViewModels.ts | 19 +- src/Explorer/ComponentRegisterer.test.ts | 8 - src/Explorer/ComponentRegisterer.ts | 3 - .../SettingsComponent.test.tsx.snap | 516 ------------------ src/Explorer/Explorer.tsx | 16 - .../D3ForceGraph.test.ts | 9 +- .../GraphExplorerComponent/D3ForceGraph.ts | 157 +++--- .../GraphExplorer.test.tsx | 29 +- .../GraphExplorerComponent/GraphExplorer.tsx | 148 +++-- .../GraphExplorerAdapter.tsx | 74 +++ .../GraphStyleComponent/GraphStyle.test.ts | 51 -- .../GraphStyleComponent.test.tsx | 67 +++ .../GraphStyleComponent.ts | 103 ---- .../GraphStyleComponent.tsx | 131 +++++ .../GraphStyleComponent.test.tsx.snap | 3 + .../graph-style-component.html | 74 --- src/Explorer/OpenActions.test.ts | 1 - src/Explorer/OpenActions.ts | 3 - .../GitHubReposPanel.test.tsx.snap | 129 ----- src/Explorer/Panes/GraphStylingPane.html | 59 -- src/Explorer/Panes/GraphStylingPane.ts | 68 --- .../GraphStylingPanel/GraphStylingPanel.tsx | 37 ++ src/Explorer/Panes/PaneComponents.ts | 11 - .../StringInputPane.test.tsx.snap | 129 ----- ...eteDatabaseConfirmationPanel.test.tsx.snap | 129 ----- src/Explorer/Tabs/GraphTab.tsx | 130 +++-- src/Main.tsx | 1 - 28 files changed, 596 insertions(+), 1516 deletions(-) create mode 100644 src/Explorer/Graph/GraphExplorerComponent/GraphExplorerAdapter.tsx delete mode 100644 src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts create mode 100644 src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.test.tsx delete mode 100644 src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts create mode 100644 src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.tsx create mode 100644 src/Explorer/Graph/GraphStyleComponent/__snapshots__/GraphStyleComponent.test.tsx.snap delete mode 100644 src/Explorer/Graph/GraphStyleComponent/graph-style-component.html delete mode 100644 src/Explorer/Panes/GraphStylingPane.html delete mode 100644 src/Explorer/Panes/GraphStylingPane.ts create mode 100644 src/Explorer/Panes/GraphStylingPanel/GraphStylingPanel.tsx diff --git a/.eslintignore b/.eslintignore index f72026dc5..967345584 100644 --- a/.eslintignore +++ b/.eslintignore @@ -84,8 +84,8 @@ src/Explorer/Graph/GraphExplorerComponent/GremlinClient.test.ts src/Explorer/Graph/GraphExplorerComponent/GremlinClient.ts src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.test.ts src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.ts -src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts -src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts +# src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts +# src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.test.ts src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.ts @@ -115,7 +115,8 @@ src/Explorer/Panes/CassandraAddCollectionPane.ts src/Explorer/Panes/ContextualPaneBase.ts src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts -src/Explorer/Panes/GraphStylingPane.ts +# src/Explorer/Panes/GraphStylingPane.ts +# src/Explorer/Panes/NewVertexPane.ts src/Explorer/Panes/PaneComponents.ts src/Explorer/Panes/RenewAdHocAccessPane.ts src/Explorer/Panes/SetupNotebooksPane.ts diff --git a/src/Contracts/ViewModels.ts b/src/Contracts/ViewModels.ts index 656b87eb8..9fb242f79 100644 --- a/src/Contracts/ViewModels.ts +++ b/src/Contracts/ViewModels.ts @@ -206,17 +206,14 @@ export enum NeighborType { BOTH, } -/** - * Set of observable related to graph configuration by user - */ -export interface GraphConfigUiData { - showNeighborType: ko.Observable; - nodeProperties: ko.ObservableArray; - nodePropertiesWithNone: ko.ObservableArray; - nodeCaptionChoice: ko.Observable; - nodeColorKeyChoice: ko.Observable; - nodeIconChoice: ko.Observable; - nodeIconSet: ko.Observable; +export interface IGraphConfigUiData { + showNeighborType: NeighborType; + nodeProperties: string[]; + nodePropertiesWithNone: string[]; + nodeCaptionChoice: string; + nodeColorKeyChoice: string; + nodeIconChoice: string; + nodeIconSet: string; } /** diff --git a/src/Explorer/ComponentRegisterer.test.ts b/src/Explorer/ComponentRegisterer.test.ts index 1f97cd6f5..16244a16c 100644 --- a/src/Explorer/ComponentRegisterer.test.ts +++ b/src/Explorer/ComponentRegisterer.test.ts @@ -12,18 +12,10 @@ describe("Component Registerer", () => { expect(ko.components.isRegistered("error-display")).toBe(true); }); - it("should register graph-style component", () => { - expect(ko.components.isRegistered("graph-style")).toBe(true); - }); - it("should register json-editor component", () => { expect(ko.components.isRegistered("json-editor")).toBe(true); }); - it("should register graph-styling-pane component", () => { - expect(ko.components.isRegistered("graph-styling-pane")).toBe(true); - }); - it("should register dynamic-list component", () => { expect(ko.components.isRegistered("dynamic-list")).toBe(true); }); diff --git a/src/Explorer/ComponentRegisterer.ts b/src/Explorer/ComponentRegisterer.ts index ddf9bb991..ff4c4f96e 100644 --- a/src/Explorer/ComponentRegisterer.ts +++ b/src/Explorer/ComponentRegisterer.ts @@ -6,12 +6,10 @@ import { ErrorDisplayComponent } from "./Controls/ErrorDisplayComponent/ErrorDis import { InputTypeaheadComponent } from "./Controls/InputTypeahead/InputTypeahead"; import { JsonEditorComponent } from "./Controls/JsonEditor/JsonEditorComponent"; import { ThroughputInputComponentAutoPilotV3 } from "./Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3"; -import { GraphStyleComponent } from "./Graph/GraphStyleComponent/GraphStyleComponent"; import * as PaneComponents from "./Panes/PaneComponents"; ko.components.register("input-typeahead", new InputTypeaheadComponent()); ko.components.register("error-display", new ErrorDisplayComponent()); -ko.components.register("graph-style", GraphStyleComponent); ko.components.register("editor", new EditorComponent()); ko.components.register("json-editor", new JsonEditorComponent()); ko.components.register("diff-editor", new DiffEditorComponent()); @@ -21,5 +19,4 @@ ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponent // Panes ko.components.register("add-database-pane", new PaneComponents.AddDatabasePaneComponent()); -ko.components.register("graph-styling-pane", new PaneComponents.GraphStylingPaneComponent()); ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent()); diff --git a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap index d413c0525..6b841cdb8 100644 --- a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap +++ b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap @@ -32,115 +32,6 @@ exports[`SettingsComponent renders 1`] = ` "_closeSynapseLinkModalDialog": [Function], "_isAfecFeatureRegistered": [Function], "_isInitializingNotebooks": false, - "_panes": Array [ - AddDatabasePane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "databaseCreateNewShared": [Function], - "databaseId": [Function], - "databaseIdLabel": [Function], - "databaseIdPlaceHolder": [Function], - "databaseIdTooltipText": [Function], - "databaseLevelThroughputTooltipText": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "freeTierExceedThroughputTooltip": [Function], - "id": "adddatabasepane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isTemplateReady": [Function], - "maxAutoPilotThroughputSet": [Function], - "maxThroughputRU": [Function], - "maxThroughputRUText": [Function], - "minThroughputRU": [Function], - "onMoreDetailsKeyPress": [Function], - "requestUnitsUsageCost": [Function], - "ruToolTipText": [Function], - "showUpsellMessage": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "upsellAnchorText": [Function], - "upsellAnchorUrl": [Function], - "upsellMessage": [Function], - "upsellMessageAriaLabel": [Function], - "visible": [Function], - }, - GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, - CassandraAddCollectionPane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "createTableQuery": [Function], - "dedicateTableThroughput": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "cassandraaddcollectionpane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isSharedAutoPilotSelected": [Function], - "isTemplateReady": [Function], - "keyspaceCreateNew": [Function], - "keyspaceHasSharedOffer": [Function], - "keyspaceId": [Function], - "keyspaceIds": [Function], - "keyspaceOffers": Map {}, - "keyspaceThroughput": [Function], - "maxThroughputRU": [Function], - "minThroughputRU": [Function], - "requestUnitsUsageCostDedicated": [Function], - "requestUnitsUsageCostShared": [Function], - "ruToolTipText": [Function], - "selectedAutoPilotThroughput": [Function], - "sharedAutoPilotThroughput": [Function], - "sharedThroughputRangeText": [Function], - "sharedThroughputSpendAck": [Function], - "sharedThroughputSpendAckText": [Function], - "sharedThroughputSpendAckVisible": [Function], - "tableId": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "userTableQuery": [Function], - "visible": [Function], - }, - ], "_refreshSparkEnabledStateForAccount": [Function], "_resetNotebookWorkspace": [Function], "addCollectionText": [Function], @@ -1026,26 +917,6 @@ exports[`SettingsComponent renders 1`] = ` }, }, }, - "graphStylingPane": GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, "hasStorageAnalyticsAfecFeature": [Function], "isAccountReady": [Function], "isAutoscaleDefaultEnabled": [Function], @@ -1142,115 +1013,6 @@ exports[`SettingsComponent renders 1`] = ` "_closeSynapseLinkModalDialog": [Function], "_isAfecFeatureRegistered": [Function], "_isInitializingNotebooks": false, - "_panes": Array [ - AddDatabasePane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "databaseCreateNewShared": [Function], - "databaseId": [Function], - "databaseIdLabel": [Function], - "databaseIdPlaceHolder": [Function], - "databaseIdTooltipText": [Function], - "databaseLevelThroughputTooltipText": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "freeTierExceedThroughputTooltip": [Function], - "id": "adddatabasepane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isTemplateReady": [Function], - "maxAutoPilotThroughputSet": [Function], - "maxThroughputRU": [Function], - "maxThroughputRUText": [Function], - "minThroughputRU": [Function], - "onMoreDetailsKeyPress": [Function], - "requestUnitsUsageCost": [Function], - "ruToolTipText": [Function], - "showUpsellMessage": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "upsellAnchorText": [Function], - "upsellAnchorUrl": [Function], - "upsellMessage": [Function], - "upsellMessageAriaLabel": [Function], - "visible": [Function], - }, - GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, - CassandraAddCollectionPane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "createTableQuery": [Function], - "dedicateTableThroughput": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "cassandraaddcollectionpane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isSharedAutoPilotSelected": [Function], - "isTemplateReady": [Function], - "keyspaceCreateNew": [Function], - "keyspaceHasSharedOffer": [Function], - "keyspaceId": [Function], - "keyspaceIds": [Function], - "keyspaceOffers": Map {}, - "keyspaceThroughput": [Function], - "maxThroughputRU": [Function], - "minThroughputRU": [Function], - "requestUnitsUsageCostDedicated": [Function], - "requestUnitsUsageCostShared": [Function], - "ruToolTipText": [Function], - "selectedAutoPilotThroughput": [Function], - "sharedAutoPilotThroughput": [Function], - "sharedThroughputRangeText": [Function], - "sharedThroughputSpendAck": [Function], - "sharedThroughputSpendAckText": [Function], - "sharedThroughputSpendAckVisible": [Function], - "tableId": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "userTableQuery": [Function], - "visible": [Function], - }, - ], "_refreshSparkEnabledStateForAccount": [Function], "_resetNotebookWorkspace": [Function], "addCollectionText": [Function], @@ -2136,26 +1898,6 @@ exports[`SettingsComponent renders 1`] = ` }, }, }, - "graphStylingPane": GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, "hasStorageAnalyticsAfecFeature": [Function], "isAccountReady": [Function], "isAutoscaleDefaultEnabled": [Function], @@ -2265,115 +2007,6 @@ exports[`SettingsComponent renders 1`] = ` "_closeSynapseLinkModalDialog": [Function], "_isAfecFeatureRegistered": [Function], "_isInitializingNotebooks": false, - "_panes": Array [ - AddDatabasePane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "databaseCreateNewShared": [Function], - "databaseId": [Function], - "databaseIdLabel": [Function], - "databaseIdPlaceHolder": [Function], - "databaseIdTooltipText": [Function], - "databaseLevelThroughputTooltipText": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "freeTierExceedThroughputTooltip": [Function], - "id": "adddatabasepane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isTemplateReady": [Function], - "maxAutoPilotThroughputSet": [Function], - "maxThroughputRU": [Function], - "maxThroughputRUText": [Function], - "minThroughputRU": [Function], - "onMoreDetailsKeyPress": [Function], - "requestUnitsUsageCost": [Function], - "ruToolTipText": [Function], - "showUpsellMessage": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "upsellAnchorText": [Function], - "upsellAnchorUrl": [Function], - "upsellMessage": [Function], - "upsellMessageAriaLabel": [Function], - "visible": [Function], - }, - GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, - CassandraAddCollectionPane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "createTableQuery": [Function], - "dedicateTableThroughput": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "cassandraaddcollectionpane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isSharedAutoPilotSelected": [Function], - "isTemplateReady": [Function], - "keyspaceCreateNew": [Function], - "keyspaceHasSharedOffer": [Function], - "keyspaceId": [Function], - "keyspaceIds": [Function], - "keyspaceOffers": Map {}, - "keyspaceThroughput": [Function], - "maxThroughputRU": [Function], - "minThroughputRU": [Function], - "requestUnitsUsageCostDedicated": [Function], - "requestUnitsUsageCostShared": [Function], - "ruToolTipText": [Function], - "selectedAutoPilotThroughput": [Function], - "sharedAutoPilotThroughput": [Function], - "sharedThroughputRangeText": [Function], - "sharedThroughputSpendAck": [Function], - "sharedThroughputSpendAckText": [Function], - "sharedThroughputSpendAckVisible": [Function], - "tableId": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "userTableQuery": [Function], - "visible": [Function], - }, - ], "_refreshSparkEnabledStateForAccount": [Function], "_resetNotebookWorkspace": [Function], "addCollectionText": [Function], @@ -3259,26 +2892,6 @@ exports[`SettingsComponent renders 1`] = ` }, }, }, - "graphStylingPane": GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, "hasStorageAnalyticsAfecFeature": [Function], "isAccountReady": [Function], "isAutoscaleDefaultEnabled": [Function], @@ -3375,115 +2988,6 @@ exports[`SettingsComponent renders 1`] = ` "_closeSynapseLinkModalDialog": [Function], "_isAfecFeatureRegistered": [Function], "_isInitializingNotebooks": false, - "_panes": Array [ - AddDatabasePane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "databaseCreateNewShared": [Function], - "databaseId": [Function], - "databaseIdLabel": [Function], - "databaseIdPlaceHolder": [Function], - "databaseIdTooltipText": [Function], - "databaseLevelThroughputTooltipText": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "freeTierExceedThroughputTooltip": [Function], - "id": "adddatabasepane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isTemplateReady": [Function], - "maxAutoPilotThroughputSet": [Function], - "maxThroughputRU": [Function], - "maxThroughputRUText": [Function], - "minThroughputRU": [Function], - "onMoreDetailsKeyPress": [Function], - "requestUnitsUsageCost": [Function], - "ruToolTipText": [Function], - "showUpsellMessage": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "upsellAnchorText": [Function], - "upsellAnchorUrl": [Function], - "upsellMessage": [Function], - "upsellMessageAriaLabel": [Function], - "visible": [Function], - }, - GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, - CassandraAddCollectionPane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "createTableQuery": [Function], - "dedicateTableThroughput": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "cassandraaddcollectionpane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isSharedAutoPilotSelected": [Function], - "isTemplateReady": [Function], - "keyspaceCreateNew": [Function], - "keyspaceHasSharedOffer": [Function], - "keyspaceId": [Function], - "keyspaceIds": [Function], - "keyspaceOffers": Map {}, - "keyspaceThroughput": [Function], - "maxThroughputRU": [Function], - "minThroughputRU": [Function], - "requestUnitsUsageCostDedicated": [Function], - "requestUnitsUsageCostShared": [Function], - "ruToolTipText": [Function], - "selectedAutoPilotThroughput": [Function], - "sharedAutoPilotThroughput": [Function], - "sharedThroughputRangeText": [Function], - "sharedThroughputSpendAck": [Function], - "sharedThroughputSpendAckText": [Function], - "sharedThroughputSpendAckVisible": [Function], - "tableId": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "userTableQuery": [Function], - "visible": [Function], - }, - ], "_refreshSparkEnabledStateForAccount": [Function], "_resetNotebookWorkspace": [Function], "addCollectionText": [Function], @@ -4369,26 +3873,6 @@ exports[`SettingsComponent renders 1`] = ` }, }, }, - "graphStylingPane": GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, "hasStorageAnalyticsAfecFeature": [Function], "isAccountReady": [Function], "isAutoscaleDefaultEnabled": [Function], diff --git a/src/Explorer/Explorer.tsx b/src/Explorer/Explorer.tsx index c909c690a..de0d8402e 100644 --- a/src/Explorer/Explorer.tsx +++ b/src/Explorer/Explorer.tsx @@ -61,7 +61,6 @@ import { DeleteCollectionConfirmationPane } from "./Panes/DeleteCollectionConfir import { DeleteDatabaseConfirmationPanel } from "./Panes/DeleteDatabaseConfirmationPanel"; import { ExecuteSprocParamsPane } from "./Panes/ExecuteSprocParamsPane/ExecuteSprocParamsPane"; import { GitHubReposPanel } from "./Panes/GitHubReposPanel/GitHubReposPanel"; -import GraphStylingPane from "./Panes/GraphStylingPane"; import { LoadQueryPane } from "./Panes/LoadQueryPane/LoadQueryPane"; import { SaveQueryPane } from "./Panes/SaveQueryPane/SaveQueryPane"; import { SettingsPane } from "./Panes/SettingsPane/SettingsPane"; @@ -151,7 +150,6 @@ export default class Explorer { // Contextual panes public addDatabasePane: AddDatabasePane; - public graphStylingPane: GraphStylingPane; public cassandraAddCollectionPane: CassandraAddCollectionPane; private gitHubClient: GitHubClient; public gitHubOAuthService: GitHubOAuthService; @@ -182,7 +180,6 @@ export default class Explorer { public openDialog: ExplorerParams["openDialog"]; public closeDialog: ExplorerParams["closeDialog"]; - private _panes: ContextualPaneBase[] = []; private _isInitializingNotebooks: boolean; private notebookBasePath: ko.Observable; private _arcadiaManager: ArcadiaResourceManager; @@ -411,13 +408,6 @@ export default class Explorer { container: this, }); - this.graphStylingPane = new GraphStylingPane({ - id: "graphstylingpane", - visible: ko.observable(false), - - container: this, - }); - this.cassandraAddCollectionPane = new CassandraAddCollectionPane({ id: "cassandraaddcollectionpane", visible: ko.observable(false), @@ -433,7 +423,6 @@ export default class Explorer { } }); - this._panes = [this.addDatabasePane, this.graphStylingPane, this.cassandraAddCollectionPane]; this.addDatabaseText.subscribe((addDatabaseText: string) => this.addDatabasePane.title(addDatabaseText)); this.isTabsContentExpanded = ko.observable(false); @@ -1058,10 +1047,6 @@ export default class Explorer { : this.selectedNode().collection) as ViewModels.Collection; } - public closeAllPanes(): void { - this._panes.forEach((pane: ContextualPaneBase) => pane.close()); - } - public isRunningOnNationalCloud(): boolean { return ( userContext.portalEnv === "blackforest" || @@ -1855,7 +1840,6 @@ export default class Explorer { public async handleOpenFileAction(path: string): Promise { if (this.isAccountReady() && !(await this._containsDefaultNotebookWorkspace(userContext.databaseAccount))) { - this.closeAllPanes(); this._openSetupNotebooksPaneForQuickstart(); } diff --git a/src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.test.ts b/src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.test.ts index 1f434d577..9c1fcdc2f 100644 --- a/src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.test.ts +++ b/src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.test.ts @@ -1,7 +1,7 @@ import * as sinon from "sinon"; -import { D3ForceGraph, LoadMoreDataAction, D3GraphNodeData } from "./D3ForceGraph"; -import { D3Node, D3Link, GraphData } from "../GraphExplorerComponent/GraphData"; import GraphTab from "../../Tabs/GraphTab"; +import { D3Link, D3Node, GraphData } from "../GraphExplorerComponent/GraphData"; +import { D3ForceGraph, D3GraphNodeData, LoadMoreDataAction } from "./D3ForceGraph"; describe("D3ForceGraph", () => { const v1Id = "v1"; @@ -68,7 +68,7 @@ describe("D3ForceGraph", () => { beforeEach(() => { forceGraph = new D3ForceGraph({ - graphConfig: GraphTab.createGraphConfig(), + igraphConfig: GraphTab.createIGraphConfig(), onHighlightedNode: sinon.spy(), onLoadMoreData: (action: LoadMoreDataAction): void => {}, @@ -141,6 +141,7 @@ describe("D3ForceGraph", () => { const mouseoverEvent = document.createEvent("Events"); mouseoverEvent.initEvent("mouseover", true, false); $(rootNode).find(".node")[0].dispatchEvent(mouseoverEvent); // [0] is v1 vertex + expect($(rootNode).find(".node")[0]).toBe(1); // onHighlightedNode is always called once to clear the selection expect((forceGraph.params.onHighlightedNode as sinon.SinonSpy).calledTwice).toBe(true); @@ -150,7 +151,7 @@ describe("D3ForceGraph", () => { expect(onHighlightedNode.id).toEqual(v1Id); }; - forceGraph.updateGraph(newGraph); + forceGraph.updateGraph(newGraph, forceGraph.igraphConfig); }); }); }); diff --git a/src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts b/src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts index 05825bf98..b6d8717c4 100644 --- a/src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts +++ b/src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts @@ -13,7 +13,7 @@ import _ from "underscore"; import * as Constants from "../../../Common/Constants"; import { NeighborType } from "../../../Contracts/ViewModels"; import { logConsoleError } from "../../../Utils/NotificationConsoleUtils"; -import { GraphConfig } from "../../Tabs/GraphTab"; +import { IGraphConfig } from "./../../Tabs/GraphTab"; import { D3Link, D3Node, GraphData } from "./GraphData"; import { GraphExplorer } from "./GraphExplorer"; @@ -48,21 +48,22 @@ interface ZoomTransform extends Point2D { export interface D3ForceGraphParameters { // Graph to parent - graphConfig: GraphConfig; - onHighlightedNode: (highlightedNode: D3GraphNodeData) => void; // a new node has been highlighted in the graph - onLoadMoreData: (action: LoadMoreDataAction) => void; + + igraphConfig: IGraphConfig; + onHighlightedNode?: (highlightedNode: D3GraphNodeData) => void; // a new node has been highlighted in the graph + onLoadMoreData?: (action: LoadMoreDataAction) => void; // parent to graph - onInitialized: (instance: GraphRenderer) => void; + onInitialized?: (instance: GraphRenderer) => void; // For unit testing purposes - onGraphUpdated: (timestamp: number) => void; + onGraphUpdated?: (timestamp: number) => void; } export interface GraphRenderer { selectNode(id: string): void; resetZoom(): void; - updateGraph(graphData: GraphData): void; + updateGraph(graphData: GraphData, igraphConfigParam?: IGraphConfig): void; enableHighlight(enable: boolean): void; } @@ -108,7 +109,7 @@ export class D3ForceGraph implements GraphRenderer { private viewCenter: Point2D; // Map a property to a graph node attribute (such as color) - private uniqueValues: (string | number)[]; // keep track of unique values + private uniqueValues: (string | number)[] = []; // keep track of unique values private graphDataWrapper: GraphData; // Communication with outside @@ -119,9 +120,11 @@ export class D3ForceGraph implements GraphRenderer { // outside -> Graph private idToSelect: ko.Observable; // Programmatically select node by id outside graph private isHighlightDisabled: boolean; + public igraphConfig: IGraphConfig; public constructor(params: D3ForceGraphParameters) { this.params = params; + this.igraphConfig = this.params.igraphConfig; this.idToSelect = ko.observable(null); this.errorMsgs = ko.observableArray([]); this.graphDataWrapper = null; @@ -151,7 +154,10 @@ export class D3ForceGraph implements GraphRenderer { this.g.remove(); } - public updateGraph(newGraph: GraphData): void { + public updateGraph(newGraph: GraphData, igraphConfigParam?: IGraphConfig): void { + if (igraphConfigParam) { + this.igraphConfig = igraphConfigParam; + } if (!newGraph || !this.simulation) { return; } @@ -159,7 +165,8 @@ export class D3ForceGraph implements GraphRenderer { this.graphDataWrapper = new GraphData(); this.graphDataWrapper.setData(newGraph); - const key = this.params.graphConfig.nodeColorKey(); + const key = this.igraphConfig.nodeColorKey; + if (key !== GraphExplorer.NONE_CHOICE) { this.updateUniqueValues(key); } @@ -265,20 +272,7 @@ export class D3ForceGraph implements GraphRenderer { }); }); - // Redraw if any of these configs change - this.params.graphConfig.nodeColor.subscribe(this.redrawGraph.bind(this)); - this.params.graphConfig.nodeColorKey.subscribe((key: string) => { - // Compute colormap - this.uniqueValues = []; - this.updateUniqueValues(key); - this.redrawGraph(); - }); - this.params.graphConfig.linkColor.subscribe(() => this.redrawGraph()); - this.params.graphConfig.showNeighborType.subscribe(() => this.redrawGraph()); - this.params.graphConfig.nodeCaption.subscribe(() => this.redrawGraph()); - this.params.graphConfig.nodeSize.subscribe(() => this.redrawGraph()); - this.params.graphConfig.linkWidth.subscribe(() => this.redrawGraph()); - this.params.graphConfig.nodeIconKey.subscribe(() => this.redrawGraph()); + this.redrawGraph(); this.instantiateSimulation(); } // initialize @@ -371,7 +365,10 @@ export class D3ForceGraph implements GraphRenderer { */ private shiftGraph(targetPosition: Point2D): Q.Promise { const deferred: Q.Deferred = Q.defer(); - const offset = { x: this.width / 2 - targetPosition.x, y: this.height / 2 - targetPosition.y }; + const offset = { + x: this.width / 2 - targetPosition.x, + y: this.height / 2 - targetPosition.y, + }; this.viewCenter = targetPosition; if (Math.abs(offset.x) > 0.5 && Math.abs(offset.y) > 0.5) { @@ -526,7 +523,10 @@ export class D3ForceGraph implements GraphRenderer { .transition() .duration(D3ForceGraph.TRANSITION_STEP3_MS) .attrTween("transform", (d: D3Node) => { - const finalPos = nodeFinalPositionMap.get(d.id) || { x: viewCenter.x, y: viewCenter.y }; + const finalPos = nodeFinalPositionMap.get(d.id) || { + x: viewCenter.x, + y: viewCenter.y, + }; const ix = interpolateNumber(viewCenter.x, finalPos.x); const iy = interpolateNumber(viewCenter.y, finalPos.y); return (t: number) => { @@ -626,10 +626,10 @@ export class D3ForceGraph implements GraphRenderer { this.addNewLinks(); - const nodes = this.simulation.nodes(); + const nodes1 = this.simulation.nodes(); this.redrawGraph(); - this.animateBigBang(nodes, newNodes); + this.animateBigBang(nodes1, newNodes); this.simulation.alpha(1).restart(); this.params.onGraphUpdated(new Date().getTime()); @@ -657,8 +657,8 @@ export class D3ForceGraph implements GraphRenderer { .append("path") .attr("class", "link") .attr("fill", "none") - .attr("stroke-width", this.params.graphConfig.linkWidth()) - .attr("stroke", this.params.graphConfig.linkColor()); + .attr("stroke-width", this.igraphConfig.linkWidth) + .attr("stroke", this.igraphConfig.linkColor); if (D3ForceGraph.useSvgMarkerEnd()) { line.attr("marker-end", `url(#${this.getArrowHeadSymbolId()}-marker)`); @@ -668,7 +668,7 @@ export class D3ForceGraph implements GraphRenderer { .append("use") .attr("xlink:href", `#${this.getArrowHeadSymbolId()}-nonMarker`) .attr("class", "markerEnd link") - .attr("fill", this.params.graphConfig.linkColor()) + .attr("fill", this.igraphConfig.linkColor) .classed(`${this.getArrowHeadSymbolId()}`, true); } @@ -724,7 +724,7 @@ export class D3ForceGraph implements GraphRenderer { .append("circle") .attr("fill", this.getNodeColor.bind(this)) .attr("class", "main") - .attr("r", this.params.graphConfig.nodeSize()); + .attr("r", this.igraphConfig.nodeSize); var iconGroup = newNodes .append("g") @@ -749,7 +749,7 @@ export class D3ForceGraph implements GraphRenderer { self.onNodeClicked(this.parentNode, d); } }); - var nodeSize = this.params.graphConfig.nodeSize(); + var nodeSize = this.igraphConfig.nodeSize; var bgsize = nodeSize + 1; iconGroup @@ -759,7 +759,7 @@ export class D3ForceGraph implements GraphRenderer { .attr("width", bgsize * 2) .attr("height", bgsize * 2) .attr("fill-opacity", (d: D3Node) => { - return this.params.graphConfig.nodeIconKey() ? 1 : 0; + return this.igraphConfig.nodeIconKey ? 1 : 0; }) .attr("class", "icon-background"); @@ -767,14 +767,13 @@ export class D3ForceGraph implements GraphRenderer { iconGroup .append("svg:image") .attr("xlink:href", (d: D3Node) => { - return D3ForceGraph.computeImageData(d, this.params.graphConfig); + return D3ForceGraph.computeImageData(d, this.igraphConfig); }) .attr("x", -nodeSize) .attr("y", -nodeSize) .attr("height", nodeSize * 2) .attr("width", nodeSize * 2) .attr("class", "icon"); - newNodes .append("text") .attr("class", "caption") @@ -808,7 +807,7 @@ export class D3ForceGraph implements GraphRenderer { .attr("x2", 0) .attr("y2", gaugeYOffset) .style("stroke-width", 1) - .style("stroke", this.params.graphConfig.linkColor()); + .style("stroke", this.igraphConfig.linkColor); parent .append("use") .attr("xlink:href", "#triangleRight") @@ -877,7 +876,7 @@ export class D3ForceGraph implements GraphRenderer { .attr("height", gaugeHeight) .style("fill", "white") .style("stroke-width", 1) - .style("stroke", this.params.graphConfig.linkColor()); + .style("stroke", this.igraphConfig.linkColor); parent .append("rect") .attr("x", (d: D3Node) => { @@ -894,7 +893,7 @@ export class D3ForceGraph implements GraphRenderer { : 0; }) .attr("height", gaugeHeight) - .style("fill", this.params.graphConfig.nodeColor()) + .style("fill", this.igraphConfig.nodeColor) .attr("visibility", (d: D3Node) => (d._pagination && d._pagination.total ? "visible" : "hidden")); parent .append("text") @@ -971,7 +970,7 @@ export class D3ForceGraph implements GraphRenderer { const self = this; nodeSelection.selectAll(".loadmore").remove(); - var nodeSize = this.params.graphConfig.nodeSize(); + var nodeSize = this.igraphConfig.nodeSize; const rootSelectionG = nodeSelection .filter((d: D3Node) => { return !!d._isRoot && !!d._pagination; @@ -995,7 +994,7 @@ export class D3ForceGraph implements GraphRenderer { this.createLoadMoreControl(missingNeighborNonRootG, nodeSize); // Don't color icons individually, just the definitions - this.svg.selectAll("#loadMoreIcon ellipse").attr("fill", this.params.graphConfig.nodeColor()); + this.svg.selectAll("#loadMoreIcon ellipse").attr("fill", this.igraphConfig.nodeColor); } /** @@ -1032,11 +1031,11 @@ export class D3ForceGraph implements GraphRenderer { * @param d */ private getNodeColor(d: D3Node): string { - if (this.params.graphConfig.nodeColorKey()) { - const val = GraphData.getNodePropValue(d, this.params.graphConfig.nodeColorKey()); + if (this.igraphConfig.nodeColorKey) { + const val = GraphData.getNodePropValue(d, this.igraphConfig.nodeColorKey); return this.lookupColorFromKey(val); } else { - return this.params.graphConfig.nodeColor(); + return this.igraphConfig.nodeColor; } } @@ -1103,12 +1102,12 @@ export class D3ForceGraph implements GraphRenderer { this.graphDataWrapper.getTargetsForId(nodeId) ); } - })(this.params.graphConfig.showNeighborType()); + })(this.igraphConfig.showNeighborType); return (!neighbors || neighbors.indexOf(d.id) === -1) && d.id !== nodeId; }); this.g.selectAll(".link").classed("inactive", (l: D3Link) => { - switch (this.params.graphConfig.showNeighborType()) { + switch (this.igraphConfig.showNeighborType) { case NeighborType.SOURCES_ONLY: return (l.target).id !== nodeId; case NeighborType.TARGETS_ONLY: @@ -1152,7 +1151,7 @@ export class D3ForceGraph implements GraphRenderer { } private retrieveNodeCaption(d: D3Node) { - let key = this.params.graphConfig.nodeCaption(); + let key = this.igraphConfig.nodeCaption; let value: string = d.id || d.label; if (key) { value = GraphData.getNodePropValue(d, key) || ""; @@ -1194,10 +1193,16 @@ export class D3ForceGraph implements GraphRenderer { } private positionLinkEnd(l: D3Link) { - const source: Point2D = { x: (l.source).x, y: (l.source).y }; - const target: Point2D = { x: (l.target).x, y: (l.target).y }; + const source: Point2D = { + x: (l.source).x, + y: (l.source).y, + }; + const target: Point2D = { + x: (l.target).x, + y: (l.target).y, + }; const d1 = D3ForceGraph.calculateControlPoint(source, target); - var radius = this.params.graphConfig.nodeSize() + 3; + var radius = this.igraphConfig.nodeSize + 3; // End const dx = target.x - d1.x; @@ -1210,10 +1215,16 @@ export class D3ForceGraph implements GraphRenderer { } private positionLink(l: D3Link) { - const source: Point2D = { x: (l.source).x, y: (l.source).y }; - const target: Point2D = { x: (l.target).x, y: (l.target).y }; + const source: Point2D = { + x: (l.source).x, + y: (l.source).y, + }; + const target: Point2D = { + x: (l.target).x, + y: (l.target).y, + }; const d1 = D3ForceGraph.calculateControlPoint(source, target); - var radius = this.params.graphConfig.nodeSize() + 3; + var radius = this.igraphConfig.nodeSize + 3; // Start var dx = d1.x - source.x; @@ -1245,13 +1256,13 @@ export class D3ForceGraph implements GraphRenderer { return d._isRoot ? "node root" : "node"; }); - this.applyConfig(this.params.graphConfig); + this.applyConfig(this.igraphConfig); } - private static computeImageData(d: D3Node, config: GraphConfig): string { - let propValue = GraphData.getNodePropValue(d, config.nodeIconKey()) || ""; + private static computeImageData(d: D3Node, config: IGraphConfig): string { + let propValue = GraphData.getNodePropValue(d, config.nodeIconKey) || ""; // Trim leading and trailing spaces to make comparison more forgiving. - let value = config.iconsMap()[propValue.trim()]; + let value = config.iconsMap[propValue.trim()]; if (!value) { return undefined; } @@ -1261,48 +1272,46 @@ export class D3ForceGraph implements GraphRenderer { /** * Update graph according to configuration or use default */ - private applyConfig(config: GraphConfig) { - if (config.nodeIconKey()) { + private applyConfig(config: IGraphConfig) { + if (config.nodeIconKey) { this.g .selectAll(".node .icon") .attr("xlink:href", (d: D3Node) => { return D3ForceGraph.computeImageData(d, config); }) - .attr("x", -config.nodeSize()) - .attr("y", -config.nodeSize()) - .attr("height", config.nodeSize() * 2) - .attr("width", config.nodeSize() * 2) + .attr("x", -config.nodeSize) + .attr("y", -config.nodeSize) + .attr("height", config.nodeSize * 2) + .attr("width", config.nodeSize * 2) .attr("class", "icon"); } else { // clear icons this.g.selectAll(".node .icon").attr("xlink:href", undefined); } this.g.selectAll(".node .icon-background").attr("fill-opacity", (d: D3Node) => { - return config.nodeIconKey() ? 1 : 0; + return config.nodeIconKey ? 1 : 0; }); - this.g.selectAll(".node text.caption").text((d: D3Node) => { return this.retrieveNodeCaption(d); }); - this.g.selectAll(".node circle.main").attr("r", config.nodeSize()); - this.g.selectAll(".node text.caption").attr("dx", config.nodeSize() + 2); + this.g.selectAll(".node circle.main").attr("r", config.nodeSize); + this.g.selectAll(".node text.caption").attr("dx", config.nodeSize + 2); this.g.selectAll(".node circle").attr("fill", this.getNodeColor.bind(this)); // Can't color nodes individually if using defs - this.svg.selectAll("#loadMoreIcon ellipse").attr("fill", this.params.graphConfig.nodeColor()); + this.svg.selectAll("#loadMoreIcon ellipse").attr("fill", config.nodeColor); + this.g.selectAll(".link").attr("stroke-width", config.linkWidth); - this.g.selectAll(".link").attr("stroke-width", config.linkWidth()); - - this.g.selectAll(".link").attr("stroke", config.linkColor()); + this.g.selectAll(".link").attr("stroke", config.linkColor); if (D3ForceGraph.useSvgMarkerEnd()) { this.svg .select(`#${this.getArrowHeadSymbolId()}-marker`) - .attr("fill", config.linkColor()) - .attr("stroke", config.linkColor()); + .attr("fill", config.linkColor) + .attr("stroke", config.linkColor); } else { - this.svg.select(`#${this.getArrowHeadSymbolId()}-nonMarker`).attr("fill", config.linkColor()); + this.svg.select(`#${this.getArrowHeadSymbolId()}-nonMarker`).attr("fill", config.linkColor); } // Reset highlight diff --git a/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx b/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx index cee9c4c76..1954186c8 100644 --- a/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx +++ b/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx @@ -1,20 +1,20 @@ jest.mock("../../../Common/dataAccess/queryDocuments"); jest.mock("../../../Common/dataAccess/queryDocumentsPage"); -import React from "react"; -import * as sinon from "sinon"; import { mount, ReactWrapper } from "enzyme"; import * as Q from "q"; +import React from "react"; +import * as sinon from "sinon"; import "../../../../externals/jquery.typeahead.min"; -import { GraphExplorer, GraphExplorerProps, GraphAccessor, GraphHighlightedNodeData } from "./GraphExplorer"; -import * as D3ForceGraph from "./D3ForceGraph"; -import { GraphData } from "./GraphData"; -import { TabComponent } from "../../Controls/Tabs/TabComponent"; -import * as DataModels from "../../../Contracts/DataModels"; -import * as StorageUtility from "../../../Shared/StorageUtility"; -import GraphTab from "../../Tabs/GraphTab"; -import { ConsoleDataType } from "../../Menus/NotificationConsole/NotificationConsoleComponent"; import { queryDocuments } from "../../../Common/dataAccess/queryDocuments"; import { queryDocumentsPage } from "../../../Common/dataAccess/queryDocumentsPage"; +import * as DataModels from "../../../Contracts/DataModels"; +import * as StorageUtility from "../../../Shared/StorageUtility"; +import { TabComponent } from "../../Controls/Tabs/TabComponent"; +import { ConsoleDataType } from "../../Menus/NotificationConsole/NotificationConsoleComponent"; +import GraphTab from "../../Tabs/GraphTab"; +import * as D3ForceGraph from "./D3ForceGraph"; +import { GraphData } from "./GraphData"; +import { GraphAccessor, GraphExplorer, GraphExplorerProps, GraphHighlightedNodeData } from "./GraphExplorer"; describe("Check whether query result is vertex array", () => { it("should reject null as vertex array", () => { @@ -146,8 +146,8 @@ describe("GraphExplorer", () => { const gremlinRU = 789.12; const createMockProps = (): GraphExplorerProps => { - const graphConfig = GraphTab.createGraphConfig(); - const graphConfigUi = GraphTab.createGraphConfigUiData(graphConfig); + const igraphConfig = GraphTab.createIGraphConfig(); + const igraphConfigUi = GraphTab.createIGraphConfigUiData(igraphConfig); return { onGraphAccessorCreated: (instance: GraphAccessor): void => {}, @@ -170,8 +170,9 @@ describe("GraphExplorer", () => { resourceId: "resourceId", /* TODO Figure out how to make this Knockout-free */ - graphConfigUiData: graphConfigUi, - graphConfig: graphConfig, + igraphConfigUiData: igraphConfigUi, + igraphConfig: igraphConfig, + setIConfigUiData: (data: string[]): void => {}, }; }; diff --git a/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx b/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx index bfd23f09c..5b2441e40 100644 --- a/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx +++ b/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx @@ -19,7 +19,7 @@ import { EditorReact } from "../../Controls/Editor/EditorReact"; import * as InputTypeaheadComponent from "../../Controls/InputTypeahead/InputTypeaheadComponent"; import * as TabComponent from "../../Controls/Tabs/TabComponent"; import { ConsoleDataType } from "../../Menus/NotificationConsole/NotificationConsoleComponent"; -import { GraphConfig } from "../../Tabs/GraphTab"; +import { IGraphConfig } from "../../Tabs/GraphTab"; import { ArraysByKeyCache } from "./ArraysByKeyCache"; import * as D3ForceGraph from "./D3ForceGraph"; import { EdgeInfoCache } from "./EdgeInfoCache"; @@ -31,10 +31,10 @@ import * as LeftPane from "./LeftPaneComponent"; import { MiddlePaneComponent } from "./MiddlePaneComponent"; import * as NodeProperties from "./NodePropertiesComponent"; import { QueryContainerComponent } from "./QueryContainerComponent"; - export interface GraphAccessor { applyFilter: () => void; addVertex: (v: ViewModels.NewVertexData) => Q.Promise; + shareIGraphConfig: (igraphConfig: IGraphConfig) => void; } export interface GraphExplorerProps { @@ -58,9 +58,10 @@ export interface GraphExplorerProps { onLoadStartKeyChange: (newKey: number) => void; resourceId: string; - /* TODO Figure out how to make this Knockout-free */ - graphConfigUiData: ViewModels.GraphConfigUiData; - graphConfig?: GraphConfig; + igraphConfigUiData: ViewModels.IGraphConfigUiData; + igraphConfig: IGraphConfig; + + setIConfigUiData?: (data: string[]) => void; } export interface GraphHighlightedNodeData { @@ -121,6 +122,10 @@ interface GraphExplorerState { filterQueryError: string; filterQueryWarning: string; filterQueryStatus: FilterQueryStatus; + change: string; + + igraphConfigUiData: ViewModels.IGraphConfigUiData; + igraphConfig: IGraphConfig; } export interface EditedProperties { @@ -218,6 +223,8 @@ export class GraphExplorer extends React.Component { - this.props.graphConfig.nodeCaption(key); - const selectedNode = this.state.highlightedNode; - if (selectedNode) { - this.updatePropertiesPane(selectedNode.id); - } - - this.render(); - }); - this.props.graphConfigUiData.nodeColorKeyChoice.subscribe((val) => { - this.props.graphConfig.nodeColorKey(val === GraphExplorer.NONE_CHOICE ? null : val); - this.render(); - }); - this.props.graphConfigUiData.showNeighborType.subscribe((val) => { - this.props.graphConfig.showNeighborType(val); - this.render(); - }); - - this.props.graphConfigUiData.nodeIconChoice.subscribe((val) => { - this.updateNodeIcons(val, this.props.graphConfigUiData.nodeIconSet()); - this.render(); - }); - this.props.graphConfigUiData.nodeIconSet.subscribe((val) => { - this.updateNodeIcons(this.props.graphConfigUiData.nodeIconChoice(), val); - this.render(); - }); - /* *************************************** */ + const selectedNode = this.state.highlightedNode; props.onGraphAccessorCreated({ applyFilter: this.submitQuery.bind(this), addVertex: this.addVertex.bind(this), + shareIGraphConfig: this.shareIGraphConfig.bind(this), }); } // constructor + public shareIGraphConfig(igraphConfig: IGraphConfig) { + this.setState({ + igraphConfig: { ...igraphConfig }, + }); + + const selectedNode = this.state.highlightedNode; + if (selectedNode) { + this.updatePropertiesPane(selectedNode.id); + this.setResultDisplay(GraphExplorer.TAB_INDEX_GRAPH); + } + } + /** * If pk is a string, return ["pk", "id"] * else return [pk, "id"] @@ -408,7 +404,7 @@ export class GraphExplorer extends React.Component { @@ -446,7 +442,7 @@ export class GraphExplorer extends React.Component { GraphExplorer.reportToConsole( @@ -809,7 +805,7 @@ export class GraphExplorer extends React.Component { let graphData = this.originalGraphData; graphData.removeEdge(edgeId, false); - this.updateGraphData(graphData); + this.updateGraphData(graphData, this.state.igraphConfig); }, (error: string) => { GraphExplorer.reportToConsole( @@ -858,7 +854,7 @@ export class GraphExplorer extends React.Component { GraphExplorer.reportToConsole(ConsoleDataType.Error, `Failed to retrieve icons. iconSet:${iconSet}`); @@ -1209,7 +1220,7 @@ export class GraphExplorer extends React.Component { @@ -1320,7 +1331,7 @@ export class GraphExplorer extends React.Component { @@ -1539,9 +1550,14 @@ export class GraphExplorer extends React.Component) { + private updateGraphData( + graphData: GraphData.GraphData, + igraphConfig?: IGraphConfig + ) { this.originalGraphData = graphData; let gd = JSON.parse(JSON.stringify(this.originalGraphData)); if (!this.d3ForceGraph) { console.warn("Attempting to update graph, but d3ForceGraph not initialized, yet."); return; } - this.d3ForceGraph.updateGraph(gd); + this.d3ForceGraph.updateGraph(gd, igraphConfig); } public onMiddlePaneInitialized(instance: D3ForceGraph.GraphRenderer): void { @@ -1694,10 +1722,12 @@ export class GraphExplorer extends React.Component this.onMiddlePaneInitialized(instance), + onInitialized: (instance: D3ForceGraph.GraphRenderer): void => { + this.onMiddlePaneInitialized(instance); + }, onGraphUpdated: this.onGraphUpdated.bind(this), }; diff --git a/src/Explorer/Graph/GraphExplorerComponent/GraphExplorerAdapter.tsx b/src/Explorer/Graph/GraphExplorerComponent/GraphExplorerAdapter.tsx new file mode 100644 index 000000000..984419398 --- /dev/null +++ b/src/Explorer/Graph/GraphExplorerComponent/GraphExplorerAdapter.tsx @@ -0,0 +1,74 @@ +import * as React from "react"; +import { ReactAdapter } from "../../../Bindings/ReactBindingHandler"; +import * as ViewModels from "../../../Contracts/ViewModels"; +import { IGraphConfig } from "../../Tabs/GraphTab"; +import { GraphAccessor, GraphExplorer } from "./GraphExplorer"; +interface Parameter { + onIsNewVertexDisabledChange: (isEnabled: boolean) => void; + onGraphAccessorCreated: (instance: GraphAccessor) => void; + onIsFilterQueryLoading: (isFilterQueryLoading: boolean) => void; + onIsValidQuery: (isValidQuery: boolean) => void; + onIsPropertyEditing: (isEditing: boolean) => void; + onIsGraphDisplayed: (isDisplayed: boolean) => void; + onResetDefaultGraphConfigValues: () => void; + + collectionPartitionKeyProperty: string; + graphBackendEndpoint: string; + databaseId: string; + collectionId: string; + masterKey: string; + + onLoadStartKey: number; + onLoadStartKeyChange: (newKey: number) => void; + resourceId: string; + + igraphConfigUiData: ViewModels.IGraphConfigUiData; + igraphConfig: IGraphConfig; + setIConfigUiData?: (data: string[]) => void; +} + +interface IGraphExplorerProps { + isChanged: boolean; +} + +interface IGraphExplorerStates { + isChangedState: boolean; +} + +export interface GraphExplorerAdapter + extends ReactAdapter, + React.Component {} +export class GraphExplorerAdapter implements ReactAdapter { + public params: Parameter; + public parameters = {}; + public isNewVertexDisabled: boolean; + + public constructor(params: Parameter, props?: IGraphExplorerProps) { + this.params = params; + } + + public renderComponent(): JSX.Element { + return ( + + ); + } +} diff --git a/src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts b/src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts deleted file mode 100644 index f88a37c81..000000000 --- a/src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import * as ko from "knockout"; -import { GraphStyleComponent, GraphStyleParams } from "./GraphStyleComponent"; -import * as ViewModels from "../../../Contracts/ViewModels"; - -function buildComponent(buttonOptions: any) { - document.body.innerHTML = GraphStyleComponent.template as any; - const vm = new GraphStyleComponent.viewModel(buttonOptions); - ko.applyBindings(vm); -} - -describe("Graph Style Component", () => { - let buildParams = (config: ViewModels.GraphConfigUiData): GraphStyleParams => { - return { - config: config, - }; - }; - - afterEach(() => { - ko.cleanNode(document); - }); - - describe("Rendering", () => { - it("should display proper list of choices passed in component parameters", () => { - const PROP2 = "prop2"; - const PROPC = "prop3"; - const params = buildParams({ - nodeCaptionChoice: ko.observable(null), - nodeIconChoice: ko.observable(null), - nodeColorKeyChoice: ko.observable(null), - nodeIconSet: ko.observable(null), - nodeProperties: ko.observableArray(["prop1", PROP2]), - nodePropertiesWithNone: ko.observableArray(["propa", "propb", PROPC]), - showNeighborType: ko.observable(null), - }); - - buildComponent(params); - - var e: any = document.querySelector(".graphStyle #nodeCaptionChoices"); - expect(e.options.length).toBe(2); - expect(e.options[1].value).toBe(PROP2); - - e = document.querySelector(".graphStyle #nodeColorKeyChoices"); - expect(e.options.length).toBe(3); - expect(e.options[2].value).toBe(PROPC); - - e = document.querySelector(".graphStyle #nodeIconChoices"); - expect(e.options.length).toBe(3); - expect(e.options[2].value).toBe(PROPC); - }); - }); -}); diff --git a/src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.test.tsx b/src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.test.tsx new file mode 100644 index 000000000..14dd36ca1 --- /dev/null +++ b/src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.test.tsx @@ -0,0 +1,67 @@ +import { render, screen } from "@testing-library/react"; +import React from "react"; +import * as ViewModels from "../../../Contracts/ViewModels"; +import { IGraphConfig } from "../../Tabs/GraphTab"; +import { GraphStyleComponent, GraphStyleProps } from "./GraphStyleComponent"; + +describe("Graph Style Component", () => { + let fakeGraphConfig: IGraphConfig; + let fakeGraphConfigUiData: ViewModels.IGraphConfigUiData; + let props: GraphStyleProps; + beforeEach(() => { + fakeGraphConfig = { + nodeColor: "orange", + nodeColorKey: "node2", + linkColor: "orange", + showNeighborType: 0, + nodeCaption: "node1", + nodeSize: 10, + linkWidth: 1, + nodeIconKey: undefined, + iconsMap: {}, + }; + fakeGraphConfigUiData = { + nodeCaptionChoice: "node1", + nodeIconChoice: undefined, + nodeColorKeyChoice: "node2", + nodeIconSet: undefined, + nodeProperties: ["node1", "node2", "node3"], + nodePropertiesWithNone: ["none", "node1", "node2", "node3"], + showNeighborType: undefined, + }; + props = { + igraphConfig: fakeGraphConfig, + igraphConfigUiData: fakeGraphConfigUiData, + getValues: (): void => undefined, + }; + + render(); + }); + + it("should render default property", () => { + const { asFragment } = render(); + expect(asFragment).toMatchSnapshot(); + }); + + it("should render node properties dropdown list ", () => { + const dropDownList = screen.getByText("Show vertex (node) as"); + expect(dropDownList).toBeDefined(); + }); + + it("should render Map this property to node color dropdown list", () => { + const nodeColorDropdownList = screen.getByText("Map this property to node color"); + expect(nodeColorDropdownList).toBeDefined(); + }); + + it("should render show neighbor options", () => { + const nodeShowNeighborOptions = screen.getByText("Show"); + expect(nodeShowNeighborOptions).toBeDefined(); + }); + + it("should call handleOnChange method", () => { + const handleOnChange = jest.fn(); + const nodeCaptionDropdownList = screen.getByText("Show vertex (node) as"); + nodeCaptionDropdownList.onchange = handleOnChange(); + expect(handleOnChange).toHaveBeenCalled(); + }); +}); diff --git a/src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts b/src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts deleted file mode 100644 index 9974e65da..000000000 --- a/src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts +++ /dev/null @@ -1,103 +0,0 @@ -import * as Constants from "../../../Common/Constants"; -import * as ViewModels from "../../../Contracts/ViewModels"; -import { WaitsForTemplateViewModel } from "../../WaitsForTemplateViewModel"; - -/** - * Parameters for this component - */ -export interface GraphStyleParams { - config: ViewModels.GraphConfigUiData; - firstFieldHasFocus?: ko.Observable; - - /** - * Callback triggered when the template is bound to the component (for testing purposes) - */ - onTemplateReady?: () => void; -} - -class GraphStyleViewModel extends WaitsForTemplateViewModel { - private params: GraphStyleParams; - - public constructor(params: GraphStyleParams) { - super(); - super.onTemplateReady((isTemplateReady: boolean) => { - if (isTemplateReady && params.onTemplateReady) { - params.onTemplateReady(); - } - }); - - this.params = params; - } - - public onAllNeighborsKeyPress = (source: any, event: KeyboardEvent): boolean => { - if (event.keyCode === Constants.KeyCodes.Space || event.keyCode === Constants.KeyCodes.Enter) { - this.params.config.showNeighborType(ViewModels.NeighborType.BOTH); - event.stopPropagation(); - return false; - } - - return true; - }; - - public onSourcesKeyPress = (source: any, event: KeyboardEvent): boolean => { - if (event.keyCode === Constants.KeyCodes.Space || event.keyCode === Constants.KeyCodes.Enter) { - this.params.config.showNeighborType(ViewModels.NeighborType.SOURCES_ONLY); - event.stopPropagation(); - return false; - } - - return true; - }; - - public onTargetsKeyPress = (source: any, event: KeyboardEvent): boolean => { - if (event.keyCode === Constants.KeyCodes.Space || event.keyCode === Constants.KeyCodes.Enter) { - this.params.config.showNeighborType(ViewModels.NeighborType.TARGETS_ONLY); - event.stopPropagation(); - return false; - } - - return true; - }; -} - -const template = ` -
-
-

Show vertex (node) as

- -
-
-

Map this property to node color

- -
-
-

Map this property to node icon

- - -
- -

Show

- -
-
- - -
-
- - -
-
- - -
-
-
`; - -export const GraphStyleComponent = { - viewModel: GraphStyleViewModel, - template, -}; diff --git a/src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.tsx b/src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.tsx new file mode 100644 index 000000000..5030ad730 --- /dev/null +++ b/src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.tsx @@ -0,0 +1,131 @@ +import { ChoiceGroup, Dropdown, IChoiceGroupOption, IDropdownOption, IDropdownStyles, Stack } from "@fluentui/react"; +import React, { FunctionComponent, useEffect, useState } from "react"; +import { IGraphConfigUiData, NeighborType } from "../../../Contracts/ViewModels"; +import { IGraphConfig } from "../../Tabs/GraphTab"; +const IGraphConfigType = { + NODE_CAPTION: "NODE_CAPTION", + NODE_COLOR: "NODE_COLOR", + NODE_ICON: "NODE_ICON", + SHOW_NEIGHBOR_TYPE: "SHOW_NEIGHBOR_TYPE", +}; +export interface GraphStyleProps { + igraphConfig: IGraphConfig; + igraphConfigUiData: IGraphConfigUiData; + getValues: (igraphConfig?: IGraphConfig) => void; +} + +export const GraphStyleComponent: FunctionComponent = ({ + igraphConfig, + igraphConfigUiData, + getValues, +}: GraphStyleProps): JSX.Element => { + const [igraphConfigState, setIGraphConfig] = useState(igraphConfig); + const [selected, setSelected] = useState(false); + + const nodePropertiesOptions = igraphConfigUiData.nodeProperties.map((nodeProperty) => ({ + key: nodeProperty, + text: nodeProperty, + })); + + const nodePropertiesWithNoneOptions = igraphConfigUiData.nodePropertiesWithNone.map((nodePropertyWithNone) => ({ + key: nodePropertyWithNone, + text: nodePropertyWithNone, + })); + + const showNeighborTypeOptions: IChoiceGroupOption[] = [ + { key: NeighborType.BOTH.toString(), text: "All neighbors" }, + { key: NeighborType.SOURCES_ONLY.toString(), text: "Sources" }, + { key: NeighborType.TARGETS_ONLY.toString(), text: "Targets" }, + ]; + + const dropdownStyles: Partial = { + dropdown: { height: 32, marginRight: 10 }, + }; + const choiceButtonStyles = { + flexContainer: [ + { + selectors: { + ".ms-ChoiceField-wrapper label": { + fontSize: 14, + paddingTop: 0, + }, + }, + }, + ], + }; + + useEffect(() => { + if (selected) { + getValues(igraphConfigState); + } + //eslint-disable-next-line + }, [igraphConfigState]); + + const handleOnChange = (val: string, igraphConfigType: string) => { + switch (igraphConfigType) { + case IGraphConfigType.NODE_CAPTION: + setSelected(true); + setIGraphConfig({ + ...igraphConfigState, + nodeCaption: val, + }); + break; + case IGraphConfigType.NODE_COLOR: + setSelected(true); + setIGraphConfig({ + ...igraphConfigState, + nodeColorKey: val, + }); + break; + case IGraphConfigType.SHOW_NEIGHBOR_TYPE: + setSelected(true); + setIGraphConfig({ + ...igraphConfigState, + showNeighborType: parseInt(val), + }); + break; + } + }; + return ( + +
+
+ + handleOnChange(options.key.toString(), IGraphConfigType.NODE_CAPTION) + } + /> +
+
+ + handleOnChange(options.key.toString(), IGraphConfigType.NODE_COLOR) + } + /> +
+ +
+ + handleOnChange(options.key.toString(), IGraphConfigType.SHOW_NEIGHBOR_TYPE) + } + /> +
+
+
+ ); +}; diff --git a/src/Explorer/Graph/GraphStyleComponent/__snapshots__/GraphStyleComponent.test.tsx.snap b/src/Explorer/Graph/GraphStyleComponent/__snapshots__/GraphStyleComponent.test.tsx.snap new file mode 100644 index 000000000..721d4cf50 --- /dev/null +++ b/src/Explorer/Graph/GraphStyleComponent/__snapshots__/GraphStyleComponent.test.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Graph Style Component should render default property 1`] = `[Function]`; diff --git a/src/Explorer/Graph/GraphStyleComponent/graph-style-component.html b/src/Explorer/Graph/GraphStyleComponent/graph-style-component.html deleted file mode 100644 index 3cc120590..000000000 --- a/src/Explorer/Graph/GraphStyleComponent/graph-style-component.html +++ /dev/null @@ -1,74 +0,0 @@ -
-
-

Show vertex (node) as

- -
-
-

Map this property to node color

- -
-
-

Map this property to node icon

- - -
- -

Show

- -
-
- - -
-
- - -
-
- - -
-
-
diff --git a/src/Explorer/OpenActions.test.ts b/src/Explorer/OpenActions.test.ts index e8113455f..0ea2057b7 100644 --- a/src/Explorer/OpenActions.test.ts +++ b/src/Explorer/OpenActions.test.ts @@ -17,7 +17,6 @@ describe("OpenActions", () => { explorer.onNewCollectionClicked = jest.fn(); explorer.cassandraAddCollectionPane = {} as CassandraAddCollectionPane; explorer.cassandraAddCollectionPane.open = jest.fn(); - explorer.closeAllPanes = () => {}; database = { id: ko.observable("db"), diff --git a/src/Explorer/OpenActions.ts b/src/Explorer/OpenActions.ts index 8a7c87f53..afc3251c2 100644 --- a/src/Explorer/OpenActions.ts +++ b/src/Explorer/OpenActions.ts @@ -140,19 +140,16 @@ function openPane(action: ActionContracts.OpenPane, explorer: Explorer) { action.paneKind === ActionContracts.PaneKind.AddCollection || (action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.AddCollection] ) { - explorer.closeAllPanes(); explorer.onNewCollectionClicked(); } else if ( action.paneKind === ActionContracts.PaneKind.CassandraAddCollection || (action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.CassandraAddCollection] ) { - explorer.closeAllPanes(); explorer.cassandraAddCollectionPane.open(); } else if ( action.paneKind === ActionContracts.PaneKind.GlobalSettings || (action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.GlobalSettings] ) { - explorer.closeAllPanes(); explorer.openSettingPane(); } } diff --git a/src/Explorer/Panes/GitHubReposPanel/__snapshots__/GitHubReposPanel.test.tsx.snap b/src/Explorer/Panes/GitHubReposPanel/__snapshots__/GitHubReposPanel.test.tsx.snap index 5da784af4..9be73eb7e 100644 --- a/src/Explorer/Panes/GitHubReposPanel/__snapshots__/GitHubReposPanel.test.tsx.snap +++ b/src/Explorer/Panes/GitHubReposPanel/__snapshots__/GitHubReposPanel.test.tsx.snap @@ -21,115 +21,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = ` "_closeSynapseLinkModalDialog": [Function], "_isAfecFeatureRegistered": [Function], "_isInitializingNotebooks": false, - "_panes": Array [ - AddDatabasePane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "databaseCreateNewShared": [Function], - "databaseId": [Function], - "databaseIdLabel": [Function], - "databaseIdPlaceHolder": [Function], - "databaseIdTooltipText": [Function], - "databaseLevelThroughputTooltipText": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "freeTierExceedThroughputTooltip": [Function], - "id": "adddatabasepane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isTemplateReady": [Function], - "maxAutoPilotThroughputSet": [Function], - "maxThroughputRU": [Function], - "maxThroughputRUText": [Function], - "minThroughputRU": [Function], - "onMoreDetailsKeyPress": [Function], - "requestUnitsUsageCost": [Function], - "ruToolTipText": [Function], - "showUpsellMessage": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "upsellAnchorText": [Function], - "upsellAnchorUrl": [Function], - "upsellMessage": [Function], - "upsellMessageAriaLabel": [Function], - "visible": [Function], - }, - GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, - CassandraAddCollectionPane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "createTableQuery": [Function], - "dedicateTableThroughput": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "cassandraaddcollectionpane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isSharedAutoPilotSelected": [Function], - "isTemplateReady": [Function], - "keyspaceCreateNew": [Function], - "keyspaceHasSharedOffer": [Function], - "keyspaceId": [Function], - "keyspaceIds": [Function], - "keyspaceOffers": Map {}, - "keyspaceThroughput": [Function], - "maxThroughputRU": [Function], - "minThroughputRU": [Function], - "requestUnitsUsageCostDedicated": [Function], - "requestUnitsUsageCostShared": [Function], - "ruToolTipText": [Function], - "selectedAutoPilotThroughput": [Function], - "sharedAutoPilotThroughput": [Function], - "sharedThroughputRangeText": [Function], - "sharedThroughputSpendAck": [Function], - "sharedThroughputSpendAckText": [Function], - "sharedThroughputSpendAckVisible": [Function], - "tableId": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "userTableQuery": [Function], - "visible": [Function], - }, - ], "_refreshSparkEnabledStateForAccount": [Function], "_resetNotebookWorkspace": [Function], "addCollectionText": [Function], @@ -1015,26 +906,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = ` }, }, }, - "graphStylingPane": GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, "hasStorageAnalyticsAfecFeature": [Function], "isAccountReady": [Function], "isAutoscaleDefaultEnabled": [Function], diff --git a/src/Explorer/Panes/GraphStylingPane.html b/src/Explorer/Panes/GraphStylingPane.html deleted file mode 100644 index b6667744c..000000000 --- a/src/Explorer/Panes/GraphStylingPane.html +++ /dev/null @@ -1,59 +0,0 @@ -
-
-
- -
-
- -
- Graph Styling -
- Close -
-
- - - -
-
- Error - - - - More details - - -
-
- - - -
- -
-
-
-
- -
-
- -
-
diff --git a/src/Explorer/Panes/GraphStylingPane.ts b/src/Explorer/Panes/GraphStylingPane.ts deleted file mode 100644 index 10188d7f1..000000000 --- a/src/Explorer/Panes/GraphStylingPane.ts +++ /dev/null @@ -1,68 +0,0 @@ -import * as ko from "knockout"; -import * as ViewModels from "../../Contracts/ViewModels"; -import { ContextualPaneBase } from "./ContextualPaneBase"; - -export default class GraphStylingPane extends ContextualPaneBase { - public graphConfigUIData: ViewModels.GraphConfigUiData; - private remoteConfig: ViewModels.GraphConfigUiData; - - constructor(options: ViewModels.PaneOptions) { - super(options); - - this.graphConfigUIData = { - showNeighborType: ko.observable(ViewModels.NeighborType.TARGETS_ONLY), - nodeProperties: ko.observableArray([]), - nodePropertiesWithNone: ko.observableArray([]), - nodeCaptionChoice: ko.observable(null), - nodeColorKeyChoice: ko.observable(null), - nodeIconChoice: ko.observable(null), - nodeIconSet: ko.observable(null), - }; - - this.graphConfigUIData.nodeCaptionChoice.subscribe((val) => { - if (this.remoteConfig) { - this.remoteConfig.nodeCaptionChoice(val); - } - }); - this.graphConfigUIData.nodeColorKeyChoice.subscribe((val) => { - if (this.remoteConfig) { - this.remoteConfig.nodeColorKeyChoice(val); - } - }); - this.graphConfigUIData.nodeIconChoice.subscribe((val) => { - if (this.remoteConfig) { - this.remoteConfig.nodeIconChoice(val); - } - }); - this.graphConfigUIData.nodeIconSet.subscribe((val) => { - if (this.remoteConfig) { - this.remoteConfig.nodeIconSet(val); - } - }); - this.graphConfigUIData.showNeighborType.subscribe((val) => { - if (this.remoteConfig) { - this.remoteConfig.showNeighborType(val); - } - }); - } - - public setData(config: ViewModels.GraphConfigUiData): void { - // Update pane ko's with config's ko - this.graphConfigUIData.nodeIconChoice(config.nodeIconChoice()); - this.graphConfigUIData.nodeIconSet(config.nodeIconSet()); - this.graphConfigUIData.nodeProperties(config.nodeProperties()); - this.graphConfigUIData.nodePropertiesWithNone(config.nodePropertiesWithNone()); - this.graphConfigUIData.showNeighborType(config.showNeighborType()); - // Make sure these two happen *after* setting the options of the dropdown, - // otherwise, the ko will not get set if the choice is not part of the options - this.graphConfigUIData.nodeCaptionChoice(config.nodeCaptionChoice()); - this.graphConfigUIData.nodeColorKeyChoice(config.nodeColorKeyChoice()); - - this.remoteConfig = config; - } - - public close() { - this.remoteConfig = null; - super.close(); - } -} diff --git a/src/Explorer/Panes/GraphStylingPanel/GraphStylingPanel.tsx b/src/Explorer/Panes/GraphStylingPanel/GraphStylingPanel.tsx new file mode 100644 index 000000000..42e7dca60 --- /dev/null +++ b/src/Explorer/Panes/GraphStylingPanel/GraphStylingPanel.tsx @@ -0,0 +1,37 @@ +import React, { FunctionComponent } from "react"; +import * as ViewModels from "../../../Contracts/ViewModels"; +import { GraphStyleComponent } from "../../Graph/GraphStyleComponent/GraphStyleComponent"; +import { IGraphConfig } from "../../Tabs/GraphTab"; +import { PanelFooterComponent } from "../PanelFooterComponent"; +interface GraphStylingProps { + closePanel: () => void; + igraphConfigUiData: ViewModels.IGraphConfigUiData; + igraphConfig: IGraphConfig; + getValues: (igraphConfig?: IGraphConfig) => void; +} + +export const GraphStylingPanel: FunctionComponent = ({ + closePanel, + igraphConfigUiData, + igraphConfig, + getValues, +}: GraphStylingProps): JSX.Element => { + const buttonLabel = "Ok"; + + const submit = () => { + closePanel(); + }; + + return ( +
+
+ +
+ + + ); +}; diff --git a/src/Explorer/Panes/PaneComponents.ts b/src/Explorer/Panes/PaneComponents.ts index 25aff2d54..655981948 100644 --- a/src/Explorer/Panes/PaneComponents.ts +++ b/src/Explorer/Panes/PaneComponents.ts @@ -1,7 +1,5 @@ import AddDatabasePaneTemplate from "./AddDatabasePane.html"; import CassandraAddCollectionPaneTemplate from "./CassandraAddCollectionPane.html"; -import GraphStylingPaneTemplate from "./GraphStylingPane.html"; - export class PaneComponent { constructor(data: any) { return data.data; @@ -17,15 +15,6 @@ export class AddDatabasePaneComponent { } } -export class GraphStylingPaneComponent { - constructor() { - return { - viewModel: PaneComponent, - template: GraphStylingPaneTemplate, - }; - } -} - export class CassandraAddCollectionPaneComponent { constructor() { return { diff --git a/src/Explorer/Panes/StringInputPane/__snapshots__/StringInputPane.test.tsx.snap b/src/Explorer/Panes/StringInputPane/__snapshots__/StringInputPane.test.tsx.snap index f779e8b74..3244fa044 100644 --- a/src/Explorer/Panes/StringInputPane/__snapshots__/StringInputPane.test.tsx.snap +++ b/src/Explorer/Panes/StringInputPane/__snapshots__/StringInputPane.test.tsx.snap @@ -11,115 +11,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = ` "_closeSynapseLinkModalDialog": [Function], "_isAfecFeatureRegistered": [Function], "_isInitializingNotebooks": false, - "_panes": Array [ - AddDatabasePane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "databaseCreateNewShared": [Function], - "databaseId": [Function], - "databaseIdLabel": [Function], - "databaseIdPlaceHolder": [Function], - "databaseIdTooltipText": [Function], - "databaseLevelThroughputTooltipText": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "freeTierExceedThroughputTooltip": [Function], - "id": "adddatabasepane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isTemplateReady": [Function], - "maxAutoPilotThroughputSet": [Function], - "maxThroughputRU": [Function], - "maxThroughputRUText": [Function], - "minThroughputRU": [Function], - "onMoreDetailsKeyPress": [Function], - "requestUnitsUsageCost": [Function], - "ruToolTipText": [Function], - "showUpsellMessage": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "upsellAnchorText": [Function], - "upsellAnchorUrl": [Function], - "upsellMessage": [Function], - "upsellMessageAriaLabel": [Function], - "visible": [Function], - }, - GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, - CassandraAddCollectionPane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "createTableQuery": [Function], - "dedicateTableThroughput": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "cassandraaddcollectionpane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isSharedAutoPilotSelected": [Function], - "isTemplateReady": [Function], - "keyspaceCreateNew": [Function], - "keyspaceHasSharedOffer": [Function], - "keyspaceId": [Function], - "keyspaceIds": [Function], - "keyspaceOffers": Map {}, - "keyspaceThroughput": [Function], - "maxThroughputRU": [Function], - "minThroughputRU": [Function], - "requestUnitsUsageCostDedicated": [Function], - "requestUnitsUsageCostShared": [Function], - "ruToolTipText": [Function], - "selectedAutoPilotThroughput": [Function], - "sharedAutoPilotThroughput": [Function], - "sharedThroughputRangeText": [Function], - "sharedThroughputSpendAck": [Function], - "sharedThroughputSpendAckText": [Function], - "sharedThroughputSpendAckVisible": [Function], - "tableId": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "userTableQuery": [Function], - "visible": [Function], - }, - ], "_refreshSparkEnabledStateForAccount": [Function], "_resetNotebookWorkspace": [Function], "addCollectionText": [Function], @@ -1005,26 +896,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = ` }, }, }, - "graphStylingPane": GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, "hasStorageAnalyticsAfecFeature": [Function], "isAccountReady": [Function], "isAutoscaleDefaultEnabled": [Function], diff --git a/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap b/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap index ace1945cb..ccce25b5b 100644 --- a/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap +++ b/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap @@ -9,115 +9,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database "_closeSynapseLinkModalDialog": [Function], "_isAfecFeatureRegistered": [Function], "_isInitializingNotebooks": false, - "_panes": Array [ - AddDatabasePane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "databaseCreateNewShared": [Function], - "databaseId": [Function], - "databaseIdLabel": [Function], - "databaseIdPlaceHolder": [Function], - "databaseIdTooltipText": [Function], - "databaseLevelThroughputTooltipText": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "freeTierExceedThroughputTooltip": [Function], - "id": "adddatabasepane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isTemplateReady": [Function], - "maxAutoPilotThroughputSet": [Function], - "maxThroughputRU": [Function], - "maxThroughputRUText": [Function], - "minThroughputRU": [Function], - "onMoreDetailsKeyPress": [Function], - "requestUnitsUsageCost": [Function], - "ruToolTipText": [Function], - "showUpsellMessage": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "upsellAnchorText": [Function], - "upsellAnchorUrl": [Function], - "upsellMessage": [Function], - "upsellMessageAriaLabel": [Function], - "visible": [Function], - }, - GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, - CassandraAddCollectionPane { - "autoPilotUsageCost": [Function], - "canConfigureThroughput": [Function], - "canExceedMaximumValue": [Function], - "canRequestSupport": [Function], - "container": [Circular], - "costsVisible": [Function], - "createTableQuery": [Function], - "dedicateTableThroughput": [Function], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "id": "cassandraaddcollectionpane", - "isAutoPilotSelected": [Function], - "isExecuting": [Function], - "isFreeTierAccount": [Function], - "isSharedAutoPilotSelected": [Function], - "isTemplateReady": [Function], - "keyspaceCreateNew": [Function], - "keyspaceHasSharedOffer": [Function], - "keyspaceId": [Function], - "keyspaceIds": [Function], - "keyspaceOffers": Map {}, - "keyspaceThroughput": [Function], - "maxThroughputRU": [Function], - "minThroughputRU": [Function], - "requestUnitsUsageCostDedicated": [Function], - "requestUnitsUsageCostShared": [Function], - "ruToolTipText": [Function], - "selectedAutoPilotThroughput": [Function], - "sharedAutoPilotThroughput": [Function], - "sharedThroughputRangeText": [Function], - "sharedThroughputSpendAck": [Function], - "sharedThroughputSpendAckText": [Function], - "sharedThroughputSpendAckVisible": [Function], - "tableId": [Function], - "throughput": [Function], - "throughputRangeText": [Function], - "throughputSpendAck": [Function], - "throughputSpendAckText": [Function], - "throughputSpendAckVisible": [Function], - "title": [Function], - "userTableQuery": [Function], - "visible": [Function], - }, - ], "_refreshSparkEnabledStateForAccount": [Function], "_resetNotebookWorkspace": [Function], "addCollectionText": [Function], @@ -1003,26 +894,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database }, }, }, - "graphStylingPane": GraphStylingPane { - "container": [Circular], - "firstFieldHasFocus": [Function], - "formErrors": [Function], - "formErrorsDetails": [Function], - "graphConfigUIData": Object { - "nodeCaptionChoice": [Function], - "nodeColorKeyChoice": [Function], - "nodeIconChoice": [Function], - "nodeIconSet": [Function], - "nodeProperties": [Function], - "nodePropertiesWithNone": [Function], - "showNeighborType": [Function], - }, - "id": "graphstylingpane", - "isExecuting": [Function], - "isTemplateReady": [Function], - "title": [Function], - "visible": [Function], - }, "hasStorageAnalyticsAfecFeature": [Function], "isAccountReady": [Function], "isAutoscaleDefaultEnabled": [Function], diff --git a/src/Explorer/Tabs/GraphTab.tsx b/src/Explorer/Tabs/GraphTab.tsx index 3402b7275..b621a1a3e 100644 --- a/src/Explorer/Tabs/GraphTab.tsx +++ b/src/Explorer/Tabs/GraphTab.tsx @@ -11,8 +11,10 @@ import { GraphExplorerError, GraphExplorerProps, } from "../Graph/GraphExplorerComponent/GraphExplorer"; +// import { GraphAccessor, GraphExplorer, GraphExplorerError } from "../Graph/GraphExplorerComponent/GraphExplorer"; +// import { GraphExplorerAdapter } from "../Graph/GraphExplorerComponent/GraphExplorerAdapter"; import { ContextualPaneBase } from "../Panes/ContextualPaneBase"; -import GraphStylingPane from "../Panes/GraphStylingPane"; +import { GraphStylingPanel } from "../Panes/GraphStylingPanel/GraphStylingPanel"; import { NewVertexPanel } from "../Panes/NewVertexPanel/NewVertexPanel"; import TabsBase from "./TabsBase"; export interface GraphIconMap { @@ -31,6 +33,18 @@ export interface GraphConfig { iconsMap: ko.Observable; } +export interface IGraphConfig { + nodeColor: string; + nodeColorKey: string; + linkColor: string; + showNeighborType: ViewModels.NeighborType; + nodeCaption: string; + nodeSize: number; + linkWidth: number; + nodeIconKey: string; + iconsMap: GraphIconMap; +} + interface GraphTabOptions extends ViewModels.TabOptions { account: DatabaseAccount; masterKey: string; @@ -39,6 +53,7 @@ interface GraphTabOptions extends ViewModels.TabOptions { collectionPartitionKeyProperty: string; } +// export default class GraphTab extends React.Component { export default class GraphTab extends TabsBase { // Graph default configuration public static readonly DEFAULT_NODE_CAPTION = "id"; @@ -51,27 +66,24 @@ export default class GraphTab extends TabsBase { private isPropertyEditing: ko.Observable; private isGraphDisplayed: ko.Observable; private graphAccessor: GraphAccessor; - private graphConfig: GraphConfig; - private graphConfigUiData: ViewModels.GraphConfigUiData; + private igraphConfig: IGraphConfig; + private igraphConfigUiData: ViewModels.IGraphConfigUiData; private isFilterQueryLoading: ko.Observable; private isValidQuery: ko.Observable; - private graphStylingPane: GraphStylingPane; private collectionPartitionKeyProperty: string; private contextualPane: ContextualPaneBase; - + public graphExplorer: GraphExplorer; + public options: GraphTabOptions; constructor(options: GraphTabOptions) { super(options); - this.graphStylingPane = options.collection && options.collection.container.graphStylingPane; this.collectionPartitionKeyProperty = options.collectionPartitionKeyProperty; - this.isNewVertexDisabled = ko.observable(false); this.isPropertyEditing = ko.observable(false); this.isGraphDisplayed = ko.observable(false); this.graphAccessor = undefined; - this.graphConfig = GraphTab.createGraphConfig(); - // TODO Merge this with this.graphConfig - this.graphConfigUiData = GraphTab.createGraphConfigUiData(this.graphConfig); + this.igraphConfig = GraphTab.createIGraphConfig(); + this.igraphConfigUiData = GraphTab.createIGraphConfigUiData(this.igraphConfig); this.graphExplorerProps = { onGraphAccessorCreated: (instance: GraphAccessor): void => { this.graphAccessor = instance; @@ -88,9 +100,9 @@ export default class GraphTab extends TabsBase { this.isGraphDisplayed(isDisplayed); this.updateNavbarWithTabsButtons(); }, - onResetDefaultGraphConfigValues: () => this.setDefaultGraphConfigValues(), - graphConfig: this.graphConfig, - graphConfigUiData: this.graphConfigUiData, + onResetDefaultGraphConfigValues: () => this.setDefaultIGraphConfigValues(), + igraphConfig: this.igraphConfig, + igraphConfigUiData: this.igraphConfigUiData, onIsFilterQueryLoadingChange: (isFilterQueryLoading: boolean): void => this.isFilterQueryLoading(isFilterQueryLoading), onIsValidQueryChange: (isValidQuery: boolean): void => this.isValidQuery(isValidQuery), @@ -106,10 +118,12 @@ export default class GraphTab extends TabsBase { } }, resourceId: options.account.id, + setIConfigUiData: this.setIGraphConfigUiData, }; this.isFilterQueryLoading = ko.observable(false); this.isValidQuery = ko.observable(true); + // this.setCaption = this.setCaption.bind(this); } public static getGremlinEndpoint(account: DatabaseAccount): string { @@ -170,60 +184,76 @@ export default class GraphTab extends TabsBase { ); } public openStyling(): void { - this.setDefaultGraphConfigValues(); - // Update the styling pane with this instance - this.graphStylingPane.setData(this.graphConfigUiData); - this.graphStylingPane.open(); + this.collection.container.openSidePanel( + "Graph Style", + { + this.igraphConfig = igraphConfig; + this.graphAccessor.shareIGraphConfig(igraphConfig); + }} + /> + ); } - public static createGraphConfig(): GraphConfig { + setIGraphConfigUiData = (val: string[]): void => { + if (val.length > 0) { + this.igraphConfigUiData = { + showNeighborType: ViewModels.NeighborType.TARGETS_ONLY, + nodeProperties: val, + nodePropertiesWithNone: [GraphExplorer.NONE_CHOICE].concat(val), + nodeCaptionChoice: this.igraphConfig.nodeCaption, + nodeColorKeyChoice: "None", + nodeIconChoice: "Node", + nodeIconSet: "", + }; + } + }; + + public static createIGraphConfig(): IGraphConfig { return { - nodeColor: ko.observable(GraphTab.NODE_COLOR), - nodeColorKey: ko.observable(undefined), - linkColor: ko.observable(GraphTab.LINK_COLOR), - showNeighborType: ko.observable(ViewModels.NeighborType.TARGETS_ONLY), - nodeCaption: ko.observable(GraphTab.DEFAULT_NODE_CAPTION), - nodeSize: ko.observable(GraphTab.NODE_SIZE), - linkWidth: ko.observable(GraphTab.LINK_WIDTH), - nodeIconKey: ko.observable(undefined), - iconsMap: ko.observable({}), + nodeColor: GraphTab.NODE_COLOR, + nodeColorKey: "None", + linkColor: GraphTab.LINK_COLOR, + showNeighborType: ViewModels.NeighborType.TARGETS_ONLY, + nodeCaption: GraphTab.DEFAULT_NODE_CAPTION, + nodeSize: GraphTab.NODE_SIZE, + linkWidth: GraphTab.LINK_WIDTH, + nodeIconKey: undefined, + iconsMap: {}, }; } - public static createGraphConfigUiData(graphConfig: GraphConfig): ViewModels.GraphConfigUiData { + public static createIGraphConfigUiData(igraphConfig: IGraphConfig): ViewModels.IGraphConfigUiData { return { - showNeighborType: ko.observable(graphConfig.showNeighborType()), - nodeProperties: ko.observableArray([]), - nodePropertiesWithNone: ko.observableArray([]), - nodeCaptionChoice: ko.observable(graphConfig.nodeCaption()), - nodeColorKeyChoice: ko.observable(graphConfig.nodeColorKey()), - nodeIconChoice: ko.observable(graphConfig.nodeIconKey()), - nodeIconSet: ko.observable(undefined), + showNeighborType: igraphConfig.showNeighborType, + nodeProperties: [], + nodePropertiesWithNone: [], + nodeCaptionChoice: igraphConfig.nodeCaption, + nodeColorKeyChoice: igraphConfig.nodeIconKey, + nodeIconChoice: igraphConfig.nodeIconKey, + nodeIconSet: undefined, }; } - /** - * Make sure graph config values are not undefined - */ - private setDefaultGraphConfigValues() { + private setDefaultIGraphConfigValues() { // Assign default values if undefined - if ( - this.graphConfigUiData.nodeCaptionChoice() === undefined && - this.graphConfigUiData.nodeProperties().length > 1 - ) { - this.graphConfigUiData.nodeCaptionChoice(this.graphConfigUiData.nodeProperties()[0]); + if (this.igraphConfigUiData.nodeCaptionChoice === undefined && this.igraphConfigUiData.nodeProperties.length > 1) { + this.igraphConfigUiData.nodeCaptionChoice = this.igraphConfigUiData.nodeProperties[0]; } if ( - this.graphConfigUiData.nodeColorKeyChoice() === undefined && - this.graphConfigUiData.nodePropertiesWithNone().length > 1 + this.igraphConfigUiData.nodeColorKeyChoice === undefined && + this.igraphConfigUiData.nodePropertiesWithNone.length > 1 ) { - this.graphConfigUiData.nodeColorKeyChoice(this.graphConfigUiData.nodePropertiesWithNone()[0]); + this.igraphConfigUiData.nodeColorKeyChoice = this.igraphConfigUiData.nodePropertiesWithNone[0]; } if ( - this.graphConfigUiData.nodeIconChoice() === undefined && - this.graphConfigUiData.nodePropertiesWithNone().length > 1 + this.igraphConfigUiData.nodeIconChoice === undefined && + this.igraphConfigUiData.nodePropertiesWithNone.length > 1 ) { - this.graphConfigUiData.nodeIconChoice(this.graphConfigUiData.nodePropertiesWithNone()[0]); + this.igraphConfigUiData.nodeIconChoice = this.igraphConfigUiData.nodePropertiesWithNone[0]; } } protected getTabsButtons(): CommandButtonComponentProps[] { diff --git a/src/Main.tsx b/src/Main.tsx index 2abf3d2f5..76bab54c2 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -155,7 +155,6 @@ const App: React.FunctionComponent = () => { isConsoleExpanded={isNotificationConsoleExpanded} />
-
{showDialog && }