Moves visualizers into their own package.

This commit is contained in:
Henning Dieterichs
2020-03-20 19:09:13 +01:00
parent 6c30519b93
commit 6b210fdbb9
38 changed files with 299 additions and 192 deletions

View File

@@ -4,5 +4,6 @@
},
"plantuml.diagramsRoot": "docs",
"plantuml.exportFormat": "png",
"plantuml.exportOutDir": "docs/exported"
"plantuml.exportOutDir": "docs/exported",
"typescript.updateImportsOnFileMove.enabled": "prompt"
}

View File

@@ -3,7 +3,8 @@
"workspaces": [
"./data-extraction",
"./extension",
"./webview"
"./webview",
"./visualization"
],
"scripts": {
"build": "yarn build-data-extraction && yarn build-extension && yarn build-ui",

View File

@@ -0,0 +1,56 @@
{
"name": "@hediet/visualization",
"version": "0.0.1",
"scripts": {
"dev": "tsc --watch",
"build": "tsc"
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"dependencies": {
"@hediet/std": "^0.6.0",
"classnames": "^2.2.6",
"mobx": "^5.15.4",
"mobx-react": "^6.1.8",
"monaco-editor": "^0.20.0",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-measure": "^2.3.0",
"react-svg-pan-zoom": "^3.8.0",
"viz.js": "^2.1.2",
"line-column": "^1.0.2",
"vis-network": "^7.3.6",
"vis-data": "^6.4.1",
"react-plotly.js": "^2.4.0",
"plotly.js": "^1.52.2"
},
"devDependencies": {
"@types/plotly.js": "1.44.28",
"@types/react-plotly.js": "^2.2.4",
"@types/html-webpack-plugin": "^3.2.2",
"@types/react-measure": "^2.0.6",
"@types/react-svg-pan-zoom": "^3.3.0",
"@types/webpack": "^4.41.6",
"@types/classnames": "^2.2.9",
"@types/react": "^16.9.22",
"@types/react-dom": "^16.9.5",
"@types/line-column": "^1.0.0",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.4.2",
"file-loader": "^5.1.0",
"fork-ts-checker-webpack-plugin": "^4.0.4",
"html-webpack-plugin": "^3.2.0",
"monaco-editor-webpack-plugin": "^1.9.0",
"node-sass": "^4.13.1",
"raw-loader": "^4.0.0",
"sass": "^1.25.0",
"sass-loader": "^8.0.2",
"style-loader": "^1.1.3",
"ts-loader": "^6.2.1",
"ts-node": "^8.6.2",
"typescript": "^3.8.2",
"webpack": "^4.41.6",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3"
}
}

View File

@@ -0,0 +1,30 @@
import * as React from "react";
import { observable, runInAction } from "mobx";
import { observer } from "mobx-react";
export function makeLazyLoadable<TProps>(
selector: () => Promise<React.ComponentClass<TProps>>
): React.ComponentClass<TProps> {
@observer
class MyComponent extends React.Component<TProps> {
@observable
component: React.ComponentClass<TProps> | undefined;
async componentDidMount() {
const result = await selector();
runInAction("Set Lazily Loaded Component", () => {
this.component = result;
});
}
render() {
if (!this.component) {
return <div>Loading...</div>;
}
const C = this.component;
return <C {...this.props} />;
}
}
return MyComponent;
}

View File

@@ -19,15 +19,15 @@ export interface VisualizationCollector {
addVisualization(visualization: Visualization): void;
}
export abstract class VisualizationProvider {
abstract getVisualizations(
export abstract class Visualizer {
abstract visualize(
data: ExtractedData,
collector: VisualizationCollector
): void;
getVisualizationsArray(data: ExtractedData): Visualization[] {
const result = new Array<Visualization>();
this.getVisualizations(data, {
this.visualize(data, {
addVisualization(visualization) {
result.push(visualization);
},
@@ -58,19 +58,14 @@ export abstract class VisualizationProvider {
}
}
export class ComposedVisualizationProvider extends VisualizationProvider {
constructor(
private readonly composedProviders: ReadonlyArray<VisualizationProvider>
) {
export class ComposedVisualizer extends Visualizer {
constructor(private readonly composedProviders: ReadonlyArray<Visualizer>) {
super();
}
getVisualizations(
data: ExtractedData,
collector: VisualizationCollector
): void {
visualize(data: ExtractedData, collector: VisualizationCollector): void {
for (const c of this.composedProviders) {
c.getVisualizations(data, collector);
c.visualize(data, collector);
}
}
}

View File

@@ -0,0 +1,7 @@
import * as React from "react";
export class VisualizerView extends React.Component {
render(): React.ReactNode {
return null;
}
}

View File

@@ -0,0 +1,3 @@
export * from "./visualizers";
export * from "./Visualizer";
export * from "./VisualizerView";

View File

@@ -1,8 +1,8 @@
import {
VisualizationProvider,
Visualizer,
VisualizationCollector,
asVisualizationId,
} from "./Visualizer";
} from "../Visualizer";
import {
ExtractedData,
isCommonDataType,
@@ -10,18 +10,15 @@ import {
} from "@hediet/debug-visualizer-data-extraction";
import { createTreeViewModelFromTreeNodeData } from "./TreeVisualizer/TreeVisualizer";
import { TreeWithPathView, TreeViewModel } from "./TreeVisualizer/Views";
import React = require("react");
import * as React from "react";
import { observer, disposeOnUnmount } from "mobx-react";
import { observable, autorun, trace } from "mobx";
import * as monaco from "monaco-editor";
import { getLanguageId } from "./text-visualizers/MonacoTextVisualizer";
import LineColumn = require("line-column");
import * as LineColumn from "line-column";
export class AstVisualizer extends VisualizationProvider {
getVisualizations(
data: ExtractedData,
collector: VisualizationCollector
): void {
export class AstVisualizer extends Visualizer {
visualize(data: ExtractedData, collector: VisualizationCollector): void {
if (isCommonDataType(data, { ast: true })) {
collector.addVisualization({
id: asVisualizationId("ast"),

View File

@@ -1,23 +1,20 @@
import {
VisualizationProvider,
Visualizer,
VisualizationCollector,
asVisualizationId,
} from "./Visualizer";
} from "../Visualizer";
import {
ExtractedData,
isCommonDataType,
CommonDataTypes,
} from "@hediet/debug-visualizer-data-extraction";
import React = require("react");
import * as React from "react";
import { observer } from "mobx-react";
import { computed, action, observable } from "mobx";
import { Icon } from "@blueprintjs/core";
export class GridVisualizer extends VisualizationProvider {
getVisualizations(
data: ExtractedData,
collector: VisualizationCollector
): void {
export class GridVisualizer extends Visualizer {
visualize(data: ExtractedData, collector: VisualizationCollector): void {
if (isCommonDataType(data, { array: true })) {
collector.addVisualization({
id: asVisualizationId("grid"),

View File

@@ -1,23 +1,20 @@
import Measure, { ContentRect } from "react-measure";
import { observer } from "mobx-react";
import React = require("react");
import * as React from "react";
import { observable, action } from "mobx";
import { Tool, ReactSVGPanZoom, Value } from "react-svg-pan-zoom";
import {
VisualizationProvider,
Visualizer,
VisualizationCollector,
asVisualizationId,
} from "./Visualizer";
} from "../Visualizer";
import {
ExtractedData,
isCommonDataType,
} from "@hediet/debug-visualizer-data-extraction";
export class SvgVisualizer extends VisualizationProvider {
getVisualizations(
data: ExtractedData,
collector: VisualizationCollector
): void {
export class SvgVisualizer extends Visualizer {
visualize(data: ExtractedData, collector: VisualizationCollector): void {
if (isCommonDataType(data, { svg: true })) {
collector.addVisualization({
id: asVisualizationId("svg"),

View File

@@ -10,17 +10,14 @@ import {
TreeNode,
} from "@hediet/debug-visualizer-data-extraction";
import {
VisualizationProvider,
Visualizer,
VisualizationCollector,
asVisualizationId,
} from "../Visualizer";
import React = require("react");
} from "../../Visualizer";
import * as React from "react";
export class TreeVisualizer extends VisualizationProvider {
getVisualizations(
data: ExtractedData,
collector: VisualizationCollector
): void {
export class TreeVisualizer extends Visualizer {
visualize(data: ExtractedData, collector: VisualizationCollector): void {
if (isCommonDataType(data, { tree: true })) {
collector.addVisualization({
id: asVisualizationId("tree"),

View File

@@ -1,10 +1,10 @@
import { observer, disposeOnUnmount } from "mobx-react";
import { observable, autorun, computed, action, runInAction } from "mobx";
import React = require("react");
import classNames = require("classnames");
import { Rectangle, Point } from "../../components/Point";
import { SvgLine } from "../../components/SvgElements";
import "./style.scss";
import * as React from "react";
import * as classNames from "classnames";
import { Rectangle, Point } from "../../utils/Point";
import { SvgLine } from "../../utils/SvgElements";
// import "./style.scss";
export class TreeViewModel<TData = unknown> {
private started = true;

View File

@@ -1,29 +1,19 @@
import { observer, disposeOnUnmount } from "mobx-react";
import * as React from "react";
import { observable, autorun, runInAction } from "mobx";
import Viz from "viz.js";
import { Module, render } from "viz.js/full.render.js";
import { SvgViewer } from "../SvgVisualizer";
import {
VisualizationProvider,
Visualizer,
VisualizationCollector,
asVisualizationId,
} from "../Visualizer";
} from "../../Visualizer";
import {
ExtractedData,
isCommonDataType,
} from "@hediet/debug-visualizer-data-extraction";
const viz: any = new Viz({
Module: () => Module({ TOTAL_MEMORY: 1 << 30 }),
render,
});
export class GraphvizDotVisualizer extends VisualizationProvider {
getVisualizations(
data: ExtractedData,
collector: VisualizationCollector
): void {
export class GraphvizDotVisualizer extends Visualizer {
visualize(data: ExtractedData, collector: VisualizationCollector): void {
if (isCommonDataType(data, { dotGraph: true })) {
collector.addVisualization({
id: asVisualizationId("graphviz-dot"),
@@ -37,6 +27,27 @@ export class GraphvizDotVisualizer extends VisualizationProvider {
}
}
class VisLoader {
private result: any | undefined;
async getViz(): Promise<any> {
if (!this.result) {
const Viz = await import("viz.js");
const { Module, render } = await import("viz.js/full.render.js");
const viz = new Viz.default({
Module: () => Module({ TOTAL_MEMORY: 1 << 30 }),
render,
});
this.result = viz;
}
return this.result;
}
}
const vizLoader = new VisLoader();
@observer
export class GraphvizDotViewer extends React.Component<{
dotCode: string;
@@ -47,6 +58,7 @@ export class GraphvizDotViewer extends React.Component<{
@disposeOnUnmount
// @ts-ignore
private readonly _updateSvgAutorun = autorun(async () => {
const viz = await vizLoader.getViz();
const svg = await viz.renderString(this.props.dotCode);
runInAction("Update svg", () => (this.svg = svg));
});

View File

@@ -2,20 +2,17 @@ import { observer } from "mobx-react";
import * as React from "react";
import { GraphvizDotViewer } from "./GraphvizDotVisualizer";
import {
VisualizationProvider,
Visualizer,
VisualizationCollector,
asVisualizationId,
} from "../Visualizer";
} from "../../Visualizer";
import {
ExtractedData,
isCommonDataType,
} from "@hediet/debug-visualizer-data-extraction";
export class GraphvizGraphVisualizer extends VisualizationProvider {
getVisualizations(
data: ExtractedData,
collector: VisualizationCollector
): void {
export class GraphvizGraphVisualizer extends Visualizer {
visualize(data: ExtractedData, collector: VisualizationCollector): void {
if (isCommonDataType(data, { graph: true })) {
collector.addVisualization({
id: asVisualizationId("graphviz-graph"),

View File

@@ -1,40 +1,10 @@
import { DataSet, Network, Options } from "vis-network";
import { observer } from "mobx-react";
import * as React from "react";
import {
VisualizationProvider,
VisualizationCollector,
asVisualizationId,
} from "../Visualizer";
import {
ExtractedData,
isCommonDataType,
NodeGraphData,
EdgeGraphData,
} from "@hediet/debug-visualizer-data-extraction";
import { DataSet, Network, Options } from "vis-network";
export class VisJsGraphVisualizer extends VisualizationProvider {
getVisualizations(
data: ExtractedData,
collector: VisualizationCollector
): void {
if (isCommonDataType(data, { graph: true })) {
collector.addVisualization({
id: asVisualizationId("vis-js-graph"),
name: "vis.js",
priority: 1001,
render() {
return (
<VisJsGraphViewer
edges={data.edges}
nodes={data.nodes}
/>
);
},
});
}
}
}
@observer
export class VisJsGraphViewer extends React.Component<{

View File

@@ -0,0 +1,36 @@
import * as React from "react";
import {
Visualizer,
VisualizationCollector,
asVisualizationId,
} from "../../Visualizer";
import {
ExtractedData,
isCommonDataType,
} from "@hediet/debug-visualizer-data-extraction";
import { makeLazyLoadable } from "../../LazyLoadable";
// import { DataSet, Network, Options } from "vis-network";
const VisJsGraphViewerLazyLoadable = makeLazyLoadable(
async () => (await import("./VisJsGraphViewer")).VisJsGraphViewer
);
export class VisJsGraphVisualizer extends Visualizer {
visualize(data: ExtractedData, collector: VisualizationCollector): void {
if (isCommonDataType(data, { graph: true })) {
collector.addVisualization({
id: asVisualizationId("vis-js-graph"),
name: "vis.js",
priority: 1001,
render() {
return (
<VisJsGraphViewerLazyLoadable
edges={data.edges}
nodes={data.nodes}
/>
);
},
});
}
}
}

View File

@@ -1,5 +1,5 @@
import "./style.scss";
import { ComposedVisualizationProvider } from "./Visualizer";
// import "./style.scss";
import { ComposedVisualizer } from "../Visualizer";
import { TreeVisualizer } from "./TreeVisualizer/TreeVisualizer";
import { GraphvizGraphVisualizer } from "./graph-visualizers/GraphvizGraphVisualizer";
import { SvgVisualizer } from "./SvgVisualizer";
@@ -8,10 +8,10 @@ import { TextVisualizer } from "./text-visualizers/TextVisualizer";
import { MonacoTextVisualizer } from "./text-visualizers/MonacoTextVisualizer";
import { AstVisualizer } from "./AstVisualizer";
import { VisJsGraphVisualizer } from "./graph-visualizers/VisJsGraphVisualizer";
import { PlotlyVisualizer } from "./PlotlyVisualizer";
import { PlotlyVisualizer } from "./plotly";
import { GridVisualizer } from "./GridVisualizer";
export const knownVisualizations = new ComposedVisualizationProvider([
export const knownVisualizations = new ComposedVisualizer([
new TreeVisualizer(),
new GraphvizGraphVisualizer(),
new VisJsGraphVisualizer(),

View File

@@ -0,0 +1,19 @@
import { observer } from "mobx-react";
import * as React from "react";
import Plot from "react-plotly.js";
@observer
export class PlotlyViewer extends React.Component<{
data: Partial<Plotly.Data>[];
}> {
render() {
return (
<Plot
style={{ width: "100%" }}
data={this.props.data}
layout={{}}
config={{ responsive: true }}
/>
);
}
}

View File

@@ -0,0 +1,30 @@
import * as React from "react";
import {
Visualizer,
VisualizationCollector,
asVisualizationId,
} from "../../Visualizer";
import {
ExtractedData,
isCommonDataType,
} from "@hediet/debug-visualizer-data-extraction";
import { makeLazyLoadable } from "../../LazyLoadable";
const PlotlyViewerLazyLoadable = makeLazyLoadable(
async () => (await import("./PlotlyViewer")).PlotlyViewer
);
export class PlotlyVisualizer extends Visualizer {
visualize(data: ExtractedData, collector: VisualizationCollector): void {
if (isCommonDataType(data, { plotly: true })) {
collector.addVisualization({
id: asVisualizationId("plotly"),
name: "plotly",
priority: 1001,
render() {
return <PlotlyViewerLazyLoadable data={data.data} />;
},
});
}
}
}

View File

@@ -1,22 +1,19 @@
import {
VisualizationProvider,
Visualizer,
VisualizationCollector,
asVisualizationId,
} from "../Visualizer";
} from "../../Visualizer";
import {
ExtractedData,
isCommonDataType,
} from "@hediet/debug-visualizer-data-extraction";
import * as monaco from "monaco-editor";
import React = require("react");
import * as React from "react";
import { observer, disposeOnUnmount } from "mobx-react";
import { autorun, observable } from "mobx";
export class MonacoTextVisualizer extends VisualizationProvider {
getVisualizations(
data: ExtractedData,
collector: VisualizationCollector
): void {
export class MonacoTextVisualizer extends Visualizer {
visualize(data: ExtractedData, collector: VisualizationCollector): void {
if (isCommonDataType(data, { text: true })) {
collector.addVisualization({
id: asVisualizationId("monaco-text"),

View File

@@ -1,19 +1,16 @@
import {
VisualizationProvider,
Visualizer,
VisualizationCollector,
asVisualizationId,
} from "../Visualizer";
} from "../../Visualizer";
import {
ExtractedData,
isCommonDataType,
} from "@hediet/debug-visualizer-data-extraction";
import React = require("react");
import * as React from "react";
export class TextVisualizer extends VisualizationProvider {
getVisualizations(
data: ExtractedData,
collector: VisualizationCollector
): void {
export class TextVisualizer extends Visualizer {
visualize(data: ExtractedData, collector: VisualizationCollector): void {
if (isCommonDataType(data, { text: true })) {
collector.addVisualization({
id: asVisualizationId("text"),

2
visualization/style.scss Normal file
View File

@@ -0,0 +1,2 @@
@import "./src/visualizers/style.scss";
@import "./src/visualizers/TreeVisualizer/style.scss";

View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "es2020",
"moduleResolution": "node",
"strict": true,
"outDir": "dist",
"skipLibCheck": true,
"rootDir": "./src",
"newLine": "LF",
"sourceMap": true,
"jsx": "react",
"experimentalDecorators": true,
"declaration": true,
"declarationMap": true,
"allowSyntheticDefaultImports": true
},
"include": ["src/**/*"]
}

View File

@@ -19,26 +19,15 @@
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-measure": "^2.3.0",
"react-svg-pan-zoom": "^3.8.0",
"viz.js": "^2.1.2",
"line-column": "^1.0.2",
"vis-network": "^7.3.6",
"vis-data": "^6.4.1",
"react-plotly.js": "^2.4.0",
"plotly.js": "^1.52.2",
"@hediet/debug-visualizer-data-extraction": "*"
},
"devDependencies": {
"@types/plotly.js": "1.44.28",
"@types/react-plotly.js": "^2.2.4",
"@types/html-webpack-plugin": "^3.2.2",
"@types/react-measure": "^2.0.6",
"@types/react-svg-pan-zoom": "^3.3.0",
"@types/webpack": "^4.41.6",
"@types/classnames": "^2.2.9",
"@types/react": "^16.9.22",
"@types/react-dom": "^16.9.5",
"@types/line-column": "^1.0.0",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.4.2",
"file-loader": "^5.1.0",

View File

@@ -1,4 +1,4 @@
import React = require("react");
import * as React from "react";
import { Model } from "../model/Model";
import { observer, disposeOnUnmount } from "mobx-react";
import { observable, action, autorun } from "mobx";

View File

@@ -1,4 +1,4 @@
import React = require("react");
import * as React from "react";
import { Button, Spinner } from "@blueprintjs/core";
import { observable, action } from "mobx";
import { observer } from "mobx-react";

View File

@@ -1,4 +1,4 @@
import React = require("react");
import * as React from "react";
import { observer } from "mobx-react";
import { observable } from "mobx";
import Measure from "react-measure";

View File

@@ -1,4 +1,4 @@
import React = require("react");
import * as React from "react";
import { Model } from "../model/Model";
import { observer } from "mobx-react";
import { NoData } from "./NoData";

View File

@@ -1,10 +1,10 @@
import React = require("react");
import * as React from "react";
import { Popover } from "@blueprintjs/core";
import { DataExtractorInfo } from "@hediet/debug-visualizer-data-extraction";
import { computed } from "mobx";
import { observer } from "mobx-react";
import { Model } from "../model/Model";
import { VisualizationId } from "../visualizers/Visualizer";
import { VisualizationId } from "@hediet/visualization";
@observer
export class VisualizerHeaderDetails extends React.Component<{ model: Model }> {

View File

@@ -4,10 +4,13 @@ import {
} from "debug-visualizer/src/contract";
import { WebSocketStream } from "@hediet/typed-json-rpc-websocket";
import { ConsoleRpcLogger } from "@hediet/typed-json-rpc";
import { observable, action, computed, when, autorun } from "mobx";
import { observable, action, computed, when } from "mobx";
import { DataExtractorId } from "@hediet/debug-visualizer-data-extraction";
import { Visualization, VisualizationId } from "../visualizers/Visualizer";
import { knownVisualizations } from "../visualizers";
import {
Visualization,
VisualizationId,
knownVisualizations,
} from "@hediet/visualization";
import { getApi as getVsCodeApi } from "./VsCodeApi";
import { MonacoBridge } from "./MonacoBridge";
import { Disposable } from "@hediet/std/disposable";

View File

@@ -1,6 +1,6 @@
import React = require("react");
import * as React from "react";
import "../style.scss";
import { DecoratedGridComponent } from "../visualizers/GridVisualizer";
import { DecoratedGridComponent } from "@hediet/visualization";
import { observable } from "mobx";
import { observer } from "mobx-react";

View File

@@ -1,6 +1,7 @@
@import "~normalize.css";
@import "~@blueprintjs/core/lib/css/blueprint.css";
@import "~@blueprintjs/icons/lib/css/blueprint-icons.css";
@import "~@hediet/visualization/style.scss";
html,
body,

View File

@@ -1,46 +0,0 @@
import { observer } from "mobx-react";
import * as React from "react";
import {
VisualizationProvider,
VisualizationCollector,
asVisualizationId,
} from "./Visualizer";
import {
ExtractedData,
isCommonDataType,
} from "@hediet/debug-visualizer-data-extraction";
import Plot from "react-plotly.js";
export class PlotlyVisualizer extends VisualizationProvider {
getVisualizations(
data: ExtractedData,
collector: VisualizationCollector
): void {
if (isCommonDataType(data, { plotly: true })) {
collector.addVisualization({
id: asVisualizationId("plotly"),
name: "plotly",
priority: 1001,
render() {
return <PlotlyViewer data={data.data} />;
},
});
}
}
}
@observer
export class PlotlyViewer extends React.Component<{
data: Partial<Plotly.Data>[];
}> {
render() {
return (
<Plot
style={{ width: "100%" }}
data={this.props.data}
layout={{}}
config={{ responsive: true }}
/>
);
}
}