mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-26 12:21:23 +00:00
Compare commits
4 Commits
resolve_De
...
fix_eslint
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b6a1b345f | ||
|
|
55837db65b | ||
|
|
9f27cb95b9 | ||
|
|
271256bffb |
@@ -46,8 +46,8 @@ src/Explorer/DataSamples/DataSamplesUtil.test.ts
|
||||
src/Explorer/DataSamples/DataSamplesUtil.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/ArraysByKeyCache.test.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/ArraysByKeyCache.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.test.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts
|
||||
# src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.test.ts
|
||||
# src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/EdgeInfoCache.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/GraphData.test.ts
|
||||
src/Explorer/Graph/GraphExplorerComponent/GraphData.ts
|
||||
@@ -81,12 +81,8 @@ src/Explorer/Tables/DataTable/DataTableBindingManager.ts
|
||||
src/Explorer/Tables/DataTable/DataTableBuilder.ts
|
||||
src/Explorer/Tables/DataTable/DataTableContextMenu.ts
|
||||
src/Explorer/Tables/DataTable/DataTableOperationManager.ts
|
||||
# src/Explorer/Tables/DataTable/DataTableOperations.ts
|
||||
src/Explorer/Tables/DataTable/DataTableViewModel.ts
|
||||
# src/Explorer/Tables/DataTable/TableCommands.ts
|
||||
# src/Explorer/Tables/DataTable/TableEntityCache.ts
|
||||
src/Explorer/Tables/DataTable/TableEntityListViewModel.ts
|
||||
# src/Explorer/Tables/Entities.ts
|
||||
src/Explorer/Tables/QueryBuilder/CustomTimestampHelper.ts
|
||||
src/Explorer/Tables/TableDataClient.ts
|
||||
src/Explorer/Tables/TableEntityProcessor.ts
|
||||
@@ -134,20 +130,13 @@ src/Explorer/Controls/Notebook/NotebookTerminalComponent.tsx
|
||||
src/Explorer/Controls/NotebookViewer/NotebookViewerComponent.tsx
|
||||
src/Explorer/Controls/TreeComponent/TreeComponent.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx
|
||||
; src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/GraphVizComponent.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/LeftPaneComponent.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/MiddlePaneComponent.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.test.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.test.tsx
|
||||
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.tsx
|
||||
src/Explorer/Menus/CommandBar/CommandBarUtil.tsx
|
||||
src/Explorer/Notebook/NotebookComponent/NotebookComponentAdapter.tsx
|
||||
; src/Explorer/Notebook/NotebookComponent/NotebookComponentBootstrapper.tsx
|
||||
src/Explorer/Notebook/NotebookComponent/VirtualCommandBarComponent.tsx
|
||||
src/Explorer/Notebook/NotebookComponent/contents/index.tsx
|
||||
; src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.tsx
|
||||
src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.tsx
|
||||
src/Explorer/Notebook/NotebookRenderer/decorators/draggable/index.tsx
|
||||
src/Explorer/Notebook/NotebookRenderer/decorators/hijack-scroll/index.tsx
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as sinon from "sinon";
|
||||
/*eslint-disable jest/no-test-callback */
|
||||
import * as sinon from "sinon";
|
||||
import GraphTab from "../../Tabs/GraphTab";
|
||||
import { D3Link, D3Node, GraphData } from "../GraphExplorerComponent/GraphData";
|
||||
import { D3ForceGraph, D3GraphNodeData, LoadMoreDataAction } from "./D3ForceGraph";
|
||||
@@ -70,6 +71,7 @@ describe("D3ForceGraph", () => {
|
||||
forceGraph = new D3ForceGraph({
|
||||
igraphConfig: GraphTab.createIGraphConfig(),
|
||||
onHighlightedNode: sinon.spy(),
|
||||
//eslint-disable-next-line
|
||||
onLoadMoreData: (action: LoadMoreDataAction): void => {},
|
||||
|
||||
// parent to graph
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { BaseType } from "d3";
|
||||
/*eslint-disable @typescript-eslint/no-explicit-any*/
|
||||
/*eslint-disable @typescript-eslint/no-this-alias*/
|
||||
import { BaseType } from "d3";
|
||||
import { map as d3Map } from "d3-collection";
|
||||
import { D3DragEvent, drag } from "d3-drag";
|
||||
import { forceCollide, forceLink, forceManyBody, forceSimulation } from "d3-force";
|
||||
@@ -261,10 +263,10 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
const self = this;
|
||||
// Select this node id
|
||||
selectAll(".node")
|
||||
.filter(function (d: D3Node, i) {
|
||||
.filter((d: D3Node) => {
|
||||
return d.id === newVal;
|
||||
})
|
||||
.each(function (d: D3Node) {
|
||||
@@ -277,15 +279,15 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
} // initialize
|
||||
|
||||
private updateUniqueValues(key: string) {
|
||||
for (var i = 0; i < this.graphDataWrapper.vertices.length; i++) {
|
||||
let vertex = this.graphDataWrapper.vertices[i];
|
||||
for (let i = 0; i < this.graphDataWrapper.vertices.length; i++) {
|
||||
const vertex = this.graphDataWrapper.vertices[i];
|
||||
|
||||
let props = D3ForceGraph.getNodeProperties(vertex);
|
||||
const props = D3ForceGraph.getNodeProperties(vertex);
|
||||
if (props.indexOf(key) === -1) {
|
||||
// Vertex doesn't have the property
|
||||
continue;
|
||||
}
|
||||
let val = GraphData.getNodePropValue(vertex, key);
|
||||
const val = GraphData.getNodePropValue(vertex, key);
|
||||
if (typeof val !== "string" && typeof val !== "number") {
|
||||
// Not a type we can map
|
||||
continue;
|
||||
@@ -313,7 +315,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
*/
|
||||
private static getNodeProperties(node: D3Node): string[] {
|
||||
let props = ["id", "label"];
|
||||
|
||||
//eslint-disable-next-line
|
||||
if (node.hasOwnProperty("properties")) {
|
||||
props = props.concat(Object.keys(node.properties));
|
||||
}
|
||||
@@ -405,7 +407,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
// Remember nodes current position
|
||||
const posMap = new Map<string, Point2D>();
|
||||
this.simulation.nodes().forEach((d: D3Node) => {
|
||||
if (d.x == undefined || d.y == undefined) {
|
||||
if (d.x === undefined || d.y === undefined) {
|
||||
return;
|
||||
}
|
||||
posMap.set(d.id, { x: d.x, y: d.y });
|
||||
@@ -549,7 +551,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
.transition()
|
||||
.delay(D3ForceGraph.TRANSITION_STEP3_MS - 100)
|
||||
.duration(D3ForceGraph.TRANSITION_STEP3_MS)
|
||||
.attrTween("fill", (t: any) => {
|
||||
.attrTween("fill", () => {
|
||||
const ic = interpolate("#ffffff", "#000000");
|
||||
return (t: number) => {
|
||||
return ic(t);
|
||||
@@ -567,7 +569,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
// Distribute nodes initial position before simulation
|
||||
const nodes = graph.vertices;
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
let v = nodes[i];
|
||||
const v = nodes[i];
|
||||
|
||||
if (v._isRoot) {
|
||||
this.rootVertex = v;
|
||||
@@ -611,6 +613,20 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
|
||||
const self = this;
|
||||
|
||||
const ticked = () => {
|
||||
self.linkSelection.select(".link").attr("d", (l: D3Link) => {
|
||||
return self.positionLink(l);
|
||||
});
|
||||
if (!D3ForceGraph.useSvgMarkerEnd()) {
|
||||
self.linkSelection.select(".markerEnd").attr("transform", (l: D3Link) => {
|
||||
return self.positionLinkEnd(l);
|
||||
});
|
||||
}
|
||||
self.nodeSelection.attr("transform", (d: D3Node) => {
|
||||
return self.positionNode(d);
|
||||
});
|
||||
};
|
||||
|
||||
this.simulation.nodes(nodes).on("tick", ticked);
|
||||
|
||||
this.simulation.force<d3.ForceLink<D3Node, D3Link>>("link").links(graph.edges);
|
||||
@@ -634,20 +650,6 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
this.simulation.alpha(1).restart();
|
||||
this.params.onGraphUpdated(new Date().getTime());
|
||||
});
|
||||
|
||||
function ticked() {
|
||||
self.linkSelection.select(".link").attr("d", (l: D3Link) => {
|
||||
return self.positionLink(l);
|
||||
});
|
||||
if (!D3ForceGraph.useSvgMarkerEnd()) {
|
||||
self.linkSelection.select(".markerEnd").attr("transform", (l: D3Link) => {
|
||||
return self.positionLinkEnd(l);
|
||||
});
|
||||
}
|
||||
self.nodeSelection.attr("transform", (d: D3Node) => {
|
||||
return self.positionNode(d);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private addNewLinks(): d3.Selection<Element, any, any, any> {
|
||||
@@ -677,7 +679,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
}
|
||||
|
||||
private addNewNodes(): d3.Selection<Element, any, any, any> {
|
||||
var self = this;
|
||||
const self = this;
|
||||
|
||||
const newNodes = this.nodeSelection
|
||||
.enter()
|
||||
@@ -705,7 +707,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
this.highlightNode(this, d);
|
||||
this.simulation.stop();
|
||||
})
|
||||
.on("mouseout", (_: MouseEvent, d: D3Node) => {
|
||||
.on("mouseout", () => {
|
||||
if (this.isHighlightDisabled || this.selectedNode || this.isDragging) {
|
||||
return;
|
||||
}
|
||||
@@ -726,7 +728,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
.attr("class", "main")
|
||||
.attr("r", this.igraphConfig.nodeSize);
|
||||
|
||||
var iconGroup = newNodes
|
||||
const iconGroup = newNodes
|
||||
.append("g")
|
||||
.attr("class", "iconContainer")
|
||||
.attr("tabindex", 0)
|
||||
@@ -749,8 +751,8 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
self.onNodeClicked(this.parentNode, d);
|
||||
}
|
||||
});
|
||||
var nodeSize = this.igraphConfig.nodeSize;
|
||||
var bgsize = nodeSize + 1;
|
||||
const nodeSize = this.igraphConfig.nodeSize;
|
||||
const bgsize = nodeSize + 1;
|
||||
|
||||
iconGroup
|
||||
.append("rect")
|
||||
@@ -758,7 +760,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
.attr("y", -bgsize)
|
||||
.attr("width", bgsize * 2)
|
||||
.attr("height", bgsize * 2)
|
||||
.attr("fill-opacity", (d: D3Node) => {
|
||||
.attr("fill-opacity", () => {
|
||||
return this.igraphConfig.nodeIconKey ? 1 : 0;
|
||||
})
|
||||
.attr("class", "icon-background");
|
||||
@@ -830,10 +832,10 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
self.loadNeighbors(d, PAGE_ACTION.NEXT_PAGE);
|
||||
}
|
||||
}) as any)
|
||||
.on("mouseover", ((e: MouseEvent, d: D3Node) => {
|
||||
.on("mouseover", ((e: MouseEvent) => {
|
||||
select(e.target as any).classed("active", true);
|
||||
}) as any)
|
||||
.on("mouseout", ((e: MouseEvent, d: D3Node) => {
|
||||
.on("mouseout", ((e: MouseEvent) => {
|
||||
select(e.target as any).classed("active", false);
|
||||
}) as any)
|
||||
.attr("visibility", (d: D3Node) => (!d._outEAllLoaded || !d._inEAllLoaded ? "visible" : "hidden"));
|
||||
@@ -859,10 +861,10 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
self.loadNeighbors(d, PAGE_ACTION.PREVIOUS_PAGE);
|
||||
}
|
||||
}) as any)
|
||||
.on("mouseover", ((e: MouseEvent, d: D3Node) => {
|
||||
.on("mouseover", ((e: MouseEvent) => {
|
||||
select(e.target as any).classed("active", true);
|
||||
}) as any)
|
||||
.on("mouseout", ((e: MouseEvent, d: D3Node) => {
|
||||
.on("mouseout", ((e: MouseEvent) => {
|
||||
select(e.target as any).classed("active", false);
|
||||
}) as any)
|
||||
.attr("visibility", (d: D3Node) =>
|
||||
@@ -955,10 +957,10 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
self.loadNeighbors(d, PAGE_ACTION.FIRST_PAGE);
|
||||
}
|
||||
}) as any)
|
||||
.on("mouseover", ((e: MouseEvent, d: D3Node) => {
|
||||
.on("mouseover", ((e: MouseEvent) => {
|
||||
select(e.target as any).classed("active", true);
|
||||
}) as any)
|
||||
.on("mouseout", ((e: MouseEvent, d: D3Node) => {
|
||||
.on("mouseout", ((e: MouseEvent) => {
|
||||
select(e.target as any).classed("active", false);
|
||||
}) as any);
|
||||
}
|
||||
@@ -967,10 +969,9 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
* Remove LoadMore subassembly for existing nodes that show all their children in the graph
|
||||
*/
|
||||
private updateLoadMore(nodeSelection: d3.Selection<Element, any, any, any>) {
|
||||
const self = this;
|
||||
nodeSelection.selectAll(".loadmore").remove();
|
||||
|
||||
var nodeSize = this.igraphConfig.nodeSize;
|
||||
const nodeSize = this.igraphConfig.nodeSize;
|
||||
const rootSelectionG = nodeSelection
|
||||
.filter((d: D3Node) => {
|
||||
return !!d._isRoot && !!d._pagination;
|
||||
@@ -1090,7 +1091,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
|
||||
private fadeNonNeighbors(nodeId: string) {
|
||||
this.g.selectAll(".node").classed("inactive", (d: D3Node) => {
|
||||
var neighbors = ((showNeighborType) => {
|
||||
const neighbors = ((showNeighborType) => {
|
||||
switch (showNeighborType) {
|
||||
case NeighborType.SOURCES_ONLY:
|
||||
return this.graphDataWrapper.getSourcesForId(nodeId);
|
||||
@@ -1151,7 +1152,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
}
|
||||
|
||||
private retrieveNodeCaption(d: D3Node) {
|
||||
let key = this.igraphConfig.nodeCaption;
|
||||
const key = this.igraphConfig.nodeCaption;
|
||||
let value: string = d.id || d.label;
|
||||
if (key) {
|
||||
value = <string>GraphData.getNodePropValue(d, key) || "";
|
||||
@@ -1202,14 +1203,14 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
y: (<D3Node>l.target).y,
|
||||
};
|
||||
const d1 = D3ForceGraph.calculateControlPoint(source, target);
|
||||
var radius = this.igraphConfig.nodeSize + 3;
|
||||
const radius = this.igraphConfig.nodeSize + 3;
|
||||
|
||||
// End
|
||||
const dx = target.x - d1.x;
|
||||
const dy = target.y - d1.y;
|
||||
const angle = Math.atan2(dy, dx);
|
||||
var ux = target.x - Math.cos(angle) * radius;
|
||||
var uy = target.y - Math.sin(angle) * radius;
|
||||
const ux = target.x - Math.cos(angle) * radius;
|
||||
const uy = target.y - Math.sin(angle) * radius;
|
||||
|
||||
return `translate(${ux},${uy}) rotate(${(angle * 180) / Math.PI})`;
|
||||
}
|
||||
@@ -1224,21 +1225,21 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
y: (<D3Node>l.target).y,
|
||||
};
|
||||
const d1 = D3ForceGraph.calculateControlPoint(source, target);
|
||||
var radius = this.igraphConfig.nodeSize + 3;
|
||||
const radius = this.igraphConfig.nodeSize + 3;
|
||||
|
||||
// Start
|
||||
var dx = d1.x - source.x;
|
||||
var dy = d1.y - source.y;
|
||||
var angle = Math.atan2(dy, dx);
|
||||
var tx = source.x + Math.cos(angle) * radius;
|
||||
var ty = source.y + Math.sin(angle) * radius;
|
||||
let dx = d1.x - source.x;
|
||||
let dy = d1.y - source.y;
|
||||
let angle = Math.atan2(dy, dx);
|
||||
const tx = source.x + Math.cos(angle) * radius;
|
||||
const ty = source.y + Math.sin(angle) * radius;
|
||||
|
||||
// End
|
||||
dx = target.x - d1.x;
|
||||
dy = target.y - d1.y;
|
||||
angle = Math.atan2(dy, dx);
|
||||
var ux = target.x - Math.cos(angle) * radius;
|
||||
var uy = target.y - Math.sin(angle) * radius;
|
||||
const ux = target.x - Math.cos(angle) * radius;
|
||||
const uy = target.y - Math.sin(angle) * radius;
|
||||
|
||||
return "M" + tx + "," + ty + "S" + d1.x + "," + d1.y + " " + ux + "," + uy;
|
||||
}
|
||||
@@ -1260,9 +1261,9 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
}
|
||||
|
||||
private static computeImageData(d: D3Node, config: IGraphConfig): string {
|
||||
let propValue = <string>GraphData.getNodePropValue(d, config.nodeIconKey) || "";
|
||||
const propValue = <string>GraphData.getNodePropValue(d, config.nodeIconKey) || "";
|
||||
// Trim leading and trailing spaces to make comparison more forgiving.
|
||||
let value = config.iconsMap[propValue.trim()];
|
||||
const value = config.iconsMap[propValue.trim()];
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -1288,7 +1289,7 @@ export class D3ForceGraph implements GraphRenderer {
|
||||
// clear icons
|
||||
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", () => {
|
||||
return config.nodeIconKey ? 1 : 0;
|
||||
});
|
||||
this.g.selectAll(".node text.caption").text((d: D3Node) => {
|
||||
|
||||
@@ -58,7 +58,7 @@ export class LeftPaneComponent extends React.Component<LeftPaneComponentProps> {
|
||||
className={className}
|
||||
as="tr"
|
||||
aria-label={node.caption}
|
||||
onActivated={(e) => this.props.onRootNodeSelected(node.id)}
|
||||
onActivated={() => this.props.onRootNodeSelected(node.id)}
|
||||
key={node.id}
|
||||
>
|
||||
<td className="resultItem">
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from "react";
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import * as Q from "q";
|
||||
import { NodePropertiesComponent, NodePropertiesComponentProps, Mode } from "./NodePropertiesComponent";
|
||||
import { GraphHighlightedNodeData, EditedProperties, EditedEdges, PossibleVertex } from "./GraphExplorer";
|
||||
import React from "react";
|
||||
import { GraphHighlightedNodeData, PossibleVertex } from "./GraphExplorer";
|
||||
import { Mode, NodePropertiesComponent, NodePropertiesComponentProps } from "./NodePropertiesComponent";
|
||||
|
||||
describe("Property pane", () => {
|
||||
const title = "My Title";
|
||||
@@ -37,17 +37,18 @@ describe("Property pane", () => {
|
||||
return {
|
||||
expandedTitle: title,
|
||||
isCollapsed: false,
|
||||
onCollapsedChanged: (newValue: boolean): void => {},
|
||||
onCollapsedChanged: jest.fn(),
|
||||
node: highlightedNode,
|
||||
getPkIdFromNodeData: (v: GraphHighlightedNodeData): string => null,
|
||||
collectionPartitionKeyProperty: null,
|
||||
updateVertexProperties: (editedProperties: EditedProperties): Q.Promise<void> => Q.resolve(),
|
||||
selectNode: (id: string): void => {},
|
||||
updatePossibleVertices: (): Q.Promise<PossibleVertex[]> => Q.resolve(null),
|
||||
possibleEdgeLabels: null,
|
||||
editGraphEdges: (editedEdges: EditedEdges): Q.Promise<any> => Q.resolve(),
|
||||
deleteHighlightedNode: (): void => {},
|
||||
onModeChanged: (newMode: Mode): void => {},
|
||||
getPkIdFromNodeData: (): string => undefined,
|
||||
collectionPartitionKeyProperty: undefined,
|
||||
updateVertexProperties: (): Q.Promise<void> => Q.resolve(),
|
||||
selectNode: jest.fn(),
|
||||
updatePossibleVertices: (): Q.Promise<PossibleVertex[]> => Q.resolve(undefined),
|
||||
possibleEdgeLabels: undefined,
|
||||
//eslint-disable-next-line
|
||||
editGraphEdges: (): Q.Promise<any> => Q.resolve(),
|
||||
deleteHighlightedNode: jest.fn(),
|
||||
onModeChanged: jest.fn(),
|
||||
viewMode: Mode.READONLY_PROP,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -72,7 +72,7 @@ export class NodePropertiesComponent extends React.Component<
|
||||
super(props);
|
||||
this.state = {
|
||||
editedProperties: {
|
||||
pkId: null,
|
||||
pkId: undefined,
|
||||
readOnlyProperties: [],
|
||||
existingProperties: [],
|
||||
addedProperties: [],
|
||||
@@ -98,15 +98,12 @@ export class NodePropertiesComponent extends React.Component<
|
||||
};
|
||||
}
|
||||
|
||||
public static getDerivedStateFromProps(
|
||||
props: NodePropertiesComponentProps,
|
||||
state: NodePropertiesComponentState
|
||||
): Partial<NodePropertiesComponentState> {
|
||||
public static getDerivedStateFromProps(props: NodePropertiesComponentProps): Partial<NodePropertiesComponentState> {
|
||||
if (props.viewMode !== Mode.READONLY_PROP) {
|
||||
return { isDeleteConfirm: false };
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
@@ -138,10 +135,10 @@ export class NodePropertiesComponent extends React.Component<
|
||||
* @param value
|
||||
*/
|
||||
private static getTypeOption(value: any): ViewModels.InputPropertyValueTypeString {
|
||||
if (value == null) {
|
||||
if (value === undefined) {
|
||||
return "null";
|
||||
}
|
||||
let type = typeof value;
|
||||
const type = typeof value;
|
||||
switch (type) {
|
||||
case "number":
|
||||
case "boolean":
|
||||
@@ -172,10 +169,9 @@ export class NodePropertiesComponent extends React.Component<
|
||||
];
|
||||
|
||||
const existingProps: ViewModels.InputProperty[] = [];
|
||||
|
||||
if (this.props.node.hasOwnProperty("properties")) {
|
||||
const hProps = this.props.node["properties"];
|
||||
for (let p in hProps) {
|
||||
for (const p in hProps) {
|
||||
const propValues = hProps[p];
|
||||
(p === partitionKeyProperty ? readOnlyProps : existingProps).push({
|
||||
key: p,
|
||||
@@ -437,7 +433,7 @@ export class NodePropertiesComponent extends React.Component<
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -307,18 +307,11 @@ function createOpenSynapseLinkDialogButton(container: Explorer): CommandButtonCo
|
||||
|
||||
function createNewDatabase(container: Explorer): CommandButtonComponentProps {
|
||||
const label = "New " + getDatabaseName();
|
||||
const newDatabaseButton = document.activeElement as HTMLElement;
|
||||
|
||||
return {
|
||||
iconSrc: AddDatabaseIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () =>
|
||||
useSidePanel
|
||||
.getState()
|
||||
.openSidePanel(
|
||||
"New " + getDatabaseName(),
|
||||
<AddDatabasePanel explorer={container} buttonElement={newDatabaseButton} />
|
||||
),
|
||||
useSidePanel.getState().openSidePanel("New " + getDatabaseName(), <AddDatabasePanel explorer={container} />),
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
|
||||
@@ -4,6 +4,8 @@ import * as React from "react";
|
||||
import { useFullScreenURLs } from "../hooks/useFullScreenURLs";
|
||||
|
||||
export const OpenFullScreen: React.FunctionComponent = () => {
|
||||
const [isReadUrlCopy, setIsReadUrlCopy] = React.useState<boolean>(false);
|
||||
const [isReadWriteUrlCopy, setIsReadWriteUrlCopy] = React.useState<boolean>(false);
|
||||
const result = useFullScreenURLs();
|
||||
if (!result) {
|
||||
return <Spinner label="Generating URLs..." ariaLive="assertive" labelPosition="right" />;
|
||||
@@ -25,8 +27,9 @@ export const OpenFullScreen: React.FunctionComponent = () => {
|
||||
<DefaultButton
|
||||
onClick={() => {
|
||||
copyToClipboard(readWriteUrl);
|
||||
setIsReadWriteUrlCopy(true);
|
||||
}}
|
||||
text="Copy"
|
||||
text={isReadWriteUrlCopy ? "Copied" : "Copy"}
|
||||
iconProps={{ iconName: "Copy" }}
|
||||
/>
|
||||
<PrimaryButton
|
||||
@@ -41,9 +44,10 @@ export const OpenFullScreen: React.FunctionComponent = () => {
|
||||
<Stack horizontal tokens={{ childrenGap: 10 }}>
|
||||
<DefaultButton
|
||||
onClick={() => {
|
||||
setIsReadUrlCopy(true);
|
||||
copyToClipboard(readUrl);
|
||||
}}
|
||||
text="Copy"
|
||||
text={isReadUrlCopy ? "Copied" : "Copy"}
|
||||
iconProps={{ iconName: "Copy" }}
|
||||
/>
|
||||
<PrimaryButton
|
||||
|
||||
@@ -23,12 +23,10 @@ import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneFor
|
||||
|
||||
export interface AddDatabasePaneProps {
|
||||
explorer: Explorer;
|
||||
buttonElement?: HTMLElement;
|
||||
}
|
||||
|
||||
export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
|
||||
explorer: container,
|
||||
buttonElement,
|
||||
}: AddDatabasePaneProps) => {
|
||||
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
|
||||
let throughput: number;
|
||||
@@ -79,7 +77,6 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
|
||||
dataExplorerArea: Constants.Areas.ContextualPane,
|
||||
};
|
||||
TelemetryProcessor.trace(Action.CreateDatabase, ActionModifiers.Open, addDatabasePaneOpenMessage);
|
||||
buttonElement.focus();
|
||||
}, []);
|
||||
|
||||
const onSubmit = () => {
|
||||
|
||||
@@ -307,23 +307,16 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||
iconSrc: AddDatabaseIcon,
|
||||
title: "New " + getDatabaseName(),
|
||||
description: undefined,
|
||||
onClick: () => this.openAddDatabasePanel(),
|
||||
onClick: () =>
|
||||
useSidePanel
|
||||
.getState()
|
||||
.openSidePanel("New " + getDatabaseName(), <AddDatabasePanel explorer={this.container} />),
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private openAddDatabasePanel() {
|
||||
const newDatabaseButton = document.activeElement as HTMLElement;
|
||||
useSidePanel
|
||||
.getState()
|
||||
.openSidePanel(
|
||||
"New " + getDatabaseName(),
|
||||
<AddDatabasePanel explorer={this.container} buttonElement={newDatabaseButton} />
|
||||
);
|
||||
}
|
||||
|
||||
private decorateOpenCollectionActivity({ databaseId, collectionId }: MostRecentActivity.OpenCollectionItem) {
|
||||
return {
|
||||
iconSrc: NotebookIcon,
|
||||
|
||||
@@ -202,14 +202,21 @@ export class CassandraAPIDataClient extends TableDataClient {
|
||||
|
||||
let updateQuery = `UPDATE ${collection.databaseId}.${collection.id()}`;
|
||||
let isPropertyUpdated = false;
|
||||
let isFirstPropertyToUpdate = true;
|
||||
for (let property in newEntity) {
|
||||
if (
|
||||
!originalDocument[property] ||
|
||||
newEntity[property]._.toString() !== originalDocument[property]._.toString()
|
||||
) {
|
||||
updateQuery += this.isStringType(newEntity[property].$)
|
||||
? ` SET ${property} = '${newEntity[property]._}',`
|
||||
: ` SET ${property} = ${newEntity[property]._},`;
|
||||
let propertyQuerySegment = this.isStringType(newEntity[property].$)
|
||||
? `${property} = '${newEntity[property]._}',`
|
||||
: `${property} = ${newEntity[property]._},`;
|
||||
// Only add the "SET" keyword once
|
||||
if (isFirstPropertyToUpdate) {
|
||||
propertyQuerySegment = " SET " + propertyQuerySegment;
|
||||
isFirstPropertyToUpdate = false;
|
||||
}
|
||||
updateQuery += propertyQuerySegment;
|
||||
isPropertyUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ export default class NotebookTabV2 extends NotebookTabBase {
|
||||
const saveButtonChildren = [];
|
||||
if (this.container.notebookManager?.gitHubOAuthService.isLoggedIn()) {
|
||||
saveButtonChildren.push({
|
||||
iconName: "Copy",
|
||||
iconName: copyToLabel,
|
||||
onCommandClick: () => this.copyNotebook(),
|
||||
commandButtonLabel: copyToLabel,
|
||||
hasPopup: false,
|
||||
|
||||
Reference in New Issue
Block a user