Migrate graph style panel to react (#619)
Co-authored-by: Steve Faulkner <southpolesteve@gmail.com>
This commit is contained in:
parent
404b1fc0f1
commit
a6b82c8340
|
@ -84,8 +84,8 @@ src/Explorer/Graph/GraphExplorerComponent/GremlinClient.test.ts
|
||||||
src/Explorer/Graph/GraphExplorerComponent/GremlinClient.ts
|
src/Explorer/Graph/GraphExplorerComponent/GremlinClient.ts
|
||||||
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.test.ts
|
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.test.ts
|
||||||
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.ts
|
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.ts
|
||||||
src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts
|
# src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts
|
||||||
src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts
|
# src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts
|
||||||
|
|
||||||
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.test.ts
|
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.test.ts
|
||||||
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.ts
|
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.ts
|
||||||
|
@ -115,7 +115,8 @@ src/Explorer/Panes/CassandraAddCollectionPane.ts
|
||||||
src/Explorer/Panes/ContextualPaneBase.ts
|
src/Explorer/Panes/ContextualPaneBase.ts
|
||||||
src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts
|
src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts
|
||||||
src/Explorer/Panes/DeleteDatabaseConfirmationPane.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/PaneComponents.ts
|
||||||
src/Explorer/Panes/RenewAdHocAccessPane.ts
|
src/Explorer/Panes/RenewAdHocAccessPane.ts
|
||||||
src/Explorer/Panes/SetupNotebooksPane.ts
|
src/Explorer/Panes/SetupNotebooksPane.ts
|
||||||
|
|
|
@ -206,17 +206,14 @@ export enum NeighborType {
|
||||||
BOTH,
|
BOTH,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export interface IGraphConfigUiData {
|
||||||
* Set of observable related to graph configuration by user
|
showNeighborType: NeighborType;
|
||||||
*/
|
nodeProperties: string[];
|
||||||
export interface GraphConfigUiData {
|
nodePropertiesWithNone: string[];
|
||||||
showNeighborType: ko.Observable<NeighborType>;
|
nodeCaptionChoice: string;
|
||||||
nodeProperties: ko.ObservableArray<string>;
|
nodeColorKeyChoice: string;
|
||||||
nodePropertiesWithNone: ko.ObservableArray<string>;
|
nodeIconChoice: string;
|
||||||
nodeCaptionChoice: ko.Observable<string>;
|
nodeIconSet: string;
|
||||||
nodeColorKeyChoice: ko.Observable<string>;
|
|
||||||
nodeIconChoice: ko.Observable<string>;
|
|
||||||
nodeIconSet: ko.Observable<string>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -12,18 +12,10 @@ describe("Component Registerer", () => {
|
||||||
expect(ko.components.isRegistered("error-display")).toBe(true);
|
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", () => {
|
it("should register json-editor component", () => {
|
||||||
expect(ko.components.isRegistered("json-editor")).toBe(true);
|
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", () => {
|
it("should register dynamic-list component", () => {
|
||||||
expect(ko.components.isRegistered("dynamic-list")).toBe(true);
|
expect(ko.components.isRegistered("dynamic-list")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,12 +6,10 @@ import { ErrorDisplayComponent } from "./Controls/ErrorDisplayComponent/ErrorDis
|
||||||
import { InputTypeaheadComponent } from "./Controls/InputTypeahead/InputTypeahead";
|
import { InputTypeaheadComponent } from "./Controls/InputTypeahead/InputTypeahead";
|
||||||
import { JsonEditorComponent } from "./Controls/JsonEditor/JsonEditorComponent";
|
import { JsonEditorComponent } from "./Controls/JsonEditor/JsonEditorComponent";
|
||||||
import { ThroughputInputComponentAutoPilotV3 } from "./Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3";
|
import { ThroughputInputComponentAutoPilotV3 } from "./Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3";
|
||||||
import { GraphStyleComponent } from "./Graph/GraphStyleComponent/GraphStyleComponent";
|
|
||||||
import * as PaneComponents from "./Panes/PaneComponents";
|
import * as PaneComponents from "./Panes/PaneComponents";
|
||||||
|
|
||||||
ko.components.register("input-typeahead", new InputTypeaheadComponent());
|
ko.components.register("input-typeahead", new InputTypeaheadComponent());
|
||||||
ko.components.register("error-display", new ErrorDisplayComponent());
|
ko.components.register("error-display", new ErrorDisplayComponent());
|
||||||
ko.components.register("graph-style", GraphStyleComponent);
|
|
||||||
ko.components.register("editor", new EditorComponent());
|
ko.components.register("editor", new EditorComponent());
|
||||||
ko.components.register("json-editor", new JsonEditorComponent());
|
ko.components.register("json-editor", new JsonEditorComponent());
|
||||||
ko.components.register("diff-editor", new DiffEditorComponent());
|
ko.components.register("diff-editor", new DiffEditorComponent());
|
||||||
|
@ -21,5 +19,4 @@ ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponent
|
||||||
// Panes
|
// Panes
|
||||||
|
|
||||||
ko.components.register("add-database-pane", new PaneComponents.AddDatabasePaneComponent());
|
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());
|
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
|
||||||
|
|
|
@ -32,115 +32,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||||
"_closeSynapseLinkModalDialog": [Function],
|
"_closeSynapseLinkModalDialog": [Function],
|
||||||
"_isAfecFeatureRegistered": [Function],
|
"_isAfecFeatureRegistered": [Function],
|
||||||
"_isInitializingNotebooks": false,
|
"_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],
|
"_refreshSparkEnabledStateForAccount": [Function],
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionText": [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],
|
"hasStorageAnalyticsAfecFeature": [Function],
|
||||||
"isAccountReady": [Function],
|
"isAccountReady": [Function],
|
||||||
"isAutoscaleDefaultEnabled": [Function],
|
"isAutoscaleDefaultEnabled": [Function],
|
||||||
|
@ -1142,115 +1013,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||||
"_closeSynapseLinkModalDialog": [Function],
|
"_closeSynapseLinkModalDialog": [Function],
|
||||||
"_isAfecFeatureRegistered": [Function],
|
"_isAfecFeatureRegistered": [Function],
|
||||||
"_isInitializingNotebooks": false,
|
"_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],
|
"_refreshSparkEnabledStateForAccount": [Function],
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionText": [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],
|
"hasStorageAnalyticsAfecFeature": [Function],
|
||||||
"isAccountReady": [Function],
|
"isAccountReady": [Function],
|
||||||
"isAutoscaleDefaultEnabled": [Function],
|
"isAutoscaleDefaultEnabled": [Function],
|
||||||
|
@ -2265,115 +2007,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||||
"_closeSynapseLinkModalDialog": [Function],
|
"_closeSynapseLinkModalDialog": [Function],
|
||||||
"_isAfecFeatureRegistered": [Function],
|
"_isAfecFeatureRegistered": [Function],
|
||||||
"_isInitializingNotebooks": false,
|
"_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],
|
"_refreshSparkEnabledStateForAccount": [Function],
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionText": [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],
|
"hasStorageAnalyticsAfecFeature": [Function],
|
||||||
"isAccountReady": [Function],
|
"isAccountReady": [Function],
|
||||||
"isAutoscaleDefaultEnabled": [Function],
|
"isAutoscaleDefaultEnabled": [Function],
|
||||||
|
@ -3375,115 +2988,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||||
"_closeSynapseLinkModalDialog": [Function],
|
"_closeSynapseLinkModalDialog": [Function],
|
||||||
"_isAfecFeatureRegistered": [Function],
|
"_isAfecFeatureRegistered": [Function],
|
||||||
"_isInitializingNotebooks": false,
|
"_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],
|
"_refreshSparkEnabledStateForAccount": [Function],
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionText": [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],
|
"hasStorageAnalyticsAfecFeature": [Function],
|
||||||
"isAccountReady": [Function],
|
"isAccountReady": [Function],
|
||||||
"isAutoscaleDefaultEnabled": [Function],
|
"isAutoscaleDefaultEnabled": [Function],
|
||||||
|
|
|
@ -61,7 +61,6 @@ import { DeleteCollectionConfirmationPane } from "./Panes/DeleteCollectionConfir
|
||||||
import { DeleteDatabaseConfirmationPanel } from "./Panes/DeleteDatabaseConfirmationPanel";
|
import { DeleteDatabaseConfirmationPanel } from "./Panes/DeleteDatabaseConfirmationPanel";
|
||||||
import { ExecuteSprocParamsPane } from "./Panes/ExecuteSprocParamsPane/ExecuteSprocParamsPane";
|
import { ExecuteSprocParamsPane } from "./Panes/ExecuteSprocParamsPane/ExecuteSprocParamsPane";
|
||||||
import { GitHubReposPanel } from "./Panes/GitHubReposPanel/GitHubReposPanel";
|
import { GitHubReposPanel } from "./Panes/GitHubReposPanel/GitHubReposPanel";
|
||||||
import GraphStylingPane from "./Panes/GraphStylingPane";
|
|
||||||
import { LoadQueryPane } from "./Panes/LoadQueryPane/LoadQueryPane";
|
import { LoadQueryPane } from "./Panes/LoadQueryPane/LoadQueryPane";
|
||||||
import { SaveQueryPane } from "./Panes/SaveQueryPane/SaveQueryPane";
|
import { SaveQueryPane } from "./Panes/SaveQueryPane/SaveQueryPane";
|
||||||
import { SettingsPane } from "./Panes/SettingsPane/SettingsPane";
|
import { SettingsPane } from "./Panes/SettingsPane/SettingsPane";
|
||||||
|
@ -151,7 +150,6 @@ export default class Explorer {
|
||||||
|
|
||||||
// Contextual panes
|
// Contextual panes
|
||||||
public addDatabasePane: AddDatabasePane;
|
public addDatabasePane: AddDatabasePane;
|
||||||
public graphStylingPane: GraphStylingPane;
|
|
||||||
public cassandraAddCollectionPane: CassandraAddCollectionPane;
|
public cassandraAddCollectionPane: CassandraAddCollectionPane;
|
||||||
private gitHubClient: GitHubClient;
|
private gitHubClient: GitHubClient;
|
||||||
public gitHubOAuthService: GitHubOAuthService;
|
public gitHubOAuthService: GitHubOAuthService;
|
||||||
|
@ -182,7 +180,6 @@ export default class Explorer {
|
||||||
public openDialog: ExplorerParams["openDialog"];
|
public openDialog: ExplorerParams["openDialog"];
|
||||||
public closeDialog: ExplorerParams["closeDialog"];
|
public closeDialog: ExplorerParams["closeDialog"];
|
||||||
|
|
||||||
private _panes: ContextualPaneBase[] = [];
|
|
||||||
private _isInitializingNotebooks: boolean;
|
private _isInitializingNotebooks: boolean;
|
||||||
private notebookBasePath: ko.Observable<string>;
|
private notebookBasePath: ko.Observable<string>;
|
||||||
private _arcadiaManager: ArcadiaResourceManager;
|
private _arcadiaManager: ArcadiaResourceManager;
|
||||||
|
@ -411,13 +408,6 @@ export default class Explorer {
|
||||||
container: this,
|
container: this,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.graphStylingPane = new GraphStylingPane({
|
|
||||||
id: "graphstylingpane",
|
|
||||||
visible: ko.observable<boolean>(false),
|
|
||||||
|
|
||||||
container: this,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.cassandraAddCollectionPane = new CassandraAddCollectionPane({
|
this.cassandraAddCollectionPane = new CassandraAddCollectionPane({
|
||||||
id: "cassandraaddcollectionpane",
|
id: "cassandraaddcollectionpane",
|
||||||
visible: ko.observable<boolean>(false),
|
visible: ko.observable<boolean>(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.addDatabaseText.subscribe((addDatabaseText: string) => this.addDatabasePane.title(addDatabaseText));
|
||||||
this.isTabsContentExpanded = ko.observable(false);
|
this.isTabsContentExpanded = ko.observable(false);
|
||||||
|
|
||||||
|
@ -1058,10 +1047,6 @@ export default class Explorer {
|
||||||
: this.selectedNode().collection) as ViewModels.Collection;
|
: this.selectedNode().collection) as ViewModels.Collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeAllPanes(): void {
|
|
||||||
this._panes.forEach((pane: ContextualPaneBase) => pane.close());
|
|
||||||
}
|
|
||||||
|
|
||||||
public isRunningOnNationalCloud(): boolean {
|
public isRunningOnNationalCloud(): boolean {
|
||||||
return (
|
return (
|
||||||
userContext.portalEnv === "blackforest" ||
|
userContext.portalEnv === "blackforest" ||
|
||||||
|
@ -1855,7 +1840,6 @@ export default class Explorer {
|
||||||
|
|
||||||
public async handleOpenFileAction(path: string): Promise<void> {
|
public async handleOpenFileAction(path: string): Promise<void> {
|
||||||
if (this.isAccountReady() && !(await this._containsDefaultNotebookWorkspace(userContext.databaseAccount))) {
|
if (this.isAccountReady() && !(await this._containsDefaultNotebookWorkspace(userContext.databaseAccount))) {
|
||||||
this.closeAllPanes();
|
|
||||||
this._openSetupNotebooksPaneForQuickstart();
|
this._openSetupNotebooksPaneForQuickstart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as sinon from "sinon";
|
import * as sinon from "sinon";
|
||||||
import { D3ForceGraph, LoadMoreDataAction, D3GraphNodeData } from "./D3ForceGraph";
|
|
||||||
import { D3Node, D3Link, GraphData } from "../GraphExplorerComponent/GraphData";
|
|
||||||
import GraphTab from "../../Tabs/GraphTab";
|
import GraphTab from "../../Tabs/GraphTab";
|
||||||
|
import { D3Link, D3Node, GraphData } from "../GraphExplorerComponent/GraphData";
|
||||||
|
import { D3ForceGraph, D3GraphNodeData, LoadMoreDataAction } from "./D3ForceGraph";
|
||||||
|
|
||||||
describe("D3ForceGraph", () => {
|
describe("D3ForceGraph", () => {
|
||||||
const v1Id = "v1";
|
const v1Id = "v1";
|
||||||
|
@ -68,7 +68,7 @@ describe("D3ForceGraph", () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
forceGraph = new D3ForceGraph({
|
forceGraph = new D3ForceGraph({
|
||||||
graphConfig: GraphTab.createGraphConfig(),
|
igraphConfig: GraphTab.createIGraphConfig(),
|
||||||
onHighlightedNode: sinon.spy(),
|
onHighlightedNode: sinon.spy(),
|
||||||
onLoadMoreData: (action: LoadMoreDataAction): void => {},
|
onLoadMoreData: (action: LoadMoreDataAction): void => {},
|
||||||
|
|
||||||
|
@ -141,6 +141,7 @@ describe("D3ForceGraph", () => {
|
||||||
const mouseoverEvent = document.createEvent("Events");
|
const mouseoverEvent = document.createEvent("Events");
|
||||||
mouseoverEvent.initEvent("mouseover", true, false);
|
mouseoverEvent.initEvent("mouseover", true, false);
|
||||||
$(rootNode).find(".node")[0].dispatchEvent(mouseoverEvent); // [0] is v1 vertex
|
$(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
|
// onHighlightedNode is always called once to clear the selection
|
||||||
expect((forceGraph.params.onHighlightedNode as sinon.SinonSpy).calledTwice).toBe(true);
|
expect((forceGraph.params.onHighlightedNode as sinon.SinonSpy).calledTwice).toBe(true);
|
||||||
|
@ -150,7 +151,7 @@ describe("D3ForceGraph", () => {
|
||||||
expect(onHighlightedNode.id).toEqual(v1Id);
|
expect(onHighlightedNode.id).toEqual(v1Id);
|
||||||
};
|
};
|
||||||
|
|
||||||
forceGraph.updateGraph(newGraph);
|
forceGraph.updateGraph(newGraph, forceGraph.igraphConfig);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,7 +13,7 @@ import _ from "underscore";
|
||||||
import * as Constants from "../../../Common/Constants";
|
import * as Constants from "../../../Common/Constants";
|
||||||
import { NeighborType } from "../../../Contracts/ViewModels";
|
import { NeighborType } from "../../../Contracts/ViewModels";
|
||||||
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
|
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
|
||||||
import { GraphConfig } from "../../Tabs/GraphTab";
|
import { IGraphConfig } from "./../../Tabs/GraphTab";
|
||||||
import { D3Link, D3Node, GraphData } from "./GraphData";
|
import { D3Link, D3Node, GraphData } from "./GraphData";
|
||||||
import { GraphExplorer } from "./GraphExplorer";
|
import { GraphExplorer } from "./GraphExplorer";
|
||||||
|
|
||||||
|
@ -48,21 +48,22 @@ interface ZoomTransform extends Point2D {
|
||||||
|
|
||||||
export interface D3ForceGraphParameters {
|
export interface D3ForceGraphParameters {
|
||||||
// Graph to parent
|
// Graph to parent
|
||||||
graphConfig: GraphConfig;
|
|
||||||
onHighlightedNode: (highlightedNode: D3GraphNodeData) => void; // a new node has been highlighted in the graph
|
igraphConfig: IGraphConfig;
|
||||||
onLoadMoreData: (action: LoadMoreDataAction) => void;
|
onHighlightedNode?: (highlightedNode: D3GraphNodeData) => void; // a new node has been highlighted in the graph
|
||||||
|
onLoadMoreData?: (action: LoadMoreDataAction) => void;
|
||||||
|
|
||||||
// parent to graph
|
// parent to graph
|
||||||
onInitialized: (instance: GraphRenderer) => void;
|
onInitialized?: (instance: GraphRenderer) => void;
|
||||||
|
|
||||||
// For unit testing purposes
|
// For unit testing purposes
|
||||||
onGraphUpdated: (timestamp: number) => void;
|
onGraphUpdated?: (timestamp: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GraphRenderer {
|
export interface GraphRenderer {
|
||||||
selectNode(id: string): void;
|
selectNode(id: string): void;
|
||||||
resetZoom(): void;
|
resetZoom(): void;
|
||||||
updateGraph(graphData: GraphData<D3Node, D3Link>): void;
|
updateGraph(graphData: GraphData<D3Node, D3Link>, igraphConfigParam?: IGraphConfig): void;
|
||||||
enableHighlight(enable: boolean): void;
|
enableHighlight(enable: boolean): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +109,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
private viewCenter: Point2D;
|
private viewCenter: Point2D;
|
||||||
|
|
||||||
// Map a property to a graph node attribute (such as color)
|
// 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<D3Node, D3Link>;
|
private graphDataWrapper: GraphData<D3Node, D3Link>;
|
||||||
|
|
||||||
// Communication with outside
|
// Communication with outside
|
||||||
|
@ -119,9 +120,11 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
// outside -> Graph
|
// outside -> Graph
|
||||||
private idToSelect: ko.Observable<string>; // Programmatically select node by id outside graph
|
private idToSelect: ko.Observable<string>; // Programmatically select node by id outside graph
|
||||||
private isHighlightDisabled: boolean;
|
private isHighlightDisabled: boolean;
|
||||||
|
public igraphConfig: IGraphConfig;
|
||||||
|
|
||||||
public constructor(params: D3ForceGraphParameters) {
|
public constructor(params: D3ForceGraphParameters) {
|
||||||
this.params = params;
|
this.params = params;
|
||||||
|
this.igraphConfig = this.params.igraphConfig;
|
||||||
this.idToSelect = ko.observable(null);
|
this.idToSelect = ko.observable(null);
|
||||||
this.errorMsgs = ko.observableArray([]);
|
this.errorMsgs = ko.observableArray([]);
|
||||||
this.graphDataWrapper = null;
|
this.graphDataWrapper = null;
|
||||||
|
@ -151,7 +154,10 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
this.g.remove();
|
this.g.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateGraph(newGraph: GraphData<D3Node, D3Link>): void {
|
public updateGraph(newGraph: GraphData<D3Node, D3Link>, igraphConfigParam?: IGraphConfig): void {
|
||||||
|
if (igraphConfigParam) {
|
||||||
|
this.igraphConfig = igraphConfigParam;
|
||||||
|
}
|
||||||
if (!newGraph || !this.simulation) {
|
if (!newGraph || !this.simulation) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -159,7 +165,8 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
this.graphDataWrapper = new GraphData<D3Node, D3Link>();
|
this.graphDataWrapper = new GraphData<D3Node, D3Link>();
|
||||||
this.graphDataWrapper.setData(newGraph);
|
this.graphDataWrapper.setData(newGraph);
|
||||||
|
|
||||||
const key = this.params.graphConfig.nodeColorKey();
|
const key = this.igraphConfig.nodeColorKey;
|
||||||
|
|
||||||
if (key !== GraphExplorer.NONE_CHOICE) {
|
if (key !== GraphExplorer.NONE_CHOICE) {
|
||||||
this.updateUniqueValues(key);
|
this.updateUniqueValues(key);
|
||||||
}
|
}
|
||||||
|
@ -265,20 +272,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Redraw if any of these configs change
|
this.redrawGraph();
|
||||||
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.instantiateSimulation();
|
this.instantiateSimulation();
|
||||||
} // initialize
|
} // initialize
|
||||||
|
|
||||||
|
@ -371,7 +365,10 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
*/
|
*/
|
||||||
private shiftGraph(targetPosition: Point2D): Q.Promise<Point2D> {
|
private shiftGraph(targetPosition: Point2D): Q.Promise<Point2D> {
|
||||||
const deferred: Q.Deferred<Point2D> = Q.defer<Point2D>();
|
const deferred: Q.Deferred<Point2D> = Q.defer<Point2D>();
|
||||||
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;
|
this.viewCenter = targetPosition;
|
||||||
|
|
||||||
if (Math.abs(offset.x) > 0.5 && Math.abs(offset.y) > 0.5) {
|
if (Math.abs(offset.x) > 0.5 && Math.abs(offset.y) > 0.5) {
|
||||||
|
@ -526,7 +523,10 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
.transition()
|
.transition()
|
||||||
.duration(D3ForceGraph.TRANSITION_STEP3_MS)
|
.duration(D3ForceGraph.TRANSITION_STEP3_MS)
|
||||||
.attrTween("transform", (d: D3Node) => {
|
.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 ix = interpolateNumber(viewCenter.x, finalPos.x);
|
||||||
const iy = interpolateNumber(viewCenter.y, finalPos.y);
|
const iy = interpolateNumber(viewCenter.y, finalPos.y);
|
||||||
return (t: number) => {
|
return (t: number) => {
|
||||||
|
@ -626,10 +626,10 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
|
|
||||||
this.addNewLinks();
|
this.addNewLinks();
|
||||||
|
|
||||||
const nodes = this.simulation.nodes();
|
const nodes1 = this.simulation.nodes();
|
||||||
this.redrawGraph();
|
this.redrawGraph();
|
||||||
|
|
||||||
this.animateBigBang(nodes, newNodes);
|
this.animateBigBang(nodes1, newNodes);
|
||||||
|
|
||||||
this.simulation.alpha(1).restart();
|
this.simulation.alpha(1).restart();
|
||||||
this.params.onGraphUpdated(new Date().getTime());
|
this.params.onGraphUpdated(new Date().getTime());
|
||||||
|
@ -657,8 +657,8 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
.append("path")
|
.append("path")
|
||||||
.attr("class", "link")
|
.attr("class", "link")
|
||||||
.attr("fill", "none")
|
.attr("fill", "none")
|
||||||
.attr("stroke-width", this.params.graphConfig.linkWidth())
|
.attr("stroke-width", this.igraphConfig.linkWidth)
|
||||||
.attr("stroke", this.params.graphConfig.linkColor());
|
.attr("stroke", this.igraphConfig.linkColor);
|
||||||
|
|
||||||
if (D3ForceGraph.useSvgMarkerEnd()) {
|
if (D3ForceGraph.useSvgMarkerEnd()) {
|
||||||
line.attr("marker-end", `url(#${this.getArrowHeadSymbolId()}-marker)`);
|
line.attr("marker-end", `url(#${this.getArrowHeadSymbolId()}-marker)`);
|
||||||
|
@ -668,7 +668,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
.append("use")
|
.append("use")
|
||||||
.attr("xlink:href", `#${this.getArrowHeadSymbolId()}-nonMarker`)
|
.attr("xlink:href", `#${this.getArrowHeadSymbolId()}-nonMarker`)
|
||||||
.attr("class", "markerEnd link")
|
.attr("class", "markerEnd link")
|
||||||
.attr("fill", this.params.graphConfig.linkColor())
|
.attr("fill", this.igraphConfig.linkColor)
|
||||||
.classed(`${this.getArrowHeadSymbolId()}`, true);
|
.classed(`${this.getArrowHeadSymbolId()}`, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,7 +724,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
.append("circle")
|
.append("circle")
|
||||||
.attr("fill", this.getNodeColor.bind(this))
|
.attr("fill", this.getNodeColor.bind(this))
|
||||||
.attr("class", "main")
|
.attr("class", "main")
|
||||||
.attr("r", this.params.graphConfig.nodeSize());
|
.attr("r", this.igraphConfig.nodeSize);
|
||||||
|
|
||||||
var iconGroup = newNodes
|
var iconGroup = newNodes
|
||||||
.append("g")
|
.append("g")
|
||||||
|
@ -749,7 +749,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
self.onNodeClicked(this.parentNode, d);
|
self.onNodeClicked(this.parentNode, d);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var nodeSize = this.params.graphConfig.nodeSize();
|
var nodeSize = this.igraphConfig.nodeSize;
|
||||||
var bgsize = nodeSize + 1;
|
var bgsize = nodeSize + 1;
|
||||||
|
|
||||||
iconGroup
|
iconGroup
|
||||||
|
@ -759,7 +759,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
.attr("width", bgsize * 2)
|
.attr("width", bgsize * 2)
|
||||||
.attr("height", bgsize * 2)
|
.attr("height", bgsize * 2)
|
||||||
.attr("fill-opacity", (d: D3Node) => {
|
.attr("fill-opacity", (d: D3Node) => {
|
||||||
return this.params.graphConfig.nodeIconKey() ? 1 : 0;
|
return this.igraphConfig.nodeIconKey ? 1 : 0;
|
||||||
})
|
})
|
||||||
.attr("class", "icon-background");
|
.attr("class", "icon-background");
|
||||||
|
|
||||||
|
@ -767,14 +767,13 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
iconGroup
|
iconGroup
|
||||||
.append("svg:image")
|
.append("svg:image")
|
||||||
.attr("xlink:href", (d: D3Node) => {
|
.attr("xlink:href", (d: D3Node) => {
|
||||||
return D3ForceGraph.computeImageData(d, this.params.graphConfig);
|
return D3ForceGraph.computeImageData(d, this.igraphConfig);
|
||||||
})
|
})
|
||||||
.attr("x", -nodeSize)
|
.attr("x", -nodeSize)
|
||||||
.attr("y", -nodeSize)
|
.attr("y", -nodeSize)
|
||||||
.attr("height", nodeSize * 2)
|
.attr("height", nodeSize * 2)
|
||||||
.attr("width", nodeSize * 2)
|
.attr("width", nodeSize * 2)
|
||||||
.attr("class", "icon");
|
.attr("class", "icon");
|
||||||
|
|
||||||
newNodes
|
newNodes
|
||||||
.append("text")
|
.append("text")
|
||||||
.attr("class", "caption")
|
.attr("class", "caption")
|
||||||
|
@ -808,7 +807,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
.attr("x2", 0)
|
.attr("x2", 0)
|
||||||
.attr("y2", gaugeYOffset)
|
.attr("y2", gaugeYOffset)
|
||||||
.style("stroke-width", 1)
|
.style("stroke-width", 1)
|
||||||
.style("stroke", this.params.graphConfig.linkColor());
|
.style("stroke", this.igraphConfig.linkColor);
|
||||||
parent
|
parent
|
||||||
.append("use")
|
.append("use")
|
||||||
.attr("xlink:href", "#triangleRight")
|
.attr("xlink:href", "#triangleRight")
|
||||||
|
@ -877,7 +876,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
.attr("height", gaugeHeight)
|
.attr("height", gaugeHeight)
|
||||||
.style("fill", "white")
|
.style("fill", "white")
|
||||||
.style("stroke-width", 1)
|
.style("stroke-width", 1)
|
||||||
.style("stroke", this.params.graphConfig.linkColor());
|
.style("stroke", this.igraphConfig.linkColor);
|
||||||
parent
|
parent
|
||||||
.append("rect")
|
.append("rect")
|
||||||
.attr("x", (d: D3Node) => {
|
.attr("x", (d: D3Node) => {
|
||||||
|
@ -894,7 +893,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
: 0;
|
: 0;
|
||||||
})
|
})
|
||||||
.attr("height", gaugeHeight)
|
.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"));
|
.attr("visibility", (d: D3Node) => (d._pagination && d._pagination.total ? "visible" : "hidden"));
|
||||||
parent
|
parent
|
||||||
.append("text")
|
.append("text")
|
||||||
|
@ -971,7 +970,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
const self = this;
|
const self = this;
|
||||||
nodeSelection.selectAll(".loadmore").remove();
|
nodeSelection.selectAll(".loadmore").remove();
|
||||||
|
|
||||||
var nodeSize = this.params.graphConfig.nodeSize();
|
var nodeSize = this.igraphConfig.nodeSize;
|
||||||
const rootSelectionG = nodeSelection
|
const rootSelectionG = nodeSelection
|
||||||
.filter((d: D3Node) => {
|
.filter((d: D3Node) => {
|
||||||
return !!d._isRoot && !!d._pagination;
|
return !!d._isRoot && !!d._pagination;
|
||||||
|
@ -995,7 +994,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
this.createLoadMoreControl(missingNeighborNonRootG, nodeSize);
|
this.createLoadMoreControl(missingNeighborNonRootG, nodeSize);
|
||||||
|
|
||||||
// Don't color icons individually, just the definitions
|
// 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
|
* @param d
|
||||||
*/
|
*/
|
||||||
private getNodeColor(d: D3Node): string {
|
private getNodeColor(d: D3Node): string {
|
||||||
if (this.params.graphConfig.nodeColorKey()) {
|
if (this.igraphConfig.nodeColorKey) {
|
||||||
const val = GraphData.getNodePropValue(d, this.params.graphConfig.nodeColorKey());
|
const val = GraphData.getNodePropValue(d, this.igraphConfig.nodeColorKey);
|
||||||
return this.lookupColorFromKey(<string>val);
|
return this.lookupColorFromKey(<string>val);
|
||||||
} else {
|
} else {
|
||||||
return this.params.graphConfig.nodeColor();
|
return this.igraphConfig.nodeColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1103,12 +1102,12 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
this.graphDataWrapper.getTargetsForId(nodeId)
|
this.graphDataWrapper.getTargetsForId(nodeId)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})(this.params.graphConfig.showNeighborType());
|
})(this.igraphConfig.showNeighborType);
|
||||||
return (!neighbors || neighbors.indexOf(d.id) === -1) && d.id !== nodeId;
|
return (!neighbors || neighbors.indexOf(d.id) === -1) && d.id !== nodeId;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.g.selectAll(".link").classed("inactive", (l: D3Link) => {
|
this.g.selectAll(".link").classed("inactive", (l: D3Link) => {
|
||||||
switch (this.params.graphConfig.showNeighborType()) {
|
switch (this.igraphConfig.showNeighborType) {
|
||||||
case NeighborType.SOURCES_ONLY:
|
case NeighborType.SOURCES_ONLY:
|
||||||
return (<D3Node>l.target).id !== nodeId;
|
return (<D3Node>l.target).id !== nodeId;
|
||||||
case NeighborType.TARGETS_ONLY:
|
case NeighborType.TARGETS_ONLY:
|
||||||
|
@ -1152,7 +1151,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private retrieveNodeCaption(d: D3Node) {
|
private retrieveNodeCaption(d: D3Node) {
|
||||||
let key = this.params.graphConfig.nodeCaption();
|
let key = this.igraphConfig.nodeCaption;
|
||||||
let value: string = d.id || d.label;
|
let value: string = d.id || d.label;
|
||||||
if (key) {
|
if (key) {
|
||||||
value = <string>GraphData.getNodePropValue(d, key) || "";
|
value = <string>GraphData.getNodePropValue(d, key) || "";
|
||||||
|
@ -1194,10 +1193,16 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private positionLinkEnd(l: D3Link) {
|
private positionLinkEnd(l: D3Link) {
|
||||||
const source: Point2D = { x: (<D3Node>l.source).x, y: (<D3Node>l.source).y };
|
const source: Point2D = {
|
||||||
const target: Point2D = { x: (<D3Node>l.target).x, y: (<D3Node>l.target).y };
|
x: (<D3Node>l.source).x,
|
||||||
|
y: (<D3Node>l.source).y,
|
||||||
|
};
|
||||||
|
const target: Point2D = {
|
||||||
|
x: (<D3Node>l.target).x,
|
||||||
|
y: (<D3Node>l.target).y,
|
||||||
|
};
|
||||||
const d1 = D3ForceGraph.calculateControlPoint(source, target);
|
const d1 = D3ForceGraph.calculateControlPoint(source, target);
|
||||||
var radius = this.params.graphConfig.nodeSize() + 3;
|
var radius = this.igraphConfig.nodeSize + 3;
|
||||||
|
|
||||||
// End
|
// End
|
||||||
const dx = target.x - d1.x;
|
const dx = target.x - d1.x;
|
||||||
|
@ -1210,10 +1215,16 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private positionLink(l: D3Link) {
|
private positionLink(l: D3Link) {
|
||||||
const source: Point2D = { x: (<D3Node>l.source).x, y: (<D3Node>l.source).y };
|
const source: Point2D = {
|
||||||
const target: Point2D = { x: (<D3Node>l.target).x, y: (<D3Node>l.target).y };
|
x: (<D3Node>l.source).x,
|
||||||
|
y: (<D3Node>l.source).y,
|
||||||
|
};
|
||||||
|
const target: Point2D = {
|
||||||
|
x: (<D3Node>l.target).x,
|
||||||
|
y: (<D3Node>l.target).y,
|
||||||
|
};
|
||||||
const d1 = D3ForceGraph.calculateControlPoint(source, target);
|
const d1 = D3ForceGraph.calculateControlPoint(source, target);
|
||||||
var radius = this.params.graphConfig.nodeSize() + 3;
|
var radius = this.igraphConfig.nodeSize + 3;
|
||||||
|
|
||||||
// Start
|
// Start
|
||||||
var dx = d1.x - source.x;
|
var dx = d1.x - source.x;
|
||||||
|
@ -1245,13 +1256,13 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
return d._isRoot ? "node root" : "node";
|
return d._isRoot ? "node root" : "node";
|
||||||
});
|
});
|
||||||
|
|
||||||
this.applyConfig(this.params.graphConfig);
|
this.applyConfig(this.igraphConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static computeImageData(d: D3Node, config: GraphConfig): string {
|
private static computeImageData(d: D3Node, config: IGraphConfig): string {
|
||||||
let propValue = <string>GraphData.getNodePropValue(d, config.nodeIconKey()) || "";
|
let propValue = <string>GraphData.getNodePropValue(d, config.nodeIconKey) || "";
|
||||||
// Trim leading and trailing spaces to make comparison more forgiving.
|
// Trim leading and trailing spaces to make comparison more forgiving.
|
||||||
let value = config.iconsMap()[propValue.trim()];
|
let value = config.iconsMap[propValue.trim()];
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -1261,48 +1272,46 @@ export class D3ForceGraph implements GraphRenderer {
|
||||||
/**
|
/**
|
||||||
* Update graph according to configuration or use default
|
* Update graph according to configuration or use default
|
||||||
*/
|
*/
|
||||||
private applyConfig(config: GraphConfig) {
|
private applyConfig(config: IGraphConfig) {
|
||||||
if (config.nodeIconKey()) {
|
if (config.nodeIconKey) {
|
||||||
this.g
|
this.g
|
||||||
.selectAll(".node .icon")
|
.selectAll(".node .icon")
|
||||||
.attr("xlink:href", (d: D3Node) => {
|
.attr("xlink:href", (d: D3Node) => {
|
||||||
return D3ForceGraph.computeImageData(d, config);
|
return D3ForceGraph.computeImageData(d, config);
|
||||||
})
|
})
|
||||||
.attr("x", -config.nodeSize())
|
.attr("x", -config.nodeSize)
|
||||||
.attr("y", -config.nodeSize())
|
.attr("y", -config.nodeSize)
|
||||||
.attr("height", config.nodeSize() * 2)
|
.attr("height", config.nodeSize * 2)
|
||||||
.attr("width", config.nodeSize() * 2)
|
.attr("width", config.nodeSize * 2)
|
||||||
.attr("class", "icon");
|
.attr("class", "icon");
|
||||||
} else {
|
} else {
|
||||||
// clear icons
|
// clear icons
|
||||||
this.g.selectAll(".node .icon").attr("xlink:href", undefined);
|
this.g.selectAll(".node .icon").attr("xlink:href", undefined);
|
||||||
}
|
}
|
||||||
this.g.selectAll(".node .icon-background").attr("fill-opacity", (d: D3Node) => {
|
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) => {
|
this.g.selectAll(".node text.caption").text((d: D3Node) => {
|
||||||
return this.retrieveNodeCaption(d);
|
return this.retrieveNodeCaption(d);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.g.selectAll(".node circle.main").attr("r", config.nodeSize());
|
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 text.caption").attr("dx", config.nodeSize + 2);
|
||||||
|
|
||||||
this.g.selectAll(".node circle").attr("fill", this.getNodeColor.bind(this));
|
this.g.selectAll(".node circle").attr("fill", this.getNodeColor.bind(this));
|
||||||
|
|
||||||
// Can't color nodes individually if using defs
|
// 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()) {
|
if (D3ForceGraph.useSvgMarkerEnd()) {
|
||||||
this.svg
|
this.svg
|
||||||
.select(`#${this.getArrowHeadSymbolId()}-marker`)
|
.select(`#${this.getArrowHeadSymbolId()}-marker`)
|
||||||
.attr("fill", config.linkColor())
|
.attr("fill", config.linkColor)
|
||||||
.attr("stroke", config.linkColor());
|
.attr("stroke", config.linkColor);
|
||||||
} else {
|
} else {
|
||||||
this.svg.select(`#${this.getArrowHeadSymbolId()}-nonMarker`).attr("fill", config.linkColor());
|
this.svg.select(`#${this.getArrowHeadSymbolId()}-nonMarker`).attr("fill", config.linkColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset highlight
|
// Reset highlight
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
jest.mock("../../../Common/dataAccess/queryDocuments");
|
jest.mock("../../../Common/dataAccess/queryDocuments");
|
||||||
jest.mock("../../../Common/dataAccess/queryDocumentsPage");
|
jest.mock("../../../Common/dataAccess/queryDocumentsPage");
|
||||||
import React from "react";
|
|
||||||
import * as sinon from "sinon";
|
|
||||||
import { mount, ReactWrapper } from "enzyme";
|
import { mount, ReactWrapper } from "enzyme";
|
||||||
import * as Q from "q";
|
import * as Q from "q";
|
||||||
|
import React from "react";
|
||||||
|
import * as sinon from "sinon";
|
||||||
import "../../../../externals/jquery.typeahead.min";
|
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 { queryDocuments } from "../../../Common/dataAccess/queryDocuments";
|
||||||
import { queryDocumentsPage } from "../../../Common/dataAccess/queryDocumentsPage";
|
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", () => {
|
describe("Check whether query result is vertex array", () => {
|
||||||
it("should reject null as vertex array", () => {
|
it("should reject null as vertex array", () => {
|
||||||
|
@ -146,8 +146,8 @@ describe("GraphExplorer", () => {
|
||||||
const gremlinRU = 789.12;
|
const gremlinRU = 789.12;
|
||||||
|
|
||||||
const createMockProps = (): GraphExplorerProps => {
|
const createMockProps = (): GraphExplorerProps => {
|
||||||
const graphConfig = GraphTab.createGraphConfig();
|
const igraphConfig = GraphTab.createIGraphConfig();
|
||||||
const graphConfigUi = GraphTab.createGraphConfigUiData(graphConfig);
|
const igraphConfigUi = GraphTab.createIGraphConfigUiData(igraphConfig);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
onGraphAccessorCreated: (instance: GraphAccessor): void => {},
|
onGraphAccessorCreated: (instance: GraphAccessor): void => {},
|
||||||
|
@ -170,8 +170,9 @@ describe("GraphExplorer", () => {
|
||||||
resourceId: "resourceId",
|
resourceId: "resourceId",
|
||||||
|
|
||||||
/* TODO Figure out how to make this Knockout-free */
|
/* TODO Figure out how to make this Knockout-free */
|
||||||
graphConfigUiData: graphConfigUi,
|
igraphConfigUiData: igraphConfigUi,
|
||||||
graphConfig: graphConfig,
|
igraphConfig: igraphConfig,
|
||||||
|
setIConfigUiData: (data: string[]): void => {},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { EditorReact } from "../../Controls/Editor/EditorReact";
|
||||||
import * as InputTypeaheadComponent from "../../Controls/InputTypeahead/InputTypeaheadComponent";
|
import * as InputTypeaheadComponent from "../../Controls/InputTypeahead/InputTypeaheadComponent";
|
||||||
import * as TabComponent from "../../Controls/Tabs/TabComponent";
|
import * as TabComponent from "../../Controls/Tabs/TabComponent";
|
||||||
import { ConsoleDataType } from "../../Menus/NotificationConsole/NotificationConsoleComponent";
|
import { ConsoleDataType } from "../../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
import { GraphConfig } from "../../Tabs/GraphTab";
|
import { IGraphConfig } from "../../Tabs/GraphTab";
|
||||||
import { ArraysByKeyCache } from "./ArraysByKeyCache";
|
import { ArraysByKeyCache } from "./ArraysByKeyCache";
|
||||||
import * as D3ForceGraph from "./D3ForceGraph";
|
import * as D3ForceGraph from "./D3ForceGraph";
|
||||||
import { EdgeInfoCache } from "./EdgeInfoCache";
|
import { EdgeInfoCache } from "./EdgeInfoCache";
|
||||||
|
@ -31,10 +31,10 @@ import * as LeftPane from "./LeftPaneComponent";
|
||||||
import { MiddlePaneComponent } from "./MiddlePaneComponent";
|
import { MiddlePaneComponent } from "./MiddlePaneComponent";
|
||||||
import * as NodeProperties from "./NodePropertiesComponent";
|
import * as NodeProperties from "./NodePropertiesComponent";
|
||||||
import { QueryContainerComponent } from "./QueryContainerComponent";
|
import { QueryContainerComponent } from "./QueryContainerComponent";
|
||||||
|
|
||||||
export interface GraphAccessor {
|
export interface GraphAccessor {
|
||||||
applyFilter: () => void;
|
applyFilter: () => void;
|
||||||
addVertex: (v: ViewModels.NewVertexData) => Q.Promise<void>;
|
addVertex: (v: ViewModels.NewVertexData) => Q.Promise<void>;
|
||||||
|
shareIGraphConfig: (igraphConfig: IGraphConfig) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GraphExplorerProps {
|
export interface GraphExplorerProps {
|
||||||
|
@ -58,9 +58,10 @@ export interface GraphExplorerProps {
|
||||||
onLoadStartKeyChange: (newKey: number) => void;
|
onLoadStartKeyChange: (newKey: number) => void;
|
||||||
resourceId: string;
|
resourceId: string;
|
||||||
|
|
||||||
/* TODO Figure out how to make this Knockout-free */
|
igraphConfigUiData: ViewModels.IGraphConfigUiData;
|
||||||
graphConfigUiData: ViewModels.GraphConfigUiData;
|
igraphConfig: IGraphConfig;
|
||||||
graphConfig?: GraphConfig;
|
|
||||||
|
setIConfigUiData?: (data: string[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GraphHighlightedNodeData {
|
export interface GraphHighlightedNodeData {
|
||||||
|
@ -121,6 +122,10 @@ interface GraphExplorerState {
|
||||||
filterQueryError: string;
|
filterQueryError: string;
|
||||||
filterQueryWarning: string;
|
filterQueryWarning: string;
|
||||||
filterQueryStatus: FilterQueryStatus;
|
filterQueryStatus: FilterQueryStatus;
|
||||||
|
change: string;
|
||||||
|
|
||||||
|
igraphConfigUiData: ViewModels.IGraphConfigUiData;
|
||||||
|
igraphConfig: IGraphConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EditedProperties {
|
export interface EditedProperties {
|
||||||
|
@ -218,6 +223,8 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
private lastReportedIsPropertyEditing: boolean;
|
private lastReportedIsPropertyEditing: boolean;
|
||||||
private lastReportedIsNewVertexDisabled: boolean;
|
private lastReportedIsNewVertexDisabled: boolean;
|
||||||
|
|
||||||
|
public getNodeProperties: string[];
|
||||||
|
public igraphConfigUi: ViewModels.IGraphConfigUiData;
|
||||||
public constructor(props: GraphExplorerProps) {
|
public constructor(props: GraphExplorerProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -237,6 +244,9 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
filterQueryError: null,
|
filterQueryError: null,
|
||||||
filterQueryWarning: null,
|
filterQueryWarning: null,
|
||||||
filterQueryStatus: FilterQueryStatus.NoResult,
|
filterQueryStatus: FilterQueryStatus.NoResult,
|
||||||
|
change: null,
|
||||||
|
igraphConfigUiData: this.props.igraphConfigUiData,
|
||||||
|
igraphConfig: this.props.igraphConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Not part of React state
|
// Not part of React state
|
||||||
|
@ -284,41 +294,27 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
this.setGremlinParams();
|
this.setGremlinParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO Make this Knockout-free ! */
|
const selectedNode = this.state.highlightedNode;
|
||||||
this.props.graphConfigUiData.nodeCaptionChoice.subscribe((key) => {
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
/* *************************************** */
|
|
||||||
|
|
||||||
props.onGraphAccessorCreated({
|
props.onGraphAccessorCreated({
|
||||||
applyFilter: this.submitQuery.bind(this),
|
applyFilter: this.submitQuery.bind(this),
|
||||||
addVertex: this.addVertex.bind(this),
|
addVertex: this.addVertex.bind(this),
|
||||||
|
shareIGraphConfig: this.shareIGraphConfig.bind(this),
|
||||||
});
|
});
|
||||||
} // constructor
|
} // 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"]
|
* If pk is a string, return ["pk", "id"]
|
||||||
* else return [pk, "id"]
|
* else return [pk, "id"]
|
||||||
|
@ -408,7 +404,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
|
|
||||||
// Update graph (in case property is being shown)
|
// Update graph (in case property is being shown)
|
||||||
this.updateInMemoryGraph(result.data);
|
this.updateInMemoryGraph(result.data);
|
||||||
this.updateGraphData(this.originalGraphData);
|
this.updateGraphData(this.originalGraphData, this.state.igraphConfig);
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
() => {
|
() => {
|
||||||
|
@ -446,7 +442,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
// Remove vertex from local cache
|
// Remove vertex from local cache
|
||||||
const graphData = this.originalGraphData;
|
const graphData = this.originalGraphData;
|
||||||
graphData.removeVertex(id, false);
|
graphData.removeVertex(id, false);
|
||||||
this.updateGraphData(graphData);
|
this.updateGraphData(graphData, this.state.igraphConfig);
|
||||||
this.setState({ highlightedNode: null });
|
this.setState({ highlightedNode: null });
|
||||||
|
|
||||||
// Remove from root map
|
// Remove from root map
|
||||||
|
@ -582,7 +578,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
this.edgeInfoCache.addVertex(vertex);
|
this.edgeInfoCache.addVertex(vertex);
|
||||||
|
|
||||||
graphData.setAsRoot(vertex.id);
|
graphData.setAsRoot(vertex.id);
|
||||||
this.updateGraphData(graphData);
|
this.updateGraphData(graphData, this.state.igraphConfig);
|
||||||
};
|
};
|
||||||
|
|
||||||
vertex._outEdgeIds = vertex._outEdgeIds || [];
|
vertex._outEdgeIds = vertex._outEdgeIds || [];
|
||||||
|
@ -788,7 +784,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
graphData.getVertexById(edge.outV)._inEAllLoaded = false;
|
graphData.getVertexById(edge.outV)._inEAllLoaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateGraphData(graphData);
|
this.updateGraphData(graphData, this.state.igraphConfig);
|
||||||
},
|
},
|
||||||
(error: string) => {
|
(error: string) => {
|
||||||
GraphExplorer.reportToConsole(
|
GraphExplorer.reportToConsole(
|
||||||
|
@ -809,7 +805,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
() => {
|
() => {
|
||||||
let graphData = this.originalGraphData;
|
let graphData = this.originalGraphData;
|
||||||
graphData.removeEdge(edgeId, false);
|
graphData.removeEdge(edgeId, false);
|
||||||
this.updateGraphData(graphData);
|
this.updateGraphData(graphData, this.state.igraphConfig);
|
||||||
},
|
},
|
||||||
(error: string) => {
|
(error: string) => {
|
||||||
GraphExplorer.reportToConsole(
|
GraphExplorer.reportToConsole(
|
||||||
|
@ -858,7 +854,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
|
|
||||||
if (vertices.length === 0) {
|
if (vertices.length === 0) {
|
||||||
// Clean graph
|
// Clean graph
|
||||||
this.updateGraphData(new GraphData.GraphData());
|
this.updateGraphData(new GraphData.GraphData(), this.state.igraphConfig);
|
||||||
this.setState({ highlightedNode: null });
|
this.setState({ highlightedNode: null });
|
||||||
GraphExplorer.reportToConsole(ConsoleDataType.Info, "Query result is empty");
|
GraphExplorer.reportToConsole(ConsoleDataType.Info, "Query result is empty");
|
||||||
}
|
}
|
||||||
|
@ -940,7 +936,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
let vertex = vertices[0];
|
let vertex = vertices[0];
|
||||||
const graphData = this.originalGraphData;
|
const graphData = this.originalGraphData;
|
||||||
graphData.addVertex(vertex);
|
graphData.addVertex(vertex);
|
||||||
this.updateGraphData(graphData);
|
this.updateGraphData(graphData, this.state.igraphConfig);
|
||||||
this.collectNodeProperties(this.originalGraphData.vertices);
|
this.collectNodeProperties(this.originalGraphData.vertices);
|
||||||
|
|
||||||
// Keep new vertex selected
|
// Keep new vertex selected
|
||||||
|
@ -1121,8 +1117,13 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
return rootMap[id];
|
return rootMap[id];
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
if (this.props.graphConfigUiData.nodeProperties().indexOf(GraphExplorer.DISPLAY_DEFAULT_PROPERTY_KEY) !== -1) {
|
if (this.state.igraphConfigUiData.nodeProperties.indexOf(GraphExplorer.DISPLAY_DEFAULT_PROPERTY_KEY) !== -1) {
|
||||||
this.props.graphConfigUiData.nodeCaptionChoice(GraphExplorer.DISPLAY_DEFAULT_PROPERTY_KEY);
|
this.setState({
|
||||||
|
igraphConfigUiData: {
|
||||||
|
...this.state.igraphConfigUiData,
|
||||||
|
nodeCaptionChoice: GraphExplorer.DISPLAY_DEFAULT_PROPERTY_KEY,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let react instantiate and render graph, before updating
|
// Let react instantiate and render graph, before updating
|
||||||
|
@ -1139,7 +1140,12 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
*/
|
*/
|
||||||
public updateNodeIcons(nodeProp: string, iconSet: string): void {
|
public updateNodeIcons(nodeProp: string, iconSet: string): void {
|
||||||
if (nodeProp === GraphExplorer.NONE_CHOICE) {
|
if (nodeProp === GraphExplorer.NONE_CHOICE) {
|
||||||
this.props.graphConfig.nodeIconKey(null);
|
this.setState({
|
||||||
|
igraphConfig: {
|
||||||
|
...this.state.igraphConfig,
|
||||||
|
nodeIconKey: undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1163,8 +1169,13 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update graph configuration
|
// Update graph configuration
|
||||||
this.props.graphConfig.iconsMap(newIconsMap);
|
this.setState({
|
||||||
this.props.graphConfig.nodeIconKey(nodeProp);
|
igraphConfig: {
|
||||||
|
...this.state.igraphConfig,
|
||||||
|
iconsMap: newIconsMap,
|
||||||
|
nodeIconKey: nodeProp,
|
||||||
|
},
|
||||||
|
});
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
GraphExplorer.reportToConsole(ConsoleDataType.Error, `Failed to retrieve icons. iconSet:${iconSet}`);
|
GraphExplorer.reportToConsole(ConsoleDataType.Error, `Failed to retrieve icons. iconSet:${iconSet}`);
|
||||||
|
@ -1209,7 +1220,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
}
|
}
|
||||||
|
|
||||||
private getPossibleRootNodes(): LeftPane.CaptionId[] {
|
private getPossibleRootNodes(): LeftPane.CaptionId[] {
|
||||||
const key = this.props.graphConfigUiData.nodeCaptionChoice();
|
const key = this.state.igraphConfig.nodeCaption;
|
||||||
return $.map(
|
return $.map(
|
||||||
this.state.rootMap,
|
this.state.rootMap,
|
||||||
(value: any, index: number): LeftPane.CaptionId => {
|
(value: any, index: number): LeftPane.CaptionId => {
|
||||||
|
@ -1320,7 +1331,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodeCaption = this.props.graphConfigUiData.nodeCaptionChoice();
|
const nodeCaption = this.state.igraphConfigUiData.nodeCaptionChoice;
|
||||||
const node = this.originalGraphData.getVertexById(this.state.highlightedNode.id);
|
const node = this.originalGraphData.getVertexById(this.state.highlightedNode.id);
|
||||||
return GraphData.GraphData.getNodePropValue(node, nodeCaption) as string;
|
return GraphData.GraphData.getNodePropValue(node, nodeCaption) as string;
|
||||||
}
|
}
|
||||||
|
@ -1410,7 +1421,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
const highlightedNodeId = this.state.highlightedNode ? this.state.highlightedNode.id : null;
|
const highlightedNodeId = this.state.highlightedNode ? this.state.highlightedNode.id : null;
|
||||||
|
|
||||||
const q = `SELECT c.id, c["${
|
const q = `SELECT c.id, c["${
|
||||||
this.props.graphConfigUiData.nodeCaptionChoice() || "id"
|
this.state.igraphConfigUiData.nodeCaptionChoice || "id"
|
||||||
}"] AS p FROM c WHERE NOT IS_DEFINED(c._isEdge)`;
|
}"] AS p FROM c WHERE NOT IS_DEFINED(c._isEdge)`;
|
||||||
return this.executeNonPagedDocDbQuery(q).then(
|
return this.executeNonPagedDocDbQuery(q).then(
|
||||||
(documents: DataModels.DocumentId[]) => {
|
(documents: DataModels.DocumentId[]) => {
|
||||||
|
@ -1539,9 +1550,14 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
});
|
});
|
||||||
|
|
||||||
const values = Object.keys(props);
|
const values = Object.keys(props);
|
||||||
this.props.graphConfigUiData.nodeProperties(values);
|
this.setState({
|
||||||
// TODO This should move out of GraphExplorer
|
igraphConfigUiData: {
|
||||||
this.props.graphConfigUiData.nodePropertiesWithNone([GraphExplorer.NONE_CHOICE].concat(values));
|
...this.state.igraphConfigUiData,
|
||||||
|
nodeProperties: values,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.setIConfigUiData(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1566,9 +1582,8 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
let sources: NeighborVertexBasicInfo[] = [];
|
let sources: NeighborVertexBasicInfo[] = [];
|
||||||
let targets: NeighborVertexBasicInfo[] = [];
|
let targets: NeighborVertexBasicInfo[] = [];
|
||||||
this.props.onResetDefaultGraphConfigValues();
|
this.props.onResetDefaultGraphConfigValues();
|
||||||
let nodeCaption = this.props.graphConfigUiData.nodeCaptionChoice();
|
let nodeCaption = this.state.igraphConfigUiData.nodeCaptionChoice;
|
||||||
this.updateSelectedNodeNeighbors(data.id, nodeCaption, sources, targets);
|
this.updateSelectedNodeNeighbors(data.id, nodeCaption, sources, targets);
|
||||||
|
|
||||||
let sData: GraphHighlightedNodeData = {
|
let sData: GraphHighlightedNodeData = {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
label: data.label,
|
label: data.label,
|
||||||
|
@ -1615,7 +1630,12 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let caption = GraphData.GraphData.getNodePropValue(gd.getVertexById(neighborId), nodeCaption) as string;
|
let caption = GraphData.GraphData.getNodePropValue(gd.getVertexById(neighborId), nodeCaption) as string;
|
||||||
sources.push({ name: caption, id: neighborId, edgeId: edge.id, edgeLabel: p });
|
sources.push({
|
||||||
|
name: caption,
|
||||||
|
id: neighborId,
|
||||||
|
edgeId: edge.id,
|
||||||
|
edgeLabel: p,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1629,7 +1649,12 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let caption = GraphData.GraphData.getNodePropValue(gd.getVertexById(neighborId), nodeCaption) as string;
|
let caption = GraphData.GraphData.getNodePropValue(gd.getVertexById(neighborId), nodeCaption) as string;
|
||||||
targets.push({ name: caption, id: neighborId, edgeId: edge.id, edgeLabel: p });
|
targets.push({
|
||||||
|
name: caption,
|
||||||
|
id: neighborId,
|
||||||
|
edgeId: edge.id,
|
||||||
|
edgeLabel: p,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1678,14 +1703,17 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
/**
|
/**
|
||||||
* Clone object and keep the original untouched (by d3)
|
* Clone object and keep the original untouched (by d3)
|
||||||
*/
|
*/
|
||||||
private updateGraphData(graphData: GraphData.GraphData<GraphData.GremlinVertex, GraphData.GremlinEdge>) {
|
private updateGraphData(
|
||||||
|
graphData: GraphData.GraphData<GraphData.GremlinVertex, GraphData.GremlinEdge>,
|
||||||
|
igraphConfig?: IGraphConfig
|
||||||
|
) {
|
||||||
this.originalGraphData = graphData;
|
this.originalGraphData = graphData;
|
||||||
let gd = JSON.parse(JSON.stringify(this.originalGraphData));
|
let gd = JSON.parse(JSON.stringify(this.originalGraphData));
|
||||||
if (!this.d3ForceGraph) {
|
if (!this.d3ForceGraph) {
|
||||||
console.warn("Attempting to update graph, but d3ForceGraph not initialized, yet.");
|
console.warn("Attempting to update graph, but d3ForceGraph not initialized, yet.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.d3ForceGraph.updateGraph(gd);
|
this.d3ForceGraph.updateGraph(gd, igraphConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onMiddlePaneInitialized(instance: D3ForceGraph.GraphRenderer): void {
|
public onMiddlePaneInitialized(instance: D3ForceGraph.GraphRenderer): void {
|
||||||
|
@ -1694,10 +1722,12 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||||
|
|
||||||
private renderMiddlePane(): JSX.Element {
|
private renderMiddlePane(): JSX.Element {
|
||||||
const forceGraphParams: D3ForceGraph.D3ForceGraphParameters = {
|
const forceGraphParams: D3ForceGraph.D3ForceGraphParameters = {
|
||||||
graphConfig: this.props.graphConfig,
|
igraphConfig: this.state.igraphConfig,
|
||||||
onHighlightedNode: this.onHighlightedNode.bind(this),
|
onHighlightedNode: this.onHighlightedNode.bind(this),
|
||||||
onLoadMoreData: this.onLoadMoreData.bind(this),
|
onLoadMoreData: this.onLoadMoreData.bind(this),
|
||||||
onInitialized: (instance: D3ForceGraph.GraphRenderer): void => this.onMiddlePaneInitialized(instance),
|
onInitialized: (instance: D3ForceGraph.GraphRenderer): void => {
|
||||||
|
this.onMiddlePaneInitialized(instance);
|
||||||
|
},
|
||||||
onGraphUpdated: this.onGraphUpdated.bind(this),
|
onGraphUpdated: this.onGraphUpdated.bind(this),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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<IGraphExplorerProps, IGraphExplorerStates> {}
|
||||||
|
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 (
|
||||||
|
<GraphExplorer
|
||||||
|
onIsNewVertexDisabledChange={this.params.onIsNewVertexDisabledChange}
|
||||||
|
onGraphAccessorCreated={this.params.onGraphAccessorCreated}
|
||||||
|
onIsFilterQueryLoadingChange={this.params.onIsFilterQueryLoading}
|
||||||
|
onIsValidQueryChange={this.params.onIsValidQuery}
|
||||||
|
onIsPropertyEditing={this.params.onIsPropertyEditing}
|
||||||
|
onIsGraphDisplayed={this.params.onIsGraphDisplayed}
|
||||||
|
onResetDefaultGraphConfigValues={this.params.onResetDefaultGraphConfigValues}
|
||||||
|
collectionPartitionKeyProperty={this.params.collectionPartitionKeyProperty}
|
||||||
|
graphBackendEndpoint={this.params.graphBackendEndpoint}
|
||||||
|
databaseId={this.params.databaseId}
|
||||||
|
collectionId={this.params.collectionId}
|
||||||
|
masterKey={this.params.masterKey}
|
||||||
|
onLoadStartKey={this.params.onLoadStartKey}
|
||||||
|
onLoadStartKeyChange={this.params.onLoadStartKeyChange}
|
||||||
|
resourceId={this.params.resourceId}
|
||||||
|
igraphConfigUiData={this.params.igraphConfigUiData}
|
||||||
|
igraphConfig={this.params.igraphConfig}
|
||||||
|
setIConfigUiData={this.params.setIConfigUiData}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -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(<GraphStyleComponent {...props} />);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render default property", () => {
|
||||||
|
const { asFragment } = render(<GraphStyleComponent {...props} />);
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
|
@ -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<boolean>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 = `
|
|
||||||
<div id="graphStyle" class="graphStyle" data-bind="setTemplateReady: true, with:params.config">
|
|
||||||
<div class="seconddivpadding">
|
|
||||||
<p>Show vertex (node) as</p>
|
|
||||||
<select id="nodeCaptionChoices" class="formTree paneselect" required data-bind="options:nodeProperties,
|
|
||||||
value:nodeCaptionChoice, hasFocus: $parent.params.firstFieldHasFocus"></select>
|
|
||||||
</div>
|
|
||||||
<div class="seconddivpadding">
|
|
||||||
<p>Map this property to node color</p>
|
|
||||||
<select id="nodeColorKeyChoices" class="formTree paneselect" required data-bind="options:nodePropertiesWithNone,
|
|
||||||
value:nodeColorKeyChoice"></select>
|
|
||||||
</div>
|
|
||||||
<div class="seconddivpadding">
|
|
||||||
<p>Map this property to node icon</p>
|
|
||||||
<select id="nodeIconChoices" class="formTree paneselect" required data-bind="options:nodePropertiesWithNone,
|
|
||||||
value:nodeIconChoice"></select>
|
|
||||||
<input type="text" data-bind="value:nodeIconSet" placeholder="Icon set: blank for collection id" class="nodeIconSet" autocomplete="off" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class="seconddivpadding">Show</p>
|
|
||||||
|
|
||||||
<div class="tabs">
|
|
||||||
<div class="tab">
|
|
||||||
<input type="radio" id="tab11" name="graphneighbortype" class="radio" data-bind="checkedValue:2, checked:showNeighborType" />
|
|
||||||
<label for="tab11" tabindex="0" data-bind="event: { keypress: $parent.onAllNeighborsKeyPress }">All neighbors</label>
|
|
||||||
</div>
|
|
||||||
<div class="tab">
|
|
||||||
<input type="radio" id="tab12" name="graphneighbortype" class="radio" data-bind="checkedValue:0, checked:showNeighborType" />
|
|
||||||
<label for="tab12" tabindex="0" data-bind="event: { keypress: $parent.onSourcesKeyPress }">Sources</label>
|
|
||||||
</div>
|
|
||||||
<div class="tab">
|
|
||||||
<input type="radio" id="tab13" name="graphneighbortype" class="radio" data-bind="checkedValue:1, checked:showNeighborType" />
|
|
||||||
<label for="tab13" tabindex="0" data-bind="event: { keypress: $parent.onTargetsKeyPress }">Targets</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
export const GraphStyleComponent = {
|
|
||||||
viewModel: GraphStyleViewModel,
|
|
||||||
template,
|
|
||||||
};
|
|
|
@ -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<GraphStyleProps> = ({
|
||||||
|
igraphConfig,
|
||||||
|
igraphConfigUiData,
|
||||||
|
getValues,
|
||||||
|
}: GraphStyleProps): JSX.Element => {
|
||||||
|
const [igraphConfigState, setIGraphConfig] = useState<IGraphConfig>(igraphConfig);
|
||||||
|
const [selected, setSelected] = useState<boolean>(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<IDropdownStyles> = {
|
||||||
|
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 (
|
||||||
|
<Stack>
|
||||||
|
<div id="graphStyle" className="graphStyle">
|
||||||
|
<div className="seconddivpadding">
|
||||||
|
<Dropdown
|
||||||
|
label="Show vertex (node) as"
|
||||||
|
options={nodePropertiesOptions}
|
||||||
|
required
|
||||||
|
selectedKey={igraphConfigState.nodeCaption}
|
||||||
|
styles={dropdownStyles}
|
||||||
|
onChange={(_, options: IDropdownOption) =>
|
||||||
|
handleOnChange(options.key.toString(), IGraphConfigType.NODE_CAPTION)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="seconddivpadding">
|
||||||
|
<Dropdown
|
||||||
|
label="Map this property to node color"
|
||||||
|
options={nodePropertiesWithNoneOptions}
|
||||||
|
required
|
||||||
|
selectedKey={igraphConfigState.nodeColorKey}
|
||||||
|
styles={dropdownStyles}
|
||||||
|
onChange={(_, options: IDropdownOption) =>
|
||||||
|
handleOnChange(options.key.toString(), IGraphConfigType.NODE_COLOR)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="seconddivpadding">
|
||||||
|
<ChoiceGroup
|
||||||
|
label="Show"
|
||||||
|
styles={choiceButtonStyles}
|
||||||
|
options={showNeighborTypeOptions}
|
||||||
|
selectedKey={igraphConfigState.showNeighborType.toString()}
|
||||||
|
onChange={(_, options: IChoiceGroupOption) =>
|
||||||
|
handleOnChange(options.key.toString(), IGraphConfigType.SHOW_NEIGHBOR_TYPE)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Graph Style Component should render default property 1`] = `[Function]`;
|
|
@ -1,74 +0,0 @@
|
||||||
<div id="graphStyle" class="graphStyle" data-bind="setTemplateReady: true, with:params.config">
|
|
||||||
<div class="seconddivpadding">
|
|
||||||
<p>Show vertex (node) as</p>
|
|
||||||
<select
|
|
||||||
id="nodeCaptionChoices"
|
|
||||||
class="formTree paneselect"
|
|
||||||
required
|
|
||||||
data-bind="options:nodeProperties,
|
|
||||||
value:nodeCaptionChoice, hasFocus: $parent.params.firstFieldHasFocus"
|
|
||||||
></select>
|
|
||||||
</div>
|
|
||||||
<div class="seconddivpadding">
|
|
||||||
<p>Map this property to node color</p>
|
|
||||||
<select
|
|
||||||
id="nodeColorKeyChoices"
|
|
||||||
class="formTree paneselect"
|
|
||||||
required
|
|
||||||
data-bind="options:nodePropertiesWithNone,
|
|
||||||
value:nodeColorKeyChoice"
|
|
||||||
></select>
|
|
||||||
</div>
|
|
||||||
<div class="seconddivpadding">
|
|
||||||
<p>Map this property to node icon</p>
|
|
||||||
<select
|
|
||||||
id="nodeIconChoices"
|
|
||||||
class="formTree paneselect"
|
|
||||||
required
|
|
||||||
data-bind="options:nodePropertiesWithNone,
|
|
||||||
value:nodeIconChoice"
|
|
||||||
></select>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
data-bind="value:nodeIconSet"
|
|
||||||
placeholder="Icon set: blank for collection id"
|
|
||||||
class="nodeIconSet"
|
|
||||||
autocomplete="off"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class="seconddivpadding">Show</p>
|
|
||||||
|
|
||||||
<div class="tabs">
|
|
||||||
<div class="tab">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
id="tab11"
|
|
||||||
name="graphneighbortype"
|
|
||||||
class="radio"
|
|
||||||
data-bind="checkedValue:2, checked:showNeighborType"
|
|
||||||
/>
|
|
||||||
<label for="tab11">All neighbors</label>
|
|
||||||
</div>
|
|
||||||
<div class="tab">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
id="tab12"
|
|
||||||
name="graphneighbortype"
|
|
||||||
class="radio"
|
|
||||||
data-bind="checkedValue:0, checked:showNeighborType"
|
|
||||||
/>
|
|
||||||
<label for="tab12">Sources</label>
|
|
||||||
</div>
|
|
||||||
<div class="tab">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
id="tab13"
|
|
||||||
name="graphneighbortype"
|
|
||||||
class="radio"
|
|
||||||
data-bind="checkedValue:1, checked:showNeighborType"
|
|
||||||
/>
|
|
||||||
<label for="tab13">Targets</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -17,7 +17,6 @@ describe("OpenActions", () => {
|
||||||
explorer.onNewCollectionClicked = jest.fn();
|
explorer.onNewCollectionClicked = jest.fn();
|
||||||
explorer.cassandraAddCollectionPane = {} as CassandraAddCollectionPane;
|
explorer.cassandraAddCollectionPane = {} as CassandraAddCollectionPane;
|
||||||
explorer.cassandraAddCollectionPane.open = jest.fn();
|
explorer.cassandraAddCollectionPane.open = jest.fn();
|
||||||
explorer.closeAllPanes = () => {};
|
|
||||||
|
|
||||||
database = {
|
database = {
|
||||||
id: ko.observable("db"),
|
id: ko.observable("db"),
|
||||||
|
|
|
@ -140,19 +140,16 @@ function openPane(action: ActionContracts.OpenPane, explorer: Explorer) {
|
||||||
action.paneKind === ActionContracts.PaneKind.AddCollection ||
|
action.paneKind === ActionContracts.PaneKind.AddCollection ||
|
||||||
(<any>action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.AddCollection]
|
(<any>action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.AddCollection]
|
||||||
) {
|
) {
|
||||||
explorer.closeAllPanes();
|
|
||||||
explorer.onNewCollectionClicked();
|
explorer.onNewCollectionClicked();
|
||||||
} else if (
|
} else if (
|
||||||
action.paneKind === ActionContracts.PaneKind.CassandraAddCollection ||
|
action.paneKind === ActionContracts.PaneKind.CassandraAddCollection ||
|
||||||
(<any>action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.CassandraAddCollection]
|
(<any>action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.CassandraAddCollection]
|
||||||
) {
|
) {
|
||||||
explorer.closeAllPanes();
|
|
||||||
explorer.cassandraAddCollectionPane.open();
|
explorer.cassandraAddCollectionPane.open();
|
||||||
} else if (
|
} else if (
|
||||||
action.paneKind === ActionContracts.PaneKind.GlobalSettings ||
|
action.paneKind === ActionContracts.PaneKind.GlobalSettings ||
|
||||||
(<any>action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.GlobalSettings]
|
(<any>action).paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.GlobalSettings]
|
||||||
) {
|
) {
|
||||||
explorer.closeAllPanes();
|
|
||||||
explorer.openSettingPane();
|
explorer.openSettingPane();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,115 +21,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
|
||||||
"_closeSynapseLinkModalDialog": [Function],
|
"_closeSynapseLinkModalDialog": [Function],
|
||||||
"_isAfecFeatureRegistered": [Function],
|
"_isAfecFeatureRegistered": [Function],
|
||||||
"_isInitializingNotebooks": false,
|
"_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],
|
"_refreshSparkEnabledStateForAccount": [Function],
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionText": [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],
|
"hasStorageAnalyticsAfecFeature": [Function],
|
||||||
"isAccountReady": [Function],
|
"isAccountReady": [Function],
|
||||||
"isAutoscaleDefaultEnabled": [Function],
|
"isAutoscaleDefaultEnabled": [Function],
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
<div data-bind="visible: visible, event: { keydown: onPaneKeyDown }">
|
|
||||||
<div class="contextual-pane-out" data-bind="click: cancel, clickBubble: false"></div>
|
|
||||||
<div class="contextual-pane" data-bind="attr: { id: id }">
|
|
||||||
<!-- Graph Styling form - Start -->
|
|
||||||
<div class="contextual-pane-in">
|
|
||||||
<form class="paneContentContainer" data-bind="submit: submit">
|
|
||||||
<!-- Graph Styling header - Start -->
|
|
||||||
<div class="firstdivbg headerline">
|
|
||||||
<span role="heading" aria-level="2">Graph Styling</span>
|
|
||||||
<div
|
|
||||||
class="closeImg"
|
|
||||||
role="button"
|
|
||||||
aria-label="Close pane"
|
|
||||||
tabindex="0"
|
|
||||||
data-bind="click: cancel, event: { keypress: onCloseKeyPress }"
|
|
||||||
>
|
|
||||||
<img src="../../../images/close-black.svg" title="Close" alt="Close" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Graph Styling header - End -->
|
|
||||||
|
|
||||||
<!-- Graph Styling errors - Start -->
|
|
||||||
<div
|
|
||||||
aria-live="assertive"
|
|
||||||
class="warningErrorContainer"
|
|
||||||
data-bind="visible: formErrors() && formErrors() !== ''"
|
|
||||||
>
|
|
||||||
<div class="warningErrorContent">
|
|
||||||
<span><img class="paneErrorIcon" src="/error_red.svg" alt="Error" /></span>
|
|
||||||
<span class="warningErrorDetailsLinkContainer">
|
|
||||||
<span class="formErrors" data-bind="text: formErrors, attr: { title: formErrors }"></span>
|
|
||||||
<a
|
|
||||||
class="errorLink"
|
|
||||||
role="link"
|
|
||||||
data-bind="visible: formErrorsDetails() && formErrorsDetails() !== '' , click: showErrorDetails"
|
|
||||||
>
|
|
||||||
More details
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Graph Styling errors - End -->
|
|
||||||
|
|
||||||
<!-- Add graph configuration - Start -->
|
|
||||||
<div class="paneMainContent">
|
|
||||||
<graph-style
|
|
||||||
id="graphStyleComponent"
|
|
||||||
params="{ config:graphConfigUIData, firstFieldHasFocus: firstFieldHasFocus }"
|
|
||||||
></graph-style>
|
|
||||||
</div>
|
|
||||||
<div class="paneFooter">
|
|
||||||
<div class="leftpanel-okbut"><input type="submit" value="OK" class="btncreatecoll1" /></div>
|
|
||||||
</div>
|
|
||||||
<!-- Add Graph configuration - End -->
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<!-- Graph Styling form - End -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<GraphStylingProps> = ({
|
||||||
|
closePanel,
|
||||||
|
igraphConfigUiData,
|
||||||
|
igraphConfig,
|
||||||
|
getValues,
|
||||||
|
}: GraphStylingProps): JSX.Element => {
|
||||||
|
const buttonLabel = "Ok";
|
||||||
|
|
||||||
|
const submit = () => {
|
||||||
|
closePanel();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form className="panelFormWrapper" onSubmit={submit}>
|
||||||
|
<div className="panelMainContent">
|
||||||
|
<GraphStyleComponent
|
||||||
|
igraphConfigUiData={igraphConfigUiData}
|
||||||
|
igraphConfig={igraphConfig}
|
||||||
|
getValues={getValues}
|
||||||
|
></GraphStyleComponent>
|
||||||
|
</div>
|
||||||
|
<PanelFooterComponent buttonLabel={buttonLabel} />
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,7 +1,5 @@
|
||||||
import AddDatabasePaneTemplate from "./AddDatabasePane.html";
|
import AddDatabasePaneTemplate from "./AddDatabasePane.html";
|
||||||
import CassandraAddCollectionPaneTemplate from "./CassandraAddCollectionPane.html";
|
import CassandraAddCollectionPaneTemplate from "./CassandraAddCollectionPane.html";
|
||||||
import GraphStylingPaneTemplate from "./GraphStylingPane.html";
|
|
||||||
|
|
||||||
export class PaneComponent {
|
export class PaneComponent {
|
||||||
constructor(data: any) {
|
constructor(data: any) {
|
||||||
return data.data;
|
return data.data;
|
||||||
|
@ -17,15 +15,6 @@ export class AddDatabasePaneComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GraphStylingPaneComponent {
|
|
||||||
constructor() {
|
|
||||||
return {
|
|
||||||
viewModel: PaneComponent,
|
|
||||||
template: GraphStylingPaneTemplate,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CassandraAddCollectionPaneComponent {
|
export class CassandraAddCollectionPaneComponent {
|
||||||
constructor() {
|
constructor() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -11,115 +11,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
|
||||||
"_closeSynapseLinkModalDialog": [Function],
|
"_closeSynapseLinkModalDialog": [Function],
|
||||||
"_isAfecFeatureRegistered": [Function],
|
"_isAfecFeatureRegistered": [Function],
|
||||||
"_isInitializingNotebooks": false,
|
"_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],
|
"_refreshSparkEnabledStateForAccount": [Function],
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionText": [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],
|
"hasStorageAnalyticsAfecFeature": [Function],
|
||||||
"isAccountReady": [Function],
|
"isAccountReady": [Function],
|
||||||
"isAutoscaleDefaultEnabled": [Function],
|
"isAutoscaleDefaultEnabled": [Function],
|
||||||
|
|
|
@ -9,115 +9,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
||||||
"_closeSynapseLinkModalDialog": [Function],
|
"_closeSynapseLinkModalDialog": [Function],
|
||||||
"_isAfecFeatureRegistered": [Function],
|
"_isAfecFeatureRegistered": [Function],
|
||||||
"_isInitializingNotebooks": false,
|
"_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],
|
"_refreshSparkEnabledStateForAccount": [Function],
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionText": [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],
|
"hasStorageAnalyticsAfecFeature": [Function],
|
||||||
"isAccountReady": [Function],
|
"isAccountReady": [Function],
|
||||||
"isAutoscaleDefaultEnabled": [Function],
|
"isAutoscaleDefaultEnabled": [Function],
|
||||||
|
|
|
@ -11,8 +11,10 @@ import {
|
||||||
GraphExplorerError,
|
GraphExplorerError,
|
||||||
GraphExplorerProps,
|
GraphExplorerProps,
|
||||||
} from "../Graph/GraphExplorerComponent/GraphExplorer";
|
} from "../Graph/GraphExplorerComponent/GraphExplorer";
|
||||||
|
// import { GraphAccessor, GraphExplorer, GraphExplorerError } from "../Graph/GraphExplorerComponent/GraphExplorer";
|
||||||
|
// import { GraphExplorerAdapter } from "../Graph/GraphExplorerComponent/GraphExplorerAdapter";
|
||||||
import { ContextualPaneBase } from "../Panes/ContextualPaneBase";
|
import { ContextualPaneBase } from "../Panes/ContextualPaneBase";
|
||||||
import GraphStylingPane from "../Panes/GraphStylingPane";
|
import { GraphStylingPanel } from "../Panes/GraphStylingPanel/GraphStylingPanel";
|
||||||
import { NewVertexPanel } from "../Panes/NewVertexPanel/NewVertexPanel";
|
import { NewVertexPanel } from "../Panes/NewVertexPanel/NewVertexPanel";
|
||||||
import TabsBase from "./TabsBase";
|
import TabsBase from "./TabsBase";
|
||||||
export interface GraphIconMap {
|
export interface GraphIconMap {
|
||||||
|
@ -31,6 +33,18 @@ export interface GraphConfig {
|
||||||
iconsMap: ko.Observable<GraphIconMap>;
|
iconsMap: ko.Observable<GraphIconMap>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
interface GraphTabOptions extends ViewModels.TabOptions {
|
||||||
account: DatabaseAccount;
|
account: DatabaseAccount;
|
||||||
masterKey: string;
|
masterKey: string;
|
||||||
|
@ -39,6 +53,7 @@ interface GraphTabOptions extends ViewModels.TabOptions {
|
||||||
collectionPartitionKeyProperty: string;
|
collectionPartitionKeyProperty: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// export default class GraphTab extends React.Component<GraphTabProps, GraphTabStates> {
|
||||||
export default class GraphTab extends TabsBase {
|
export default class GraphTab extends TabsBase {
|
||||||
// Graph default configuration
|
// Graph default configuration
|
||||||
public static readonly DEFAULT_NODE_CAPTION = "id";
|
public static readonly DEFAULT_NODE_CAPTION = "id";
|
||||||
|
@ -51,27 +66,24 @@ export default class GraphTab extends TabsBase {
|
||||||
private isPropertyEditing: ko.Observable<boolean>;
|
private isPropertyEditing: ko.Observable<boolean>;
|
||||||
private isGraphDisplayed: ko.Observable<boolean>;
|
private isGraphDisplayed: ko.Observable<boolean>;
|
||||||
private graphAccessor: GraphAccessor;
|
private graphAccessor: GraphAccessor;
|
||||||
private graphConfig: GraphConfig;
|
private igraphConfig: IGraphConfig;
|
||||||
private graphConfigUiData: ViewModels.GraphConfigUiData;
|
private igraphConfigUiData: ViewModels.IGraphConfigUiData;
|
||||||
private isFilterQueryLoading: ko.Observable<boolean>;
|
private isFilterQueryLoading: ko.Observable<boolean>;
|
||||||
private isValidQuery: ko.Observable<boolean>;
|
private isValidQuery: ko.Observable<boolean>;
|
||||||
private graphStylingPane: GraphStylingPane;
|
|
||||||
private collectionPartitionKeyProperty: string;
|
private collectionPartitionKeyProperty: string;
|
||||||
private contextualPane: ContextualPaneBase;
|
private contextualPane: ContextualPaneBase;
|
||||||
|
public graphExplorer: GraphExplorer;
|
||||||
|
public options: GraphTabOptions;
|
||||||
constructor(options: GraphTabOptions) {
|
constructor(options: GraphTabOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
|
|
||||||
this.graphStylingPane = options.collection && options.collection.container.graphStylingPane;
|
|
||||||
this.collectionPartitionKeyProperty = options.collectionPartitionKeyProperty;
|
this.collectionPartitionKeyProperty = options.collectionPartitionKeyProperty;
|
||||||
|
|
||||||
this.isNewVertexDisabled = ko.observable(false);
|
this.isNewVertexDisabled = ko.observable(false);
|
||||||
this.isPropertyEditing = ko.observable(false);
|
this.isPropertyEditing = ko.observable(false);
|
||||||
this.isGraphDisplayed = ko.observable(false);
|
this.isGraphDisplayed = ko.observable(false);
|
||||||
this.graphAccessor = undefined;
|
this.graphAccessor = undefined;
|
||||||
this.graphConfig = GraphTab.createGraphConfig();
|
this.igraphConfig = GraphTab.createIGraphConfig();
|
||||||
// TODO Merge this with this.graphConfig
|
this.igraphConfigUiData = GraphTab.createIGraphConfigUiData(this.igraphConfig);
|
||||||
this.graphConfigUiData = GraphTab.createGraphConfigUiData(this.graphConfig);
|
|
||||||
this.graphExplorerProps = {
|
this.graphExplorerProps = {
|
||||||
onGraphAccessorCreated: (instance: GraphAccessor): void => {
|
onGraphAccessorCreated: (instance: GraphAccessor): void => {
|
||||||
this.graphAccessor = instance;
|
this.graphAccessor = instance;
|
||||||
|
@ -88,9 +100,9 @@ export default class GraphTab extends TabsBase {
|
||||||
this.isGraphDisplayed(isDisplayed);
|
this.isGraphDisplayed(isDisplayed);
|
||||||
this.updateNavbarWithTabsButtons();
|
this.updateNavbarWithTabsButtons();
|
||||||
},
|
},
|
||||||
onResetDefaultGraphConfigValues: () => this.setDefaultGraphConfigValues(),
|
onResetDefaultGraphConfigValues: () => this.setDefaultIGraphConfigValues(),
|
||||||
graphConfig: this.graphConfig,
|
igraphConfig: this.igraphConfig,
|
||||||
graphConfigUiData: this.graphConfigUiData,
|
igraphConfigUiData: this.igraphConfigUiData,
|
||||||
onIsFilterQueryLoadingChange: (isFilterQueryLoading: boolean): void =>
|
onIsFilterQueryLoadingChange: (isFilterQueryLoading: boolean): void =>
|
||||||
this.isFilterQueryLoading(isFilterQueryLoading),
|
this.isFilterQueryLoading(isFilterQueryLoading),
|
||||||
onIsValidQueryChange: (isValidQuery: boolean): void => this.isValidQuery(isValidQuery),
|
onIsValidQueryChange: (isValidQuery: boolean): void => this.isValidQuery(isValidQuery),
|
||||||
|
@ -106,10 +118,12 @@ export default class GraphTab extends TabsBase {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
resourceId: options.account.id,
|
resourceId: options.account.id,
|
||||||
|
setIConfigUiData: this.setIGraphConfigUiData,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.isFilterQueryLoading = ko.observable(false);
|
this.isFilterQueryLoading = ko.observable(false);
|
||||||
this.isValidQuery = ko.observable(true);
|
this.isValidQuery = ko.observable(true);
|
||||||
|
// this.setCaption = this.setCaption.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getGremlinEndpoint(account: DatabaseAccount): string {
|
public static getGremlinEndpoint(account: DatabaseAccount): string {
|
||||||
|
@ -170,60 +184,76 @@ export default class GraphTab extends TabsBase {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public openStyling(): void {
|
public openStyling(): void {
|
||||||
this.setDefaultGraphConfigValues();
|
this.collection.container.openSidePanel(
|
||||||
// Update the styling pane with this instance
|
"Graph Style",
|
||||||
this.graphStylingPane.setData(this.graphConfigUiData);
|
<GraphStylingPanel
|
||||||
this.graphStylingPane.open();
|
closePanel={this.collection.container.closeSidePanel}
|
||||||
|
igraphConfigUiData={this.igraphConfigUiData}
|
||||||
|
igraphConfig={this.igraphConfig}
|
||||||
|
getValues={(igraphConfig?: IGraphConfig): void => {
|
||||||
|
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 {
|
return {
|
||||||
nodeColor: ko.observable(GraphTab.NODE_COLOR),
|
nodeColor: GraphTab.NODE_COLOR,
|
||||||
nodeColorKey: ko.observable(undefined),
|
nodeColorKey: "None",
|
||||||
linkColor: ko.observable(GraphTab.LINK_COLOR),
|
linkColor: GraphTab.LINK_COLOR,
|
||||||
showNeighborType: ko.observable(ViewModels.NeighborType.TARGETS_ONLY),
|
showNeighborType: ViewModels.NeighborType.TARGETS_ONLY,
|
||||||
nodeCaption: ko.observable(GraphTab.DEFAULT_NODE_CAPTION),
|
nodeCaption: GraphTab.DEFAULT_NODE_CAPTION,
|
||||||
nodeSize: ko.observable(GraphTab.NODE_SIZE),
|
nodeSize: GraphTab.NODE_SIZE,
|
||||||
linkWidth: ko.observable(GraphTab.LINK_WIDTH),
|
linkWidth: GraphTab.LINK_WIDTH,
|
||||||
nodeIconKey: ko.observable(undefined),
|
nodeIconKey: undefined,
|
||||||
iconsMap: ko.observable({}),
|
iconsMap: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createGraphConfigUiData(graphConfig: GraphConfig): ViewModels.GraphConfigUiData {
|
public static createIGraphConfigUiData(igraphConfig: IGraphConfig): ViewModels.IGraphConfigUiData {
|
||||||
return {
|
return {
|
||||||
showNeighborType: ko.observable(graphConfig.showNeighborType()),
|
showNeighborType: igraphConfig.showNeighborType,
|
||||||
nodeProperties: ko.observableArray([]),
|
nodeProperties: [],
|
||||||
nodePropertiesWithNone: ko.observableArray([]),
|
nodePropertiesWithNone: [],
|
||||||
nodeCaptionChoice: ko.observable(graphConfig.nodeCaption()),
|
nodeCaptionChoice: igraphConfig.nodeCaption,
|
||||||
nodeColorKeyChoice: ko.observable(graphConfig.nodeColorKey()),
|
nodeColorKeyChoice: igraphConfig.nodeIconKey,
|
||||||
nodeIconChoice: ko.observable(graphConfig.nodeIconKey()),
|
nodeIconChoice: igraphConfig.nodeIconKey,
|
||||||
nodeIconSet: ko.observable(undefined),
|
nodeIconSet: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private setDefaultIGraphConfigValues() {
|
||||||
* Make sure graph config values are not undefined
|
|
||||||
*/
|
|
||||||
private setDefaultGraphConfigValues() {
|
|
||||||
// Assign default values if undefined
|
// Assign default values if undefined
|
||||||
if (
|
if (this.igraphConfigUiData.nodeCaptionChoice === undefined && this.igraphConfigUiData.nodeProperties.length > 1) {
|
||||||
this.graphConfigUiData.nodeCaptionChoice() === undefined &&
|
this.igraphConfigUiData.nodeCaptionChoice = this.igraphConfigUiData.nodeProperties[0];
|
||||||
this.graphConfigUiData.nodeProperties().length > 1
|
|
||||||
) {
|
|
||||||
this.graphConfigUiData.nodeCaptionChoice(this.graphConfigUiData.nodeProperties()[0]);
|
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
this.graphConfigUiData.nodeColorKeyChoice() === undefined &&
|
this.igraphConfigUiData.nodeColorKeyChoice === undefined &&
|
||||||
this.graphConfigUiData.nodePropertiesWithNone().length > 1
|
this.igraphConfigUiData.nodePropertiesWithNone.length > 1
|
||||||
) {
|
) {
|
||||||
this.graphConfigUiData.nodeColorKeyChoice(this.graphConfigUiData.nodePropertiesWithNone()[0]);
|
this.igraphConfigUiData.nodeColorKeyChoice = this.igraphConfigUiData.nodePropertiesWithNone[0];
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
this.graphConfigUiData.nodeIconChoice() === undefined &&
|
this.igraphConfigUiData.nodeIconChoice === undefined &&
|
||||||
this.graphConfigUiData.nodePropertiesWithNone().length > 1
|
this.igraphConfigUiData.nodePropertiesWithNone.length > 1
|
||||||
) {
|
) {
|
||||||
this.graphConfigUiData.nodeIconChoice(this.graphConfigUiData.nodePropertiesWithNone()[0]);
|
this.igraphConfigUiData.nodeIconChoice = this.igraphConfigUiData.nodePropertiesWithNone[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected getTabsButtons(): CommandButtonComponentProps[] {
|
protected getTabsButtons(): CommandButtonComponentProps[] {
|
||||||
|
|
|
@ -155,7 +155,6 @@ const App: React.FunctionComponent = () => {
|
||||||
isConsoleExpanded={isNotificationConsoleExpanded}
|
isConsoleExpanded={isNotificationConsoleExpanded}
|
||||||
/>
|
/>
|
||||||
<div data-bind='component: { name: "add-database-pane", params: {data: addDatabasePane} }' />
|
<div data-bind='component: { name: "add-database-pane", params: {data: addDatabasePane} }' />
|
||||||
<div data-bind='component: { name: "graph-styling-pane", params: { data: graphStylingPane} }' />
|
|
||||||
<div data-bind='component: { name: "cassandra-add-collection-pane", params: { data: cassandraAddCollectionPane} }' />
|
<div data-bind='component: { name: "cassandra-add-collection-pane", params: { data: cassandraAddCollectionPane} }' />
|
||||||
{showDialog && <Dialog {...dialogProps} />}
|
{showDialog && <Dialog {...dialogProps} />}
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue